From: Dmitry Torokhov Make sure that input_work is not running when unloading the module; submit/retrieve key release data into/from input_fifo in one shot. Signed-off-by: Dmitry Torokhov Cc: Stelian Pop Signed-off-by: Andrew Morton --- drivers/char/sonypi.c | 122 +++++++++++++++++++++++++------------------------- 1 files changed, 63 insertions(+), 59 deletions(-) diff -puN drivers/char/sonypi.c~sonypi-make-sure-that-input_work-is-not-running-when-unloading drivers/char/sonypi.c --- 25/drivers/char/sonypi.c~sonypi-make-sure-that-input_work-is-not-running-when-unloading 2005-06-03 02:13:08.000000000 -0700 +++ 25-akpm/drivers/char/sonypi.c 2005-06-03 02:13:08.000000000 -0700 @@ -439,6 +439,11 @@ static struct { { 0, 0 }, }; +struct sonypi_keypress { + struct input_dev *dev; + int key; +}; + static struct sonypi_device { struct pci_dev *dev; struct platform_device *pdev; @@ -710,22 +715,61 @@ static void sonypi_setbluetoothpower(u8 static void input_keyrelease(void *data) { - struct input_dev *input_dev; - int key; - - while (1) { - if (kfifo_get(sonypi_device.input_fifo, - (unsigned char *)&input_dev, - sizeof(input_dev)) != sizeof(input_dev)) - return; - if (kfifo_get(sonypi_device.input_fifo, - (unsigned char *)&key, - sizeof(key)) != sizeof(key)) - return; + struct sonypi_keypress kp; + while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp, + sizeof(kp)) == sizeof(kp)) { msleep(10); - input_report_key(input_dev, key, 0); - input_sync(input_dev); + input_report_key(kp.dev, kp.key, 0); + input_sync(kp.dev); + } +} + +static void sonypi_report_input_event(u8 event) +{ + struct input_dev *jog_dev = &sonypi_device.input_jog_dev; + struct input_dev *key_dev = &sonypi_device.input_key_dev; + struct sonypi_keypress kp = { NULL }; + int i; + + switch (event) { + case SONYPI_EVENT_JOGDIAL_UP: + case SONYPI_EVENT_JOGDIAL_UP_PRESSED: + input_report_rel(jog_dev, REL_WHEEL, 1); + input_sync(jog_dev); + break; + + case SONYPI_EVENT_JOGDIAL_DOWN: + case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: + input_report_rel(jog_dev, REL_WHEEL, -1); + input_sync(jog_dev); + break; + + case SONYPI_EVENT_JOGDIAL_PRESSED: + kp.key = BTN_MIDDLE; + kp.dev = jog_dev; + break; + + case SONYPI_EVENT_FNKEY_RELEASED: + /* Nothing, not all VAIOs generate this event */ + break; + + default: + for (i = 0; sonypi_inputkeys[i].sonypiev; i++) + if (event == sonypi_inputkeys[i].sonypiev) { + kp.dev = key_dev; + kp.key = sonypi_inputkeys[i].inputev; + break; + } + break; + } + + if (kp.dev) { + input_report_key(kp.dev, kp.key, 1); + input_sync(kp.dev); + kfifo_put(sonypi_device.input_fifo, + (unsigned char *)&kp, sizeof(kp)); + schedule_work(&sonypi_device.input_work); } } @@ -768,51 +812,8 @@ found: printk(KERN_INFO "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2); - if (useinput) { - struct input_dev *input_jog_dev = &sonypi_device.input_jog_dev; - struct input_dev *input_key_dev = &sonypi_device.input_key_dev; - switch (event) { - case SONYPI_EVENT_JOGDIAL_UP: - case SONYPI_EVENT_JOGDIAL_UP_PRESSED: - input_report_rel(input_jog_dev, REL_WHEEL, 1); - break; - case SONYPI_EVENT_JOGDIAL_DOWN: - case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: - input_report_rel(input_jog_dev, REL_WHEEL, -1); - break; - case SONYPI_EVENT_JOGDIAL_PRESSED: { - int key = BTN_MIDDLE; - input_report_key(input_jog_dev, key, 1); - kfifo_put(sonypi_device.input_fifo, - (unsigned char *)&input_jog_dev, - sizeof(input_jog_dev)); - kfifo_put(sonypi_device.input_fifo, - (unsigned char *)&key, sizeof(key)); - break; - } - case SONYPI_EVENT_FNKEY_RELEASED: - /* Nothing, not all VAIOs generate this event */ - break; - } - input_sync(input_jog_dev); - - for (i = 0; sonypi_inputkeys[i].sonypiev; i++) { - int key; - - if (event != sonypi_inputkeys[i].sonypiev) - continue; - - key = sonypi_inputkeys[i].inputev; - input_report_key(input_key_dev, key, 1); - kfifo_put(sonypi_device.input_fifo, - (unsigned char *)&input_key_dev, - sizeof(input_key_dev)); - kfifo_put(sonypi_device.input_fifo, - (unsigned char *)&key, sizeof(key)); - } - input_sync(input_key_dev); - schedule_work(&sonypi_device.input_work); - } + if (useinput) + sonypi_report_input_event(event); kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); @@ -1337,6 +1338,9 @@ static void __devexit sonypi_remove(void { sonypi_disable(); + synchronize_sched(); /* Allow sonypi interrupt to complete. */ + flush_scheduled_work(); + platform_device_unregister(sonypi_device.pdev); if (useinput) { _