diff options
Diffstat (limited to 'drivers/misc/sony-laptop.c')
-rw-r--r-- | drivers/misc/sony-laptop.c | 368 |
1 files changed, 308 insertions, 60 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 9623eaf4f89f..303e48ca0e8a 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
@@ -142,43 +142,124 @@ struct sony_laptop_keypress { | |||
142 | int key; | 142 | int key; |
143 | }; | 143 | }; |
144 | 144 | ||
145 | /* Correspondance table between sonypi events and input layer events */ | 145 | /* Correspondance table between sonypi events |
146 | static struct { | 146 | * and input layer indexes in the keymap |
147 | int sonypiev; | 147 | */ |
148 | int inputev; | 148 | static int sony_laptop_input_index[] = { |
149 | } sony_laptop_inputkeys[] = { | 149 | -1, /* no event */ |
150 | { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA }, | 150 | -1, /* SONYPI_EVENT_JOGDIAL_DOWN */ |
151 | { SONYPI_EVENT_FNKEY_ONLY, KEY_FN }, | 151 | -1, /* SONYPI_EVENT_JOGDIAL_UP */ |
152 | { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC }, | 152 | -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ |
153 | { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 }, | 153 | -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */ |
154 | { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 }, | 154 | -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */ |
155 | { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 }, | 155 | -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */ |
156 | { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 }, | 156 | 0, /* SONYPI_EVENT_CAPTURE_PRESSED */ |
157 | { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 }, | 157 | 1, /* SONYPI_EVENT_CAPTURE_RELEASED */ |
158 | { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 }, | 158 | 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ |
159 | { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 }, | 159 | 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ |
160 | { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 }, | 160 | 4, /* SONYPI_EVENT_FNKEY_ESC */ |
161 | { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 }, | 161 | 5, /* SONYPI_EVENT_FNKEY_F1 */ |
162 | { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 }, | 162 | 6, /* SONYPI_EVENT_FNKEY_F2 */ |
163 | { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 }, | 163 | 7, /* SONYPI_EVENT_FNKEY_F3 */ |
164 | { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 }, | 164 | 8, /* SONYPI_EVENT_FNKEY_F4 */ |
165 | { SONYPI_EVENT_FNKEY_1, KEY_FN_1 }, | 165 | 9, /* SONYPI_EVENT_FNKEY_F5 */ |
166 | { SONYPI_EVENT_FNKEY_2, KEY_FN_2 }, | 166 | 10, /* SONYPI_EVENT_FNKEY_F6 */ |
167 | { SONYPI_EVENT_FNKEY_D, KEY_FN_D }, | 167 | 11, /* SONYPI_EVENT_FNKEY_F7 */ |
168 | { SONYPI_EVENT_FNKEY_E, KEY_FN_E }, | 168 | 12, /* SONYPI_EVENT_FNKEY_F8 */ |
169 | { SONYPI_EVENT_FNKEY_F, KEY_FN_F }, | 169 | 13, /* SONYPI_EVENT_FNKEY_F9 */ |
170 | { SONYPI_EVENT_FNKEY_S, KEY_FN_S }, | 170 | 14, /* SONYPI_EVENT_FNKEY_F10 */ |
171 | { SONYPI_EVENT_FNKEY_B, KEY_FN_B }, | 171 | 15, /* SONYPI_EVENT_FNKEY_F11 */ |
172 | { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE }, | 172 | 16, /* SONYPI_EVENT_FNKEY_F12 */ |
173 | { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE }, | 173 | 17, /* SONYPI_EVENT_FNKEY_1 */ |
174 | { SONYPI_EVENT_PKEY_P1, KEY_PROG1 }, | 174 | 18, /* SONYPI_EVENT_FNKEY_2 */ |
175 | { SONYPI_EVENT_PKEY_P2, KEY_PROG2 }, | 175 | 19, /* SONYPI_EVENT_FNKEY_D */ |
176 | { SONYPI_EVENT_PKEY_P3, KEY_PROG3 }, | 176 | 20, /* SONYPI_EVENT_FNKEY_E */ |
177 | { SONYPI_EVENT_BACK_PRESSED, KEY_BACK }, | 177 | 21, /* SONYPI_EVENT_FNKEY_F */ |
178 | { SONYPI_EVENT_HELP_PRESSED, KEY_HELP }, | 178 | 22, /* SONYPI_EVENT_FNKEY_S */ |
179 | { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM }, | 179 | 23, /* SONYPI_EVENT_FNKEY_B */ |
180 | { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB }, | 180 | 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */ |
181 | { 0, 0 }, | 181 | 25, /* SONYPI_EVENT_PKEY_P1 */ |
182 | 26, /* SONYPI_EVENT_PKEY_P2 */ | ||
183 | 27, /* SONYPI_EVENT_PKEY_P3 */ | ||
184 | 28, /* SONYPI_EVENT_BACK_PRESSED */ | ||
185 | -1, /* SONYPI_EVENT_LID_CLOSED */ | ||
186 | -1, /* SONYPI_EVENT_LID_OPENED */ | ||
187 | 29, /* SONYPI_EVENT_BLUETOOTH_ON */ | ||
188 | 30, /* SONYPI_EVENT_BLUETOOTH_OFF */ | ||
189 | 31, /* SONYPI_EVENT_HELP_PRESSED */ | ||
190 | 32, /* SONYPI_EVENT_FNKEY_ONLY */ | ||
191 | 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | ||
192 | 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */ | ||
193 | 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | ||
194 | 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | ||
195 | 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | ||
196 | 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */ | ||
197 | 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | ||
198 | 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | ||
199 | 41, /* SONYPI_EVENT_ZOOM_PRESSED */ | ||
200 | 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */ | ||
201 | 43, /* SONYPI_EVENT_MEYE_FACE */ | ||
202 | 44, /* SONYPI_EVENT_MEYE_OPPOSITE */ | ||
203 | 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */ | ||
204 | 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */ | ||
205 | -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */ | ||
206 | -1, /* SONYPI_EVENT_BATTERY_INSERT */ | ||
207 | -1, /* SONYPI_EVENT_BATTERY_REMOVE */ | ||
208 | -1, /* SONYPI_EVENT_FNKEY_RELEASED */ | ||
209 | 47, /* SONYPI_EVENT_WIRELESS_ON */ | ||
210 | 48, /* SONYPI_EVENT_WIRELESS_OFF */ | ||
211 | }; | ||
212 | |||
213 | static int sony_laptop_input_keycode_map[] = { | ||
214 | KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */ | ||
215 | KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */ | ||
216 | KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ | ||
217 | KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ | ||
218 | KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */ | ||
219 | KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */ | ||
220 | KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */ | ||
221 | KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */ | ||
222 | KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */ | ||
223 | KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */ | ||
224 | KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */ | ||
225 | KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */ | ||
226 | KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */ | ||
227 | KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */ | ||
228 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ | ||
229 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ | ||
230 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ | ||
231 | KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ | ||
232 | KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ | ||
233 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ | ||
234 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ | ||
235 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ | ||
236 | KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */ | ||
237 | KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */ | ||
238 | KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */ | ||
239 | KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */ | ||
240 | KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */ | ||
241 | KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */ | ||
242 | KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */ | ||
243 | KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */ | ||
244 | KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */ | ||
245 | KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */ | ||
246 | KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */ | ||
247 | KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | ||
248 | KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */ | ||
249 | KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | ||
250 | KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | ||
251 | KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | ||
252 | KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */ | ||
253 | KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | ||
254 | KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | ||
255 | KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */ | ||
256 | BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */ | ||
257 | KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */ | ||
258 | KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */ | ||
259 | KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */ | ||
260 | KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ | ||
261 | KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ | ||
262 | KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ | ||
182 | }; | 263 | }; |
183 | 264 | ||
184 | /* release buttons after a short delay if pressed */ | 265 | /* release buttons after a short delay if pressed */ |
@@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event) | |||
202 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; | 283 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; |
203 | struct input_dev *key_dev = sony_laptop_input.key_dev; | 284 | struct input_dev *key_dev = sony_laptop_input.key_dev; |
204 | struct sony_laptop_keypress kp = { NULL }; | 285 | struct sony_laptop_keypress kp = { NULL }; |
205 | int i; | ||
206 | 286 | ||
207 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { | 287 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { |
208 | /* Nothing, not all VAIOs generate this event */ | 288 | /* Nothing, not all VAIOs generate this event */ |
@@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event) | |||
231 | break; | 311 | break; |
232 | 312 | ||
233 | default: | 313 | default: |
234 | for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) | 314 | if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { |
235 | if (event == sony_laptop_inputkeys[i].sonypiev) { | 315 | dprintk("sony_laptop_report_input_event, event not known: %d\n", event); |
316 | break; | ||
317 | } | ||
318 | if (sony_laptop_input_index[event] != -1) { | ||
319 | kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; | ||
320 | if (kp.key != KEY_UNKNOWN) | ||
236 | kp.dev = key_dev; | 321 | kp.dev = key_dev; |
237 | kp.key = sony_laptop_inputkeys[i].inputev; | 322 | } |
238 | break; | ||
239 | } | ||
240 | break; | 323 | break; |
241 | } | 324 | } |
242 | 325 | ||
243 | if (kp.dev) { | 326 | if (kp.dev) { |
244 | input_report_key(kp.dev, kp.key, 1); | 327 | input_report_key(kp.dev, kp.key, 1); |
328 | /* we emit the scancode so we can always remap the key */ | ||
329 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); | ||
245 | input_sync(kp.dev); | 330 | input_sync(kp.dev); |
246 | kfifo_put(sony_laptop_input.fifo, | 331 | kfifo_put(sony_laptop_input.fifo, |
247 | (unsigned char *)&kp, sizeof(kp)); | 332 | (unsigned char *)&kp, sizeof(kp)); |
@@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void) | |||
296 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; | 381 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; |
297 | 382 | ||
298 | /* Initialize the Input Drivers: special keys */ | 383 | /* Initialize the Input Drivers: special keys */ |
299 | key_dev->evbit[0] = BIT(EV_KEY); | 384 | set_bit(EV_KEY, key_dev->evbit); |
300 | for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) | 385 | set_bit(EV_MSC, key_dev->evbit); |
301 | if (sony_laptop_inputkeys[i].inputev) | 386 | set_bit(MSC_SCAN, key_dev->mscbit); |
302 | set_bit(sony_laptop_inputkeys[i].inputev, | 387 | key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); |
303 | key_dev->keybit); | 388 | key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); |
389 | key_dev->keycode = &sony_laptop_input_keycode_map; | ||
390 | for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { | ||
391 | if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { | ||
392 | set_bit(sony_laptop_input_keycode_map[i], | ||
393 | key_dev->keybit); | ||
394 | } | ||
395 | } | ||
304 | 396 | ||
305 | error = input_register_device(key_dev); | 397 | error = input_register_device(key_dev); |
306 | if (error) | 398 | if (error) |
@@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW"); | |||
487 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); | 579 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); |
488 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); | 580 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); |
489 | 581 | ||
582 | SNC_HANDLE_NAMES(lidstate_get, "GLID"); | ||
583 | |||
584 | SNC_HANDLE_NAMES(indicatorlamp_get, "GILS"); | ||
585 | SNC_HANDLE_NAMES(indicatorlamp_set, "SILS"); | ||
586 | |||
587 | SNC_HANDLE_NAMES(gainbass_get, "GMGB"); | ||
588 | SNC_HANDLE_NAMES(gainbass_set, "CMGB"); | ||
589 | |||
490 | SNC_HANDLE_NAMES(PID_get, "GPID"); | 590 | SNC_HANDLE_NAMES(PID_get, "GPID"); |
491 | 591 | ||
492 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); | 592 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); |
@@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = { | |||
507 | boolean_validate, 0), | 607 | boolean_validate, 0), |
508 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, | 608 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, |
509 | boolean_validate, 1), | 609 | boolean_validate, 1), |
610 | SNC_HANDLE(lidstate, snc_lidstate_get, NULL, | ||
611 | boolean_validate, 0), | ||
612 | SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, | ||
613 | boolean_validate, 0), | ||
614 | SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, | ||
615 | boolean_validate, 0), | ||
510 | /* unknown methods */ | 616 | /* unknown methods */ |
511 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), | 617 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), |
512 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), | 618 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), |
@@ -689,13 +795,116 @@ static struct backlight_ops sony_backlight_ops = { | |||
689 | }; | 795 | }; |
690 | 796 | ||
691 | /* | 797 | /* |
798 | * New SNC-only Vaios event mapping to driver known keys | ||
799 | */ | ||
800 | struct sony_nc_event { | ||
801 | u8 data; | ||
802 | u8 event; | ||
803 | }; | ||
804 | |||
805 | static struct sony_nc_event *sony_nc_events; | ||
806 | |||
807 | /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence | ||
808 | * for Fn keys | ||
809 | */ | ||
810 | static int sony_nc_C_enable(struct dmi_system_id *id) | ||
811 | { | ||
812 | int result = 0; | ||
813 | |||
814 | printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); | ||
815 | |||
816 | sony_nc_events = id->driver_data; | ||
817 | |||
818 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 | ||
819 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 | ||
820 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 | ||
821 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 | ||
822 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 | ||
823 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { | ||
824 | printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " | ||
825 | "functionalities may be missing\n"); | ||
826 | return 1; | ||
827 | } | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | static struct sony_nc_event sony_C_events[] = { | ||
832 | { 0x81, SONYPI_EVENT_FNKEY_F1 }, | ||
833 | { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, | ||
834 | { 0x85, SONYPI_EVENT_FNKEY_F5 }, | ||
835 | { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, | ||
836 | { 0x86, SONYPI_EVENT_FNKEY_F6 }, | ||
837 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, | ||
838 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, | ||
839 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, | ||
840 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, | ||
841 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, | ||
842 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, | ||
843 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | ||
844 | { 0, 0 }, | ||
845 | }; | ||
846 | |||
847 | /* SNC-only model map */ | ||
848 | struct dmi_system_id sony_nc_ids[] = { | ||
849 | { | ||
850 | .ident = "Sony Vaio FE Series", | ||
851 | .callback = sony_nc_C_enable, | ||
852 | .driver_data = sony_C_events, | ||
853 | .matches = { | ||
854 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
855 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), | ||
856 | }, | ||
857 | }, | ||
858 | { | ||
859 | .ident = "Sony Vaio C Series", | ||
860 | .callback = sony_nc_C_enable, | ||
861 | .driver_data = sony_C_events, | ||
862 | .matches = { | ||
863 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
864 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), | ||
865 | }, | ||
866 | }, | ||
867 | { } | ||
868 | }; | ||
869 | |||
870 | /* | ||
692 | * ACPI callbacks | 871 | * ACPI callbacks |
693 | */ | 872 | */ |
694 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) | 873 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) |
695 | { | 874 | { |
696 | dprintk("sony_acpi_notify, event: %d\n", event); | 875 | struct sony_nc_event *evmap; |
697 | sony_laptop_report_input_event(event); | 876 | u32 ev = event; |
698 | acpi_bus_generate_event(sony_nc_acpi_device, 1, event); | 877 | int result; |
878 | |||
879 | if (ev == 0x92) { | ||
880 | /* read the key pressed from EC.GECR | ||
881 | * A call to SN07 with 0x0202 will do it as well respecting | ||
882 | * the current protocol on different OSes | ||
883 | * | ||
884 | * Note: the path for GECR may be | ||
885 | * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) | ||
886 | * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) | ||
887 | * | ||
888 | * TODO: we may want to do the same for the older GHKE -need | ||
889 | * dmi list- so this snippet may become one more callback. | ||
890 | */ | ||
891 | if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) | ||
892 | dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); | ||
893 | else | ||
894 | ev = result & 0xFF; | ||
895 | } | ||
896 | |||
897 | if (sony_nc_events) | ||
898 | for (evmap = sony_nc_events; evmap->event; evmap++) { | ||
899 | if (evmap->data == ev) { | ||
900 | ev = evmap->event; | ||
901 | break; | ||
902 | } | ||
903 | } | ||
904 | |||
905 | dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); | ||
906 | sony_laptop_report_input_event(ev); | ||
907 | acpi_bus_generate_event(sony_nc_acpi_device, 1, ev); | ||
699 | } | 908 | } |
700 | 909 | ||
701 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | 910 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, |
@@ -732,6 +941,10 @@ static int sony_nc_resume(struct acpi_device *device) | |||
732 | break; | 941 | break; |
733 | } | 942 | } |
734 | } | 943 | } |
944 | |||
945 | /* re-initialize models with specific requirements */ | ||
946 | dmi_check_system(sony_nc_ids); | ||
947 | |||
735 | return 0; | 948 | return 0; |
736 | } | 949 | } |
737 | 950 | ||
@@ -750,6 +963,15 @@ static int sony_nc_add(struct acpi_device *device) | |||
750 | 963 | ||
751 | sony_nc_acpi_handle = device->handle; | 964 | sony_nc_acpi_handle = device->handle; |
752 | 965 | ||
966 | /* read device status */ | ||
967 | result = acpi_bus_get_status(device); | ||
968 | /* bail IFF the above call was successful and the device is not present */ | ||
969 | if (!result && !device->status.present) { | ||
970 | dprintk("Device not present\n"); | ||
971 | result = -ENODEV; | ||
972 | goto outwalk; | ||
973 | } | ||
974 | |||
753 | if (debug) { | 975 | if (debug) { |
754 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, | 976 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, |
755 | 1, sony_walk_callback, NULL, NULL); | 977 | 1, sony_walk_callback, NULL, NULL); |
@@ -760,6 +982,15 @@ static int sony_nc_add(struct acpi_device *device) | |||
760 | } | 982 | } |
761 | } | 983 | } |
762 | 984 | ||
985 | /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1 | ||
986 | * should be respected as we already checked for the device presence above */ | ||
987 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) { | ||
988 | dprintk("Invoking _INI\n"); | ||
989 | if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI, | ||
990 | NULL, NULL))) | ||
991 | dprintk("_INI Method failed\n"); | ||
992 | } | ||
993 | |||
763 | /* setup input devices and helper fifo */ | 994 | /* setup input devices and helper fifo */ |
764 | result = sony_laptop_setup_input(); | 995 | result = sony_laptop_setup_input(); |
765 | if (result) { | 996 | if (result) { |
@@ -772,7 +1003,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
772 | ACPI_DEVICE_NOTIFY, | 1003 | ACPI_DEVICE_NOTIFY, |
773 | sony_acpi_notify, NULL); | 1004 | sony_acpi_notify, NULL); |
774 | if (ACPI_FAILURE(status)) { | 1005 | if (ACPI_FAILURE(status)) { |
775 | printk(KERN_WARNING DRV_PFX "unable to install notify handler\n"); | 1006 | printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status); |
776 | result = -ENODEV; | 1007 | result = -ENODEV; |
777 | goto outinput; | 1008 | goto outinput; |
778 | } | 1009 | } |
@@ -795,6 +1026,9 @@ static int sony_nc_add(struct acpi_device *device) | |||
795 | 1026 | ||
796 | } | 1027 | } |
797 | 1028 | ||
1029 | /* initialize models with specific requirements */ | ||
1030 | dmi_check_system(sony_nc_ids); | ||
1031 | |||
798 | result = sony_pf_add(); | 1032 | result = sony_pf_add(); |
799 | if (result) | 1033 | if (result) |
800 | goto outbacklight; | 1034 | goto outbacklight; |
@@ -908,7 +1142,9 @@ static struct acpi_driver sony_nc_driver = { | |||
908 | #define SONYPI_DEVICE_TYPE2 0x00000002 | 1142 | #define SONYPI_DEVICE_TYPE2 0x00000002 |
909 | #define SONYPI_DEVICE_TYPE3 0x00000004 | 1143 | #define SONYPI_DEVICE_TYPE3 0x00000004 |
910 | 1144 | ||
911 | #define SONY_PIC_EV_MASK 0xff | 1145 | #define SONYPI_TYPE1_OFFSET 0x04 |
1146 | #define SONYPI_TYPE2_OFFSET 0x12 | ||
1147 | #define SONYPI_TYPE3_OFFSET 0x12 | ||
912 | 1148 | ||
913 | struct sony_pic_ioport { | 1149 | struct sony_pic_ioport { |
914 | struct acpi_resource_io io; | 1150 | struct acpi_resource_io io; |
@@ -922,6 +1158,7 @@ struct sony_pic_irq { | |||
922 | 1158 | ||
923 | struct sony_pic_dev { | 1159 | struct sony_pic_dev { |
924 | int model; | 1160 | int model; |
1161 | u16 evport_offset; | ||
925 | u8 camera_power; | 1162 | u8 camera_power; |
926 | u8 bluetooth_power; | 1163 | u8 bluetooth_power; |
927 | u8 wwan_power; | 1164 | u8 wwan_power; |
@@ -1999,20 +2236,17 @@ end: | |||
1999 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) | 2236 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) |
2000 | { | 2237 | { |
2001 | int i, j; | 2238 | int i, j; |
2002 | u32 port_val = 0; | ||
2003 | u8 ev = 0; | 2239 | u8 ev = 0; |
2004 | u8 data_mask = 0; | 2240 | u8 data_mask = 0; |
2005 | u8 device_event = 0; | 2241 | u8 device_event = 0; |
2006 | 2242 | ||
2007 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; | 2243 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; |
2008 | 2244 | ||
2009 | acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val, | 2245 | ev = inb_p(dev->cur_ioport->io.minimum); |
2010 | dev->cur_ioport->io.address_length); | 2246 | data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset); |
2011 | ev = port_val & SONY_PIC_EV_MASK; | ||
2012 | data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8)); | ||
2013 | 2247 | ||
2014 | dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n", | 2248 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
2015 | port_val, ev, data_mask, dev->cur_ioport->io.minimum); | 2249 | ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset); |
2016 | 2250 | ||
2017 | if (ev == 0x00 || ev == 0xff) | 2251 | if (ev == 0x00 || ev == 0xff) |
2018 | return IRQ_HANDLED; | 2252 | return IRQ_HANDLED; |
@@ -2103,6 +2337,20 @@ static int sony_pic_add(struct acpi_device *device) | |||
2103 | spic_dev.model = sony_pic_detect_device_type(); | 2337 | spic_dev.model = sony_pic_detect_device_type(); |
2104 | mutex_init(&spic_dev.lock); | 2338 | mutex_init(&spic_dev.lock); |
2105 | 2339 | ||
2340 | /* model specific characteristics */ | ||
2341 | switch(spic_dev.model) { | ||
2342 | case SONYPI_DEVICE_TYPE1: | ||
2343 | spic_dev.evport_offset = SONYPI_TYPE1_OFFSET; | ||
2344 | break; | ||
2345 | case SONYPI_DEVICE_TYPE3: | ||
2346 | spic_dev.evport_offset = SONYPI_TYPE3_OFFSET; | ||
2347 | break; | ||
2348 | case SONYPI_DEVICE_TYPE2: | ||
2349 | default: | ||
2350 | spic_dev.evport_offset = SONYPI_TYPE2_OFFSET; | ||
2351 | break; | ||
2352 | } | ||
2353 | |||
2106 | /* read _PRS resources */ | 2354 | /* read _PRS resources */ |
2107 | result = sony_pic_possible_resources(device); | 2355 | result = sony_pic_possible_resources(device); |
2108 | if (result) { | 2356 | if (result) { |