Skip to content

Commit 5afac72

Browse files
MichaelZaidmanJiri Kosina
authored andcommitted
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: Germain Hebert <[email protected]> Signed-off-by: Germain Hebert <[email protected]> Signed-off-by: Michael Zaidman <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent c2500bd commit 5afac72

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

drivers/hid/hid-ft260.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ static int ft260_i2c_reset(struct hid_device *hdev)
303303
return ret;
304304
}
305305

306-
static int ft260_xfer_status(struct ft260_device *dev)
306+
static int ft260_xfer_status(struct ft260_device *dev, u8 bus_busy)
307307
{
308308
struct hid_device *hdev = dev->hdev;
309309
struct ft260_get_i2c_status_report report;
@@ -334,7 +334,7 @@ static int ft260_xfer_status(struct ft260_device *dev)
334334
ft260_dbg("bus_status %#02x, clock %u\n", report.bus_status,
335335
dev->clock);
336336

337-
if (report.bus_status & FT260_I2C_STATUS_CTRL_BUSY)
337+
if (report.bus_status & (FT260_I2C_STATUS_CTRL_BUSY | bus_busy))
338338
return -EAGAIN;
339339

340340
/*
@@ -369,8 +369,11 @@ static int ft260_hid_output_report(struct hid_device *hdev, u8 *data,
369369
static int ft260_hid_output_report_check_status(struct ft260_device *dev,
370370
u8 *data, int len)
371371
{
372+
u8 bus_busy;
372373
int ret, usec, try = 100;
373374
struct hid_device *hdev = dev->hdev;
375+
struct ft260_i2c_write_request_report *rep =
376+
(struct ft260_i2c_write_request_report *)data;
374377

375378
ret = ft260_hid_output_report(hdev, data, len);
376379
if (ret < 0) {
@@ -388,8 +391,18 @@ static int ft260_hid_output_report_check_status(struct ft260_device *dev,
388391
ft260_dbg("wait %d usec, len %d\n", usec, len);
389392
}
390393

394+
/*
395+
* Do not check the busy bit for combined transactions
396+
* since the controller keeps the bus busy between writing
397+
* and reading IOs to ensure an atomic operation.
398+
*/
399+
if (rep->flag == FT260_FLAG_START)
400+
bus_busy = 0;
401+
else
402+
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
403+
391404
do {
392-
ret = ft260_xfer_status(dev);
405+
ret = ft260_xfer_status(dev, bus_busy);
393406
if (ret != -EAGAIN)
394407
break;
395408
} while (--try);
@@ -488,6 +501,7 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
488501
int timeout, ret = 0;
489502
struct ft260_i2c_read_request_report rep;
490503
struct hid_device *hdev = dev->hdev;
504+
u8 bus_busy = 0;
491505

492506
if ((flag & FT260_FLAG_START_REPEATED) == FT260_FLAG_START_REPEATED)
493507
flag = FT260_FLAG_START_REPEATED;
@@ -531,7 +545,10 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
531545

532546
dev->read_buf = NULL;
533547

534-
ret = ft260_xfer_status(dev);
548+
if (flag & FT260_FLAG_STOP)
549+
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
550+
551+
ret = ft260_xfer_status(dev, bus_busy);
535552
if (ret < 0) {
536553
ret = -EIO;
537554
ft260_i2c_reset(hdev);
@@ -1003,7 +1020,7 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
10031020
mutex_init(&dev->lock);
10041021
init_completion(&dev->wait);
10051022

1006-
ret = ft260_xfer_status(dev);
1023+
ret = ft260_xfer_status(dev, FT260_I2C_STATUS_BUS_BUSY);
10071024
if (ret)
10081025
ft260_i2c_reset(hdev);
10091026

0 commit comments

Comments
 (0)