Skip to content

Commit 9af867c

Browse files
jhovoldBenjamin Tissoires
authored andcommitted
HID: i2c-hid: fix handling of unpopulated devices
A recent commit reordered probe so that the interrupt line is now requested before making sure that the device exists. This breaks machines like the Lenovo ThinkPad X13s which rely on the HID driver to probe second-source devices and only register the variant that is actually populated. Specifically, the interrupt line may now already be (temporarily) claimed when doing asynchronous probing of the touchpad: genirq: Flags mismatch irq 191. 00082008 (hid-over-i2c) vs. 00082008 (hid-over-i2c) i2c_hid_of 21-0015: Could not register for hid-over-i2c interrupt, irq = 191, ret = -16 i2c_hid_of: probe of 21-0015 failed with error -16 Fix this by restoring the old behaviour of first making sure the device exists before requesting the interrupt line. Note that something like this should probably be implemented also for "panel followers", whose actual probe is currently effectively deferred until the DRM panel is probed (e.g. by powering down the device after making sure it exists and only then register it as a follower). Fixes: 675cd87 ("HID: i2c-hid: Rearrange probe() to power things up later") Cc: Douglas Anderson <[email protected]> Cc: Maxime Ripard <[email protected]> Signed-off-by: Johan Hovold <[email protected]> Tested-by: Dennis Gilmore <[email protected]> Reviewed-by: Douglas Anderson <[email protected]> Tested-by: Douglas Anderson <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent b009aa3 commit 9af867c

File tree

1 file changed

+81
-63
lines changed

1 file changed

+81
-63
lines changed

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

Lines changed: 81 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -998,45 +998,29 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)
998998
return hid_driver_reset_resume(hid);
999999
}
10001000

1001-
/**
1002-
* __do_i2c_hid_core_initial_power_up() - First time power up of the i2c-hid device.
1003-
* @ihid: The ihid object created during probe.
1004-
*
1005-
* This function is called at probe time.
1006-
*
1007-
* The initial power on is where we do some basic validation that the device
1008-
* exists, where we fetch the HID descriptor, and where we create the actual
1009-
* HID devices.
1010-
*
1011-
* Return: 0 or error code.
1001+
/*
1002+
* Check that the device exists and parse the HID descriptor.
10121003
*/
1013-
static int __do_i2c_hid_core_initial_power_up(struct i2c_hid *ihid)
1004+
static int __i2c_hid_core_probe(struct i2c_hid *ihid)
10141005
{
10151006
struct i2c_client *client = ihid->client;
10161007
struct hid_device *hid = ihid->hid;
10171008
int ret;
10181009

1019-
ret = i2c_hid_core_power_up(ihid);
1020-
if (ret)
1021-
return ret;
1022-
10231010
/* Make sure there is something at this address */
10241011
ret = i2c_smbus_read_byte(client);
10251012
if (ret < 0) {
10261013
i2c_hid_dbg(ihid, "nothing at this address: %d\n", ret);
1027-
ret = -ENXIO;
1028-
goto err;
1014+
return -ENXIO;
10291015
}
10301016

10311017
ret = i2c_hid_fetch_hid_descriptor(ihid);
10321018
if (ret < 0) {
10331019
dev_err(&client->dev,
10341020
"Failed to fetch the HID Descriptor\n");
1035-
goto err;
1021+
return ret;
10361022
}
10371023

1038-
enable_irq(client->irq);
1039-
10401024
hid->version = le16_to_cpu(ihid->hdesc.bcdVersion);
10411025
hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
10421026
hid->product = le16_to_cpu(ihid->hdesc.wProductID);
@@ -1050,17 +1034,49 @@ static int __do_i2c_hid_core_initial_power_up(struct i2c_hid *ihid)
10501034

10511035
ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
10521036

1037+
return 0;
1038+
}
1039+
1040+
static int i2c_hid_core_register_hid(struct i2c_hid *ihid)
1041+
{
1042+
struct i2c_client *client = ihid->client;
1043+
struct hid_device *hid = ihid->hid;
1044+
int ret;
1045+
1046+
enable_irq(client->irq);
1047+
10531048
ret = hid_add_device(hid);
10541049
if (ret) {
10551050
if (ret != -ENODEV)
10561051
hid_err(client, "can't add hid device: %d\n", ret);
1057-
goto err;
1052+
disable_irq(client->irq);
1053+
return ret;
10581054
}
10591055

10601056
return 0;
1057+
}
1058+
1059+
static int i2c_hid_core_probe_panel_follower(struct i2c_hid *ihid)
1060+
{
1061+
int ret;
1062+
1063+
ret = i2c_hid_core_power_up(ihid);
1064+
if (ret)
1065+
return ret;
10611066

1062-
err:
1067+
ret = __i2c_hid_core_probe(ihid);
1068+
if (ret)
1069+
goto err_power_down;
1070+
1071+
ret = i2c_hid_core_register_hid(ihid);
1072+
if (ret)
1073+
goto err_power_down;
1074+
1075+
return 0;
1076+
1077+
err_power_down:
10631078
i2c_hid_core_power_down(ihid);
1079+
10641080
return ret;
10651081
}
10661082

@@ -1077,7 +1093,7 @@ static void ihid_core_panel_prepare_work(struct work_struct *work)
10771093
* steps.
10781094
*/
10791095
if (!hid->version)
1080-
ret = __do_i2c_hid_core_initial_power_up(ihid);
1096+
ret = i2c_hid_core_probe_panel_follower(ihid);
10811097
else
10821098
ret = i2c_hid_core_resume(ihid);
10831099

@@ -1136,7 +1152,6 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
11361152
struct device *dev = &ihid->client->dev;
11371153
int ret;
11381154

1139-
ihid->is_panel_follower = true;
11401155
ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_funcs;
11411156

11421157
/*
@@ -1156,30 +1171,6 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
11561171
return 0;
11571172
}
11581173

1159-
static int i2c_hid_core_initial_power_up(struct i2c_hid *ihid)
1160-
{
1161-
/*
1162-
* If we're a panel follower, we'll register and do our initial power
1163-
* up when the panel turns on; otherwise we do it right away.
1164-
*/
1165-
if (drm_is_panel_follower(&ihid->client->dev))
1166-
return i2c_hid_core_register_panel_follower(ihid);
1167-
else
1168-
return __do_i2c_hid_core_initial_power_up(ihid);
1169-
}
1170-
1171-
static void i2c_hid_core_final_power_down(struct i2c_hid *ihid)
1172-
{
1173-
/*
1174-
* If we're a follower, the act of unfollowing will cause us to be
1175-
* powered down. Otherwise we need to manually do it.
1176-
*/
1177-
if (ihid->is_panel_follower)
1178-
drm_panel_remove_follower(&ihid->panel_follower);
1179-
else
1180-
i2c_hid_core_suspend(ihid, true);
1181-
}
1182-
11831174
int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
11841175
u16 hid_descriptor_address, u32 quirks)
11851176
{
@@ -1211,6 +1202,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
12111202
ihid->ops = ops;
12121203
ihid->client = client;
12131204
ihid->wHIDDescRegister = cpu_to_le16(hid_descriptor_address);
1205+
ihid->is_panel_follower = drm_is_panel_follower(&client->dev);
12141206

12151207
init_waitqueue_head(&ihid->wait);
12161208
mutex_init(&ihid->reset_lock);
@@ -1224,14 +1216,10 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
12241216
return ret;
12251217
device_enable_async_suspend(&client->dev);
12261218

1227-
ret = i2c_hid_init_irq(client);
1228-
if (ret < 0)
1229-
goto err_buffers_allocated;
1230-
12311219
hid = hid_allocate_device();
12321220
if (IS_ERR(hid)) {
12331221
ret = PTR_ERR(hid);
1234-
goto err_irq;
1222+
goto err_free_buffers;
12351223
}
12361224

12371225
ihid->hid = hid;
@@ -1242,19 +1230,42 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
12421230
hid->bus = BUS_I2C;
12431231
hid->initial_quirks = quirks;
12441232

1245-
ret = i2c_hid_core_initial_power_up(ihid);
1233+
/* Power on and probe unless device is a panel follower. */
1234+
if (!ihid->is_panel_follower) {
1235+
ret = i2c_hid_core_power_up(ihid);
1236+
if (ret < 0)
1237+
goto err_destroy_device;
1238+
1239+
ret = __i2c_hid_core_probe(ihid);
1240+
if (ret < 0)
1241+
goto err_power_down;
1242+
}
1243+
1244+
ret = i2c_hid_init_irq(client);
1245+
if (ret < 0)
1246+
goto err_power_down;
1247+
1248+
/*
1249+
* If we're a panel follower, we'll register when the panel turns on;
1250+
* otherwise we do it right away.
1251+
*/
1252+
if (ihid->is_panel_follower)
1253+
ret = i2c_hid_core_register_panel_follower(ihid);
1254+
else
1255+
ret = i2c_hid_core_register_hid(ihid);
12461256
if (ret)
1247-
goto err_mem_free;
1257+
goto err_free_irq;
12481258

12491259
return 0;
12501260

1251-
err_mem_free:
1252-
hid_destroy_device(hid);
1253-
1254-
err_irq:
1261+
err_free_irq:
12551262
free_irq(client->irq, ihid);
1256-
1257-
err_buffers_allocated:
1263+
err_power_down:
1264+
if (!ihid->is_panel_follower)
1265+
i2c_hid_core_power_down(ihid);
1266+
err_destroy_device:
1267+
hid_destroy_device(hid);
1268+
err_free_buffers:
12581269
i2c_hid_free_buffers(ihid);
12591270

12601271
return ret;
@@ -1266,7 +1277,14 @@ void i2c_hid_core_remove(struct i2c_client *client)
12661277
struct i2c_hid *ihid = i2c_get_clientdata(client);
12671278
struct hid_device *hid;
12681279

1269-
i2c_hid_core_final_power_down(ihid);
1280+
/*
1281+
* If we're a follower, the act of unfollowing will cause us to be
1282+
* powered down. Otherwise we need to manually do it.
1283+
*/
1284+
if (ihid->is_panel_follower)
1285+
drm_panel_remove_follower(&ihid->panel_follower);
1286+
else
1287+
i2c_hid_core_suspend(ihid, true);
12701288

12711289
hid = ihid->hid;
12721290
hid_destroy_device(hid);

0 commit comments

Comments
 (0)