Skip to content

Commit ff18ab5

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.8/i2c-hid' into for-linus
- rework of wait-for-reset in order to reduce the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET qurk; the success rate is now 50% better, but there are still further improvements to be made (Hans de Goede)
2 parents 82a18fc + 7d7a252 commit ff18ab5

File tree

1 file changed

+70
-67
lines changed

1 file changed

+70
-67
lines changed

drivers/hid/i2c-hid/i2c-hid-core.c

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,11 @@
4444
#include "i2c-hid.h"
4545

4646
/* quirks to control the device */
47-
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
48-
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
49-
#define I2C_HID_QUIRK_BOGUS_IRQ BIT(4)
50-
#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5)
51-
#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6)
52-
#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7)
47+
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(0)
48+
#define I2C_HID_QUIRK_BOGUS_IRQ BIT(1)
49+
#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(2)
50+
#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3)
51+
#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4)
5352

5453
/* Command opcodes */
5554
#define I2C_HID_OPCODE_RESET 0x01
@@ -120,8 +119,6 @@ static const struct i2c_hid_quirks {
120119
__u16 idProduct;
121120
__u32 quirks;
122121
} i2c_hid_quirks[] = {
123-
{ USB_VENDOR_ID_WEIDA, HID_ANY_ID,
124-
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
125122
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
126123
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
127124
{ I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15,
@@ -395,8 +392,7 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)
395392
* The call will get a return value (EREMOTEIO) but device will be
396393
* triggered and activated. After that, it goes like a normal device.
397394
*/
398-
if (power_state == I2C_HID_PWR_ON &&
399-
ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
395+
if (power_state == I2C_HID_PWR_ON) {
400396
ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON);
401397

402398
/* Device was already activated */
@@ -426,12 +422,23 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)
426422
return ret;
427423
}
428424

429-
static int i2c_hid_execute_reset(struct i2c_hid *ihid)
425+
static int i2c_hid_start_hwreset(struct i2c_hid *ihid)
430426
{
431427
size_t length = 0;
432428
int ret;
433429

434-
i2c_hid_dbg(ihid, "resetting...\n");
430+
i2c_hid_dbg(ihid, "%s\n", __func__);
431+
432+
/*
433+
* This prevents sending feature reports while the device is
434+
* being reset. Otherwise we may lose the reset complete
435+
* interrupt.
436+
*/
437+
lockdep_assert_held(&ihid->reset_lock);
438+
439+
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
440+
if (ret)
441+
return ret;
435442

436443
/* Prepare reset command. Command register goes first. */
437444
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
@@ -444,60 +451,40 @@ static int i2c_hid_execute_reset(struct i2c_hid *ihid)
444451

445452
ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
446453
if (ret) {
447-
dev_err(&ihid->client->dev, "failed to reset device.\n");
448-
goto out;
449-
}
450-
451-
if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
452-
msleep(100);
453-
goto out;
454+
dev_err(&ihid->client->dev,
455+
"failed to reset device: %d\n", ret);
456+
goto err_clear_reset;
454457
}
455458

456-
i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
457-
if (!wait_event_timeout(ihid->wait,
458-
!test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
459-
msecs_to_jiffies(5000))) {
460-
ret = -ENODATA;
461-
goto out;
462-
}
463-
i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
459+
return 0;
464460

465-
out:
461+
err_clear_reset:
466462
clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
463+
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
467464
return ret;
468465
}
469466

470-
static int i2c_hid_hwreset(struct i2c_hid *ihid)
467+
static int i2c_hid_finish_hwreset(struct i2c_hid *ihid)
471468
{
472-
int ret;
469+
int ret = 0;
473470

474-
i2c_hid_dbg(ihid, "%s\n", __func__);
475-
476-
/*
477-
* This prevents sending feature reports while the device is
478-
* being reset. Otherwise we may lose the reset complete
479-
* interrupt.
480-
*/
481-
mutex_lock(&ihid->reset_lock);
482-
483-
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
484-
if (ret)
485-
goto out_unlock;
471+
i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
486472

487-
ret = i2c_hid_execute_reset(ihid);
488-
if (ret) {
489-
dev_err(&ihid->client->dev,
490-
"failed to reset device: %d\n", ret);
491-
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
492-
goto out_unlock;
473+
if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
474+
msleep(100);
475+
clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
476+
} else if (!wait_event_timeout(ihid->wait,
477+
!test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
478+
msecs_to_jiffies(1000))) {
479+
dev_warn(&ihid->client->dev, "device did not ack reset within 1000 ms\n");
480+
clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
493481
}
482+
i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
494483

495484
/* At least some SIS devices need this after reset */
496485
if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
497486
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
498487

499-
out_unlock:
500-
mutex_unlock(&ihid->reset_lock);
501488
return ret;
502489
}
503490

@@ -729,11 +716,10 @@ static int i2c_hid_parse(struct hid_device *hid)
729716
struct i2c_client *client = hid->driver_data;
730717
struct i2c_hid *ihid = i2c_get_clientdata(client);
731718
struct i2c_hid_desc *hdesc = &ihid->hdesc;
719+
char *rdesc = NULL, *use_override = NULL;
732720
unsigned int rsize;
733-
char *rdesc;
734721
int ret;
735722
int tries = 3;
736-
char *use_override;
737723

738724
i2c_hid_dbg(ihid, "entering %s\n", __func__);
739725

@@ -743,14 +729,15 @@ static int i2c_hid_parse(struct hid_device *hid)
743729
return -EINVAL;
744730
}
745731

732+
mutex_lock(&ihid->reset_lock);
746733
do {
747-
ret = i2c_hid_hwreset(ihid);
734+
ret = i2c_hid_start_hwreset(ihid);
748735
if (ret)
749736
msleep(1000);
750737
} while (tries-- > 0 && ret);
751738

752739
if (ret)
753-
return ret;
740+
goto abort_reset;
754741

755742
use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
756743
&rsize);
@@ -762,8 +749,8 @@ static int i2c_hid_parse(struct hid_device *hid)
762749
rdesc = kzalloc(rsize, GFP_KERNEL);
763750

764751
if (!rdesc) {
765-
dbg_hid("couldn't allocate rdesc memory\n");
766-
return -ENOMEM;
752+
ret = -ENOMEM;
753+
goto abort_reset;
767754
}
768755

769756
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
@@ -773,23 +760,34 @@ static int i2c_hid_parse(struct hid_device *hid)
773760
rdesc, rsize);
774761
if (ret) {
775762
hid_err(hid, "reading report descriptor failed\n");
776-
kfree(rdesc);
777-
return -EIO;
763+
goto abort_reset;
778764
}
779765
}
780766

767+
/*
768+
* Windows directly reads the report-descriptor after sending reset
769+
* and then waits for resets completion afterwards. Some touchpads
770+
* actually wait for the report-descriptor to be read before signalling
771+
* reset completion.
772+
*/
773+
ret = i2c_hid_finish_hwreset(ihid);
774+
abort_reset:
775+
clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
776+
mutex_unlock(&ihid->reset_lock);
777+
if (ret)
778+
goto out;
779+
781780
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
782781

783782
ret = hid_parse_report(hid, rdesc, rsize);
783+
if (ret)
784+
dbg_hid("parsing report descriptor failed\n");
785+
786+
out:
784787
if (!use_override)
785788
kfree(rdesc);
786789

787-
if (ret) {
788-
dbg_hid("parsing report descriptor failed\n");
789-
return ret;
790-
}
791-
792-
return 0;
790+
return ret;
793791
}
794792

795793
static int i2c_hid_start(struct hid_device *hid)
@@ -987,10 +985,15 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)
987985
* However some ALPS touchpads generate IRQ storm without reset, so
988986
* let's still reset them here.
989987
*/
990-
if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
991-
ret = i2c_hid_hwreset(ihid);
992-
else
988+
if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) {
989+
mutex_lock(&ihid->reset_lock);
990+
ret = i2c_hid_start_hwreset(ihid);
991+
if (ret == 0)
992+
ret = i2c_hid_finish_hwreset(ihid);
993+
mutex_unlock(&ihid->reset_lock);
994+
} else {
993995
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
996+
}
994997

995998
if (ret)
996999
return ret;

0 commit comments

Comments
 (0)