When a device is opened via input_open_device(), the driver's open() callback is invoked. Some drivers, like cm109, submit URBs or perform other hardware initialization in their open() callbacks. However, the input core does not prevent dev->event() from being called concurrently during the driver's open() execution. For instance, if a console beep occurs, the kbd handler might inject an EV_SND event. This can lead to double list_add BUGs if the driver submits the same URB in both open() and event() paths without adequate synchronization. To fix this, introduce a ready flag in the input_dev structure. For complex devices (where dev->open is defined), this flag is set to true only after the driver's open() method successfully completes. The core now checks ready in input_event_dispose() and input_dev_toggle() to prevent events from reaching the hardware before it is fully prepared. For simple devices (no open callback), events are delivered immediately. We also replay the logical state in input_open_device() by calling input_dev_toggle() right after marking the device ready, ensuring no events are permanently lost. In the inhibit path, we ensure that physical feedback (LEDs/sounds) is turned off before the device is closed, and we synchronize the inhibited state transition under the event lock to prevent races with incoming events.
Showing the changes to include (1 of 2 files). Show all
Unified · Split
| @@ -128,11 +128,14 @@ enum input_clock_type { · 127 unmodified lines | ||
| 128 | 128 | * @devres_managed: indicates that devices is managed with devres framework |
| 129 | 129 | * and needs not be explicitly unregistered or freed. |
| 130 | 130 | * @timestamp: storage for a timestamp set by input_set_timestamp called |
| 131 | − * by a driver | |
| 131 | + * by a driver | |
| 132 | 132 | * @inhibited: indicates that the input device is inhibited. If that is |
| 133 | − * the case then input core ignores any events generated by the device. | |
| 134 | − * Device's close() is called when it is being inhibited and its open() | |
| 135 | − * is called when it is being uninhibited. | |
| 133 | + * the case then input core ignores any events generated by the device. | |
| 134 | + * Device's close() is called when it is being inhibited and its open() | |
| 135 | + * is called when it is being uninhibited. | |
| 136 | + * @ready: indicates that the device has been successfully opened and is | |
| 137 | + * prepared to process events (like LEDs or sounds) sent from the | |
| 138 | + * input core. | |
| 136 | 139 | */ |
| 137 | 140 | struct input_dev { |
| 138 | 141 | const char *name; |
| @@ -209,6 +212,7 @@ struct input_dev { · 70 unmodified lines | ||
| 209 | 212 | ktime_t timestamp[INPUT_CLK_MAX]; |
| 210 | 213 | |
| 211 | 214 | bool inhibited; |
| 215 | + bool ready; | |
| 212 | 216 | }; |
| 213 | 217 | #define to_input_dev(d) container_of(d, struct input_dev, dev) |
| 214 | 218 | |