Commit fb2ce3c005ede30b65b891c58ff56398df6089f8

Authored by Dmitry Torokhov
1 parent 16a334c0de

Sonypi: 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 <dtor@mail.ru>

Showing 1 changed file with 63 additions and 59 deletions Side-by-side Diff

drivers/char/sonypi.c
... ... @@ -439,6 +439,11 @@
439 439 { 0, 0 },
440 440 };
441 441  
  442 +struct sonypi_keypress {
  443 + struct input_dev *dev;
  444 + int key;
  445 +};
  446 +
442 447 static struct sonypi_device {
443 448 struct pci_dev *dev;
444 449 struct platform_device *pdev;
445 450  
446 451  
447 452  
... ... @@ -710,25 +715,64 @@
710 715  
711 716 static void input_keyrelease(void *data)
712 717 {
713   - struct input_dev *input_dev;
714   - int key;
  718 + struct sonypi_keypress kp;
715 719  
716   - while (1) {
717   - if (kfifo_get(sonypi_device.input_fifo,
718   - (unsigned char *)&input_dev,
719   - sizeof(input_dev)) != sizeof(input_dev))
720   - return;
721   - if (kfifo_get(sonypi_device.input_fifo,
722   - (unsigned char *)&key,
723   - sizeof(key)) != sizeof(key))
724   - return;
725   -
  720 + while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp,
  721 + sizeof(kp)) == sizeof(kp)) {
726 722 msleep(10);
727   - input_report_key(input_dev, key, 0);
728   - input_sync(input_dev);
  723 + input_report_key(kp.dev, kp.key, 0);
  724 + input_sync(kp.dev);
729 725 }
730 726 }
731 727  
  728 +static void sonypi_report_input_event(u8 event)
  729 +{
  730 + struct input_dev *jog_dev = &sonypi_device.input_jog_dev;
  731 + struct input_dev *key_dev = &sonypi_device.input_key_dev;
  732 + struct sonypi_keypress kp = { NULL };
  733 + int i;
  734 +
  735 + switch (event) {
  736 + case SONYPI_EVENT_JOGDIAL_UP:
  737 + case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
  738 + input_report_rel(jog_dev, REL_WHEEL, 1);
  739 + input_sync(jog_dev);
  740 + break;
  741 +
  742 + case SONYPI_EVENT_JOGDIAL_DOWN:
  743 + case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
  744 + input_report_rel(jog_dev, REL_WHEEL, -1);
  745 + input_sync(jog_dev);
  746 + break;
  747 +
  748 + case SONYPI_EVENT_JOGDIAL_PRESSED:
  749 + kp.key = BTN_MIDDLE;
  750 + kp.dev = jog_dev;
  751 + break;
  752 +
  753 + case SONYPI_EVENT_FNKEY_RELEASED:
  754 + /* Nothing, not all VAIOs generate this event */
  755 + break;
  756 +
  757 + default:
  758 + for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
  759 + if (event == sonypi_inputkeys[i].sonypiev) {
  760 + kp.dev = key_dev;
  761 + kp.key = sonypi_inputkeys[i].inputev;
  762 + break;
  763 + }
  764 + break;
  765 + }
  766 +
  767 + if (kp.dev) {
  768 + input_report_key(kp.dev, kp.key, 1);
  769 + input_sync(kp.dev);
  770 + kfifo_put(sonypi_device.input_fifo,
  771 + (unsigned char *)&kp, sizeof(kp));
  772 + schedule_work(&sonypi_device.input_work);
  773 + }
  774 +}
  775 +
732 776 /* Interrupt handler: some event is available */
733 777 static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs)
734 778 {
735 779  
... ... @@ -768,52 +812,9 @@
768 812 printk(KERN_INFO
769 813 "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
770 814  
771   - if (useinput) {
772   - struct input_dev *input_jog_dev = &sonypi_device.input_jog_dev;
773   - struct input_dev *input_key_dev = &sonypi_device.input_key_dev;
774   - switch (event) {
775   - case SONYPI_EVENT_JOGDIAL_UP:
776   - case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
777   - input_report_rel(input_jog_dev, REL_WHEEL, 1);
778   - break;
779   - case SONYPI_EVENT_JOGDIAL_DOWN:
780   - case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
781   - input_report_rel(input_jog_dev, REL_WHEEL, -1);
782   - break;
783   - case SONYPI_EVENT_JOGDIAL_PRESSED: {
784   - int key = BTN_MIDDLE;
785   - input_report_key(input_jog_dev, key, 1);
786   - kfifo_put(sonypi_device.input_fifo,
787   - (unsigned char *)&input_jog_dev,
788   - sizeof(input_jog_dev));
789   - kfifo_put(sonypi_device.input_fifo,
790   - (unsigned char *)&key, sizeof(key));
791   - break;
792   - }
793   - case SONYPI_EVENT_FNKEY_RELEASED:
794   - /* Nothing, not all VAIOs generate this event */
795   - break;
796   - }
797   - input_sync(input_jog_dev);
  815 + if (useinput)
  816 + sonypi_report_input_event(event);
798 817  
799   - for (i = 0; sonypi_inputkeys[i].sonypiev; i++) {
800   - int key;
801   -
802   - if (event != sonypi_inputkeys[i].sonypiev)
803   - continue;
804   -
805   - key = sonypi_inputkeys[i].inputev;
806   - input_report_key(input_key_dev, key, 1);
807   - kfifo_put(sonypi_device.input_fifo,
808   - (unsigned char *)&input_key_dev,
809   - sizeof(input_key_dev));
810   - kfifo_put(sonypi_device.input_fifo,
811   - (unsigned char *)&key, sizeof(key));
812   - }
813   - input_sync(input_key_dev);
814   - schedule_work(&sonypi_device.input_work);
815   - }
816   -
817 818 kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
818 819 kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
819 820 wake_up_interruptible(&sonypi_device.fifo_proc_list);
... ... @@ -1336,6 +1337,9 @@
1336 1337 static void __devexit sonypi_remove(void)
1337 1338 {
1338 1339 sonypi_disable();
  1340 +
  1341 + synchronize_sched(); /* Allow sonypi interrupt to complete. */
  1342 + flush_scheduled_work();
1339 1343  
1340 1344 platform_device_unregister(sonypi_device.pdev);
1341 1345