aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig15
-rw-r--r--drivers/misc/asus-laptop.c151
-rw-r--r--drivers/misc/sony-laptop.c2131
3 files changed, 2034 insertions, 263 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 445c4b10c41e..a3c525b2616a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -112,16 +112,21 @@ config SONY_LAPTOP
112 depends on X86 && ACPI 112 depends on X86 && ACPI
113 select BACKLIGHT_CLASS_DEVICE 113 select BACKLIGHT_CLASS_DEVICE
114 ---help--- 114 ---help---
115 This mini-driver drives the SNC device present in the ACPI BIOS of 115 This mini-driver drives the SNC and SPIC devices present in the ACPI
116 the Sony Vaio laptops. 116 BIOS of the Sony Vaio laptops.
117 117
118 It gives access to some extra laptop functionalities. In its current 118 It gives access to some extra laptop functionalities like Bluetooth,
119 form, this driver let the user set or query the screen brightness 119 screen brightness control, Fn keys and allows powering on/off some
120 through the backlight subsystem and remove/apply power to some
121 devices. 120 devices.
122 121
123 Read <file:Documentation/sony-laptop.txt> for more information. 122 Read <file:Documentation/sony-laptop.txt> for more information.
124 123
124config SONY_LAPTOP_OLD
125 bool "Sonypi compatibility"
126 depends on SONY_LAPTOP
127 ---help---
128 Build the sonypi driver compatibility code into the sony-laptop driver.
129
125config THINKPAD_ACPI 130config THINKPAD_ACPI
126 tristate "ThinkPad ACPI Laptop Extras" 131 tristate "ThinkPad ACPI Laptop Extras"
127 depends on X86 && ACPI 132 depends on X86 && ACPI
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 4b232124a1ab..65c32a95e121 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * 4 *
5 * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor 5 * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
6 * Copyright (C) 2006 Corentin Chary 6 * Copyright (C) 2006-2007 Corentin Chary
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@
48#include <acpi/acpi_bus.h> 48#include <acpi/acpi_bus.h>
49#include <asm/uaccess.h> 49#include <asm/uaccess.h>
50 50
51#define ASUS_LAPTOP_VERSION "0.40" 51#define ASUS_LAPTOP_VERSION "0.41"
52 52
53#define ASUS_HOTK_NAME "Asus Laptop Support" 53#define ASUS_HOTK_NAME "Asus Laptop Support"
54#define ASUS_HOTK_CLASS "hotkey" 54#define ASUS_HOTK_CLASS "hotkey"
@@ -81,7 +81,8 @@
81#define TLED_ON 0x08 //touchpad LED 81#define TLED_ON 0x08 //touchpad LED
82#define RLED_ON 0x10 //Record LED 82#define RLED_ON 0x10 //Record LED
83#define PLED_ON 0x20 //Phone LED 83#define PLED_ON 0x20 //Phone LED
84#define LCD_ON 0x40 //LCD backlight 84#define GLED_ON 0x40 //Gaming LED
85#define LCD_ON 0x80 //LCD backlight
85 86
86#define ASUS_LOG ASUS_HOTK_FILE ": " 87#define ASUS_LOG ASUS_HOTK_FILE ": "
87#define ASUS_ERR KERN_ERR ASUS_LOG 88#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -94,6 +95,19 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
94MODULE_DESCRIPTION(ASUS_HOTK_NAME); 95MODULE_DESCRIPTION(ASUS_HOTK_NAME);
95MODULE_LICENSE("GPL"); 96MODULE_LICENSE("GPL");
96 97
98/* WAPF defines the behavior of the Fn+Fx wlan key
99 * The significance of values is yet to be found, but
100 * most of the time:
101 * 0x0 will do nothing
102 * 0x1 will allow to control the device with Fn+Fx key.
103 * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
104 * 0x5 like 0x1 or 0x4
105 * So, if something doesn't work as you want, just try other values =)
106 */
107static uint wapf = 1;
108module_param(wapf, uint, 0644);
109MODULE_PARM_DESC(wapf, "WAPF value");
110
97#define ASUS_HANDLE(object, paths...) \ 111#define ASUS_HANDLE(object, paths...) \
98 static acpi_handle object##_handle = NULL; \ 112 static acpi_handle object##_handle = NULL; \
99 static char *object##_paths[] = { paths } 113 static char *object##_paths[] = { paths }
@@ -103,6 +117,7 @@ ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
103ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); 117ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
104ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ 118ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
105ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ 119ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
120ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
106 121
107/* LEDD */ 122/* LEDD */
108ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); 123ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
@@ -221,6 +236,7 @@ ASUS_LED(mled, "mail");
221ASUS_LED(tled, "touchpad"); 236ASUS_LED(tled, "touchpad");
222ASUS_LED(rled, "record"); 237ASUS_LED(rled, "record");
223ASUS_LED(pled, "phone"); 238ASUS_LED(pled, "phone");
239ASUS_LED(gled, "gaming");
224 240
225/* 241/*
226 * This function evaluates an ACPI method, given an int as parameter, the 242 * This function evaluates an ACPI method, given an int as parameter, the
@@ -245,32 +261,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
245 return (status == AE_OK); 261 return (status == AE_OK);
246} 262}
247 263
248static int read_acpi_int(acpi_handle handle, const char *method, int *val,
249 struct acpi_object_list *params)
250{
251 struct acpi_buffer output;
252 union acpi_object out_obj;
253 acpi_status status;
254
255 output.length = sizeof(out_obj);
256 output.pointer = &out_obj;
257
258 status = acpi_evaluate_object(handle, (char *)method, params, &output);
259 *val = out_obj.integer.value;
260 return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
261}
262
263static int read_wireless_status(int mask) 264static int read_wireless_status(int mask)
264{ 265{
265 int status; 266 ulong status;
267 acpi_status rv = AE_OK;
266 268
267 if (!wireless_status_handle) 269 if (!wireless_status_handle)
268 return (hotk->status & mask) ? 1 : 0; 270 return (hotk->status & mask) ? 1 : 0;
269 271
270 if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) { 272 rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
271 return (status & mask) ? 1 : 0; 273 if (ACPI_FAILURE(rv))
272 } else
273 printk(ASUS_WARNING "Error reading Wireless status\n"); 274 printk(ASUS_WARNING "Error reading Wireless status\n");
275 else
276 return (status & mask) ? 1 : 0;
274 277
275 return (hotk->status & mask) ? 1 : 0; 278 return (hotk->status & mask) ? 1 : 0;
276} 279}
@@ -285,19 +288,28 @@ static int read_status(int mask)
285 return (hotk->status & mask) ? 1 : 0; 288 return (hotk->status & mask) ? 1 : 0;
286} 289}
287 290
288static void write_status(acpi_handle handle, int out, int mask, int invert) 291static void write_status(acpi_handle handle, int out, int mask)
289{ 292{
290 hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); 293 hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
291 294
292 if (invert) /* invert target value */ 295 switch (mask) {
296 case MLED_ON:
293 out = !out & 0x1; 297 out = !out & 0x1;
298 break;
299 case GLED_ON:
300 out = (out & 0x1) + 1;
301 break;
302 default:
303 out &= 0x1;
304 break;
305 }
294 306
295 if (handle && !write_acpi_int(handle, NULL, out, NULL)) 307 if (handle && !write_acpi_int(handle, NULL, out, NULL))
296 printk(ASUS_WARNING " write failed\n"); 308 printk(ASUS_WARNING " write failed %x\n", mask);
297} 309}
298 310
299/* /sys/class/led handlers */ 311/* /sys/class/led handlers */
300#define ASUS_LED_HANDLER(object, mask, invert) \ 312#define ASUS_LED_HANDLER(object, mask) \
301 static void object##_led_set(struct led_classdev *led_cdev, \ 313 static void object##_led_set(struct led_classdev *led_cdev, \
302 enum led_brightness value) \ 314 enum led_brightness value) \
303 { \ 315 { \
@@ -307,13 +319,14 @@ static void write_status(acpi_handle handle, int out, int mask, int invert)
307 static void object##_led_update(struct work_struct *ignored) \ 319 static void object##_led_update(struct work_struct *ignored) \
308 { \ 320 { \
309 int value = object##_led_wk; \ 321 int value = object##_led_wk; \
310 write_status(object##_set_handle, value, (mask), (invert)); \ 322 write_status(object##_set_handle, value, (mask)); \
311 } 323 }
312 324
313ASUS_LED_HANDLER(mled, MLED_ON, 1); 325ASUS_LED_HANDLER(mled, MLED_ON);
314ASUS_LED_HANDLER(pled, PLED_ON, 0); 326ASUS_LED_HANDLER(pled, PLED_ON);
315ASUS_LED_HANDLER(rled, RLED_ON, 0); 327ASUS_LED_HANDLER(rled, RLED_ON);
316ASUS_LED_HANDLER(tled, TLED_ON, 0); 328ASUS_LED_HANDLER(tled, TLED_ON);
329ASUS_LED_HANDLER(gled, GLED_ON);
317 330
318static int get_lcd_state(void) 331static int get_lcd_state(void)
319{ 332{
@@ -338,7 +351,7 @@ static int set_lcd_state(int value)
338 printk(ASUS_WARNING "Error switching LCD\n"); 351 printk(ASUS_WARNING "Error switching LCD\n");
339 } 352 }
340 353
341 write_status(NULL, lcd, LCD_ON, 0); 354 write_status(NULL, lcd, LCD_ON);
342 return 0; 355 return 0;
343} 356}
344 357
@@ -354,9 +367,11 @@ static void lcd_blank(int blank)
354 367
355static int read_brightness(struct backlight_device *bd) 368static int read_brightness(struct backlight_device *bd)
356{ 369{
357 int value; 370 ulong value;
371 acpi_status rv = AE_OK;
358 372
359 if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL)) 373 rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
374 if (ACPI_FAILURE(rv))
360 printk(ASUS_WARNING "Error reading brightness\n"); 375 printk(ASUS_WARNING "Error reading brightness\n");
361 376
362 return value; 377 return value;
@@ -403,8 +418,10 @@ static ssize_t show_infos(struct device *dev,
403 struct device_attribute *attr, char *page) 418 struct device_attribute *attr, char *page)
404{ 419{
405 int len = 0; 420 int len = 0;
406 int temp; 421 ulong temp;
407 char buf[16]; //enough for all info 422 char buf[16]; //enough for all info
423 acpi_status rv = AE_OK;
424
408 /* 425 /*
409 * We use the easy way, we don't care of off and count, so we don't set eof 426 * We use the easy way, we don't care of off and count, so we don't set eof
410 * to 1 427 * to 1
@@ -418,9 +435,10 @@ static ssize_t show_infos(struct device *dev,
418 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. 435 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
419 * The significance of others is yet to be found. 436 * The significance of others is yet to be found.
420 */ 437 */
421 if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL)) 438 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
422 len += 439 if (!ACPI_FAILURE(rv))
423 sprintf(page + len, "SFUN value : 0x%04x\n", temp); 440 len += sprintf(page + len, "SFUN value : 0x%04x\n",
441 (uint) temp);
424 /* 442 /*
425 * Another value for userspace: the ASYM method returns 0x02 for 443 * Another value for userspace: the ASYM method returns 0x02 for
426 * battery low and 0x04 for battery critical, its readings tend to be 444 * battery low and 0x04 for battery critical, its readings tend to be
@@ -428,9 +446,10 @@ static ssize_t show_infos(struct device *dev,
428 * Note: since not all the laptops provide this method, errors are 446 * Note: since not all the laptops provide this method, errors are
429 * silently ignored. 447 * silently ignored.
430 */ 448 */
431 if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL)) 449 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
432 len += 450 if (!ACPI_FAILURE(rv))
433 sprintf(page + len, "ASYM value : 0x%04x\n", temp); 451 len += sprintf(page + len, "ASYM value : 0x%04x\n",
452 (uint) temp);
434 if (asus_info) { 453 if (asus_info) {
435 snprintf(buf, 16, "%d", asus_info->length); 454 snprintf(buf, 16, "%d", asus_info->length);
436 len += sprintf(page + len, "DSDT length : %s\n", buf); 455 len += sprintf(page + len, "DSDT length : %s\n", buf);
@@ -465,7 +484,7 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
465} 484}
466 485
467static ssize_t store_status(const char *buf, size_t count, 486static ssize_t store_status(const char *buf, size_t count,
468 acpi_handle handle, int mask, int invert) 487 acpi_handle handle, int mask)
469{ 488{
470 int rv, value; 489 int rv, value;
471 int out = 0; 490 int out = 0;
@@ -474,7 +493,7 @@ static ssize_t store_status(const char *buf, size_t count,
474 if (rv > 0) 493 if (rv > 0)
475 out = value ? 1 : 0; 494 out = value ? 1 : 0;
476 495
477 write_status(handle, out, mask, invert); 496 write_status(handle, out, mask);
478 497
479 return rv; 498 return rv;
480} 499}
@@ -515,7 +534,7 @@ static ssize_t show_wlan(struct device *dev,
515static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, 534static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
516 const char *buf, size_t count) 535 const char *buf, size_t count)
517{ 536{
518 return store_status(buf, count, wl_switch_handle, WL_ON, 0); 537 return store_status(buf, count, wl_switch_handle, WL_ON);
519} 538}
520 539
521/* 540/*
@@ -531,7 +550,7 @@ static ssize_t store_bluetooth(struct device *dev,
531 struct device_attribute *attr, const char *buf, 550 struct device_attribute *attr, const char *buf,
532 size_t count) 551 size_t count)
533{ 552{
534 return store_status(buf, count, bt_switch_handle, BT_ON, 0); 553 return store_status(buf, count, bt_switch_handle, BT_ON);
535} 554}
536 555
537/* 556/*
@@ -547,12 +566,15 @@ static void set_display(int value)
547 566
548static int read_display(void) 567static int read_display(void)
549{ 568{
550 int value = 0; 569 ulong value = 0;
570 acpi_status rv = AE_OK;
551 571
552 /* In most of the case, we know how to set the display, but sometime 572 /* In most of the case, we know how to set the display, but sometime
553 we can't read it */ 573 we can't read it */
554 if (display_get_handle) { 574 if (display_get_handle) {
555 if (!read_acpi_int(display_get_handle, NULL, &value, NULL)) 575 rv = acpi_evaluate_integer(display_get_handle, NULL,
576 NULL, &value);
577 if (ACPI_FAILURE(rv))
556 printk(ASUS_WARNING "Error reading display status\n"); 578 printk(ASUS_WARNING "Error reading display status\n");
557 } 579 }
558 580
@@ -656,10 +678,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
656 * switched 678 * switched
657 */ 679 */
658 if (event == ATKD_LCD_ON) { 680 if (event == ATKD_LCD_ON) {
659 write_status(NULL, 1, LCD_ON, 0); 681 write_status(NULL, 1, LCD_ON);
660 lcd_blank(FB_BLANK_UNBLANK); 682 lcd_blank(FB_BLANK_UNBLANK);
661 } else if (event == ATKD_LCD_OFF) { 683 } else if (event == ATKD_LCD_OFF) {
662 write_status(NULL, 0, LCD_ON, 0); 684 write_status(NULL, 0, LCD_ON);
663 lcd_blank(FB_BLANK_POWERDOWN); 685 lcd_blank(FB_BLANK_POWERDOWN);
664 } 686 }
665 687
@@ -771,7 +793,7 @@ static int asus_hotk_get_info(void)
771{ 793{
772 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 794 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
773 union acpi_object *model = NULL; 795 union acpi_object *model = NULL;
774 int bsts_result, hwrs_result; 796 ulong bsts_result, hwrs_result;
775 char *string = NULL; 797 char *string = NULL;
776 acpi_status status; 798 acpi_status status;
777 799
@@ -794,11 +816,16 @@ static int asus_hotk_get_info(void)
794 } 816 }
795 817
796 /* This needs to be called for some laptops to init properly */ 818 /* This needs to be called for some laptops to init properly */
797 if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL)) 819 status =
820 acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
821 if (ACPI_FAILURE(status))
798 printk(ASUS_WARNING "Error calling BSTS\n"); 822 printk(ASUS_WARNING "Error calling BSTS\n");
799 else if (bsts_result) 823 else if (bsts_result)
800 printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", 824 printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
801 bsts_result); 825 (uint) bsts_result);
826
827 /* This too ... */
828 write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
802 829
803 /* 830 /*
804 * Try to match the object returned by INIT to the specific model. 831 * Try to match the object returned by INIT to the specific model.
@@ -831,6 +858,7 @@ static int asus_hotk_get_info(void)
831 ASUS_HANDLE_INIT(tled_set); 858 ASUS_HANDLE_INIT(tled_set);
832 ASUS_HANDLE_INIT(rled_set); 859 ASUS_HANDLE_INIT(rled_set);
833 ASUS_HANDLE_INIT(pled_set); 860 ASUS_HANDLE_INIT(pled_set);
861 ASUS_HANDLE_INIT(gled_set);
834 862
835 ASUS_HANDLE_INIT(ledd_set); 863 ASUS_HANDLE_INIT(ledd_set);
836 864
@@ -840,7 +868,9 @@ static int asus_hotk_get_info(void)
840 * The significance of others is yet to be found. 868 * The significance of others is yet to be found.
841 * If we don't find the method, we assume the device are present. 869 * If we don't find the method, we assume the device are present.
842 */ 870 */
843 if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL)) 871 status =
872 acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
873 if (ACPI_FAILURE(status))
844 hwrs_result = WL_HWRS | BT_HWRS; 874 hwrs_result = WL_HWRS | BT_HWRS;
845 875
846 if (hwrs_result & WL_HWRS) 876 if (hwrs_result & WL_HWRS)
@@ -928,11 +958,15 @@ static int asus_hotk_add(struct acpi_device *device)
928 asus_hotk_found = 1; 958 asus_hotk_found = 1;
929 959
930 /* WLED and BLED are on by default */ 960 /* WLED and BLED are on by default */
931 write_status(bt_switch_handle, 1, BT_ON, 0); 961 write_status(bt_switch_handle, 1, BT_ON);
932 write_status(wl_switch_handle, 1, WL_ON, 0); 962 write_status(wl_switch_handle, 1, WL_ON);
963
964 /* If the h/w switch is off, we need to check the real status */
965 write_status(NULL, read_status(BT_ON), BT_ON);
966 write_status(NULL, read_status(WL_ON), WL_ON);
933 967
934 /* LCD Backlight is on by default */ 968 /* LCD Backlight is on by default */
935 write_status(NULL, 1, LCD_ON, 0); 969 write_status(NULL, 1, LCD_ON);
936 970
937 /* LED display is off by default */ 971 /* LED display is off by default */
938 hotk->ledd_status = 0xFFF; 972 hotk->ledd_status = 0xFFF;
@@ -991,6 +1025,7 @@ static void asus_led_exit(void)
991 ASUS_LED_UNREGISTER(tled); 1025 ASUS_LED_UNREGISTER(tled);
992 ASUS_LED_UNREGISTER(pled); 1026 ASUS_LED_UNREGISTER(pled);
993 ASUS_LED_UNREGISTER(rled); 1027 ASUS_LED_UNREGISTER(rled);
1028 ASUS_LED_UNREGISTER(gled);
994 1029
995 destroy_workqueue(led_workqueue); 1030 destroy_workqueue(led_workqueue);
996} 1031}
@@ -1062,6 +1097,10 @@ static int asus_led_init(struct device *dev)
1062 if (rv) 1097 if (rv)
1063 return rv; 1098 return rv;
1064 1099
1100 rv = ASUS_LED_REGISTER(gled, dev);
1101 if (rv)
1102 return rv;
1103
1065 led_workqueue = create_singlethread_workqueue("led_workqueue"); 1104 led_workqueue = create_singlethread_workqueue("led_workqueue");
1066 if (!led_workqueue) 1105 if (!led_workqueue)
1067 return -ENOMEM; 1106 return -ENOMEM;
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index ac708bc2f9f3..c15c1f61bd1b 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * ACPI Sony Notebook Control Driver (SNC) 2 * ACPI Sony Notebook Control Driver (SNC and SPIC)
3 * 3 *
4 * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> 4 * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
5 * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> 5 * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
@@ -7,6 +7,25 @@
7 * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c 7 * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
8 * which are copyrighted by their respective authors. 8 * which are copyrighted by their respective authors.
9 * 9 *
10 * The SNY6001 driver part is based on the sonypi driver which includes
11 * material from:
12 *
13 * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
14 *
15 * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
16 *
17 * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
18 *
19 * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
20 *
21 * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
22 *
23 * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
24 *
25 * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
26 *
27 * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
28 *
10 * This program is free software; you can redistribute it and/or modify 29 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 30 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 31 * the Free Software Foundation; either version 2 of the License, or
@@ -31,40 +50,404 @@
31#include <linux/backlight.h> 50#include <linux/backlight.h>
32#include <linux/platform_device.h> 51#include <linux/platform_device.h>
33#include <linux/err.h> 52#include <linux/err.h>
53#include <linux/dmi.h>
54#include <linux/pci.h>
55#include <linux/interrupt.h>
56#include <linux/delay.h>
57#include <linux/input.h>
58#include <linux/kfifo.h>
59#include <linux/workqueue.h>
60#include <linux/acpi.h>
34#include <acpi/acpi_drivers.h> 61#include <acpi/acpi_drivers.h>
35#include <acpi/acpi_bus.h> 62#include <acpi/acpi_bus.h>
36#include <asm/uaccess.h> 63#include <asm/uaccess.h>
64#include <linux/sonypi.h>
65#include <linux/sony-laptop.h>
66#ifdef CONFIG_SONY_LAPTOP_OLD
67#include <linux/poll.h>
68#include <linux/miscdevice.h>
69#endif
37 70
38#define ACPI_SNC_CLASS "sony" 71#define DRV_PFX "sony-laptop: "
39#define ACPI_SNC_HID "SNY5001" 72#define dprintk(msg...) do { \
40#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4" 73 if (debug) printk(KERN_WARNING DRV_PFX msg); \
74} while (0)
41 75
42/* the device uses 1-based values, while the backlight subsystem uses 76#define SONY_LAPTOP_DRIVER_VERSION "0.5"
43 0-based values */ 77
44#define SONY_MAX_BRIGHTNESS 8 78#define SONY_NC_CLASS "sony-nc"
79#define SONY_NC_HID "SNY5001"
80#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
45 81
46#define LOG_PFX KERN_WARNING "sony-laptop: " 82#define SONY_PIC_CLASS "sony-pic"
83#define SONY_PIC_HID "SNY6001"
84#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
47 85
48MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); 86MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
49MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME); 87MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
50MODULE_LICENSE("GPL"); 88MODULE_LICENSE("GPL");
89MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
51 90
52static int debug; 91static int debug;
53module_param(debug, int, 0); 92module_param(debug, int, 0);
54MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " 93MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
55 "the development of this driver"); 94 "the development of this driver");
56 95
57static ssize_t sony_acpi_show(struct device *, struct device_attribute *, 96static int no_spic; /* = 0 */
97module_param(no_spic, int, 0444);
98MODULE_PARM_DESC(no_spic,
99 "set this if you don't want to enable the SPIC device");
100
101static int compat; /* = 0 */
102module_param(compat, int, 0444);
103MODULE_PARM_DESC(compat,
104 "set this if you want to enable backward compatibility mode");
105
106static unsigned long mask = 0xffffffff;
107module_param(mask, ulong, 0644);
108MODULE_PARM_DESC(mask,
109 "set this to the mask of event you want to enable (see doc)");
110
111static int camera; /* = 0 */
112module_param(camera, int, 0444);
113MODULE_PARM_DESC(camera,
114 "set this to 1 to enable Motion Eye camera controls "
115 "(only use it if you have a C1VE or C1VN model)");
116
117#ifdef CONFIG_SONY_LAPTOP_OLD
118static int minor = -1;
119module_param(minor, int, 0);
120MODULE_PARM_DESC(minor,
121 "minor number of the misc device for the SPIC compatibility code, "
122 "default is -1 (automatic)");
123#endif
124
125/*********** Input Devices ***********/
126
127#define SONY_LAPTOP_BUF_SIZE 128
128struct sony_laptop_input_s {
129 atomic_t users;
130 struct input_dev *jog_dev;
131 struct input_dev *key_dev;
132 struct kfifo *fifo;
133 spinlock_t fifo_lock;
134 struct workqueue_struct *wq;
135};
136static struct sony_laptop_input_s sony_laptop_input = {
137 .users = ATOMIC_INIT(0),
138};
139
140struct sony_laptop_keypress {
141 struct input_dev *dev;
142 int key;
143};
144
145/* Correspondance table between sonypi events and input layer events */
146static struct {
147 int sonypiev;
148 int inputev;
149} sony_laptop_inputkeys[] = {
150 { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
151 { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
152 { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
153 { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
154 { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
155 { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
156 { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
157 { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
158 { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
159 { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
160 { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
161 { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
162 { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
163 { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
164 { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
165 { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
166 { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
167 { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
168 { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
169 { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
170 { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
171 { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
172 { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
173 { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
174 { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
175 { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
176 { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
177 { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
178 { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
179 { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
180 { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
181 { 0, 0 },
182};
183
184/* release buttons after a short delay if pressed */
185static void do_sony_laptop_release_key(struct work_struct *work)
186{
187 struct sony_laptop_keypress kp;
188
189 while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
190 sizeof(kp)) == sizeof(kp)) {
191 msleep(10);
192 input_report_key(kp.dev, kp.key, 0);
193 input_sync(kp.dev);
194 }
195}
196static DECLARE_WORK(sony_laptop_release_key_work,
197 do_sony_laptop_release_key);
198
199/* forward event to the input subsytem */
200static void sony_laptop_report_input_event(u8 event)
201{
202 struct input_dev *jog_dev = sony_laptop_input.jog_dev;
203 struct input_dev *key_dev = sony_laptop_input.key_dev;
204 struct sony_laptop_keypress kp = { NULL };
205 int i;
206
207 if (event == SONYPI_EVENT_FNKEY_RELEASED) {
208 /* Nothing, not all VAIOs generate this event */
209 return;
210 }
211
212 /* report events */
213 switch (event) {
214 /* jog_dev events */
215 case SONYPI_EVENT_JOGDIAL_UP:
216 case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
217 input_report_rel(jog_dev, REL_WHEEL, 1);
218 input_sync(jog_dev);
219 return;
220
221 case SONYPI_EVENT_JOGDIAL_DOWN:
222 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
223 input_report_rel(jog_dev, REL_WHEEL, -1);
224 input_sync(jog_dev);
225 return;
226
227 /* key_dev events */
228 case SONYPI_EVENT_JOGDIAL_PRESSED:
229 kp.key = BTN_MIDDLE;
230 kp.dev = jog_dev;
231 break;
232
233 default:
234 for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
235 if (event == sony_laptop_inputkeys[i].sonypiev) {
236 kp.dev = key_dev;
237 kp.key = sony_laptop_inputkeys[i].inputev;
238 break;
239 }
240 break;
241 }
242
243 if (kp.dev) {
244 input_report_key(kp.dev, kp.key, 1);
245 input_sync(kp.dev);
246 kfifo_put(sony_laptop_input.fifo,
247 (unsigned char *)&kp, sizeof(kp));
248
249 if (!work_pending(&sony_laptop_release_key_work))
250 queue_work(sony_laptop_input.wq,
251 &sony_laptop_release_key_work);
252 } else
253 dprintk("unknown input event %.2x\n", event);
254}
255
256static int sony_laptop_setup_input(void)
257{
258 struct input_dev *jog_dev;
259 struct input_dev *key_dev;
260 int i;
261 int error;
262
263 /* don't run again if already initialized */
264 if (atomic_add_return(1, &sony_laptop_input.users) > 1)
265 return 0;
266
267 /* kfifo */
268 spin_lock_init(&sony_laptop_input.fifo_lock);
269 sony_laptop_input.fifo =
270 kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
271 &sony_laptop_input.fifo_lock);
272 if (IS_ERR(sony_laptop_input.fifo)) {
273 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
274 error = PTR_ERR(sony_laptop_input.fifo);
275 goto err_dec_users;
276 }
277
278 /* init workqueue */
279 sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
280 if (!sony_laptop_input.wq) {
281 printk(KERN_ERR DRV_PFX
282 "Unabe to create workqueue.\n");
283 error = -ENXIO;
284 goto err_free_kfifo;
285 }
286
287 /* input keys */
288 key_dev = input_allocate_device();
289 if (!key_dev) {
290 error = -ENOMEM;
291 goto err_destroy_wq;
292 }
293
294 key_dev->name = "Sony Vaio Keys";
295 key_dev->id.bustype = BUS_ISA;
296 key_dev->id.vendor = PCI_VENDOR_ID_SONY;
297
298 /* Initialize the Input Drivers: special keys */
299 key_dev->evbit[0] = BIT(EV_KEY);
300 for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
301 if (sony_laptop_inputkeys[i].inputev)
302 set_bit(sony_laptop_inputkeys[i].inputev,
303 key_dev->keybit);
304
305 error = input_register_device(key_dev);
306 if (error)
307 goto err_free_keydev;
308
309 sony_laptop_input.key_dev = key_dev;
310
311 /* jogdial */
312 jog_dev = input_allocate_device();
313 if (!jog_dev) {
314 error = -ENOMEM;
315 goto err_unregister_keydev;
316 }
317
318 jog_dev->name = "Sony Vaio Jogdial";
319 jog_dev->id.bustype = BUS_ISA;
320 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
321
322 jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
323 jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
324 jog_dev->relbit[0] = BIT(REL_WHEEL);
325
326 error = input_register_device(jog_dev);
327 if (error)
328 goto err_free_jogdev;
329
330 sony_laptop_input.jog_dev = jog_dev;
331
332 return 0;
333
334err_free_jogdev:
335 input_free_device(jog_dev);
336
337err_unregister_keydev:
338 input_unregister_device(key_dev);
339 /* to avoid kref underflow below at input_free_device */
340 key_dev = NULL;
341
342err_free_keydev:
343 input_free_device(key_dev);
344
345err_destroy_wq:
346 destroy_workqueue(sony_laptop_input.wq);
347
348err_free_kfifo:
349 kfifo_free(sony_laptop_input.fifo);
350
351err_dec_users:
352 atomic_dec(&sony_laptop_input.users);
353 return error;
354}
355
356static void sony_laptop_remove_input(void)
357{
358 /* cleanup only after the last user has gone */
359 if (!atomic_dec_and_test(&sony_laptop_input.users))
360 return;
361
362 /* flush workqueue first */
363 flush_workqueue(sony_laptop_input.wq);
364
365 /* destroy input devs */
366 input_unregister_device(sony_laptop_input.key_dev);
367 sony_laptop_input.key_dev = NULL;
368
369 if (sony_laptop_input.jog_dev) {
370 input_unregister_device(sony_laptop_input.jog_dev);
371 sony_laptop_input.jog_dev = NULL;
372 }
373
374 destroy_workqueue(sony_laptop_input.wq);
375 kfifo_free(sony_laptop_input.fifo);
376}
377
378/*********** Platform Device ***********/
379
380static atomic_t sony_pf_users = ATOMIC_INIT(0);
381static struct platform_driver sony_pf_driver = {
382 .driver = {
383 .name = "sony-laptop",
384 .owner = THIS_MODULE,
385 }
386};
387static struct platform_device *sony_pf_device;
388
389static int sony_pf_add(void)
390{
391 int ret = 0;
392
393 /* don't run again if already initialized */
394 if (atomic_add_return(1, &sony_pf_users) > 1)
395 return 0;
396
397 ret = platform_driver_register(&sony_pf_driver);
398 if (ret)
399 goto out;
400
401 sony_pf_device = platform_device_alloc("sony-laptop", -1);
402 if (!sony_pf_device) {
403 ret = -ENOMEM;
404 goto out_platform_registered;
405 }
406
407 ret = platform_device_add(sony_pf_device);
408 if (ret)
409 goto out_platform_alloced;
410
411 return 0;
412
413 out_platform_alloced:
414 platform_device_put(sony_pf_device);
415 sony_pf_device = NULL;
416 out_platform_registered:
417 platform_driver_unregister(&sony_pf_driver);
418 out:
419 atomic_dec(&sony_pf_users);
420 return ret;
421}
422
423static void sony_pf_remove(void)
424{
425 /* deregister only after the last user has gone */
426 if (!atomic_dec_and_test(&sony_pf_users))
427 return;
428
429 platform_device_del(sony_pf_device);
430 platform_device_put(sony_pf_device);
431 platform_driver_unregister(&sony_pf_driver);
432}
433
434/*********** SNC (SNY5001) Device ***********/
435
436/* the device uses 1-based values, while the backlight subsystem uses
437 0-based values */
438#define SONY_MAX_BRIGHTNESS 8
439
440#define SNC_VALIDATE_IN 0
441#define SNC_VALIDATE_OUT 1
442
443static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
58 char *); 444 char *);
59static ssize_t sony_acpi_store(struct device *, struct device_attribute *, 445static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
60 const char *, size_t); 446 const char *, size_t);
61static int boolean_validate(const int, const int); 447static int boolean_validate(const int, const int);
62static int brightness_default_validate(const int, const int); 448static int brightness_default_validate(const int, const int);
63 449
64#define SNC_VALIDATE_IN 0 450struct sony_nc_value {
65#define SNC_VALIDATE_OUT 1
66
67struct sony_acpi_value {
68 char *name; /* name of the entry */ 451 char *name; /* name of the entry */
69 char **acpiget; /* names of the ACPI get function */ 452 char **acpiget; /* names of the ACPI get function */
70 char **acpiset; /* names of the ACPI set function */ 453 char **acpiset; /* names of the ACPI set function */
@@ -75,65 +458,65 @@ struct sony_acpi_value {
75 struct device_attribute devattr; /* sysfs atribute */ 458 struct device_attribute devattr; /* sysfs atribute */
76}; 459};
77 460
78#define HANDLE_NAMES(_name, _values...) \ 461#define SNC_HANDLE_NAMES(_name, _values...) \
79 static char *snc_##_name[] = { _values, NULL } 462 static char *snc_##_name[] = { _values, NULL }
80 463
81#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \ 464#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
82 { \ 465 { \
83 .name = __stringify(_name), \ 466 .name = __stringify(_name), \
84 .acpiget = _getters, \ 467 .acpiget = _getters, \
85 .acpiset = _setters, \ 468 .acpiset = _setters, \
86 .validate = _validate, \ 469 .validate = _validate, \
87 .debug = _debug, \ 470 .debug = _debug, \
88 .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ 471 .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
89 } 472 }
90 473
91#define SONY_ACPI_VALUE_NULL { .name = NULL } 474#define SNC_HANDLE_NULL { .name = NULL }
92 475
93HANDLE_NAMES(fnkey_get, "GHKE"); 476SNC_HANDLE_NAMES(fnkey_get, "GHKE");
94 477
95HANDLE_NAMES(brightness_def_get, "GPBR"); 478SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
96HANDLE_NAMES(brightness_def_set, "SPBR"); 479SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
97 480
98HANDLE_NAMES(cdpower_get, "GCDP"); 481SNC_HANDLE_NAMES(cdpower_get, "GCDP");
99HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); 482SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
100 483
101HANDLE_NAMES(audiopower_get, "GAZP"); 484SNC_HANDLE_NAMES(audiopower_get, "GAZP");
102HANDLE_NAMES(audiopower_set, "AZPW"); 485SNC_HANDLE_NAMES(audiopower_set, "AZPW");
103 486
104HANDLE_NAMES(lanpower_get, "GLNP"); 487SNC_HANDLE_NAMES(lanpower_get, "GLNP");
105HANDLE_NAMES(lanpower_set, "LNPW"); 488SNC_HANDLE_NAMES(lanpower_set, "LNPW");
106 489
107HANDLE_NAMES(PID_get, "GPID"); 490SNC_HANDLE_NAMES(PID_get, "GPID");
108 491
109HANDLE_NAMES(CTR_get, "GCTR"); 492SNC_HANDLE_NAMES(CTR_get, "GCTR");
110HANDLE_NAMES(CTR_set, "SCTR"); 493SNC_HANDLE_NAMES(CTR_set, "SCTR");
111 494
112HANDLE_NAMES(PCR_get, "GPCR"); 495SNC_HANDLE_NAMES(PCR_get, "GPCR");
113HANDLE_NAMES(PCR_set, "SPCR"); 496SNC_HANDLE_NAMES(PCR_set, "SPCR");
114 497
115HANDLE_NAMES(CMI_get, "GCMI"); 498SNC_HANDLE_NAMES(CMI_get, "GCMI");
116HANDLE_NAMES(CMI_set, "SCMI"); 499SNC_HANDLE_NAMES(CMI_set, "SCMI");
117 500
118static struct sony_acpi_value sony_acpi_values[] = { 501static struct sony_nc_value sony_nc_values[] = {
119 SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, 502 SNC_HANDLE(brightness_default, snc_brightness_def_get,
120 snc_brightness_def_set, brightness_default_validate, 0), 503 snc_brightness_def_set, brightness_default_validate, 0),
121 SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0), 504 SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
122 SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), 505 SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
123 SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, 506 SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
124 boolean_validate, 0), 507 boolean_validate, 0),
125 SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, 508 SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
126 boolean_validate, 1), 509 boolean_validate, 1),
127 /* unknown methods */ 510 /* unknown methods */
128 SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1), 511 SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
129 SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), 512 SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
130 SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), 513 SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
131 SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), 514 SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
132 SONY_ACPI_VALUE_NULL 515 SNC_HANDLE_NULL
133}; 516};
134 517
135static acpi_handle sony_acpi_handle; 518static acpi_handle sony_nc_acpi_handle;
136static struct acpi_device *sony_acpi_acpi_device = NULL; 519static struct acpi_device *sony_nc_acpi_device = NULL;
137 520
138/* 521/*
139 * acpi_evaluate_object wrappers 522 * acpi_evaluate_object wrappers
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
153 return 0; 536 return 0;
154 } 537 }
155 538
156 printk(LOG_PFX "acpi_callreadfunc failed\n"); 539 printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
157 540
158 return -1; 541 return -1;
159} 542}
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
179 if (status == AE_OK) { 562 if (status == AE_OK) {
180 if (result != NULL) { 563 if (result != NULL) {
181 if (out_obj.type != ACPI_TYPE_INTEGER) { 564 if (out_obj.type != ACPI_TYPE_INTEGER) {
182 printk(LOG_PFX "acpi_evaluate_object bad " 565 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
183 "return type\n"); 566 "return type\n");
184 return -1; 567 return -1;
185 } 568 }
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
188 return 0; 571 return 0;
189 } 572 }
190 573
191 printk(LOG_PFX "acpi_evaluate_object failed\n"); 574 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
192 575
193 return -1; 576 return -1;
194} 577}
195 578
196/* 579/*
197 * sony_acpi_values input/output validate functions 580 * sony_nc_values input/output validate functions
198 */ 581 */
199 582
200/* brightness_default_validate: 583/* brightness_default_validate:
@@ -229,19 +612,19 @@ static int boolean_validate(const int direction, const int value)
229} 612}
230 613
231/* 614/*
232 * Sysfs show/store common to all sony_acpi_values 615 * Sysfs show/store common to all sony_nc_values
233 */ 616 */
234static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, 617static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
235 char *buffer) 618 char *buffer)
236{ 619{
237 int value; 620 int value;
238 struct sony_acpi_value *item = 621 struct sony_nc_value *item =
239 container_of(attr, struct sony_acpi_value, devattr); 622 container_of(attr, struct sony_nc_value, devattr);
240 623
241 if (!*item->acpiget) 624 if (!*item->acpiget)
242 return -EIO; 625 return -EIO;
243 626
244 if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) 627 if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
245 return -EIO; 628 return -EIO;
246 629
247 if (item->validate) 630 if (item->validate)
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
250 return snprintf(buffer, PAGE_SIZE, "%d\n", value); 633 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
251} 634}
252 635
253static ssize_t sony_acpi_store(struct device *dev, 636static ssize_t sony_nc_sysfs_store(struct device *dev,
254 struct device_attribute *attr, 637 struct device_attribute *attr,
255 const char *buffer, size_t count) 638 const char *buffer, size_t count)
256{ 639{
257 int value; 640 int value;
258 struct sony_acpi_value *item = 641 struct sony_nc_value *item =
259 container_of(attr, struct sony_acpi_value, devattr); 642 container_of(attr, struct sony_nc_value, devattr);
260 643
261 if (!item->acpiset) 644 if (!item->acpiset)
262 return -EIO; 645 return -EIO;
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct device *dev,
272 if (value < 0) 655 if (value < 0)
273 return value; 656 return value;
274 657
275 if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) 658 if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
276 return -EIO; 659 return -EIO;
277 item->value = value; 660 item->value = value;
278 item->valid = 1; 661 item->valid = 1;
279 return count; 662 return count;
280} 663}
281 664
282/*
283 * Platform device
284 */
285static struct platform_driver sncpf_driver = {
286 .driver = {
287 .name = "sony-laptop",
288 .owner = THIS_MODULE,
289 }
290};
291static struct platform_device *sncpf_device;
292
293static int sony_snc_pf_add(void)
294{
295 acpi_handle handle;
296 struct sony_acpi_value *item;
297 int ret = 0;
298
299 ret = platform_driver_register(&sncpf_driver);
300 if (ret)
301 goto out;
302
303 sncpf_device = platform_device_alloc("sony-laptop", -1);
304 if (!sncpf_device) {
305 ret = -ENOMEM;
306 goto out_platform_registered;
307 }
308
309 ret = platform_device_add(sncpf_device);
310 if (ret)
311 goto out_platform_alloced;
312
313 for (item = sony_acpi_values; item->name; ++item) {
314
315 if (!debug && item->debug)
316 continue;
317
318 /* find the available acpiget as described in the DSDT */
319 for (; item->acpiget && *item->acpiget; ++item->acpiget) {
320 if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
321 *item->acpiget,
322 &handle))) {
323 if (debug)
324 printk(LOG_PFX "Found %s getter: %s\n",
325 item->name, *item->acpiget);
326 item->devattr.attr.mode |= S_IRUGO;
327 break;
328 }
329 }
330
331 /* find the available acpiset as described in the DSDT */
332 for (; item->acpiset && *item->acpiset; ++item->acpiset) {
333 if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
334 *item->acpiset,
335 &handle))) {
336 if (debug)
337 printk(LOG_PFX "Found %s setter: %s\n",
338 item->name, *item->acpiset);
339 item->devattr.attr.mode |= S_IWUSR;
340 break;
341 }
342 }
343
344 if (item->devattr.attr.mode != 0) {
345 ret =
346 device_create_file(&sncpf_device->dev,
347 &item->devattr);
348 if (ret)
349 goto out_sysfs;
350 }
351 }
352
353 return 0;
354
355 out_sysfs:
356 for (item = sony_acpi_values; item->name; ++item) {
357 device_remove_file(&sncpf_device->dev, &item->devattr);
358 }
359 platform_device_del(sncpf_device);
360 out_platform_alloced:
361 platform_device_put(sncpf_device);
362 out_platform_registered:
363 platform_driver_unregister(&sncpf_driver);
364 out:
365 return ret;
366}
367
368static void sony_snc_pf_remove(void)
369{
370 struct sony_acpi_value *item;
371
372 for (item = sony_acpi_values; item->name; ++item) {
373 device_remove_file(&sncpf_device->dev, &item->devattr);
374 }
375
376 platform_device_del(sncpf_device);
377 platform_device_put(sncpf_device);
378 platform_driver_unregister(&sncpf_driver);
379}
380 665
381/* 666/*
382 * Backlight device 667 * Backlight device
383 */ 668 */
384static int sony_backlight_update_status(struct backlight_device *bd) 669static int sony_backlight_update_status(struct backlight_device *bd)
385{ 670{
386 return acpi_callsetfunc(sony_acpi_handle, "SBRT", 671 return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
387 bd->props.brightness + 1, NULL); 672 bd->props.brightness + 1, NULL);
388} 673}
389 674
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
391{ 676{
392 int value; 677 int value;
393 678
394 if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value)) 679 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
395 return 0; 680 return 0;
396 /* brightness levels are 1-based, while backlight ones are 0-based */ 681 /* brightness levels are 1-based, while backlight ones are 0-based */
397 return value - 1; 682 return value - 1;
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlight_ops = {
408 */ 693 */
409static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) 694static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
410{ 695{
411 if (debug) 696 dprintk("sony_acpi_notify, event: %d\n", event);
412 printk(LOG_PFX "sony_acpi_notify, event: %d\n", event); 697 sony_laptop_report_input_event(event);
413 acpi_bus_generate_event(sony_acpi_acpi_device, 1, event); 698 acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
414} 699}
415 700
416static acpi_status sony_walk_callback(acpi_handle handle, u32 level, 701static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
422 node = (struct acpi_namespace_node *)handle; 707 node = (struct acpi_namespace_node *)handle;
423 operand = (union acpi_operand_object *)node->object; 708 operand = (union acpi_operand_object *)node->object;
424 709
425 printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii, 710 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
426 (u32) operand->method.param_count); 711 (u32) operand->method.param_count);
427 712
428 return AE_OK; 713 return AE_OK;
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
431/* 716/*
432 * ACPI device 717 * ACPI device
433 */ 718 */
434static int sony_acpi_resume(struct acpi_device *device) 719static int sony_nc_resume(struct acpi_device *device)
435{ 720{
436 struct sony_acpi_value *item; 721 struct sony_nc_value *item;
437 722
438 for (item = sony_acpi_values; item->name; item++) { 723 for (item = sony_nc_values; item->name; item++) {
439 int ret; 724 int ret;
440 725
441 if (!item->valid) 726 if (!item->valid)
442 continue; 727 continue;
443 ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset, 728 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
444 item->value, NULL); 729 item->value, NULL);
445 if (ret < 0) { 730 if (ret < 0) {
446 printk("%s: %d\n", __FUNCTION__, ret); 731 printk("%s: %d\n", __FUNCTION__, ret);
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_device *device)
450 return 0; 735 return 0;
451} 736}
452 737
453static int sony_acpi_add(struct acpi_device *device) 738static int sony_nc_add(struct acpi_device *device)
454{ 739{
455 acpi_status status; 740 acpi_status status;
456 int result = 0; 741 int result = 0;
457 acpi_handle handle; 742 acpi_handle handle;
743 struct sony_nc_value *item;
744
745 printk(KERN_INFO DRV_PFX "%s v%s.\n",
746 SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
458 747
459 sony_acpi_acpi_device = device; 748 sony_nc_acpi_device = device;
749 strcpy(acpi_device_class(device), "sony/hotkey");
460 750
461 sony_acpi_handle = device->handle; 751 sony_nc_acpi_handle = device->handle;
462 752
463 if (debug) { 753 if (debug) {
464 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle, 754 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
465 1, sony_walk_callback, NULL, NULL); 755 1, sony_walk_callback, NULL, NULL);
466 if (ACPI_FAILURE(status)) { 756 if (ACPI_FAILURE(status)) {
467 printk(LOG_PFX "unable to walk acpi resources\n"); 757 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
468 result = -ENODEV; 758 result = -ENODEV;
469 goto outwalk; 759 goto outwalk;
470 } 760 }
471 } 761 }
472 762
473 status = acpi_install_notify_handler(sony_acpi_handle, 763 /* setup input devices and helper fifo */
764 result = sony_laptop_setup_input();
765 if (result) {
766 printk(KERN_ERR DRV_PFX
767 "Unabe to create input devices.\n");
768 goto outwalk;
769 }
770
771 status = acpi_install_notify_handler(sony_nc_acpi_handle,
474 ACPI_DEVICE_NOTIFY, 772 ACPI_DEVICE_NOTIFY,
475 sony_acpi_notify, NULL); 773 sony_acpi_notify, NULL);
476 if (ACPI_FAILURE(status)) { 774 if (ACPI_FAILURE(status)) {
477 printk(LOG_PFX "unable to install notify handler\n"); 775 printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
478 result = -ENODEV; 776 result = -ENODEV;
479 goto outwalk; 777 goto outinput;
480 } 778 }
481 779
482 if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) { 780 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
483 sony_backlight_device = backlight_device_register("sony", NULL, 781 sony_backlight_device = backlight_device_register("sony", NULL,
484 NULL, 782 NULL,
485 &sony_backlight_ops); 783 &sony_backlight_ops);
486 784
487 if (IS_ERR(sony_backlight_device)) { 785 if (IS_ERR(sony_backlight_device)) {
488 printk(LOG_PFX "unable to register backlight device\n"); 786 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
489 sony_backlight_device = NULL; 787 sony_backlight_device = NULL;
490 } else { 788 } else {
491 sony_backlight_device->props.brightness = 789 sony_backlight_device->props.brightness =
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_device *device)
497 795
498 } 796 }
499 797
500 if (sony_snc_pf_add()) 798 result = sony_pf_add();
799 if (result)
501 goto outbacklight; 800 goto outbacklight;
502 801
503 printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n"); 802 /* create sony_pf sysfs attributes related to the SNC device */
803 for (item = sony_nc_values; item->name; ++item) {
804
805 if (!debug && item->debug)
806 continue;
807
808 /* find the available acpiget as described in the DSDT */
809 for (; item->acpiget && *item->acpiget; ++item->acpiget) {
810 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
811 *item->acpiget,
812 &handle))) {
813 dprintk("Found %s getter: %s\n",
814 item->name, *item->acpiget);
815 item->devattr.attr.mode |= S_IRUGO;
816 break;
817 }
818 }
819
820 /* find the available acpiset as described in the DSDT */
821 for (; item->acpiset && *item->acpiset; ++item->acpiset) {
822 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
823 *item->acpiset,
824 &handle))) {
825 dprintk("Found %s setter: %s\n",
826 item->name, *item->acpiset);
827 item->devattr.attr.mode |= S_IWUSR;
828 break;
829 }
830 }
831
832 if (item->devattr.attr.mode != 0) {
833 result =
834 device_create_file(&sony_pf_device->dev,
835 &item->devattr);
836 if (result)
837 goto out_sysfs;
838 }
839 }
504 840
505 return 0; 841 return 0;
506 842
843 out_sysfs:
844 for (item = sony_nc_values; item->name; ++item) {
845 device_remove_file(&sony_pf_device->dev, &item->devattr);
846 }
847 sony_pf_remove();
848
507 outbacklight: 849 outbacklight:
508 if (sony_backlight_device) 850 if (sony_backlight_device)
509 backlight_device_unregister(sony_backlight_device); 851 backlight_device_unregister(sony_backlight_device);
510 852
511 status = acpi_remove_notify_handler(sony_acpi_handle, 853 status = acpi_remove_notify_handler(sony_nc_acpi_handle,
512 ACPI_DEVICE_NOTIFY, 854 ACPI_DEVICE_NOTIFY,
513 sony_acpi_notify); 855 sony_acpi_notify);
514 if (ACPI_FAILURE(status)) 856 if (ACPI_FAILURE(status))
515 printk(LOG_PFX "unable to remove notify handler\n"); 857 printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
858
859 outinput:
860 sony_laptop_remove_input();
861
516 outwalk: 862 outwalk:
517 return result; 863 return result;
518} 864}
519 865
520static int sony_acpi_remove(struct acpi_device *device, int type) 866static int sony_nc_remove(struct acpi_device *device, int type)
521{ 867{
522 acpi_status status; 868 acpi_status status;
869 struct sony_nc_value *item;
523 870
524 if (sony_backlight_device) 871 if (sony_backlight_device)
525 backlight_device_unregister(sony_backlight_device); 872 backlight_device_unregister(sony_backlight_device);
526 873
527 sony_acpi_acpi_device = NULL; 874 sony_nc_acpi_device = NULL;
528 875
529 status = acpi_remove_notify_handler(sony_acpi_handle, 876 status = acpi_remove_notify_handler(sony_nc_acpi_handle,
530 ACPI_DEVICE_NOTIFY, 877 ACPI_DEVICE_NOTIFY,
531 sony_acpi_notify); 878 sony_acpi_notify);
532 if (ACPI_FAILURE(status)) 879 if (ACPI_FAILURE(status))
533 printk(LOG_PFX "unable to remove notify handler\n"); 880 printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
534 881
535 sony_snc_pf_remove(); 882 for (item = sony_nc_values; item->name; ++item) {
883 device_remove_file(&sony_pf_device->dev, &item->devattr);
884 }
536 885
537 printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n"); 886 sony_pf_remove();
887 sony_laptop_remove_input();
888 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
538 889
539 return 0; 890 return 0;
540} 891}
541 892
542static struct acpi_driver sony_acpi_driver = { 893static struct acpi_driver sony_nc_driver = {
543 .name = ACPI_SNC_DRIVER_NAME, 894 .name = SONY_NC_DRIVER_NAME,
544 .class = ACPI_SNC_CLASS, 895 .class = SONY_NC_CLASS,
545 .ids = ACPI_SNC_HID, 896 .ids = SONY_NC_HID,
897 .owner = THIS_MODULE,
546 .ops = { 898 .ops = {
547 .add = sony_acpi_add, 899 .add = sony_nc_add,
548 .remove = sony_acpi_remove, 900 .remove = sony_nc_remove,
549 .resume = sony_acpi_resume, 901 .resume = sony_nc_resume,
550 }, 902 },
551}; 903};
552 904
553static int __init sony_acpi_init(void) 905/*********** SPIC (SNY6001) Device ***********/
906
907#define SONYPI_DEVICE_TYPE1 0x00000001
908#define SONYPI_DEVICE_TYPE2 0x00000002
909#define SONYPI_DEVICE_TYPE3 0x00000004
910
911#define SONY_PIC_EV_MASK 0xff
912
913struct sony_pic_ioport {
914 struct acpi_resource_io io;
915 struct list_head list;
916};
917
918struct sony_pic_irq {
919 struct acpi_resource_irq irq;
920 struct list_head list;
921};
922
923struct sony_pic_dev {
924 int model;
925 u8 camera_power;
926 u8 bluetooth_power;
927 u8 wwan_power;
928 struct acpi_device *acpi_dev;
929 struct sony_pic_irq *cur_irq;
930 struct sony_pic_ioport *cur_ioport;
931 struct list_head interrupts;
932 struct list_head ioports;
933 struct mutex lock;
934};
935
936static struct sony_pic_dev spic_dev = {
937 .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
938 .ioports = LIST_HEAD_INIT(spic_dev.ioports),
939};
940
941/* Event masks */
942#define SONYPI_JOGGER_MASK 0x00000001
943#define SONYPI_CAPTURE_MASK 0x00000002
944#define SONYPI_FNKEY_MASK 0x00000004
945#define SONYPI_BLUETOOTH_MASK 0x00000008
946#define SONYPI_PKEY_MASK 0x00000010
947#define SONYPI_BACK_MASK 0x00000020
948#define SONYPI_HELP_MASK 0x00000040
949#define SONYPI_LID_MASK 0x00000080
950#define SONYPI_ZOOM_MASK 0x00000100
951#define SONYPI_THUMBPHRASE_MASK 0x00000200
952#define SONYPI_MEYE_MASK 0x00000400
953#define SONYPI_MEMORYSTICK_MASK 0x00000800
954#define SONYPI_BATTERY_MASK 0x00001000
955#define SONYPI_WIRELESS_MASK 0x00002000
956
957struct sonypi_event {
958 u8 data;
959 u8 event;
960};
961
962/* The set of possible button release events */
963static struct sonypi_event sonypi_releaseev[] = {
964 { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
965 { 0, 0 }
966};
967
968/* The set of possible jogger events */
969static struct sonypi_event sonypi_joggerev[] = {
970 { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
971 { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
972 { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
973 { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
974 { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
975 { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
976 { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
977 { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
978 { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
979 { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
980 { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
981 { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
982 { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
983 { 0, 0 }
984};
985
986/* The set of possible capture button events */
987static struct sonypi_event sonypi_captureev[] = {
988 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
989 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
990 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
991 { 0, 0 }
992};
993
994/* The set of possible fnkeys events */
995static struct sonypi_event sonypi_fnkeyev[] = {
996 { 0x10, SONYPI_EVENT_FNKEY_ESC },
997 { 0x11, SONYPI_EVENT_FNKEY_F1 },
998 { 0x12, SONYPI_EVENT_FNKEY_F2 },
999 { 0x13, SONYPI_EVENT_FNKEY_F3 },
1000 { 0x14, SONYPI_EVENT_FNKEY_F4 },
1001 { 0x15, SONYPI_EVENT_FNKEY_F5 },
1002 { 0x16, SONYPI_EVENT_FNKEY_F6 },
1003 { 0x17, SONYPI_EVENT_FNKEY_F7 },
1004 { 0x18, SONYPI_EVENT_FNKEY_F8 },
1005 { 0x19, SONYPI_EVENT_FNKEY_F9 },
1006 { 0x1a, SONYPI_EVENT_FNKEY_F10 },
1007 { 0x1b, SONYPI_EVENT_FNKEY_F11 },
1008 { 0x1c, SONYPI_EVENT_FNKEY_F12 },
1009 { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
1010 { 0x21, SONYPI_EVENT_FNKEY_1 },
1011 { 0x22, SONYPI_EVENT_FNKEY_2 },
1012 { 0x31, SONYPI_EVENT_FNKEY_D },
1013 { 0x32, SONYPI_EVENT_FNKEY_E },
1014 { 0x33, SONYPI_EVENT_FNKEY_F },
1015 { 0x34, SONYPI_EVENT_FNKEY_S },
1016 { 0x35, SONYPI_EVENT_FNKEY_B },
1017 { 0x36, SONYPI_EVENT_FNKEY_ONLY },
1018 { 0, 0 }
1019};
1020
1021/* The set of possible program key events */
1022static struct sonypi_event sonypi_pkeyev[] = {
1023 { 0x01, SONYPI_EVENT_PKEY_P1 },
1024 { 0x02, SONYPI_EVENT_PKEY_P2 },
1025 { 0x04, SONYPI_EVENT_PKEY_P3 },
1026 { 0x5c, SONYPI_EVENT_PKEY_P1 },
1027 { 0, 0 }
1028};
1029
1030/* The set of possible bluetooth events */
1031static struct sonypi_event sonypi_blueev[] = {
1032 { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
1033 { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
1034 { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
1035 { 0, 0 }
1036};
1037
1038/* The set of possible wireless events */
1039static struct sonypi_event sonypi_wlessev[] = {
1040 { 0x59, SONYPI_EVENT_WIRELESS_ON },
1041 { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
1042 { 0, 0 }
1043};
1044
1045/* The set of possible back button events */
1046static struct sonypi_event sonypi_backev[] = {
1047 { 0x20, SONYPI_EVENT_BACK_PRESSED },
1048 { 0, 0 }
1049};
1050
1051/* The set of possible help button events */
1052static struct sonypi_event sonypi_helpev[] = {
1053 { 0x3b, SONYPI_EVENT_HELP_PRESSED },
1054 { 0, 0 }
1055};
1056
1057
1058/* The set of possible lid events */
1059static struct sonypi_event sonypi_lidev[] = {
1060 { 0x51, SONYPI_EVENT_LID_CLOSED },
1061 { 0x50, SONYPI_EVENT_LID_OPENED },
1062 { 0, 0 }
1063};
1064
1065/* The set of possible zoom events */
1066static struct sonypi_event sonypi_zoomev[] = {
1067 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
1068 { 0, 0 }
1069};
1070
1071/* The set of possible thumbphrase events */
1072static struct sonypi_event sonypi_thumbphraseev[] = {
1073 { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
1074 { 0, 0 }
1075};
1076
1077/* The set of possible motioneye camera events */
1078static struct sonypi_event sonypi_meyeev[] = {
1079 { 0x00, SONYPI_EVENT_MEYE_FACE },
1080 { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
1081 { 0, 0 }
1082};
1083
1084/* The set of possible memorystick events */
1085static struct sonypi_event sonypi_memorystickev[] = {
1086 { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
1087 { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
1088 { 0, 0 }
1089};
1090
1091/* The set of possible battery events */
1092static struct sonypi_event sonypi_batteryev[] = {
1093 { 0x20, SONYPI_EVENT_BATTERY_INSERT },
1094 { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
1095 { 0, 0 }
1096};
1097
1098static struct sonypi_eventtypes {
1099 int model;
1100 u8 data;
1101 unsigned long mask;
1102 struct sonypi_event * events;
1103} sony_pic_eventtypes[] = {
1104 { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
1105 { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
1106 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
1107 { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
1108 { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
1109 { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1110 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1111 { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
1112 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1113 { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
1114
1115 { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
1116 { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
1117 { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
1118 { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
1119 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1120 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1121 { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
1122 { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
1123 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
1124 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
1125 { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
1126 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1127 { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1128 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1129
1130 { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
1131 { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1132 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1133 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1134 { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1135 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1136 { 0 }
1137};
1138
1139static int sony_pic_detect_device_type(void)
1140{
1141 struct pci_dev *pcidev;
1142 int model = 0;
1143
1144 if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1145 PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
1146 model = SONYPI_DEVICE_TYPE1;
1147
1148 else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1149 PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
1150 model = SONYPI_DEVICE_TYPE3;
1151
1152 else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1153 PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
1154 model = SONYPI_DEVICE_TYPE3;
1155
1156 else
1157 model = SONYPI_DEVICE_TYPE2;
1158
1159 if (pcidev)
1160 pci_dev_put(pcidev);
1161
1162 printk(KERN_INFO DRV_PFX "detected Type%d model\n",
1163 model == SONYPI_DEVICE_TYPE1 ? 1 :
1164 model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
1165 return model;
1166}
1167
1168#define ITERATIONS_LONG 10000
1169#define ITERATIONS_SHORT 10
1170#define wait_on_command(command, iterations) { \
1171 unsigned int n = iterations; \
1172 while (--n && (command)) \
1173 udelay(1); \
1174 if (!n) \
1175 dprintk("command failed at %s : %s (line %d)\n", \
1176 __FILE__, __FUNCTION__, __LINE__); \
1177}
1178
1179static u8 sony_pic_call1(u8 dev)
1180{
1181 u8 v1, v2;
1182
1183 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
1184 ITERATIONS_LONG);
1185 outb(dev, spic_dev.cur_ioport->io.minimum + 4);
1186 v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
1187 v2 = inb_p(spic_dev.cur_ioport->io.minimum);
1188 dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
1189 return v2;
1190}
1191
1192static u8 sony_pic_call2(u8 dev, u8 fn)
1193{
1194 u8 v1;
1195
1196 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
1197 ITERATIONS_LONG);
1198 outb(dev, spic_dev.cur_ioport->io.minimum + 4);
1199 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
1200 ITERATIONS_LONG);
1201 outb(fn, spic_dev.cur_ioport->io.minimum);
1202 v1 = inb_p(spic_dev.cur_ioport->io.minimum);
1203 dprintk("sony_pic_call2: 0x%.4x\n", v1);
1204 return v1;
1205}
1206
1207static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
1208{
1209 u8 v1;
1210
1211 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
1212 outb(dev, spic_dev.cur_ioport->io.minimum + 4);
1213 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
1214 outb(fn, spic_dev.cur_ioport->io.minimum);
1215 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
1216 outb(v, spic_dev.cur_ioport->io.minimum);
1217 v1 = inb_p(spic_dev.cur_ioport->io.minimum);
1218 dprintk("sony_pic_call3: 0x%.4x\n", v1);
1219 return v1;
1220}
1221
1222/* camera tests and poweron/poweroff */
1223#define SONYPI_CAMERA_PICTURE 5
1224#define SONYPI_CAMERA_CONTROL 0x10
1225
1226#define SONYPI_CAMERA_BRIGHTNESS 0
1227#define SONYPI_CAMERA_CONTRAST 1
1228#define SONYPI_CAMERA_HUE 2
1229#define SONYPI_CAMERA_COLOR 3
1230#define SONYPI_CAMERA_SHARPNESS 4
1231
1232#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
1233#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
1234#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
1235#define SONYPI_CAMERA_MUTE_MASK 0x40
1236
1237/* the rest don't need a loop until not 0xff */
1238#define SONYPI_CAMERA_AGC 6
1239#define SONYPI_CAMERA_AGC_MASK 0x30
1240#define SONYPI_CAMERA_SHUTTER_MASK 0x7
1241
1242#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
1243#define SONYPI_CAMERA_CONTROL 0x10
1244
1245#define SONYPI_CAMERA_STATUS 7
1246#define SONYPI_CAMERA_STATUS_READY 0x2
1247#define SONYPI_CAMERA_STATUS_POSITION 0x4
1248
1249#define SONYPI_DIRECTION_BACKWARDS 0x4
1250
1251#define SONYPI_CAMERA_REVISION 8
1252#define SONYPI_CAMERA_ROMVERSION 9
1253
1254static int __sony_pic_camera_ready(void)
1255{
1256 u8 v;
1257
1258 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
1259 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
1260}
1261
1262static int __sony_pic_camera_off(void)
1263{
1264 if (!camera) {
1265 printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
1266 return -ENODEV;
1267 }
1268
1269 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
1270 SONYPI_CAMERA_MUTE_MASK),
1271 ITERATIONS_SHORT);
1272
1273 if (spic_dev.camera_power) {
1274 sony_pic_call2(0x91, 0);
1275 spic_dev.camera_power = 0;
1276 }
1277 return 0;
1278}
1279
1280static int __sony_pic_camera_on(void)
554{ 1281{
555 return acpi_bus_register_driver(&sony_acpi_driver); 1282 int i, j, x;
1283
1284 if (!camera) {
1285 printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
1286 return -ENODEV;
1287 }
1288
1289 if (spic_dev.camera_power)
1290 return 0;
1291
1292 for (j = 5; j > 0; j--) {
1293
1294 for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
1295 msleep(10);
1296 sony_pic_call1(0x93);
1297
1298 for (i = 400; i > 0; i--) {
1299 if (__sony_pic_camera_ready())
1300 break;
1301 msleep(10);
1302 }
1303 if (i)
1304 break;
1305 }
1306
1307 if (j == 0) {
1308 printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
1309 return -ENODEV;
1310 }
1311
1312 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
1313 0x5a),
1314 ITERATIONS_SHORT);
1315
1316 spic_dev.camera_power = 1;
1317 return 0;
1318}
1319
1320/* External camera command (exported to the motion eye v4l driver) */
1321int sony_pic_camera_command(int command, u8 value)
1322{
1323 if (!camera)
1324 return -EIO;
1325
1326 mutex_lock(&spic_dev.lock);
1327
1328 switch (command) {
1329 case SONY_PIC_COMMAND_SETCAMERA:
1330 if (value)
1331 __sony_pic_camera_on();
1332 else
1333 __sony_pic_camera_off();
1334 break;
1335 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
1336 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
1337 ITERATIONS_SHORT);
1338 break;
1339 case SONY_PIC_COMMAND_SETCAMERACONTRAST:
1340 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
1341 ITERATIONS_SHORT);
1342 break;
1343 case SONY_PIC_COMMAND_SETCAMERAHUE:
1344 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
1345 ITERATIONS_SHORT);
1346 break;
1347 case SONY_PIC_COMMAND_SETCAMERACOLOR:
1348 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
1349 ITERATIONS_SHORT);
1350 break;
1351 case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
1352 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
1353 ITERATIONS_SHORT);
1354 break;
1355 case SONY_PIC_COMMAND_SETCAMERAPICTURE:
1356 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
1357 ITERATIONS_SHORT);
1358 break;
1359 case SONY_PIC_COMMAND_SETCAMERAAGC:
1360 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
1361 ITERATIONS_SHORT);
1362 break;
1363 default:
1364 printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
1365 command);
1366 break;
1367 }
1368 mutex_unlock(&spic_dev.lock);
1369 return 0;
1370}
1371EXPORT_SYMBOL(sony_pic_camera_command);
1372
1373/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
1374static void sony_pic_set_wwanpower(u8 state)
1375{
1376 state = !!state;
1377 mutex_lock(&spic_dev.lock);
1378 if (spic_dev.wwan_power == state) {
1379 mutex_unlock(&spic_dev.lock);
1380 return;
1381 }
1382 sony_pic_call2(0xB0, state);
1383 spic_dev.wwan_power = state;
1384 mutex_unlock(&spic_dev.lock);
1385}
1386
1387static ssize_t sony_pic_wwanpower_store(struct device *dev,
1388 struct device_attribute *attr,
1389 const char *buffer, size_t count)
1390{
1391 unsigned long value;
1392 if (count > 31)
1393 return -EINVAL;
1394
1395 value = simple_strtoul(buffer, NULL, 10);
1396 sony_pic_set_wwanpower(value);
1397
1398 return count;
1399}
1400
1401static ssize_t sony_pic_wwanpower_show(struct device *dev,
1402 struct device_attribute *attr, char *buffer)
1403{
1404 ssize_t count;
1405 mutex_lock(&spic_dev.lock);
1406 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
1407 mutex_unlock(&spic_dev.lock);
1408 return count;
1409}
1410
1411/* bluetooth subsystem power state */
1412static void __sony_pic_set_bluetoothpower(u8 state)
1413{
1414 state = !!state;
1415 if (spic_dev.bluetooth_power == state)
1416 return;
1417 sony_pic_call2(0x96, state);
1418 sony_pic_call1(0x82);
1419 spic_dev.bluetooth_power = state;
1420}
1421
1422static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
1423 struct device_attribute *attr,
1424 const char *buffer, size_t count)
1425{
1426 unsigned long value;
1427 if (count > 31)
1428 return -EINVAL;
1429
1430 value = simple_strtoul(buffer, NULL, 10);
1431 mutex_lock(&spic_dev.lock);
1432 __sony_pic_set_bluetoothpower(value);
1433 mutex_unlock(&spic_dev.lock);
1434
1435 return count;
1436}
1437
1438static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
1439 struct device_attribute *attr, char *buffer)
1440{
1441 ssize_t count = 0;
1442 mutex_lock(&spic_dev.lock);
1443 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
1444 mutex_unlock(&spic_dev.lock);
1445 return count;
1446}
1447
1448/* fan speed */
1449/* FAN0 information (reverse engineered from ACPI tables) */
1450#define SONY_PIC_FAN0_STATUS 0x93
1451static int sony_pic_set_fanspeed(unsigned long value)
1452{
1453 return ec_write(SONY_PIC_FAN0_STATUS, value);
1454}
1455
1456static int sony_pic_get_fanspeed(u8 *value)
1457{
1458 return ec_read(SONY_PIC_FAN0_STATUS, value);
1459}
1460
1461static ssize_t sony_pic_fanspeed_store(struct device *dev,
1462 struct device_attribute *attr,
1463 const char *buffer, size_t count)
1464{
1465 unsigned long value;
1466 if (count > 31)
1467 return -EINVAL;
1468
1469 value = simple_strtoul(buffer, NULL, 10);
1470 if (sony_pic_set_fanspeed(value))
1471 return -EIO;
1472
1473 return count;
1474}
1475
1476static ssize_t sony_pic_fanspeed_show(struct device *dev,
1477 struct device_attribute *attr, char *buffer)
1478{
1479 u8 value = 0;
1480 if (sony_pic_get_fanspeed(&value))
1481 return -EIO;
1482
1483 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
1484}
1485
1486#define SPIC_ATTR(_name, _mode) \
1487struct device_attribute spic_attr_##_name = __ATTR(_name, \
1488 _mode, sony_pic_## _name ##_show, \
1489 sony_pic_## _name ##_store)
1490
1491static SPIC_ATTR(bluetoothpower, 0644);
1492static SPIC_ATTR(wwanpower, 0644);
1493static SPIC_ATTR(fanspeed, 0644);
1494
1495static struct attribute *spic_attributes[] = {
1496 &spic_attr_bluetoothpower.attr,
1497 &spic_attr_wwanpower.attr,
1498 &spic_attr_fanspeed.attr,
1499 NULL
1500};
1501
1502static struct attribute_group spic_attribute_group = {
1503 .attrs = spic_attributes
1504};
1505
1506/******** SONYPI compatibility **********/
1507#ifdef CONFIG_SONY_LAPTOP_OLD
1508
1509/* battery / brightness / temperature addresses */
1510#define SONYPI_BAT_FLAGS 0x81
1511#define SONYPI_LCD_LIGHT 0x96
1512#define SONYPI_BAT1_PCTRM 0xa0
1513#define SONYPI_BAT1_LEFT 0xa2
1514#define SONYPI_BAT1_MAXRT 0xa4
1515#define SONYPI_BAT2_PCTRM 0xa8
1516#define SONYPI_BAT2_LEFT 0xaa
1517#define SONYPI_BAT2_MAXRT 0xac
1518#define SONYPI_BAT1_MAXTK 0xb0
1519#define SONYPI_BAT1_FULL 0xb2
1520#define SONYPI_BAT2_MAXTK 0xb8
1521#define SONYPI_BAT2_FULL 0xba
1522#define SONYPI_TEMP_STATUS 0xC1
1523
1524struct sonypi_compat_s {
1525 struct fasync_struct *fifo_async;
1526 struct kfifo *fifo;
1527 spinlock_t fifo_lock;
1528 wait_queue_head_t fifo_proc_list;
1529 atomic_t open_count;
1530};
1531static struct sonypi_compat_s sonypi_compat = {
1532 .open_count = ATOMIC_INIT(0),
1533};
1534
1535static int sonypi_misc_fasync(int fd, struct file *filp, int on)
1536{
1537 int retval;
1538
1539 retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
1540 if (retval < 0)
1541 return retval;
1542 return 0;
1543}
1544
1545static int sonypi_misc_release(struct inode *inode, struct file *file)
1546{
1547 sonypi_misc_fasync(-1, file, 0);
1548 atomic_dec(&sonypi_compat.open_count);
1549 return 0;
1550}
1551
1552static int sonypi_misc_open(struct inode *inode, struct file *file)
1553{
1554 /* Flush input queue on first open */
1555 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
1556 kfifo_reset(sonypi_compat.fifo);
1557 return 0;
1558}
1559
1560static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
1561 size_t count, loff_t *pos)
1562{
1563 ssize_t ret;
1564 unsigned char c;
1565
1566 if ((kfifo_len(sonypi_compat.fifo) == 0) &&
1567 (file->f_flags & O_NONBLOCK))
1568 return -EAGAIN;
1569
1570 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
1571 kfifo_len(sonypi_compat.fifo) != 0);
1572 if (ret)
1573 return ret;
1574
1575 while (ret < count &&
1576 (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
1577 if (put_user(c, buf++))
1578 return -EFAULT;
1579 ret++;
1580 }
1581
1582 if (ret > 0) {
1583 struct inode *inode = file->f_path.dentry->d_inode;
1584 inode->i_atime = current_fs_time(inode->i_sb);
1585 }
1586
1587 return ret;
1588}
1589
1590static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
1591{
1592 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
1593 if (kfifo_len(sonypi_compat.fifo))
1594 return POLLIN | POLLRDNORM;
1595 return 0;
1596}
1597
1598static int ec_read16(u8 addr, u16 *value)
1599{
1600 u8 val_lb, val_hb;
1601 if (ec_read(addr, &val_lb))
1602 return -1;
1603 if (ec_read(addr + 1, &val_hb))
1604 return -1;
1605 *value = val_lb | (val_hb << 8);
1606 return 0;
1607}
1608
1609static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
1610 unsigned int cmd, unsigned long arg)
1611{
1612 int ret = 0;
1613 void __user *argp = (void __user *)arg;
1614 u8 val8;
1615 u16 val16;
1616 int value;
1617
1618 mutex_lock(&spic_dev.lock);
1619 switch (cmd) {
1620 case SONYPI_IOCGBRT:
1621 if (sony_backlight_device == NULL) {
1622 ret = -EIO;
1623 break;
1624 }
1625 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
1626 ret = -EIO;
1627 break;
1628 }
1629 val8 = ((value & 0xff) - 1) << 5;
1630 if (copy_to_user(argp, &val8, sizeof(val8)))
1631 ret = -EFAULT;
1632 break;
1633 case SONYPI_IOCSBRT:
1634 if (sony_backlight_device == NULL) {
1635 ret = -EIO;
1636 break;
1637 }
1638 if (copy_from_user(&val8, argp, sizeof(val8))) {
1639 ret = -EFAULT;
1640 break;
1641 }
1642 if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
1643 (val8 >> 5) + 1, NULL)) {
1644 ret = -EIO;
1645 break;
1646 }
1647 /* sync the backlight device status */
1648 sony_backlight_device->props.brightness =
1649 sony_backlight_get_brightness(sony_backlight_device);
1650 break;
1651 case SONYPI_IOCGBAT1CAP:
1652 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
1653 ret = -EIO;
1654 break;
1655 }
1656 if (copy_to_user(argp, &val16, sizeof(val16)))
1657 ret = -EFAULT;
1658 break;
1659 case SONYPI_IOCGBAT1REM:
1660 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
1661 ret = -EIO;
1662 break;
1663 }
1664 if (copy_to_user(argp, &val16, sizeof(val16)))
1665 ret = -EFAULT;
1666 break;
1667 case SONYPI_IOCGBAT2CAP:
1668 if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
1669 ret = -EIO;
1670 break;
1671 }
1672 if (copy_to_user(argp, &val16, sizeof(val16)))
1673 ret = -EFAULT;
1674 break;
1675 case SONYPI_IOCGBAT2REM:
1676 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
1677 ret = -EIO;
1678 break;
1679 }
1680 if (copy_to_user(argp, &val16, sizeof(val16)))
1681 ret = -EFAULT;
1682 break;
1683 case SONYPI_IOCGBATFLAGS:
1684 if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
1685 ret = -EIO;
1686 break;
1687 }
1688 val8 &= 0x07;
1689 if (copy_to_user(argp, &val8, sizeof(val8)))
1690 ret = -EFAULT;
1691 break;
1692 case SONYPI_IOCGBLUE:
1693 val8 = spic_dev.bluetooth_power;
1694 if (copy_to_user(argp, &val8, sizeof(val8)))
1695 ret = -EFAULT;
1696 break;
1697 case SONYPI_IOCSBLUE:
1698 if (copy_from_user(&val8, argp, sizeof(val8))) {
1699 ret = -EFAULT;
1700 break;
1701 }
1702 __sony_pic_set_bluetoothpower(val8);
1703 break;
1704 /* FAN Controls */
1705 case SONYPI_IOCGFAN:
1706 if (sony_pic_get_fanspeed(&val8)) {
1707 ret = -EIO;
1708 break;
1709 }
1710 if (copy_to_user(argp, &val8, sizeof(val8)))
1711 ret = -EFAULT;
1712 break;
1713 case SONYPI_IOCSFAN:
1714 if (copy_from_user(&val8, argp, sizeof(val8))) {
1715 ret = -EFAULT;
1716 break;
1717 }
1718 if (sony_pic_set_fanspeed(val8))
1719 ret = -EIO;
1720 break;
1721 /* GET Temperature (useful under APM) */
1722 case SONYPI_IOCGTEMP:
1723 if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
1724 ret = -EIO;
1725 break;
1726 }
1727 if (copy_to_user(argp, &val8, sizeof(val8)))
1728 ret = -EFAULT;
1729 break;
1730 default:
1731 ret = -EINVAL;
1732 }
1733 mutex_unlock(&spic_dev.lock);
1734 return ret;
1735}
1736
1737static const struct file_operations sonypi_misc_fops = {
1738 .owner = THIS_MODULE,
1739 .read = sonypi_misc_read,
1740 .poll = sonypi_misc_poll,
1741 .open = sonypi_misc_open,
1742 .release = sonypi_misc_release,
1743 .fasync = sonypi_misc_fasync,
1744 .ioctl = sonypi_misc_ioctl,
1745};
1746
1747static struct miscdevice sonypi_misc_device = {
1748 .minor = MISC_DYNAMIC_MINOR,
1749 .name = "sonypi",
1750 .fops = &sonypi_misc_fops,
1751};
1752
1753static void sonypi_compat_report_event(u8 event)
1754{
1755 kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
1756 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
1757 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
1758}
1759
1760static int sonypi_compat_init(void)
1761{
1762 int error;
1763
1764 spin_lock_init(&sonypi_compat.fifo_lock);
1765 sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
1766 &sonypi_compat.fifo_lock);
1767 if (IS_ERR(sonypi_compat.fifo)) {
1768 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
1769 return PTR_ERR(sonypi_compat.fifo);
1770 }
1771
1772 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
1773
1774 if (minor != -1)
1775 sonypi_misc_device.minor = minor;
1776 error = misc_register(&sonypi_misc_device);
1777 if (error) {
1778 printk(KERN_ERR DRV_PFX "misc_register failed\n");
1779 goto err_free_kfifo;
1780 }
1781 if (minor == -1)
1782 printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
1783 sonypi_misc_device.minor);
1784
1785 return 0;
1786
1787err_free_kfifo:
1788 kfifo_free(sonypi_compat.fifo);
1789 return error;
1790}
1791
1792static void sonypi_compat_exit(void)
1793{
1794 misc_deregister(&sonypi_misc_device);
1795 kfifo_free(sonypi_compat.fifo);
1796}
1797#else
1798static int sonypi_compat_init(void) { return 0; }
1799static void sonypi_compat_exit(void) { }
1800static void sonypi_compat_report_event(u8 event) { }
1801#endif /* CONFIG_SONY_LAPTOP_OLD */
1802
1803/*
1804 * ACPI callbacks
1805 */
1806static acpi_status
1807sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
1808{
1809 u32 i;
1810 struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
1811
1812 switch (resource->type) {
1813 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
1814 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
1815 return AE_OK;
1816
1817 case ACPI_RESOURCE_TYPE_IRQ:
1818 {
1819 struct acpi_resource_irq *p = &resource->data.irq;
1820 struct sony_pic_irq *interrupt = NULL;
1821 if (!p || !p->interrupt_count) {
1822 /*
1823 * IRQ descriptors may have no IRQ# bits set,
1824 * particularly those those w/ _STA disabled
1825 */
1826 dprintk("Blank IRQ resource\n");
1827 return AE_OK;
1828 }
1829 for (i = 0; i < p->interrupt_count; i++) {
1830 if (!p->interrupts[i]) {
1831 printk(KERN_WARNING DRV_PFX
1832 "Invalid IRQ %d\n",
1833 p->interrupts[i]);
1834 continue;
1835 }
1836 interrupt = kzalloc(sizeof(*interrupt),
1837 GFP_KERNEL);
1838 if (!interrupt)
1839 return AE_ERROR;
1840
1841 list_add_tail(&interrupt->list, &dev->interrupts);
1842 interrupt->irq.triggering = p->triggering;
1843 interrupt->irq.polarity = p->polarity;
1844 interrupt->irq.sharable = p->sharable;
1845 interrupt->irq.interrupt_count = 1;
1846 interrupt->irq.interrupts[0] = p->interrupts[i];
1847 }
1848 return AE_OK;
1849 }
1850 case ACPI_RESOURCE_TYPE_IO:
1851 {
1852 struct acpi_resource_io *io = &resource->data.io;
1853 struct sony_pic_ioport *ioport = NULL;
1854 if (!io) {
1855 dprintk("Blank IO resource\n");
1856 return AE_OK;
1857 }
1858
1859 ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
1860 if (!ioport)
1861 return AE_ERROR;
1862
1863 list_add_tail(&ioport->list, &dev->ioports);
1864 memcpy(&ioport->io, io, sizeof(*io));
1865 return AE_OK;
1866 }
1867 default:
1868 dprintk("Resource %d isn't an IRQ nor an IO port\n",
1869 resource->type);
1870
1871 case ACPI_RESOURCE_TYPE_END_TAG:
1872 return AE_OK;
1873 }
1874 return AE_CTRL_TERMINATE;
1875}
1876
1877static int sony_pic_possible_resources(struct acpi_device *device)
1878{
1879 int result = 0;
1880 acpi_status status = AE_OK;
1881
1882 if (!device)
1883 return -EINVAL;
1884
1885 /* get device status */
1886 /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
1887 dprintk("Evaluating _STA\n");
1888 result = acpi_bus_get_status(device);
1889 if (result) {
1890 printk(KERN_WARNING DRV_PFX "Unable to read status\n");
1891 goto end;
1892 }
1893
1894 if (!device->status.enabled)
1895 dprintk("Device disabled\n");
1896 else
1897 dprintk("Device enabled\n");
1898
1899 /*
1900 * Query and parse 'method'
1901 */
1902 dprintk("Evaluating %s\n", METHOD_NAME__PRS);
1903 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
1904 sony_pic_read_possible_resource, &spic_dev);
1905 if (ACPI_FAILURE(status)) {
1906 printk(KERN_WARNING DRV_PFX
1907 "Failure evaluating %s\n",
1908 METHOD_NAME__PRS);
1909 result = -ENODEV;
1910 }
1911end:
1912 return result;
1913}
1914
1915/*
1916 * Disable the spic device by calling its _DIS method
1917 */
1918static int sony_pic_disable(struct acpi_device *device)
1919{
1920 if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
1921 return -ENXIO;
1922
1923 dprintk("Device disabled\n");
1924 return 0;
1925}
1926
1927
1928/*
1929 * Based on drivers/acpi/pci_link.c:acpi_pci_link_set
1930 *
1931 * Call _SRS to set current resources
1932 */
1933static int sony_pic_enable(struct acpi_device *device,
1934 struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
1935{
1936 acpi_status status;
1937 int result = 0;
1938 struct {
1939 struct acpi_resource io_res;
1940 struct acpi_resource irq_res;
1941 struct acpi_resource end;
1942 } *resource;
1943 struct acpi_buffer buffer = { 0, NULL };
1944
1945 if (!ioport || !irq)
1946 return -EINVAL;
1947
1948 /* init acpi_buffer */
1949 resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
1950 if (!resource)
1951 return -ENOMEM;
1952
1953 buffer.length = sizeof(*resource) + 1;
1954 buffer.pointer = resource;
1955
1956 /* setup io resource */
1957 resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
1958 resource->io_res.length = sizeof(struct acpi_resource);
1959 memcpy(&resource->io_res.data.io, &ioport->io,
1960 sizeof(struct acpi_resource_io));
1961
1962 /* setup irq resource */
1963 resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
1964 resource->irq_res.length = sizeof(struct acpi_resource);
1965 memcpy(&resource->irq_res.data.irq, &irq->irq,
1966 sizeof(struct acpi_resource_irq));
1967 /* we requested a shared irq */
1968 resource->irq_res.data.irq.sharable = ACPI_SHARED;
1969
1970 resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
1971
1972 /* Attempt to set the resource */
1973 dprintk("Evaluating _SRS\n");
1974 status = acpi_set_current_resources(device->handle, &buffer);
1975
1976 /* check for total failure */
1977 if (ACPI_FAILURE(status)) {
1978 printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
1979 result = -ENODEV;
1980 goto end;
1981 }
1982
1983 /* Necessary device initializations calls (from sonypi) */
1984 sony_pic_call1(0x82);
1985 sony_pic_call2(0x81, 0xff);
1986 sony_pic_call1(compat ? 0x92 : 0x82);
1987
1988end:
1989 kfree(resource);
1990 return result;
1991}
1992
1993/*****************
1994 *
1995 * ISR: some event is available
1996 *
1997 *****************/
1998static irqreturn_t sony_pic_irq(int irq, void *dev_id)
1999{
2000 int i, j;
2001 u32 port_val = 0;
2002 u8 ev = 0;
2003 u8 data_mask = 0;
2004 u8 device_event = 0;
2005
2006 struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
2007
2008 acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
2009 dev->cur_ioport->io.address_length);
2010 ev = port_val & SONY_PIC_EV_MASK;
2011 data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
2012
2013 dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
2014 port_val, ev, data_mask, dev->cur_ioport->io.minimum);
2015
2016 if (ev == 0x00 || ev == 0xff)
2017 return IRQ_HANDLED;
2018
2019 for (i = 0; sony_pic_eventtypes[i].model; i++) {
2020
2021 if (spic_dev.model != sony_pic_eventtypes[i].model)
2022 continue;
2023
2024 if ((data_mask & sony_pic_eventtypes[i].data) !=
2025 sony_pic_eventtypes[i].data)
2026 continue;
2027
2028 if (!(mask & sony_pic_eventtypes[i].mask))
2029 continue;
2030
2031 for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
2032 if (ev == sony_pic_eventtypes[i].events[j].data) {
2033 device_event =
2034 sony_pic_eventtypes[i].events[j].event;
2035 goto found;
2036 }
2037 }
2038 }
2039 return IRQ_HANDLED;
2040
2041found:
2042 sony_laptop_report_input_event(device_event);
2043 acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
2044 sonypi_compat_report_event(device_event);
2045
2046 return IRQ_HANDLED;
2047}
2048
2049/*****************
2050 *
2051 * ACPI driver
2052 *
2053 *****************/
2054static int sony_pic_remove(struct acpi_device *device, int type)
2055{
2056 struct sony_pic_ioport *io, *tmp_io;
2057 struct sony_pic_irq *irq, *tmp_irq;
2058
2059 sonypi_compat_exit();
2060
2061 if (sony_pic_disable(device)) {
2062 printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
2063 return -ENXIO;
2064 }
2065
2066 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
2067 release_region(spic_dev.cur_ioport->io.minimum,
2068 spic_dev.cur_ioport->io.address_length);
2069
2070 sony_laptop_remove_input();
2071
2072 /* pf attrs */
2073 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
2074 sony_pf_remove();
2075
2076 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
2077 list_del(&io->list);
2078 kfree(io);
2079 }
2080 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
2081 list_del(&irq->list);
2082 kfree(irq);
2083 }
2084 spic_dev.cur_ioport = NULL;
2085 spic_dev.cur_irq = NULL;
2086
2087 dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
2088 return 0;
2089}
2090
2091static int sony_pic_add(struct acpi_device *device)
2092{
2093 int result;
2094 struct sony_pic_ioport *io, *tmp_io;
2095 struct sony_pic_irq *irq, *tmp_irq;
2096
2097 printk(KERN_INFO DRV_PFX "%s v%s.\n",
2098 SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
2099
2100 spic_dev.acpi_dev = device;
2101 strcpy(acpi_device_class(device), "sony/hotkey");
2102 spic_dev.model = sony_pic_detect_device_type();
2103 mutex_init(&spic_dev.lock);
2104
2105 /* read _PRS resources */
2106 result = sony_pic_possible_resources(device);
2107 if (result) {
2108 printk(KERN_ERR DRV_PFX
2109 "Unabe to read possible resources.\n");
2110 goto err_free_resources;
2111 }
2112
2113 /* setup input devices and helper fifo */
2114 result = sony_laptop_setup_input();
2115 if (result) {
2116 printk(KERN_ERR DRV_PFX
2117 "Unabe to create input devices.\n");
2118 goto err_free_resources;
2119 }
2120
2121 /* request io port */
2122 list_for_each_entry(io, &spic_dev.ioports, list) {
2123 if (request_region(io->io.minimum, io->io.address_length,
2124 "Sony Programable I/O Device")) {
2125 dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
2126 io->io.minimum, io->io.maximum,
2127 io->io.address_length);
2128 spic_dev.cur_ioport = io;
2129 break;
2130 }
2131 }
2132 if (!spic_dev.cur_ioport) {
2133 printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
2134 result = -ENODEV;
2135 goto err_remove_input;
2136 }
2137
2138 /* request IRQ */
2139 list_for_each_entry(irq, &spic_dev.interrupts, list) {
2140 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
2141 IRQF_SHARED, "sony-laptop", &spic_dev)) {
2142 dprintk("IRQ: %d - triggering: %d - "
2143 "polarity: %d - shr: %d\n",
2144 irq->irq.interrupts[0],
2145 irq->irq.triggering,
2146 irq->irq.polarity,
2147 irq->irq.sharable);
2148 spic_dev.cur_irq = irq;
2149 break;
2150 }
2151 }
2152 if (!spic_dev.cur_irq) {
2153 printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
2154 result = -ENODEV;
2155 goto err_release_region;
2156 }
2157
2158 /* set resource status _SRS */
2159 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
2160 if (result) {
2161 printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
2162 goto err_free_irq;
2163 }
2164
2165 spic_dev.bluetooth_power = -1;
2166 /* create device attributes */
2167 result = sony_pf_add();
2168 if (result)
2169 goto err_disable_device;
2170
2171 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
2172 if (result)
2173 goto err_remove_pf;
2174
2175 if (sonypi_compat_init())
2176 goto err_remove_pf;
2177
2178 return 0;
2179
2180err_remove_pf:
2181 sony_pf_remove();
2182
2183err_disable_device:
2184 sony_pic_disable(device);
2185
2186err_free_irq:
2187 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
2188
2189err_release_region:
2190 release_region(spic_dev.cur_ioport->io.minimum,
2191 spic_dev.cur_ioport->io.address_length);
2192
2193err_remove_input:
2194 sony_laptop_remove_input();
2195
2196err_free_resources:
2197 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
2198 list_del(&io->list);
2199 kfree(io);
2200 }
2201 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
2202 list_del(&irq->list);
2203 kfree(irq);
2204 }
2205 spic_dev.cur_ioport = NULL;
2206 spic_dev.cur_irq = NULL;
2207
2208 return result;
2209}
2210
2211static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
2212{
2213 if (sony_pic_disable(device))
2214 return -ENXIO;
2215 return 0;
2216}
2217
2218static int sony_pic_resume(struct acpi_device *device)
2219{
2220 sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
2221 return 0;
2222}
2223
2224static struct acpi_driver sony_pic_driver = {
2225 .name = SONY_PIC_DRIVER_NAME,
2226 .class = SONY_PIC_CLASS,
2227 .ids = SONY_PIC_HID,
2228 .owner = THIS_MODULE,
2229 .ops = {
2230 .add = sony_pic_add,
2231 .remove = sony_pic_remove,
2232 .suspend = sony_pic_suspend,
2233 .resume = sony_pic_resume,
2234 },
2235};
2236
2237static struct dmi_system_id __initdata sonypi_dmi_table[] = {
2238 {
2239 .ident = "Sony Vaio",
2240 .matches = {
2241 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
2242 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
2243 },
2244 },
2245 {
2246 .ident = "Sony Vaio",
2247 .matches = {
2248 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
2249 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
2250 },
2251 },
2252 { }
2253};
2254
2255static int __init sony_laptop_init(void)
2256{
2257 int result;
2258
2259 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
2260 result = acpi_bus_register_driver(&sony_pic_driver);
2261 if (result) {
2262 printk(KERN_ERR DRV_PFX
2263 "Unable to register SPIC driver.");
2264 goto out;
2265 }
2266 }
2267
2268 result = acpi_bus_register_driver(&sony_nc_driver);
2269 if (result) {
2270 printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
2271 goto out_unregister_pic;
2272 }
2273
2274 return 0;
2275
2276out_unregister_pic:
2277 if (!no_spic)
2278 acpi_bus_unregister_driver(&sony_pic_driver);
2279out:
2280 return result;
556} 2281}
557 2282
558static void __exit sony_acpi_exit(void) 2283static void __exit sony_laptop_exit(void)
559{ 2284{
560 acpi_bus_unregister_driver(&sony_acpi_driver); 2285 acpi_bus_unregister_driver(&sony_nc_driver);
2286 if (!no_spic)
2287 acpi_bus_unregister_driver(&sony_pic_driver);
561} 2288}
562 2289
563module_init(sony_acpi_init); 2290module_init(sony_laptop_init);
564module_exit(sony_acpi_exit); 2291module_exit(sony_laptop_exit);