Commit fb2ce3c005ede30b65b891c58ff56398df6089f8
1 parent
16a334c0de
Exists in
master
and in
7 other branches
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 |