aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authormalattia@linux.it <malattia@linux.it>2007-04-09 04:19:08 -0400
committerLen Brown <len.brown@intel.com>2007-04-10 16:01:19 -0400
commit1549ee6fb122400c0767b5f3da2c42abbc4f750a (patch)
treee7c3b3c19f34e42a9bff6d7e36f66175904cfd01 /drivers/misc
parent33a04454527edd33d4a6332a2944d2b4f46fbb18 (diff)
sony-laptop: Unify the input subsystem event forwarding
SNC and SPIC events are forwarded to the same input devices and are thus handled together. Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/sony-laptop.c541
1 files changed, 276 insertions, 265 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index b797c8cb47df..cf8d7927dc5c 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -97,18 +97,266 @@ MODULE_PARM_DESC(no_spic,
97static int compat; /* = 0 */ 97static int compat; /* = 0 */
98module_param(compat, int, 0444); 98module_param(compat, int, 0444);
99MODULE_PARM_DESC(compat, 99MODULE_PARM_DESC(compat,
100 "set this if you want to enable backward compatibility mode"); 100 "set this if you want to enable backward compatibility mode for SPIC");
101
102static int force_jog; /* = 0 */
103module_param(force_jog, int, 0444);
104MODULE_PARM_DESC(force_jog,
105 "set this if the driver doesn't detect your jogdial");
106 101
107static unsigned long mask = 0xffffffff; 102static unsigned long mask = 0xffffffff;
108module_param(mask, ulong, 0644); 103module_param(mask, ulong, 0644);
109MODULE_PARM_DESC(mask, 104MODULE_PARM_DESC(mask,
110 "set this to the mask of event you want to enable (see doc)"); 105 "set this to the mask of event you want to enable (see doc)");
111 106
107/*********** Input Devices ***********/
108
109#define SONY_LAPTOP_BUF_SIZE 128
110struct sony_laptop_input_s {
111 atomic_t users;
112 struct input_dev *jog_dev;
113 struct input_dev *key_dev;
114 struct kfifo *fifo;
115 spinlock_t fifo_lock;
116 struct workqueue_struct *wq;
117};
118static struct sony_laptop_input_s sony_laptop_input = {
119 .users = ATOMIC_INIT(0),
120};
121
122struct sony_laptop_keypress {
123 struct input_dev *dev;
124 int key;
125};
126
127/* Correspondance table between sonypi events and input layer events */
128static struct {
129 int sonypiev;
130 int inputev;
131} sony_laptop_inputkeys[] = {
132 { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
133 { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
134 { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
135 { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
136 { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
137 { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
138 { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
139 { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
140 { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
141 { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
142 { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
143 { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
144 { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
145 { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
146 { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
147 { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
148 { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
149 { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
150 { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
151 { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
152 { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
153 { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
154 { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
155 { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
156 { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
157 { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
158 { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
159 { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
160 { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
161 { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
162 { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
163 { 0, 0 },
164};
165
166/* release buttons after a short delay if pressed */
167static void do_sony_laptop_release_key(struct work_struct *work)
168{
169 struct sony_laptop_keypress kp;
170
171 while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
172 sizeof(kp)) == sizeof(kp)) {
173 msleep(10);
174 input_report_key(kp.dev, kp.key, 0);
175 input_sync(kp.dev);
176 }
177}
178static DECLARE_WORK(sony_laptop_release_key_work,
179 do_sony_laptop_release_key);
180
181/* forward event to the input subsytem */
182static void sony_laptop_report_input_event(u8 event)
183{
184 struct input_dev *jog_dev = sony_laptop_input.jog_dev;
185 struct input_dev *key_dev = sony_laptop_input.key_dev;
186 struct sony_laptop_keypress kp = { NULL };
187 int i;
188
189 if (event == SONYPI_EVENT_FNKEY_RELEASED) {
190 /* Nothing, not all VAIOs generate this event */
191 return;
192 }
193
194 /* report events */
195 switch (event) {
196 /* jog_dev events */
197 case SONYPI_EVENT_JOGDIAL_UP:
198 case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
199 input_report_rel(jog_dev, REL_WHEEL, 1);
200 input_sync(jog_dev);
201 return;
202
203 case SONYPI_EVENT_JOGDIAL_DOWN:
204 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
205 input_report_rel(jog_dev, REL_WHEEL, -1);
206 input_sync(jog_dev);
207 return;
208
209 /* key_dev events */
210 case SONYPI_EVENT_JOGDIAL_PRESSED:
211 kp.key = BTN_MIDDLE;
212 kp.dev = jog_dev;
213 break;
214
215 default:
216 for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
217 if (event == sony_laptop_inputkeys[i].sonypiev) {
218 kp.dev = key_dev;
219 kp.key = sony_laptop_inputkeys[i].inputev;
220 break;
221 }
222 break;
223 }
224
225 if (kp.dev) {
226 input_report_key(kp.dev, kp.key, 1);
227 input_sync(kp.dev);
228 kfifo_put(sony_laptop_input.fifo,
229 (unsigned char *)&kp, sizeof(kp));
230
231 if (!work_pending(&sony_laptop_release_key_work))
232 queue_work(sony_laptop_input.wq,
233 &sony_laptop_release_key_work);
234 } else
235 dprintk("unknown input event %.2x\n", event);
236}
237
238static int sony_laptop_setup_input(void)
239{
240 struct input_dev *jog_dev;
241 struct input_dev *key_dev;
242 int i;
243 int error;
244
245 /* don't run again if already initialized */
246 if (atomic_add_return(1, &sony_laptop_input.users) > 1)
247 return 0;
248
249 /* kfifo */
250 spin_lock_init(&sony_laptop_input.fifo_lock);
251 sony_laptop_input.fifo =
252 kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
253 &sony_laptop_input.fifo_lock);
254 if (IS_ERR(sony_laptop_input.fifo)) {
255 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
256 error = PTR_ERR(sony_laptop_input.fifo);
257 goto err_dec_users;
258 }
259
260 /* init workqueue */
261 sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
262 if (!sony_laptop_input.wq) {
263 printk(KERN_ERR DRV_PFX
264 "Unabe to create workqueue.\n");
265 error = -ENXIO;
266 goto err_free_kfifo;
267 }
268
269 /* input keys */
270 key_dev = input_allocate_device();
271 if (!key_dev) {
272 error = -ENOMEM;
273 goto err_destroy_wq;
274 }
275
276 key_dev->name = "Sony Vaio Keys";
277 key_dev->id.bustype = BUS_ISA;
278 key_dev->id.vendor = PCI_VENDOR_ID_SONY;
279
280 /* Initialize the Input Drivers: special keys */
281 key_dev->evbit[0] = BIT(EV_KEY);
282 for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
283 if (sony_laptop_inputkeys[i].inputev)
284 set_bit(sony_laptop_inputkeys[i].inputev,
285 key_dev->keybit);
286
287 error = input_register_device(key_dev);
288 if (error)
289 goto err_free_keydev;
290
291 sony_laptop_input.key_dev = key_dev;
292
293 /* jogdial */
294 jog_dev = input_allocate_device();
295 if (!jog_dev) {
296 error = -ENOMEM;
297 goto err_unregister_keydev;
298 }
299
300 jog_dev->name = "Sony Vaio Jogdial";
301 jog_dev->id.bustype = BUS_ISA;
302 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
303
304 jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
305 jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
306 jog_dev->relbit[0] = BIT(REL_WHEEL);
307
308 error = input_register_device(jog_dev);
309 if (error)
310 goto err_free_jogdev;
311
312 sony_laptop_input.jog_dev = jog_dev;
313
314 return 0;
315
316err_free_jogdev:
317 input_free_device(jog_dev);
318
319err_unregister_keydev:
320 input_unregister_device(key_dev);
321 /* to avoid kref underflow below at input_free_device */
322 key_dev = NULL;
323
324err_free_keydev:
325 input_free_device(key_dev);
326
327err_destroy_wq:
328 destroy_workqueue(sony_laptop_input.wq);
329
330err_free_kfifo:
331 kfifo_free(sony_laptop_input.fifo);
332
333err_dec_users:
334 atomic_dec(&sony_laptop_input.users);
335 return error;
336}
337
338static void sony_laptop_remove_input(void)
339{
340 /* cleanup only after the last user has gone */
341 if (!atomic_dec_and_test(&sony_laptop_input.users))
342 return;
343
344 /* flush workqueue first */
345 flush_workqueue(sony_laptop_input.wq);
346
347 /* destroy input devs */
348 input_unregister_device(sony_laptop_input.key_dev);
349 sony_laptop_input.key_dev = NULL;
350
351 if (sony_laptop_input.jog_dev) {
352 input_unregister_device(sony_laptop_input.jog_dev);
353 sony_laptop_input.jog_dev = NULL;
354 }
355
356 destroy_workqueue(sony_laptop_input.wq);
357 kfifo_free(sony_laptop_input.fifo);
358}
359
112/*********** Platform Device ***********/ 360/*********** Platform Device ***********/
113 361
114static atomic_t sony_pf_users = ATOMIC_INIT(0); 362static atomic_t sony_pf_users = ATOMIC_INIT(0);
@@ -428,6 +676,7 @@ static struct backlight_ops sony_backlight_ops = {
428static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) 676static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
429{ 677{
430 dprintk("sony_acpi_notify, event: %d\n", event); 678 dprintk("sony_acpi_notify, event: %d\n", event);
679 sony_laptop_report_input_event(event);
431 acpi_bus_generate_event(sony_nc_acpi_device, 1, event); 680 acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
432} 681}
433 682
@@ -490,13 +739,21 @@ static int sony_nc_add(struct acpi_device *device)
490 } 739 }
491 } 740 }
492 741
742 /* setup input devices and helper fifo */
743 result = sony_laptop_setup_input();
744 if (result) {
745 printk(KERN_ERR DRV_PFX
746 "Unabe to create input devices.\n");
747 goto outwalk;
748 }
749
493 status = acpi_install_notify_handler(sony_nc_acpi_handle, 750 status = acpi_install_notify_handler(sony_nc_acpi_handle,
494 ACPI_DEVICE_NOTIFY, 751 ACPI_DEVICE_NOTIFY,
495 sony_acpi_notify, NULL); 752 sony_acpi_notify, NULL);
496 if (ACPI_FAILURE(status)) { 753 if (ACPI_FAILURE(status)) {
497 printk(LOG_PFX "unable to install notify handler\n"); 754 printk(LOG_PFX "unable to install notify handler\n");
498 result = -ENODEV; 755 result = -ENODEV;
499 goto outwalk; 756 goto outinput;
500 } 757 }
501 758
502 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { 759 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
@@ -568,6 +825,7 @@ static int sony_nc_add(struct acpi_device *device)
568 device_remove_file(&sony_pf_device->dev, &item->devattr); 825 device_remove_file(&sony_pf_device->dev, &item->devattr);
569 } 826 }
570 sony_pf_remove(); 827 sony_pf_remove();
828
571 outbacklight: 829 outbacklight:
572 if (sony_backlight_device) 830 if (sony_backlight_device)
573 backlight_device_unregister(sony_backlight_device); 831 backlight_device_unregister(sony_backlight_device);
@@ -577,6 +835,10 @@ static int sony_nc_add(struct acpi_device *device)
577 sony_acpi_notify); 835 sony_acpi_notify);
578 if (ACPI_FAILURE(status)) 836 if (ACPI_FAILURE(status))
579 printk(LOG_PFX "unable to remove notify handler\n"); 837 printk(LOG_PFX "unable to remove notify handler\n");
838
839 outinput:
840 sony_laptop_remove_input();
841
580 outwalk: 842 outwalk:
581 return result; 843 return result;
582} 844}
@@ -602,6 +864,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
602 } 864 }
603 865
604 sony_pf_remove(); 866 sony_pf_remove();
867 sony_laptop_remove_input();
605 868
606 printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully removed\n"); 869 printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully removed\n");
607 870
@@ -626,13 +889,8 @@ static struct acpi_driver sony_nc_driver = {
626#define SONYPI_DEVICE_TYPE2 0x00000002 889#define SONYPI_DEVICE_TYPE2 0x00000002
627#define SONYPI_DEVICE_TYPE3 0x00000004 890#define SONYPI_DEVICE_TYPE3 0x00000004
628 891
629#define SONY_EC_JOGB 0x82
630#define SONY_EC_JOGB_MASK 0x02
631
632#define SONY_PIC_EV_MASK 0xff 892#define SONY_PIC_EV_MASK 0xff
633 893
634#define SONYPI_BUF_SIZE 128
635
636struct sony_pic_ioport { 894struct sony_pic_ioport {
637 struct acpi_resource_io io; 895 struct acpi_resource_io io;
638 struct list_head list; 896 struct list_head list;
@@ -650,12 +908,6 @@ struct sony_pic_dev {
650 struct sony_pic_ioport *cur_ioport; 908 struct sony_pic_ioport *cur_ioport;
651 struct list_head interrupts; 909 struct list_head interrupts;
652 struct list_head ioports; 910 struct list_head ioports;
653
654 struct input_dev *input_jog_dev;
655 struct input_dev *input_key_dev;
656 struct kfifo *input_fifo;
657 spinlock_t input_fifo_lock;
658 struct workqueue_struct *sony_pic_wq;
659}; 911};
660 912
661static struct sony_pic_dev spic_dev = { 913static struct sony_pic_dev spic_dev = {
@@ -929,250 +1181,9 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
929 return v1; 1181 return v1;
930} 1182}
931 1183
932/***************** 1184/*
933 *
934 * INPUT Device
935 *
936 *****************/
937struct sony_pic_keypress {
938 struct input_dev *dev;
939 int key;
940};
941
942/* Correspondance table between sonypi events and input layer events */
943static struct {
944 int sonypiev;
945 int inputev;
946} sony_pic_inputkeys[] = {
947 { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
948 { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
949 { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
950 { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
951 { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
952 { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
953 { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
954 { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
955 { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
956 { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
957 { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
958 { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
959 { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
960 { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
961 { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
962 { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
963 { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
964 { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
965 { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
966 { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
967 { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
968 { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
969 { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
970 { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
971 { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
972 { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
973 { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
974 { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
975 { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
976 { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
977 { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
978 { 0, 0 },
979};
980
981/* release buttons after a short delay if pressed */
982static void do_sony_pic_release_key(struct work_struct *work)
983{
984 struct sony_pic_keypress kp;
985
986 while (kfifo_get(spic_dev.input_fifo, (unsigned char *)&kp,
987 sizeof(kp)) == sizeof(kp)) {
988 msleep(10);
989 input_report_key(kp.dev, kp.key, 0);
990 input_sync(kp.dev);
991 }
992}
993static DECLARE_WORK(sony_pic_release_key_work,
994 do_sony_pic_release_key);
995
996/* forward event to the input subsytem */
997static void sony_pic_report_input_event(u8 event)
998{
999 struct input_dev *jog_dev = spic_dev.input_jog_dev;
1000 struct input_dev *key_dev = spic_dev.input_key_dev;
1001 struct sony_pic_keypress kp = { NULL };
1002 int i;
1003
1004 if (event == SONYPI_EVENT_FNKEY_RELEASED) {
1005 /* Nothing, not all VAIOs generate this event */
1006 return;
1007 }
1008
1009 /* report jog_dev events */
1010 if (jog_dev) {
1011 switch (event) {
1012 case SONYPI_EVENT_JOGDIAL_UP:
1013 case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
1014 input_report_rel(jog_dev, REL_WHEEL, 1);
1015 input_sync(jog_dev);
1016 return;
1017
1018 case SONYPI_EVENT_JOGDIAL_DOWN:
1019 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
1020 input_report_rel(jog_dev, REL_WHEEL, -1);
1021 input_sync(jog_dev);
1022 return;
1023
1024 default:
1025 break;
1026 }
1027 }
1028
1029 switch (event) {
1030 case SONYPI_EVENT_JOGDIAL_PRESSED:
1031 kp.key = BTN_MIDDLE;
1032 kp.dev = jog_dev;
1033 break;
1034
1035 default:
1036 for (i = 0; sony_pic_inputkeys[i].sonypiev; i++)
1037 if (event == sony_pic_inputkeys[i].sonypiev) {
1038 kp.dev = key_dev;
1039 kp.key = sony_pic_inputkeys[i].inputev;
1040 break;
1041 }
1042 break;
1043 }
1044
1045 if (kp.dev) {
1046 input_report_key(kp.dev, kp.key, 1);
1047 input_sync(kp.dev);
1048 kfifo_put(spic_dev.input_fifo,
1049 (unsigned char *)&kp, sizeof(kp));
1050
1051 if (!work_pending(&sony_pic_release_key_work))
1052 queue_work(spic_dev.sony_pic_wq,
1053 &sony_pic_release_key_work);
1054 }
1055}
1056
1057static int sony_pic_setup_input(void)
1058{
1059 struct input_dev *jog_dev;
1060 struct input_dev *key_dev;
1061 int i;
1062 int error;
1063 u8 jog_present = 0;
1064
1065 /* kfifo */
1066 spin_lock_init(&spic_dev.input_fifo_lock);
1067 spic_dev.input_fifo =
1068 kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
1069 &spic_dev.input_fifo_lock);
1070 if (IS_ERR(spic_dev.input_fifo)) {
1071 printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
1072 return PTR_ERR(spic_dev.input_fifo);
1073 }
1074
1075 /* init workqueue */
1076 spic_dev.sony_pic_wq = create_singlethread_workqueue("sony-pic");
1077 if (!spic_dev.sony_pic_wq) {
1078 printk(KERN_ERR DRV_PFX
1079 "Unabe to create workqueue.\n");
1080 error = -ENXIO;
1081 goto err_free_kfifo;
1082 }
1083
1084 /* input keys */
1085 key_dev = input_allocate_device();
1086 if (!key_dev) {
1087 error = -ENOMEM;
1088 goto err_destroy_wq;
1089 }
1090
1091 key_dev->name = "Sony Vaio Keys";
1092 key_dev->id.bustype = BUS_ISA;
1093 key_dev->id.vendor = PCI_VENDOR_ID_SONY;
1094
1095 /* Initialize the Input Drivers: special keys */
1096 key_dev->evbit[0] = BIT(EV_KEY);
1097 for (i = 0; sony_pic_inputkeys[i].sonypiev; i++)
1098 if (sony_pic_inputkeys[i].inputev)
1099 set_bit(sony_pic_inputkeys[i].inputev, key_dev->keybit);
1100
1101 error = input_register_device(key_dev);
1102 if (error)
1103 goto err_free_keydev;
1104
1105 spic_dev.input_key_dev = key_dev;
1106
1107 /* jogdial - really reliable ? */
1108 ec_read(SONY_EC_JOGB, &jog_present);
1109 if (jog_present & SONY_EC_JOGB_MASK || force_jog) {
1110 jog_dev = input_allocate_device();
1111 if (!jog_dev) {
1112 error = -ENOMEM;
1113 goto err_unregister_keydev;
1114 }
1115
1116 jog_dev->name = "Sony Vaio Jogdial";
1117 jog_dev->id.bustype = BUS_ISA;
1118 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
1119
1120 jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
1121 jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
1122 jog_dev->relbit[0] = BIT(REL_WHEEL);
1123
1124 error = input_register_device(jog_dev);
1125 if (error)
1126 goto err_free_jogdev;
1127
1128 spic_dev.input_jog_dev = jog_dev;
1129 }
1130
1131 return 0;
1132
1133err_free_jogdev:
1134 input_free_device(jog_dev);
1135
1136err_unregister_keydev:
1137 input_unregister_device(key_dev);
1138 /* to avoid kref underflow below at input_free_device */
1139 key_dev = NULL;
1140
1141err_free_keydev:
1142 input_free_device(key_dev);
1143
1144err_destroy_wq:
1145 destroy_workqueue(spic_dev.sony_pic_wq);
1146
1147err_free_kfifo:
1148 kfifo_free(spic_dev.input_fifo);
1149
1150 return error;
1151}
1152
1153static void sony_pic_remove_input(void)
1154{
1155 /* flush workqueue first */
1156 flush_workqueue(spic_dev.sony_pic_wq);
1157
1158 /* destroy input devs */
1159 input_unregister_device(spic_dev.input_key_dev);
1160 spic_dev.input_key_dev = NULL;
1161
1162 if (spic_dev.input_jog_dev) {
1163 input_unregister_device(spic_dev.input_jog_dev);
1164 spic_dev.input_jog_dev = NULL;
1165 }
1166
1167 destroy_workqueue(spic_dev.sony_pic_wq);
1168 kfifo_free(spic_dev.input_fifo);
1169}
1170
1171/********************
1172 *
1173 * ACPI callbacks 1185 * ACPI callbacks
1174 * 1186 */
1175 ********************/
1176static acpi_status 1187static acpi_status
1177sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) 1188sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
1178{ 1189{
@@ -1409,7 +1420,7 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
1409 return IRQ_HANDLED; 1420 return IRQ_HANDLED;
1410 1421
1411found: 1422found:
1412 sony_pic_report_input_event(device_event); 1423 sony_laptop_report_input_event(device_event);
1413 acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event); 1424 acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
1414 1425
1415 return IRQ_HANDLED; 1426 return IRQ_HANDLED;
@@ -1434,7 +1445,7 @@ static int sony_pic_remove(struct acpi_device *device, int type)
1434 release_region(spic_dev.cur_ioport->io.minimum, 1445 release_region(spic_dev.cur_ioport->io.minimum,
1435 spic_dev.cur_ioport->io.address_length); 1446 spic_dev.cur_ioport->io.address_length);
1436 1447
1437 sony_pic_remove_input(); 1448 sony_laptop_remove_input();
1438 1449
1439 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { 1450 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
1440 list_del(&io->list); 1451 list_del(&io->list);
@@ -1474,7 +1485,7 @@ static int sony_pic_add(struct acpi_device *device)
1474 } 1485 }
1475 1486
1476 /* setup input devices and helper fifo */ 1487 /* setup input devices and helper fifo */
1477 result = sony_pic_setup_input(); 1488 result = sony_laptop_setup_input();
1478 if (result) { 1489 if (result) {
1479 printk(KERN_ERR DRV_PFX 1490 printk(KERN_ERR DRV_PFX
1480 "Unabe to create input devices.\n"); 1491 "Unabe to create input devices.\n");
@@ -1535,7 +1546,7 @@ err_release_region:
1535 spic_dev.cur_ioport->io.address_length); 1546 spic_dev.cur_ioport->io.address_length);
1536 1547
1537err_remove_input: 1548err_remove_input:
1538 sony_pic_remove_input(); 1549 sony_laptop_remove_input();
1539 1550
1540err_free_resources: 1551err_free_resources:
1541 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { 1552 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {