diff options
author | Peter Maydell | 2017-01-09 12:56:49 +0100 |
---|---|---|
committer | Peter Maydell | 2017-01-09 12:56:49 +0100 |
commit | 8305f9bdf7ca41ee5cabe018fb37b73472c1162d (patch) | |
tree | 72a6405226f7e5dfe46e6ceaec16b4eeb61c9169 /hw/i2c/core.c | |
parent | Merge remote-tracking branch 'remotes/gonglei/tags/cryptodev-next-20161224' i... (diff) | |
parent | hw/ssi/imx_spi.c: Remove MSGDATA register support (diff) | |
download | qemu-8305f9bdf7ca41ee5cabe018fb37b73472c1162d.tar.gz qemu-8305f9bdf7ca41ee5cabe018fb37b73472c1162d.tar.xz qemu-8305f9bdf7ca41ee5cabe018fb37b73472c1162d.zip |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170109' into staging
target-arm queue:
* i2c: Allow I2C devices to NAK start events
* hw/char: QOM'ify exynos4210_uart.c
* clean up and refactor virt-acpi-build.c
* virt-acpi-build: Don't incorrectly claim architectural timer
to be edge-triggered
* m25p80: Don't let rogue SPI controllers cause buffer overruns
* imx_spi: Remove broken MSGDATA register support
# gpg: Signature made Mon 09 Jan 2017 11:52:49 GMT
# gpg: using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg: aka "Peter Maydell <pmaydell@gmail.com>"
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20170109: (21 commits)
hw/ssi/imx_spi.c: Remove MSGDATA register support
m25p80: don't let rogue SPI controllers cause buffer overruns
hw/arm/virt-acpi-build: Don't incorrectly claim architectural timer to be edge-triggered
hw/arm/virt: remove VirtGuestInfo
hw/arm/virt-acpi-build: don't save VirtGuestInfo on AcpiBuildState
hw/arm/virt-acpi-build: remove redundant members from VirtGuestInfo
hw/arm/virt: pass VirtMachineState instead of VirtGuestInfo
hw/arm/virt: move VirtMachineState/Class to virt.h
hw/arm/virt: remove include/hw/arm/virt-acpi-build.h
hw/arm/virt: eliminate struct VirtGuestInfoState
hw/arm/virt: use VirtMachineState.gic_version
hw/arm/virt: parameter passing cleanups
hw/arm/virt-acpi-build: fadt: improve flag naming
hw/arm/virt-acpi-build: gtdt: improve flag naming
hw/arm/virt-acpi-build: name GIC CPU Interface Structure appropriately
hw/arm/virt-acpi-build: add all missing cpu_to_le's
hw/arm/virt: Don't incorrectly claim architectural timer to be edge-triggered
hw/arm/virt: Rename 'vbi' variables to 'vms'
hw/arm/virt: Merge VirtBoardInfo and VirtMachineState
hw/char: QOM'ify exynos4210_uart.c
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/i2c/core.c')
-rw-r--r-- | hw/i2c/core.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/hw/i2c/core.c b/hw/i2c/core.c index e40781ea3b..2c1234cdff 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -88,18 +88,26 @@ int i2c_bus_busy(I2CBus *bus) return !QLIST_EMPTY(&bus->current_devs); } +/* TODO: Make this handle multiple masters. */ /* - * Returns non-zero if the address is not valid. If this is called - * again without an intervening i2c_end_transfer(), like in the SMBus - * case where the operation is switched from write to read, this - * function will not rescan the bus and thus cannot fail. + * Start or continue an i2c transaction. When this is called for the + * first time or after an i2c_end_transfer(), if it returns an error + * the bus transaction is terminated (or really never started). If + * this is called after another i2c_start_transfer() without an + * intervening i2c_end_transfer(), and it returns an error, the + * transaction will not be terminated. The caller must do it. + * + * This corresponds with the way real hardware works. The SMBus + * protocol uses a start transfer to switch from write to read mode + * without releasing the bus. If that fails, the bus is still + * in a transaction. */ -/* TODO: Make this handle multiple masters. */ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) { BusChild *kid; I2CSlaveClass *sc; I2CNode *node; + bool bus_scanned = false; if (address == I2C_BROADCAST) { /* @@ -130,6 +138,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) } } } + bus_scanned = true; } if (QLIST_EMPTY(&bus->current_devs)) { @@ -137,11 +146,21 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) } QLIST_FOREACH(node, &bus->current_devs, next) { + int rv; + sc = I2C_SLAVE_GET_CLASS(node->elt); /* If the bus is already busy, assume this is a repeated start condition. */ + if (sc->event) { - sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND); + rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND); + if (rv && !bus->broadcast) { + if (bus_scanned) { + /* First call, terminate the transfer. */ + i2c_end_transfer(bus); + } + return rv; + } } } return 0; |