Skip to content

Commit abdd3d0

Browse files
ndreysbentiss
authored andcommitted
HID: logitech-hidpp: split g920_get_config()
Original version of g920_get_config() contained two kind of actions: 1. Device specific communication to query/set some parameters which requires active communication channel with the device, or, put in other way, for the call to be sandwiched between hid_device_io_start() and hid_device_io_stop(). 2. Input subsystem specific FF controller initialization which, in order to access a valid 'struct hid_input' via 'hid->inputs.next', requires claimed hidinput which means be executed after the call to hid_hw_start() with connect_mask containing HID_CONNECT_HIDINPUT. Location of g920_get_config() can only fulfill requirements for #1 and not #2, which might result in following backtrace: [ 88.312258] logitech-hidpp-device 0003:046D:C262.0005: HID++ 4.2 device connected. [ 88.320298] BUG: kernel NULL pointer dereference, address: 0000000000000018 [ 88.320304] #PF: supervisor read access in kernel mode [ 88.320307] #PF: error_code(0x0000) - not-present page [ 88.320309] PGD 0 P4D 0 [ 88.320315] Oops: 0000 [#1] SMP PTI [ 88.320320] CPU: 1 PID: 3080 Comm: systemd-udevd Not tainted 5.4.0-rc1+ #31 [ 88.320322] Hardware name: Apple Inc. MacBookPro11,1/Mac-189A3D4F975D5FFC, BIOS 149.0.0.0.0 09/17/2018 [ 88.320334] RIP: 0010:hidpp_probe+0x61f/0x948 [hid_logitech_hidpp] [ 88.320338] Code: 81 00 00 48 89 ef e8 f0 d6 ff ff 41 89 c6 85 c0 75 b5 0f b6 44 24 28 48 8b 5d 00 88 44 24 1e 89 44 24 0c 48 8b 83 18 1c 00 00 <48> 8b 48 18 48 8b 83 10 19 00 00 48 8b 40 40 48 89 0c 24 0f b7 80 [ 88.320341] RSP: 0018:ffffb0a6824aba68 EFLAGS: 00010246 [ 88.320345] RAX: 0000000000000000 RBX: ffff93a50756e000 RCX: 0000000000010408 [ 88.320347] RDX: 0000000000000000 RSI: ffff93a51f0ad0a0 RDI: 000000000002d0a0 [ 88.320350] RBP: ffff93a50416da28 R08: ffff93a50416da70 R09: ffff93a50416da70 [ 88.320352] R10: 000000148ae9e60c R11: 00000000000f1525 R12: ffff93a50756e000 [ 88.320354] R13: ffff93a50756f8d0 R14: 0000000000000000 R15: ffff93a50756fc38 [ 88.320358] FS: 00007f8d8c1e0940(0000) GS:ffff93a51f080000(0000) knlGS:0000000000000000 [ 88.320361] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 88.320363] CR2: 0000000000000018 CR3: 00000003996d8003 CR4: 00000000001606e0 [ 88.320366] Call Trace: [ 88.320377] ? _cond_resched+0x15/0x30 [ 88.320387] ? create_pinctrl+0x2f/0x3c0 [ 88.320393] ? kernfs_link_sibling+0x94/0xe0 [ 88.320398] ? _cond_resched+0x15/0x30 [ 88.320402] ? kernfs_activate+0x5f/0x80 [ 88.320406] ? kernfs_add_one+0xe2/0x130 [ 88.320411] hid_device_probe+0x106/0x170 [ 88.320419] really_probe+0x147/0x3c0 [ 88.320424] driver_probe_device+0xb6/0x100 [ 88.320428] device_driver_attach+0x53/0x60 [ 88.320433] __driver_attach+0x8a/0x150 [ 88.320437] ? device_driver_attach+0x60/0x60 [ 88.320440] bus_for_each_dev+0x78/0xc0 [ 88.320445] bus_add_driver+0x14d/0x1f0 [ 88.320450] driver_register+0x6c/0xc0 [ 88.320453] ? 0xffffffffc0d67000 [ 88.320457] __hid_register_driver+0x4c/0x80 [ 88.320464] do_one_initcall+0x46/0x1f4 [ 88.320469] ? _cond_resched+0x15/0x30 [ 88.320474] ? kmem_cache_alloc_trace+0x162/0x220 [ 88.320481] ? do_init_module+0x23/0x230 [ 88.320486] do_init_module+0x5c/0x230 [ 88.320491] load_module+0x26e1/0x2990 [ 88.320502] ? ima_post_read_file+0xf0/0x100 [ 88.320508] ? __do_sys_finit_module+0xaa/0x110 [ 88.320512] __do_sys_finit_module+0xaa/0x110 [ 88.320520] do_syscall_64+0x5b/0x180 [ 88.320525] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 88.320528] RIP: 0033:0x7f8d8d1f01fd [ 88.320532] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 5b 8c 0c 00 f7 d8 64 89 01 48 [ 88.320535] RSP: 002b:00007ffefa3bb068 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 88.320539] RAX: ffffffffffffffda RBX: 000055922040cb40 RCX: 00007f8d8d1f01fd [ 88.320541] RDX: 0000000000000000 RSI: 00007f8d8ce4984d RDI: 0000000000000006 [ 88.320543] RBP: 0000000000020000 R08: 0000000000000000 R09: 0000000000000007 [ 88.320545] R10: 0000000000000006 R11: 0000000000000246 R12: 00007f8d8ce4984d [ 88.320547] R13: 0000000000000000 R14: 000055922040efc0 R15: 000055922040cb40 [ 88.320551] Modules linked in: hid_logitech_hidpp(+) fuse rfcomm ccm xt_CHECKSUM xt_MASQUERADE bridge stp llc nf_nat_tftp nf_conntrack_tftp nf_conntrack_netbios_ns nf_conntrack_broadcast xt_CT ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_nat ip6table_nat ip6table_mangle ip6table_raw ip6table_security iptable_nat nf_nat tun iptable_mangle iptable_raw iptable_security nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 libcrc32c ip_set nfnetlink ebtable_filter ebtables ip6table_filter ip6_tables cmac bnep sunrpc dm_crypt nls_utf8 hfsplus intel_rapl_msr intel_rapl_common ath9k_htc ath9k_common x86_pkg_temp_thermal intel_powerclamp b43 ath9k_hw coretemp snd_hda_codec_hdmi cordic kvm_intel snd_hda_codec_cirrus mac80211 snd_hda_codec_generic ledtrig_audio kvm snd_hda_intel snd_intel_nhlt irqbypass snd_hda_codec btusb btrtl snd_hda_core ath btbcm ssb snd_hwdep btintel snd_seq crct10dif_pclmul iTCO_wdt snd_seq_device crc32_pclmul bluetooth mmc_core iTCO_vendor_support joydev cfg80211 [ 88.320602] applesmc ghash_clmulni_intel ecdh_generic snd_pcm input_polldev intel_cstate ecc intel_uncore thunderbolt snd_timer i2c_i801 libarc4 rfkill intel_rapl_perf lpc_ich mei_me pcspkr bcm5974 snd bcma mei soundcore acpi_als sbs kfifo_buf sbshc industrialio apple_bl i915 i2c_algo_bit drm_kms_helper drm uas crc32c_intel usb_storage video hid_apple [ 88.320630] CR2: 0000000000000018 [ 88.320633] ---[ end trace 933491c8a4fadeb7 ]--- [ 88.320642] RIP: 0010:hidpp_probe+0x61f/0x948 [hid_logitech_hidpp] [ 88.320645] Code: 81 00 00 48 89 ef e8 f0 d6 ff ff 41 89 c6 85 c0 75 b5 0f b6 44 24 28 48 8b 5d 00 88 44 24 1e 89 44 24 0c 48 8b 83 18 1c 00 00 <48> 8b 48 18 48 8b 83 10 19 00 00 48 8b 40 40 48 89 0c 24 0f b7 80 [ 88.320647] RSP: 0018:ffffb0a6824aba68 EFLAGS: 00010246 [ 88.320650] RAX: 0000000000000000 RBX: ffff93a50756e000 RCX: 0000000000010408 [ 88.320652] RDX: 0000000000000000 RSI: ffff93a51f0ad0a0 RDI: 000000000002d0a0 [ 88.320655] RBP: ffff93a50416da28 R08: ffff93a50416da70 R09: ffff93a50416da70 [ 88.320657] R10: 000000148ae9e60c R11: 00000000000f1525 R12: ffff93a50756e000 [ 88.320659] R13: ffff93a50756f8d0 R14: 0000000000000000 R15: ffff93a50756fc38 [ 88.320662] FS: 00007f8d8c1e0940(0000) GS:ffff93a51f080000(0000) knlGS:0000000000000000 [ 88.320664] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 88.320667] CR2: 0000000000000018 CR3: 00000003996d8003 CR4: 00000000001606e0 To solve this issue: 1. Split g920_get_config() such that all of the device specific communication remains a part of the function and input subsystem initialization bits go to hidpp_ff_init() 2. Move call to hidpp_ff_init() from being a part of g920_get_config() to be the last step of .probe(), right after a call to hid_hw_start() with connect_mask containing HID_CONNECT_HIDINPUT. Fixes: 91cf9a9 ("HID: logitech-hidpp: make .probe usbhid capable") Signed-off-by: Andrey Smirnov <[email protected]> Tested-by: Sam Bazley <[email protected]> Cc: Jiri Kosina <[email protected]> Cc: Benjamin Tissoires <[email protected]> Cc: Henrik Rydberg <[email protected]> Cc: Pierre-Loup A. Griffais <[email protected]> Cc: Austin Palmer <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] # 5.2+ Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 67b18df commit abdd3d0

File tree

1 file changed

+96
-54
lines changed

1 file changed

+96
-54
lines changed

drivers/hid/hid-logitech-hidpp.c

Lines changed: 96 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,7 @@ static void hidpp_touchpad_raw_xy_event(struct hidpp_device *hidpp_dev,
16691669

16701670
#define HIDPP_FF_EFFECTID_NONE -1
16711671
#define HIDPP_FF_EFFECTID_AUTOCENTER -2
1672+
#define HIDPP_AUTOCENTER_PARAMS_LENGTH 18
16721673

16731674
#define HIDPP_FF_MAX_PARAMS 20
16741675
#define HIDPP_FF_RESERVED_SLOTS 1
@@ -2009,7 +2010,7 @@ static int hidpp_ff_erase_effect(struct input_dev *dev, int effect_id)
20092010
static void hidpp_ff_set_autocenter(struct input_dev *dev, u16 magnitude)
20102011
{
20112012
struct hidpp_ff_private_data *data = dev->ff->private;
2012-
u8 params[18];
2013+
u8 params[HIDPP_AUTOCENTER_PARAMS_LENGTH];
20132014

20142015
dbg_hid("Setting autocenter to %d.\n", magnitude);
20152016

@@ -2081,17 +2082,16 @@ static void hidpp_ff_destroy(struct ff_device *ff)
20812082
kfree(data->effect_ids);
20822083
}
20832084

2084-
static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
2085+
static int hidpp_ff_init(struct hidpp_device *hidpp,
2086+
struct hidpp_ff_private_data *data)
20852087
{
20862088
struct hid_device *hid = hidpp->hid_dev;
20872089
struct hid_input *hidinput;
20882090
struct input_dev *dev;
20892091
const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
20902092
const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice);
20912093
struct ff_device *ff;
2092-
struct hidpp_report response;
2093-
struct hidpp_ff_private_data *data;
2094-
int error, j, num_slots;
2094+
int error, j, num_slots = data->num_effects;
20952095
u8 version;
20962096

20972097
if (list_empty(&hid->inputs)) {
@@ -2116,27 +2116,17 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
21162116
for (j = 0; hidpp_ff_effects_v2[j] >= 0; j++)
21172117
set_bit(hidpp_ff_effects_v2[j], dev->ffbit);
21182118

2119-
/* Read number of slots available in device */
2120-
error = hidpp_send_fap_command_sync(hidpp, feature_index,
2121-
HIDPP_FF_GET_INFO, NULL, 0, &response);
2122-
if (error) {
2123-
if (error < 0)
2124-
return error;
2125-
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
2126-
__func__, error);
2127-
return -EPROTO;
2128-
}
2129-
2130-
num_slots = response.fap.params[0] - HIDPP_FF_RESERVED_SLOTS;
2131-
21322119
error = input_ff_create(dev, num_slots);
21332120

21342121
if (error) {
21352122
hid_err(dev, "Failed to create FF device!\n");
21362123
return error;
21372124
}
2138-
2139-
data = kzalloc(sizeof(*data), GFP_KERNEL);
2125+
/*
2126+
* Create a copy of passed data, so we can transfer memory
2127+
* ownership to FF core
2128+
*/
2129+
data = kmemdup(data, sizeof(*data), GFP_KERNEL);
21402130
if (!data)
21412131
return -ENOMEM;
21422132
data->effect_ids = kcalloc(num_slots, sizeof(int), GFP_KERNEL);
@@ -2152,10 +2142,7 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
21522142
}
21532143

21542144
data->hidpp = hidpp;
2155-
data->feature_index = feature_index;
21562145
data->version = version;
2157-
data->slot_autocenter = 0;
2158-
data->num_effects = num_slots;
21592146
for (j = 0; j < num_slots; j++)
21602147
data->effect_ids[j] = -1;
21612148

@@ -2169,37 +2156,14 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
21692156
ff->set_autocenter = hidpp_ff_set_autocenter;
21702157
ff->destroy = hidpp_ff_destroy;
21712158

2172-
2173-
/* reset all forces */
2174-
error = hidpp_send_fap_command_sync(hidpp, feature_index,
2175-
HIDPP_FF_RESET_ALL, NULL, 0, &response);
2176-
2177-
/* Read current Range */
2178-
error = hidpp_send_fap_command_sync(hidpp, feature_index,
2179-
HIDPP_FF_GET_APERTURE, NULL, 0, &response);
2180-
if (error)
2181-
hid_warn(hidpp->hid_dev, "Failed to read range from device!\n");
2182-
data->range = error ? 900 : get_unaligned_be16(&response.fap.params[0]);
2183-
21842159
/* Create sysfs interface */
21852160
error = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
21862161
if (error)
21872162
hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d!\n", error);
21882163

2189-
/* Read the current gain values */
2190-
error = hidpp_send_fap_command_sync(hidpp, feature_index,
2191-
HIDPP_FF_GET_GLOBAL_GAINS, NULL, 0, &response);
2192-
if (error)
2193-
hid_warn(hidpp->hid_dev, "Failed to read gain values from device!\n");
2194-
data->gain = error ? 0xffff : get_unaligned_be16(&response.fap.params[0]);
2195-
/* ignore boost value at response.fap.params[2] */
2196-
21972164
/* init the hardware command queue */
21982165
atomic_set(&data->workqueue_size, 0);
21992166

2200-
/* initialize with zero autocenter to get wheel in usable state */
2201-
hidpp_ff_set_autocenter(dev, 0);
2202-
22032167
hid_info(hid, "Force feedback support loaded (firmware release %d).\n",
22042168
version);
22052169

@@ -2732,24 +2696,93 @@ static int k400_connect(struct hid_device *hdev, bool connected)
27322696

27332697
#define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123
27342698

2735-
static int g920_get_config(struct hidpp_device *hidpp)
2699+
static int g920_ff_set_autocenter(struct hidpp_device *hidpp,
2700+
struct hidpp_ff_private_data *data)
27362701
{
2702+
struct hidpp_report response;
2703+
u8 params[HIDPP_AUTOCENTER_PARAMS_LENGTH] = {
2704+
[1] = HIDPP_FF_EFFECT_SPRING | HIDPP_FF_EFFECT_AUTOSTART,
2705+
};
2706+
int ret;
2707+
2708+
/* initialize with zero autocenter to get wheel in usable state */
2709+
2710+
dbg_hid("Setting autocenter to 0.\n");
2711+
ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
2712+
HIDPP_FF_DOWNLOAD_EFFECT,
2713+
params, ARRAY_SIZE(params),
2714+
&response);
2715+
if (ret)
2716+
hid_warn(hidpp->hid_dev, "Failed to autocenter device!\n");
2717+
else
2718+
data->slot_autocenter = response.fap.params[0];
2719+
2720+
return ret;
2721+
}
2722+
2723+
static int g920_get_config(struct hidpp_device *hidpp,
2724+
struct hidpp_ff_private_data *data)
2725+
{
2726+
struct hidpp_report response;
27372727
u8 feature_type;
2738-
u8 feature_index;
27392728
int ret;
27402729

2730+
memset(data, 0, sizeof(*data));
2731+
27412732
/* Find feature and store for later use */
27422733
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
2743-
&feature_index, &feature_type);
2734+
&data->feature_index, &feature_type);
27442735
if (ret)
27452736
return ret;
27462737

2747-
ret = hidpp_ff_init(hidpp, feature_index);
2738+
/* Read number of slots available in device */
2739+
ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
2740+
HIDPP_FF_GET_INFO,
2741+
NULL, 0,
2742+
&response);
2743+
if (ret) {
2744+
if (ret < 0)
2745+
return ret;
2746+
hid_err(hidpp->hid_dev,
2747+
"%s: received protocol error 0x%02x\n", __func__, ret);
2748+
return -EPROTO;
2749+
}
2750+
2751+
data->num_effects = response.fap.params[0] - HIDPP_FF_RESERVED_SLOTS;
2752+
2753+
/* reset all forces */
2754+
ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
2755+
HIDPP_FF_RESET_ALL,
2756+
NULL, 0,
2757+
&response);
27482758
if (ret)
2749-
hid_warn(hidpp->hid_dev, "Unable to initialize force feedback support, errno %d\n",
2750-
ret);
2759+
hid_warn(hidpp->hid_dev, "Failed to reset all forces!\n");
27512760

2752-
return 0;
2761+
ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
2762+
HIDPP_FF_GET_APERTURE,
2763+
NULL, 0,
2764+
&response);
2765+
if (ret) {
2766+
hid_warn(hidpp->hid_dev,
2767+
"Failed to read range from device!\n");
2768+
}
2769+
data->range = ret ?
2770+
900 : get_unaligned_be16(&response.fap.params[0]);
2771+
2772+
/* Read the current gain values */
2773+
ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
2774+
HIDPP_FF_GET_GLOBAL_GAINS,
2775+
NULL, 0,
2776+
&response);
2777+
if (ret)
2778+
hid_warn(hidpp->hid_dev,
2779+
"Failed to read gain values from device!\n");
2780+
data->gain = ret ?
2781+
0xffff : get_unaligned_be16(&response.fap.params[0]);
2782+
2783+
/* ignore boost value at response.fap.params[2] */
2784+
2785+
return g920_ff_set_autocenter(hidpp, data);
27532786
}
27542787

27552788
/* -------------------------------------------------------------------------- */
@@ -3512,6 +3545,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
35123545
int ret;
35133546
bool connected;
35143547
unsigned int connect_mask = HID_CONNECT_DEFAULT;
3548+
struct hidpp_ff_private_data data;
35153549

35163550
/* report_fixup needs drvdata to be set before we call hid_parse */
35173551
hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL);
@@ -3621,7 +3655,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
36213655
if (ret)
36223656
goto hid_hw_init_fail;
36233657
} else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
3624-
ret = g920_get_config(hidpp);
3658+
ret = g920_get_config(hidpp, &data);
36253659
if (ret)
36263660
goto hid_hw_init_fail;
36273661
}
@@ -3643,6 +3677,14 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
36433677
goto hid_hw_start_fail;
36443678
}
36453679

3680+
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
3681+
ret = hidpp_ff_init(hidpp, &data);
3682+
if (ret)
3683+
hid_warn(hidpp->hid_dev,
3684+
"Unable to initialize force feedback support, errno %d\n",
3685+
ret);
3686+
}
3687+
36463688
return ret;
36473689

36483690
hid_hw_init_fail:

0 commit comments

Comments
 (0)