Skip to content

Commit 65d6c17

Browse files
MichaelZaidmangregkh
authored andcommitted
HID: ft260: missed NACK from busy device
[ Upstream commit 5afac72 ] 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 <germain.hebert@ca.abb.com> Signed-off-by: Germain Hebert <germain.hebert@ca.abb.com> Signed-off-by: Michael Zaidman <michael.zaidman@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Stable-dep-of: bf3e39d ("HID: ft260: fix stack-use-after-return write in I2C read race") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1236373 commit 65d6c17

1 file changed

Lines changed: 22 additions & 5 deletions

File tree

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
if (report.bus_status & FT260_I2C_STATUS_BUS_BUSY)
@@ -379,8 +379,11 @@ static int ft260_hid_output_report(struct hid_device *hdev, u8 *data,
379379
static int ft260_hid_output_report_check_status(struct ft260_device *dev,
380380
u8 *data, int len)
381381
{
382+
u8 bus_busy;
382383
int ret, usec, try = 100;
383384
struct hid_device *hdev = dev->hdev;
385+
struct ft260_i2c_write_request_report *rep =
386+
(struct ft260_i2c_write_request_report *)data;
384387

385388
ret = ft260_hid_output_report(hdev, data, len);
386389
if (ret < 0) {
@@ -398,8 +401,18 @@ static int ft260_hid_output_report_check_status(struct ft260_device *dev,
398401
ft260_dbg("wait %d usec, len %d\n", usec, len);
399402
}
400403

404+
/*
405+
* Do not check the busy bit for combined transactions
406+
* since the controller keeps the bus busy between writing
407+
* and reading IOs to ensure an atomic operation.
408+
*/
409+
if (rep->flag == FT260_FLAG_START)
410+
bus_busy = 0;
411+
else
412+
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
413+
401414
do {
402-
ret = ft260_xfer_status(dev);
415+
ret = ft260_xfer_status(dev, bus_busy);
403416
if (ret != -EAGAIN)
404417
break;
405418
} while (--try);
@@ -487,6 +500,7 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
487500
{
488501
struct ft260_i2c_read_request_report rep;
489502
struct hid_device *hdev = dev->hdev;
503+
u8 bus_busy = 0;
490504
int timeout;
491505
int ret = 0;
492506

@@ -525,7 +539,10 @@ static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
525539

526540
dev->read_buf = NULL;
527541

528-
ret = ft260_xfer_status(dev);
542+
if (flag & FT260_FLAG_STOP)
543+
bus_busy = FT260_I2C_STATUS_BUS_BUSY;
544+
545+
ret = ft260_xfer_status(dev, bus_busy);
529546
if (ret < 0) {
530547
ret = -EIO;
531548
ft260_i2c_reset(hdev);
@@ -1004,7 +1021,7 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
10041021
mutex_init(&dev->lock);
10051022
init_completion(&dev->wait);
10061023

1007-
ret = ft260_xfer_status(dev);
1024+
ret = ft260_xfer_status(dev, FT260_I2C_STATUS_BUS_BUSY);
10081025
if (ret)
10091026
ft260_i2c_reset(hdev);
10101027

0 commit comments

Comments
 (0)