Commit 5afac727 authored by Michael Zaidman's avatar Michael Zaidman Committed by Jiri Kosina

HID: ft260: missed NACK from busy device

When writing into a slow device like an EEPROM chip, the
controller may exit the busy state before the device releases
the bus. In this case, the ft260_xfer_status returns success
before the data transfer completion.

The patch fixes it by returning from the ft260_xfer_status()
with the "-EAGAIN" on both controller and bus busy status when
appropriate.

It does not apply to the i2c combined transactions when after
the write IO, the controller keeps the bus busy until the read
IO and then between reading IOs to ensure an atomic operation.
Co-developed-by: default avatarGermain Hebert <germain.hebert@ca.abb.com>
Signed-off-by: default avatarGermain Hebert <germain.hebert@ca.abb.com>
Signed-off-by: default avatarMichael Zaidman <michael.zaidman@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent c2500bdf
...@@ -303,7 +303,7 @@ static int ft260_i2c_reset(struct hid_device *hdev) ...@@ -303,7 +303,7 @@ static int ft260_i2c_reset(struct hid_device *hdev)
return ret; return ret;
} }
static int ft260_xfer_status(struct ft260_device *dev) static int ft260_xfer_status(struct ft260_device *dev, u8 bus_busy)
{ {
struct hid_device *hdev = dev->hdev; struct hid_device *hdev = dev->hdev;
struct ft260_get_i2c_status_report report; struct ft260_get_i2c_status_report report;
...@@ -334,7 +334,7 @@ static int ft260_xfer_status(struct ft260_device *dev) ...@@ -334,7 +334,7 @@ static int ft260_xfer_status(struct ft260_device *dev)
ft260_dbg("bus_status %#02x, clock %u\n", report.bus_status, ft260_dbg("bus_status %#02x, clock %u\n", report.bus_status,
dev->clock); dev->clock);
if (report.bus_status & FT260_I2C_STATUS_CTRL_BUSY) if (report.bus_status & (FT260_I2C_STATUS_CTRL_BUSY | bus_busy))
return -EAGAIN; return -EAGAIN;
/* /*
...@@ -369,8 +369,11 @@ static int ft260_hid_output_report(struct hid_device *hdev, u8 *data, ...@@ -369,8 +369,11 @@ static int ft260_hid_output_report(struct hid_device *hdev, u8 *data,
static int ft260_hid_output_report_check_status(struct ft260_device *dev, static int ft260_hid_output_report_check_status(struct ft260_device *dev,
u8 *data, int len) u8 *data, int len)
{ {
u8 bus_busy;
int ret, usec, try = 100; int ret, usec, try = 100;
struct hid_device *hdev = dev->hdev; struct hid_device *hdev = dev->hdev;
struct ft260_i2c_write_request_report *rep =
(struct ft260_i2c_write_request_report *)data;
ret = ft260_hid_output_report(hdev, data, len); ret = ft260_hid_output_report(hdev, data, len);
if (ret < 0) { if (ret < 0) {
...@@ -388,8 +391,18 @@ static int ft260_hid_output_report_check_status(struct ft260_device *dev, ...@@ -388,8 +391,18 @@ static int ft260_hid_output_report_check_status(struct ft260_device *dev,
ft260_dbg("wait %d usec, len %d\n", usec, len); ft260_dbg("wait %d usec, len %d\n", usec, len);
} }
/*
* Do not check the busy bit for combined transactions
* since the controller keeps the bus busy between writing
* and reading IOs to ensure an atomic operation.
*/
if (rep->flag == FT260_FLAG_START)
bus_busy = 0;
else
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
do { do {
ret = ft260_xfer_status(dev); ret = ft260_xfer_status(dev, bus_busy);
if (ret != -EAGAIN) if (ret != -EAGAIN)
break; break;
} while (--try); } while (--try);
...@@ -488,6 +501,7 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data, ...@@ -488,6 +501,7 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
int timeout, ret = 0; int timeout, ret = 0;
struct ft260_i2c_read_request_report rep; struct ft260_i2c_read_request_report rep;
struct hid_device *hdev = dev->hdev; struct hid_device *hdev = dev->hdev;
u8 bus_busy = 0;
if ((flag & FT260_FLAG_START_REPEATED) == FT260_FLAG_START_REPEATED) if ((flag & FT260_FLAG_START_REPEATED) == FT260_FLAG_START_REPEATED)
flag = FT260_FLAG_START_REPEATED; flag = FT260_FLAG_START_REPEATED;
...@@ -531,7 +545,10 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data, ...@@ -531,7 +545,10 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
dev->read_buf = NULL; dev->read_buf = NULL;
ret = ft260_xfer_status(dev); if (flag & FT260_FLAG_STOP)
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
ret = ft260_xfer_status(dev, bus_busy);
if (ret < 0) { if (ret < 0) {
ret = -EIO; ret = -EIO;
ft260_i2c_reset(hdev); ft260_i2c_reset(hdev);
...@@ -1003,7 +1020,7 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1003,7 +1020,7 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
mutex_init(&dev->lock); mutex_init(&dev->lock);
init_completion(&dev->wait); init_completion(&dev->wait);
ret = ft260_xfer_status(dev); ret = ft260_xfer_status(dev, FT260_I2C_STATUS_BUS_BUSY);
if (ret) if (ret)
ft260_i2c_reset(hdev); ft260_i2c_reset(hdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment