Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: wacom: Do not register input devices until after hid_hw_start

If a input device is opened before hid_hw_start is called, events may
not be received from the hardware. In the case of USB-backed devices,
for example, the hid_hw_start function is responsible for filling in
the URB which is submitted when the input device is opened. If a device
is opened prematurely, polling will never start because the device will
not have been in the correct state to send the URB.

Because the wacom driver registers its input devices before calling
hid_hw_start, there is a window of time where a device can be opened
and end up in an inoperable state. Some ARM-based Chromebooks in particular
reliably trigger this bug.

This commit splits the wacom_register_inputs function into two pieces.
One which is responsible for setting up the allocated inputs (and runs
prior to hid_hw_start so that devices are ready for any input events
they may end up receiving) and another which only registers the devices
(and runs after hid_hw_start to ensure devices can be immediately opened
without issue). Note that the functions to initialize the LEDs and remotes
are also moved after hid_hw_start to maintain their own dependency chains.

Fixes: 7704ac937345 ("HID: wacom: implement generic HID handling for pen generic devices")
Cc: stable@vger.kernel.org # v3.18+
Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Tested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>

authored by

Jason Gerecke and committed by
Jiri Kosina
c1d6708b 411a20db

+43 -20
+43 -20
drivers/hid/wacom_sys.c
··· 2087 2087 return 0; 2088 2088 } 2089 2089 2090 - static int wacom_register_inputs(struct wacom *wacom) 2090 + static int wacom_setup_inputs(struct wacom *wacom) 2091 2091 { 2092 2092 struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; 2093 2093 struct wacom_wac *wacom_wac = &(wacom->wacom_wac); ··· 2106 2106 input_free_device(pen_input_dev); 2107 2107 wacom_wac->pen_input = NULL; 2108 2108 pen_input_dev = NULL; 2109 - } else { 2110 - error = input_register_device(pen_input_dev); 2111 - if (error) 2112 - goto fail; 2113 2109 } 2114 2110 2115 2111 error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); ··· 2114 2118 input_free_device(touch_input_dev); 2115 2119 wacom_wac->touch_input = NULL; 2116 2120 touch_input_dev = NULL; 2117 - } else { 2118 - error = input_register_device(touch_input_dev); 2119 - if (error) 2120 - goto fail; 2121 2121 } 2122 2122 2123 2123 error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); ··· 2122 2130 input_free_device(pad_input_dev); 2123 2131 wacom_wac->pad_input = NULL; 2124 2132 pad_input_dev = NULL; 2125 - } else { 2133 + } 2134 + 2135 + return 0; 2136 + } 2137 + 2138 + static int wacom_register_inputs(struct wacom *wacom) 2139 + { 2140 + struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; 2141 + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); 2142 + int error = 0; 2143 + 2144 + pen_input_dev = wacom_wac->pen_input; 2145 + touch_input_dev = wacom_wac->touch_input; 2146 + pad_input_dev = wacom_wac->pad_input; 2147 + 2148 + if (pen_input_dev) { 2149 + error = input_register_device(pen_input_dev); 2150 + if (error) 2151 + goto fail; 2152 + } 2153 + 2154 + if (touch_input_dev) { 2155 + error = input_register_device(touch_input_dev); 2156 + if (error) 2157 + goto fail; 2158 + } 2159 + 2160 + if (pad_input_dev) { 2126 2161 error = input_register_device(pad_input_dev); 2127 2162 if (error) 2128 2163 goto fail; ··· 2402 2383 if (error) 2403 2384 goto fail; 2404 2385 2386 + error = wacom_setup_inputs(wacom); 2387 + if (error) 2388 + goto fail; 2389 + 2390 + if (features->type == HID_GENERIC) 2391 + connect_mask |= HID_CONNECT_DRIVER; 2392 + 2393 + /* Regular HID work starts now */ 2394 + error = hid_hw_start(hdev, connect_mask); 2395 + if (error) { 2396 + hid_err(hdev, "hw start failed\n"); 2397 + goto fail; 2398 + } 2399 + 2405 2400 error = wacom_register_inputs(wacom); 2406 2401 if (error) 2407 2402 goto fail; ··· 2428 2395 error = wacom_initialize_remotes(wacom); 2429 2396 if (error) 2430 2397 goto fail; 2431 - } 2432 - 2433 - if (features->type == HID_GENERIC) 2434 - connect_mask |= HID_CONNECT_DRIVER; 2435 - 2436 - /* Regular HID work starts now */ 2437 - error = hid_hw_start(hdev, connect_mask); 2438 - if (error) { 2439 - hid_err(hdev, "hw start failed\n"); 2440 - goto fail; 2441 2398 } 2442 2399 2443 2400 if (!wireless) {