aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-04-12 18:24:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-04-12 18:24:23 -0400
commitd77d9597ad8f2bd381a5168005a21e82df6f18eb (patch)
tree43b4ceb5662b41ad340ae781f136afbeb30deeec
parent0bba01695b74fdd2f9286243bb39f88544d81401 (diff)
parentb569ab3911aca64841bd819720d2b241aa09d713 (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: thinkpad-acpi fails to load with newer Thinkpad X201s BIOS acer-wmi: Fix capitalisation of GUID in module alias sony-laptop: keyboard backlight fixes sony-laptop: only show the handles sysfs file in debug mode samsung-laptop: set backlight type staging: samsung-laptop has moved to platform/x86 samsung-laptop: Samsung R410P backlight driver samsung-laptop: add support for N230 model platform-drivers: x86: pmic: Restore the dropped buslock/unlock sony-laptop: fix early NULL pointer dereference msi-laptop: fix config-dependent build error eeepc-wmi: add keys found on EeePC 1215T asus-wmi: swap input name and phys asus-laptop: remove removed features from feature-removal-schedule.txt
-rw-r--r--Documentation/feature-removal-schedule.txt20
-rw-r--r--drivers/platform/x86/Kconfig3
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/asus-wmi.c4
-rw-r--r--drivers/platform/x86/eeepc-wmi.c2
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c43
-rw-r--r--drivers/platform/x86/samsung-laptop.c17
-rw-r--r--drivers/platform/x86/sony-laptop.c65
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c3
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/samsung-laptop/Kconfig10
-rw-r--r--drivers/staging/samsung-laptop/Makefile1
-rw-r--r--drivers/staging/samsung-laptop/TODO5
-rw-r--r--drivers/staging/samsung-laptop/samsung-laptop.c843
15 files changed, 114 insertions, 907 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 274b32d12532..492e81df2968 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -387,26 +387,6 @@ Who: Tejun Heo <tj@kernel.org>
387 387
388---------------------------- 388----------------------------
389 389
390What: Support for lcd_switch and display_get in asus-laptop driver
391When: March 2010
392Why: These two features use non-standard interfaces. There are the
393 only features that really need multiple path to guess what's
394 the right method name on a specific laptop.
395
396 Removing them will allow to remove a lot of code an significantly
397 clean the drivers.
398
399 This will affect the backlight code which won't be able to know
400 if the backlight is on or off. The platform display file will also be
401 write only (like the one in eeepc-laptop).
402
403 This should'nt affect a lot of user because they usually know
404 when their display is on or off.
405
406Who: Corentin Chary <corentin.chary@gmail.com>
407
408----------------------------
409
410What: sysfs-class-rfkill state file 390What: sysfs-class-rfkill state file
411When: Feb 2014 391When: Feb 2014
412Files: net/rfkill/core.c 392Files: net/rfkill/core.c
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2ee442c2a5db..0485e394712a 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -187,7 +187,8 @@ config MSI_LAPTOP
187 depends on ACPI 187 depends on ACPI
188 depends on BACKLIGHT_CLASS_DEVICE 188 depends on BACKLIGHT_CLASS_DEVICE
189 depends on RFKILL 189 depends on RFKILL
190 depends on SERIO_I8042 190 depends on INPUT && SERIO_I8042
191 select INPUT_SPARSEKMAP
191 ---help--- 192 ---help---
192 This is a driver for laptops built by MSI (MICRO-STAR 193 This is a driver for laptops built by MSI (MICRO-STAR
193 INTERNATIONAL): 194 INTERNATIONAL):
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 5ea6c3477d17..ac4e7f83ce6c 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
89#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" 89#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
90 90
91MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 91MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
92MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); 92MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
93MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); 93MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
94 94
95enum acer_wmi_event_ids { 95enum acer_wmi_event_ids {
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index efc776cb0c66..832a3fd7c1c8 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -201,8 +201,8 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
201 if (!asus->inputdev) 201 if (!asus->inputdev)
202 return -ENOMEM; 202 return -ENOMEM;
203 203
204 asus->inputdev->name = asus->driver->input_phys; 204 asus->inputdev->name = asus->driver->input_name;
205 asus->inputdev->phys = asus->driver->input_name; 205 asus->inputdev->phys = asus->driver->input_phys;
206 asus->inputdev->id.bustype = BUS_HOST; 206 asus->inputdev->id.bustype = BUS_HOST;
207 asus->inputdev->dev.parent = &asus->platform_device->dev; 207 asus->inputdev->dev.parent = &asus->platform_device->dev;
208 208
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 0ddc434fb93b..649dcadd8ea3 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -67,9 +67,11 @@ static const struct key_entry eeepc_wmi_keymap[] = {
67 { KE_KEY, 0x82, { KEY_CAMERA } }, 67 { KE_KEY, 0x82, { KEY_CAMERA } },
68 { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, 68 { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } },
69 { KE_KEY, 0x88, { KEY_WLAN } }, 69 { KE_KEY, 0x88, { KEY_WLAN } },
70 { KE_KEY, 0xbd, { KEY_CAMERA } },
70 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, 71 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
71 { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ 72 { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
72 { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ 73 { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
74 { KE_KEY, 0xe8, { KEY_SCREENLOCK } },
73 { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, 75 { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
74 { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, 76 { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
75 { KE_KEY, 0xec, { KEY_CAMERA_UP } }, 77 { KE_KEY, 0xec, { KEY_CAMERA_UP } },
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index d653104b59cb..7bbb5388e564 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -74,6 +74,19 @@ struct pmic_gpio {
74 u32 trigger_type; 74 u32 trigger_type;
75}; 75};
76 76
77static void pmic_program_irqtype(int gpio, int type)
78{
79 if (type & IRQ_TYPE_EDGE_RISING)
80 intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
81 else
82 intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
83
84 if (type & IRQ_TYPE_EDGE_FALLING)
85 intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
86 else
87 intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
88};
89
77static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 90static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
78{ 91{
79 if (offset > 8) { 92 if (offset > 8) {
@@ -166,16 +179,38 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
166 return pg->irq_base + offset; 179 return pg->irq_base + offset;
167} 180}
168 181
182static void pmic_bus_lock(struct irq_data *data)
183{
184 struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
185
186 mutex_lock(&pg->buslock);
187}
188
189static void pmic_bus_sync_unlock(struct irq_data *data)
190{
191 struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
192
193 if (pg->update_type) {
194 unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE;
195
196 pmic_program_irqtype(gpio, pg->trigger_type);
197 pg->update_type = 0;
198 }
199 mutex_unlock(&pg->buslock);
200}
201
169/* the gpiointr register is read-clear, so just do nothing. */ 202/* the gpiointr register is read-clear, so just do nothing. */
170static void pmic_irq_unmask(struct irq_data *data) { } 203static void pmic_irq_unmask(struct irq_data *data) { }
171 204
172static void pmic_irq_mask(struct irq_data *data) { } 205static void pmic_irq_mask(struct irq_data *data) { }
173 206
174static struct irq_chip pmic_irqchip = { 207static struct irq_chip pmic_irqchip = {
175 .name = "PMIC-GPIO", 208 .name = "PMIC-GPIO",
176 .irq_mask = pmic_irq_mask, 209 .irq_mask = pmic_irq_mask,
177 .irq_unmask = pmic_irq_unmask, 210 .irq_unmask = pmic_irq_unmask,
178 .irq_set_type = pmic_irq_type, 211 .irq_set_type = pmic_irq_type,
212 .irq_bus_lock = pmic_irq_buslock,
213 .irq_bus_sync_unlock = pmic_bus_sync_unlock,
179}; 214};
180 215
181static irqreturn_t pmic_irq_handler(int irq, void *data) 216static irqreturn_t pmic_irq_handler(int irq, void *data)
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index de434c6dc2d6..d347116d150e 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -571,6 +571,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
571 .callback = dmi_check_cb, 571 .callback = dmi_check_cb,
572 }, 572 },
573 { 573 {
574 .ident = "R410 Plus",
575 .matches = {
576 DMI_MATCH(DMI_SYS_VENDOR,
577 "SAMSUNG ELECTRONICS CO., LTD."),
578 DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
579 DMI_MATCH(DMI_BOARD_NAME, "R460"),
580 },
581 .callback = dmi_check_cb,
582 },
583 {
574 .ident = "R518", 584 .ident = "R518",
575 .matches = { 585 .matches = {
576 DMI_MATCH(DMI_SYS_VENDOR, 586 DMI_MATCH(DMI_SYS_VENDOR,
@@ -591,12 +601,12 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
591 .callback = dmi_check_cb, 601 .callback = dmi_check_cb,
592 }, 602 },
593 { 603 {
594 .ident = "N150/N210/N220", 604 .ident = "N150/N210/N220/N230",
595 .matches = { 605 .matches = {
596 DMI_MATCH(DMI_SYS_VENDOR, 606 DMI_MATCH(DMI_SYS_VENDOR,
597 "SAMSUNG ELECTRONICS CO., LTD."), 607 "SAMSUNG ELECTRONICS CO., LTD."),
598 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), 608 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
599 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), 609 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
600 }, 610 },
601 .callback = dmi_check_cb, 611 .callback = dmi_check_cb,
602 }, 612 },
@@ -771,6 +781,7 @@ static int __init samsung_init(void)
771 781
772 /* create a backlight device to talk to this one */ 782 /* create a backlight device to talk to this one */
773 memset(&props, 0, sizeof(struct backlight_properties)); 783 memset(&props, 0, sizeof(struct backlight_properties));
784 props.type = BACKLIGHT_PLATFORM;
774 props.max_brightness = sabi_config->max_brightness; 785 props.max_brightness = sabi_config->max_brightness;
775 backlight_device = backlight_device_register("samsung", &sdev->dev, 786 backlight_device = backlight_device_register("samsung", &sdev->dev,
776 NULL, &backlight_ops, 787 NULL, &backlight_ops,
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index e642f5f29504..8f709aec4da0 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -138,6 +138,8 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
138 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " 138 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
139 "(default: 0)"); 139 "(default: 0)");
140 140
141static void sony_nc_kbd_backlight_resume(void);
142
141enum sony_nc_rfkill { 143enum sony_nc_rfkill {
142 SONY_WIFI, 144 SONY_WIFI,
143 SONY_BLUETOOTH, 145 SONY_BLUETOOTH,
@@ -771,11 +773,6 @@ static int sony_nc_handles_setup(struct platform_device *pd)
771 if (!handles) 773 if (!handles)
772 return -ENOMEM; 774 return -ENOMEM;
773 775
774 sysfs_attr_init(&handles->devattr.attr);
775 handles->devattr.attr.name = "handles";
776 handles->devattr.attr.mode = S_IRUGO;
777 handles->devattr.show = sony_nc_handles_show;
778
779 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 776 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
780 if (!acpi_callsetfunc(sony_nc_acpi_handle, 777 if (!acpi_callsetfunc(sony_nc_acpi_handle,
781 "SN00", i + 0x20, &result)) { 778 "SN00", i + 0x20, &result)) {
@@ -785,11 +782,18 @@ static int sony_nc_handles_setup(struct platform_device *pd)
785 } 782 }
786 } 783 }
787 784
788 /* allow reading capabilities via sysfs */ 785 if (debug) {
789 if (device_create_file(&pd->dev, &handles->devattr)) { 786 sysfs_attr_init(&handles->devattr.attr);
790 kfree(handles); 787 handles->devattr.attr.name = "handles";
791 handles = NULL; 788 handles->devattr.attr.mode = S_IRUGO;
792 return -1; 789 handles->devattr.show = sony_nc_handles_show;
790
791 /* allow reading capabilities via sysfs */
792 if (device_create_file(&pd->dev, &handles->devattr)) {
793 kfree(handles);
794 handles = NULL;
795 return -1;
796 }
793 } 797 }
794 798
795 return 0; 799 return 0;
@@ -798,7 +802,8 @@ static int sony_nc_handles_setup(struct platform_device *pd)
798static int sony_nc_handles_cleanup(struct platform_device *pd) 802static int sony_nc_handles_cleanup(struct platform_device *pd)
799{ 803{
800 if (handles) { 804 if (handles) {
801 device_remove_file(&pd->dev, &handles->devattr); 805 if (debug)
806 device_remove_file(&pd->dev, &handles->devattr);
802 kfree(handles); 807 kfree(handles);
803 handles = NULL; 808 handles = NULL;
804 } 809 }
@@ -808,6 +813,11 @@ static int sony_nc_handles_cleanup(struct platform_device *pd)
808static int sony_find_snc_handle(int handle) 813static int sony_find_snc_handle(int handle)
809{ 814{
810 int i; 815 int i;
816
817 /* not initialized yet, return early */
818 if (!handles)
819 return -1;
820
811 for (i = 0; i < 0x10; i++) { 821 for (i = 0; i < 0x10; i++) {
812 if (handles->cap[i] == handle) { 822 if (handles->cap[i] == handle) {
813 dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", 823 dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
@@ -1168,6 +1178,9 @@ static int sony_nc_resume(struct acpi_device *device)
1168 /* re-read rfkill state */ 1178 /* re-read rfkill state */
1169 sony_nc_rfkill_update(); 1179 sony_nc_rfkill_update();
1170 1180
1181 /* restore kbd backlight states */
1182 sony_nc_kbd_backlight_resume();
1183
1171 return 0; 1184 return 0;
1172} 1185}
1173 1186
@@ -1355,6 +1368,7 @@ out_no_enum:
1355#define KBDBL_HANDLER 0x137 1368#define KBDBL_HANDLER 0x137
1356#define KBDBL_PRESENT 0xB00 1369#define KBDBL_PRESENT 0xB00
1357#define SET_MODE 0xC00 1370#define SET_MODE 0xC00
1371#define SET_STATE 0xD00
1358#define SET_TIMEOUT 0xE00 1372#define SET_TIMEOUT 0xE00
1359 1373
1360struct kbd_backlight { 1374struct kbd_backlight {
@@ -1377,6 +1391,10 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1377 (value << 0x10) | SET_MODE, &result)) 1391 (value << 0x10) | SET_MODE, &result))
1378 return -EIO; 1392 return -EIO;
1379 1393
1394 /* Try to turn the light on/off immediately */
1395 sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
1396 &result);
1397
1380 kbdbl_handle->mode = value; 1398 kbdbl_handle->mode = value;
1381 1399
1382 return 0; 1400 return 0;
@@ -1458,7 +1476,7 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1458{ 1476{
1459 int result; 1477 int result;
1460 1478
1461 if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) 1479 if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
1462 return 0; 1480 return 0;
1463 if (!(result & 0x02)) 1481 if (!(result & 0x02))
1464 return 0; 1482 return 0;
@@ -1501,13 +1519,36 @@ outkzalloc:
1501static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) 1519static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1502{ 1520{
1503 if (kbdbl_handle) { 1521 if (kbdbl_handle) {
1522 int result;
1523
1504 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1524 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1505 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); 1525 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
1526
1527 /* restore the default hw behaviour */
1528 sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result);
1529 sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result);
1530
1506 kfree(kbdbl_handle); 1531 kfree(kbdbl_handle);
1507 } 1532 }
1508 return 0; 1533 return 0;
1509} 1534}
1510 1535
1536static void sony_nc_kbd_backlight_resume(void)
1537{
1538 int ignore = 0;
1539
1540 if (!kbdbl_handle)
1541 return;
1542
1543 if (kbdbl_handle->mode == 0)
1544 sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore);
1545
1546 if (kbdbl_handle->timeout != 0)
1547 sony_call_snc_handle(KBDBL_HANDLER,
1548 (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
1549 &ignore);
1550}
1551
1511static void sony_nc_backlight_setup(void) 1552static void sony_nc_backlight_setup(void)
1512{ 1553{
1513 acpi_handle unused; 1554 acpi_handle unused;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a08561f5349e..efb3b6b9bcdb 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -8618,8 +8618,7 @@ static bool __pure __init tpacpi_is_valid_fw_id(const char* const s,
8618 tpacpi_is_fw_digit(s[1]) && 8618 tpacpi_is_fw_digit(s[1]) &&
8619 s[2] == t && s[3] == 'T' && 8619 s[2] == t && s[3] == 'T' &&
8620 tpacpi_is_fw_digit(s[4]) && 8620 tpacpi_is_fw_digit(s[4]) &&
8621 tpacpi_is_fw_digit(s[5]) && 8621 tpacpi_is_fw_digit(s[5]);
8622 s[6] == 'W' && s[7] == 'W';
8623} 8622}
8624 8623
8625/* returns 0 - probe ok, or < 0 - probe error. 8624/* returns 0 - probe ok, or < 0 - probe error.
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index dca4a0bb6ca9..e3786f161bc3 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -131,8 +131,6 @@ source "drivers/staging/wlags49_h2/Kconfig"
131 131
132source "drivers/staging/wlags49_h25/Kconfig" 132source "drivers/staging/wlags49_h25/Kconfig"
133 133
134source "drivers/staging/samsung-laptop/Kconfig"
135
136source "drivers/staging/sm7xx/Kconfig" 134source "drivers/staging/sm7xx/Kconfig"
137 135
138source "drivers/staging/dt3155v4l/Kconfig" 136source "drivers/staging/dt3155v4l/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index eb93012b6f59..f0d5c5315612 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -48,7 +48,6 @@ obj-$(CONFIG_XVMALLOC) += zram/
48obj-$(CONFIG_ZCACHE) += zcache/ 48obj-$(CONFIG_ZCACHE) += zcache/
49obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ 49obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
50obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ 50obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
51obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/
52obj-$(CONFIG_FB_SM7XX) += sm7xx/ 51obj-$(CONFIG_FB_SM7XX) += sm7xx/
53obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ 52obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
54obj-$(CONFIG_CRYSTALHD) += crystalhd/ 53obj-$(CONFIG_CRYSTALHD) += crystalhd/
diff --git a/drivers/staging/samsung-laptop/Kconfig b/drivers/staging/samsung-laptop/Kconfig
deleted file mode 100644
index f27c60864c26..000000000000
--- a/drivers/staging/samsung-laptop/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
1config SAMSUNG_LAPTOP
2 tristate "Samsung Laptop driver"
3 default n
4 depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
5 help
6 This module implements a driver for the N128 Samsung Laptop
7 providing control over the Wireless LED and the LCD backlight
8
9 To compile this driver as a module, choose
10 M here: the module will be called samsung-laptop.
diff --git a/drivers/staging/samsung-laptop/Makefile b/drivers/staging/samsung-laptop/Makefile
deleted file mode 100644
index 3c6f42045211..000000000000
--- a/drivers/staging/samsung-laptop/Makefile
+++ /dev/null
@@ -1 +0,0 @@
1obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
diff --git a/drivers/staging/samsung-laptop/TODO b/drivers/staging/samsung-laptop/TODO
deleted file mode 100644
index f7a6d589916e..000000000000
--- a/drivers/staging/samsung-laptop/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
1TODO:
2 - review from other developers
3 - figure out ACPI video issues
4
5Please send patches to Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c
deleted file mode 100644
index 25294462b8b6..000000000000
--- a/drivers/staging/samsung-laptop/samsung-laptop.c
+++ /dev/null
@@ -1,843 +0,0 @@
1/*
2 * Samsung Laptop driver
3 *
4 * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
5 * Copyright (C) 2009,2011 Novell Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/delay.h>
18#include <linux/pci.h>
19#include <linux/backlight.h>
20#include <linux/fb.h>
21#include <linux/dmi.h>
22#include <linux/platform_device.h>
23#include <linux/rfkill.h>
24
25/*
26 * This driver is needed because a number of Samsung laptops do not hook
27 * their control settings through ACPI. So we have to poke around in the
28 * BIOS to do things like brightness values, and "special" key controls.
29 */
30
31/*
32 * We have 0 - 8 as valid brightness levels. The specs say that level 0 should
33 * be reserved by the BIOS (which really doesn't make much sense), we tell
34 * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
35 */
36#define MAX_BRIGHT 0x07
37
38
39#define SABI_IFACE_MAIN 0x00
40#define SABI_IFACE_SUB 0x02
41#define SABI_IFACE_COMPLETE 0x04
42#define SABI_IFACE_DATA 0x05
43
44/* Structure to get data back to the calling function */
45struct sabi_retval {
46 u8 retval[20];
47};
48
49struct sabi_header_offsets {
50 u8 port;
51 u8 re_mem;
52 u8 iface_func;
53 u8 en_mem;
54 u8 data_offset;
55 u8 data_segment;
56};
57
58struct sabi_commands {
59 /*
60 * Brightness is 0 - 8, as described above.
61 * Value 0 is for the BIOS to use
62 */
63 u8 get_brightness;
64 u8 set_brightness;
65
66 /*
67 * first byte:
68 * 0x00 - wireless is off
69 * 0x01 - wireless is on
70 * second byte:
71 * 0x02 - 3G is off
72 * 0x03 - 3G is on
73 * TODO, verify 3G is correct, that doesn't seem right...
74 */
75 u8 get_wireless_button;
76 u8 set_wireless_button;
77
78 /* 0 is off, 1 is on */
79 u8 get_backlight;
80 u8 set_backlight;
81
82 /*
83 * 0x80 or 0x00 - no action
84 * 0x81 - recovery key pressed
85 */
86 u8 get_recovery_mode;
87 u8 set_recovery_mode;
88
89 /*
90 * on seclinux: 0 is low, 1 is high,
91 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
92 */
93 u8 get_performance_level;
94 u8 set_performance_level;
95
96 /*
97 * Tell the BIOS that Linux is running on this machine.
98 * 81 is on, 80 is off
99 */
100 u8 set_linux;
101};
102
103struct sabi_performance_level {
104 const char *name;
105 u8 value;
106};
107
108struct sabi_config {
109 const char *test_string;
110 u16 main_function;
111 const struct sabi_header_offsets header_offsets;
112 const struct sabi_commands commands;
113 const struct sabi_performance_level performance_levels[4];
114 u8 min_brightness;
115 u8 max_brightness;
116};
117
118static const struct sabi_config sabi_configs[] = {
119 {
120 .test_string = "SECLINUX",
121
122 .main_function = 0x4c49,
123
124 .header_offsets = {
125 .port = 0x00,
126 .re_mem = 0x02,
127 .iface_func = 0x03,
128 .en_mem = 0x04,
129 .data_offset = 0x05,
130 .data_segment = 0x07,
131 },
132
133 .commands = {
134 .get_brightness = 0x00,
135 .set_brightness = 0x01,
136
137 .get_wireless_button = 0x02,
138 .set_wireless_button = 0x03,
139
140 .get_backlight = 0x04,
141 .set_backlight = 0x05,
142
143 .get_recovery_mode = 0x06,
144 .set_recovery_mode = 0x07,
145
146 .get_performance_level = 0x08,
147 .set_performance_level = 0x09,
148
149 .set_linux = 0x0a,
150 },
151
152 .performance_levels = {
153 {
154 .name = "silent",
155 .value = 0,
156 },
157 {
158 .name = "normal",
159 .value = 1,
160 },
161 { },
162 },
163 .min_brightness = 1,
164 .max_brightness = 8,
165 },
166 {
167 .test_string = "SwSmi@",
168
169 .main_function = 0x5843,
170
171 .header_offsets = {
172 .port = 0x00,
173 .re_mem = 0x04,
174 .iface_func = 0x02,
175 .en_mem = 0x03,
176 .data_offset = 0x05,
177 .data_segment = 0x07,
178 },
179
180 .commands = {
181 .get_brightness = 0x10,
182 .set_brightness = 0x11,
183
184 .get_wireless_button = 0x12,
185 .set_wireless_button = 0x13,
186
187 .get_backlight = 0x2d,
188 .set_backlight = 0x2e,
189
190 .get_recovery_mode = 0xff,
191 .set_recovery_mode = 0xff,
192
193 .get_performance_level = 0x31,
194 .set_performance_level = 0x32,
195
196 .set_linux = 0xff,
197 },
198
199 .performance_levels = {
200 {
201 .name = "normal",
202 .value = 0,
203 },
204 {
205 .name = "silent",
206 .value = 1,
207 },
208 {
209 .name = "overclock",
210 .value = 2,
211 },
212 { },
213 },
214 .min_brightness = 0,
215 .max_brightness = 8,
216 },
217 { },
218};
219
220static const struct sabi_config *sabi_config;
221
222static void __iomem *sabi;
223static void __iomem *sabi_iface;
224static void __iomem *f0000_segment;
225static struct backlight_device *backlight_device;
226static struct mutex sabi_mutex;
227static struct platform_device *sdev;
228static struct rfkill *rfk;
229
230static int force;
231module_param(force, bool, 0);
232MODULE_PARM_DESC(force,
233 "Disable the DMI check and forces the driver to be loaded");
234
235static int debug;
236module_param(debug, bool, S_IRUGO | S_IWUSR);
237MODULE_PARM_DESC(debug, "Debug enabled or not");
238
239static int sabi_get_command(u8 command, struct sabi_retval *sretval)
240{
241 int retval = 0;
242 u16 port = readw(sabi + sabi_config->header_offsets.port);
243 u8 complete, iface_data;
244
245 mutex_lock(&sabi_mutex);
246
247 /* enable memory to be able to write to it */
248 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
249
250 /* write out the command */
251 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
252 writew(command, sabi_iface + SABI_IFACE_SUB);
253 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
254 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
255
256 /* write protect memory to make it safe */
257 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
258
259 /* see if the command actually succeeded */
260 complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
261 iface_data = readb(sabi_iface + SABI_IFACE_DATA);
262 if (complete != 0xaa || iface_data == 0xff) {
263 pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
264 command, complete, iface_data);
265 retval = -EINVAL;
266 goto exit;
267 }
268 /*
269 * Save off the data into a structure so the caller use it.
270 * Right now we only want the first 4 bytes,
271 * There are commands that need more, but not for the ones we
272 * currently care about.
273 */
274 sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
275 sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
276 sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
277 sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
278
279exit:
280 mutex_unlock(&sabi_mutex);
281 return retval;
282
283}
284
285static int sabi_set_command(u8 command, u8 data)
286{
287 int retval = 0;
288 u16 port = readw(sabi + sabi_config->header_offsets.port);
289 u8 complete, iface_data;
290
291 mutex_lock(&sabi_mutex);
292
293 /* enable memory to be able to write to it */
294 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
295
296 /* write out the command */
297 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
298 writew(command, sabi_iface + SABI_IFACE_SUB);
299 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
300 writeb(data, sabi_iface + SABI_IFACE_DATA);
301 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
302
303 /* write protect memory to make it safe */
304 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
305
306 /* see if the command actually succeeded */
307 complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
308 iface_data = readb(sabi_iface + SABI_IFACE_DATA);
309 if (complete != 0xaa || iface_data == 0xff) {
310 pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
311 command, complete, iface_data);
312 retval = -EINVAL;
313 }
314
315 mutex_unlock(&sabi_mutex);
316 return retval;
317}
318
319static void test_backlight(void)
320{
321 struct sabi_retval sretval;
322
323 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
324 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
325
326 sabi_set_command(sabi_config->commands.set_backlight, 0);
327 printk(KERN_DEBUG "backlight should be off\n");
328
329 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
330 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
331
332 msleep(1000);
333
334 sabi_set_command(sabi_config->commands.set_backlight, 1);
335 printk(KERN_DEBUG "backlight should be on\n");
336
337 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
338 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
339}
340
341static void test_wireless(void)
342{
343 struct sabi_retval sretval;
344
345 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
346 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
347
348 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
349 printk(KERN_DEBUG "wireless led should be off\n");
350
351 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
352 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
353
354 msleep(1000);
355
356 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
357 printk(KERN_DEBUG "wireless led should be on\n");
358
359 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
360 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
361}
362
363static u8 read_brightness(void)
364{
365 struct sabi_retval sretval;
366 int user_brightness = 0;
367 int retval;
368
369 retval = sabi_get_command(sabi_config->commands.get_brightness,
370 &sretval);
371 if (!retval) {
372 user_brightness = sretval.retval[0];
373 if (user_brightness != 0)
374 user_brightness -= sabi_config->min_brightness;
375 }
376 return user_brightness;
377}
378
379static void set_brightness(u8 user_brightness)
380{
381 u8 user_level = user_brightness - sabi_config->min_brightness;
382
383 sabi_set_command(sabi_config->commands.set_brightness, user_level);
384}
385
386static int get_brightness(struct backlight_device *bd)
387{
388 return (int)read_brightness();
389}
390
391static int update_status(struct backlight_device *bd)
392{
393 set_brightness(bd->props.brightness);
394
395 if (bd->props.power == FB_BLANK_UNBLANK)
396 sabi_set_command(sabi_config->commands.set_backlight, 1);
397 else
398 sabi_set_command(sabi_config->commands.set_backlight, 0);
399 return 0;
400}
401
402static const struct backlight_ops backlight_ops = {
403 .get_brightness = get_brightness,
404 .update_status = update_status,
405};
406
407static int rfkill_set(void *data, bool blocked)
408{
409 /* Do something with blocked...*/
410 /*
411 * blocked == false is on
412 * blocked == true is off
413 */
414 if (blocked)
415 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
416 else
417 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
418
419 return 0;
420}
421
422static struct rfkill_ops rfkill_ops = {
423 .set_block = rfkill_set,
424};
425
426static int init_wireless(struct platform_device *sdev)
427{
428 int retval;
429
430 rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
431 &rfkill_ops, NULL);
432 if (!rfk)
433 return -ENOMEM;
434
435 retval = rfkill_register(rfk);
436 if (retval) {
437 rfkill_destroy(rfk);
438 return -ENODEV;
439 }
440
441 return 0;
442}
443
444static void destroy_wireless(void)
445{
446 rfkill_unregister(rfk);
447 rfkill_destroy(rfk);
448}
449
450static ssize_t get_performance_level(struct device *dev,
451 struct device_attribute *attr, char *buf)
452{
453 struct sabi_retval sretval;
454 int retval;
455 int i;
456
457 /* Read the state */
458 retval = sabi_get_command(sabi_config->commands.get_performance_level,
459 &sretval);
460 if (retval)
461 return retval;
462
463 /* The logic is backwards, yeah, lots of fun... */
464 for (i = 0; sabi_config->performance_levels[i].name; ++i) {
465 if (sretval.retval[0] == sabi_config->performance_levels[i].value)
466 return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
467 }
468 return sprintf(buf, "%s\n", "unknown");
469}
470
471static ssize_t set_performance_level(struct device *dev,
472 struct device_attribute *attr, const char *buf,
473 size_t count)
474{
475 if (count >= 1) {
476 int i;
477 for (i = 0; sabi_config->performance_levels[i].name; ++i) {
478 const struct sabi_performance_level *level =
479 &sabi_config->performance_levels[i];
480 if (!strncasecmp(level->name, buf, strlen(level->name))) {
481 sabi_set_command(sabi_config->commands.set_performance_level,
482 level->value);
483 break;
484 }
485 }
486 if (!sabi_config->performance_levels[i].name)
487 return -EINVAL;
488 }
489 return count;
490}
491static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
492 get_performance_level, set_performance_level);
493
494
495static int __init dmi_check_cb(const struct dmi_system_id *id)
496{
497 pr_info("found laptop model '%s'\n",
498 id->ident);
499 return 0;
500}
501
502static struct dmi_system_id __initdata samsung_dmi_table[] = {
503 {
504 .ident = "N128",
505 .matches = {
506 DMI_MATCH(DMI_SYS_VENDOR,
507 "SAMSUNG ELECTRONICS CO., LTD."),
508 DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
509 DMI_MATCH(DMI_BOARD_NAME, "N128"),
510 },
511 .callback = dmi_check_cb,
512 },
513 {
514 .ident = "N130",
515 .matches = {
516 DMI_MATCH(DMI_SYS_VENDOR,
517 "SAMSUNG ELECTRONICS CO., LTD."),
518 DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
519 DMI_MATCH(DMI_BOARD_NAME, "N130"),
520 },
521 .callback = dmi_check_cb,
522 },
523 {
524 .ident = "X125",
525 .matches = {
526 DMI_MATCH(DMI_SYS_VENDOR,
527 "SAMSUNG ELECTRONICS CO., LTD."),
528 DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
529 DMI_MATCH(DMI_BOARD_NAME, "X125"),
530 },
531 .callback = dmi_check_cb,
532 },
533 {
534 .ident = "X120/X170",
535 .matches = {
536 DMI_MATCH(DMI_SYS_VENDOR,
537 "SAMSUNG ELECTRONICS CO., LTD."),
538 DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
539 DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
540 },
541 .callback = dmi_check_cb,
542 },
543 {
544 .ident = "NC10",
545 .matches = {
546 DMI_MATCH(DMI_SYS_VENDOR,
547 "SAMSUNG ELECTRONICS CO., LTD."),
548 DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
549 DMI_MATCH(DMI_BOARD_NAME, "NC10"),
550 },
551 .callback = dmi_check_cb,
552 },
553 {
554 .ident = "NP-Q45",
555 .matches = {
556 DMI_MATCH(DMI_SYS_VENDOR,
557 "SAMSUNG ELECTRONICS CO., LTD."),
558 DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
559 DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
560 },
561 .callback = dmi_check_cb,
562 },
563 {
564 .ident = "X360",
565 .matches = {
566 DMI_MATCH(DMI_SYS_VENDOR,
567 "SAMSUNG ELECTRONICS CO., LTD."),
568 DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
569 DMI_MATCH(DMI_BOARD_NAME, "X360"),
570 },
571 .callback = dmi_check_cb,
572 },
573 {
574 .ident = "R410 Plus",
575 .matches = {
576 DMI_MATCH(DMI_SYS_VENDOR,
577 "SAMSUNG ELECTRONICS CO., LTD."),
578 DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
579 DMI_MATCH(DMI_BOARD_NAME, "R460"),
580 },
581 .callback = dmi_check_cb,
582 },
583 {
584 .ident = "R518",
585 .matches = {
586 DMI_MATCH(DMI_SYS_VENDOR,
587 "SAMSUNG ELECTRONICS CO., LTD."),
588 DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
589 DMI_MATCH(DMI_BOARD_NAME, "R518"),
590 },
591 .callback = dmi_check_cb,
592 },
593 {
594 .ident = "R519/R719",
595 .matches = {
596 DMI_MATCH(DMI_SYS_VENDOR,
597 "SAMSUNG ELECTRONICS CO., LTD."),
598 DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
599 DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
600 },
601 .callback = dmi_check_cb,
602 },
603 {
604 .ident = "N150/N210/N220/N230",
605 .matches = {
606 DMI_MATCH(DMI_SYS_VENDOR,
607 "SAMSUNG ELECTRONICS CO., LTD."),
608 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
609 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
610 },
611 .callback = dmi_check_cb,
612 },
613 {
614 .ident = "N150P/N210P/N220P",
615 .matches = {
616 DMI_MATCH(DMI_SYS_VENDOR,
617 "SAMSUNG ELECTRONICS CO., LTD."),
618 DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
619 DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
620 },
621 .callback = dmi_check_cb,
622 },
623 {
624 .ident = "R530/R730",
625 .matches = {
626 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
627 DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
628 DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
629 },
630 .callback = dmi_check_cb,
631 },
632 {
633 .ident = "NF110/NF210/NF310",
634 .matches = {
635 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
636 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
637 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
638 },
639 .callback = dmi_check_cb,
640 },
641 {
642 .ident = "N145P/N250P/N260P",
643 .matches = {
644 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
645 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
646 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
647 },
648 .callback = dmi_check_cb,
649 },
650 {
651 .ident = "R70/R71",
652 .matches = {
653 DMI_MATCH(DMI_SYS_VENDOR,
654 "SAMSUNG ELECTRONICS CO., LTD."),
655 DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
656 DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
657 },
658 .callback = dmi_check_cb,
659 },
660 {
661 .ident = "P460",
662 .matches = {
663 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
664 DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
665 DMI_MATCH(DMI_BOARD_NAME, "P460"),
666 },
667 .callback = dmi_check_cb,
668 },
669 { },
670};
671MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
672
673static int find_signature(void __iomem *memcheck, const char *testStr)
674{
675 int i = 0;
676 int loca;
677
678 for (loca = 0; loca < 0xffff; loca++) {
679 char temp = readb(memcheck + loca);
680
681 if (temp == testStr[i]) {
682 if (i == strlen(testStr)-1)
683 break;
684 ++i;
685 } else {
686 i = 0;
687 }
688 }
689 return loca;
690}
691
692static int __init samsung_init(void)
693{
694 struct backlight_properties props;
695 struct sabi_retval sretval;
696 unsigned int ifaceP;
697 int i;
698 int loca;
699 int retval;
700
701 mutex_init(&sabi_mutex);
702
703 if (!force && !dmi_check_system(samsung_dmi_table))
704 return -ENODEV;
705
706 f0000_segment = ioremap_nocache(0xf0000, 0xffff);
707 if (!f0000_segment) {
708 pr_err("Can't map the segment at 0xf0000\n");
709 return -EINVAL;
710 }
711
712 /* Try to find one of the signatures in memory to find the header */
713 for (i = 0; sabi_configs[i].test_string != 0; ++i) {
714 sabi_config = &sabi_configs[i];
715 loca = find_signature(f0000_segment, sabi_config->test_string);
716 if (loca != 0xffff)
717 break;
718 }
719
720 if (loca == 0xffff) {
721 pr_err("This computer does not support SABI\n");
722 goto error_no_signature;
723 }
724
725 /* point to the SMI port Number */
726 loca += 1;
727 sabi = (f0000_segment + loca);
728
729 if (debug) {
730 printk(KERN_DEBUG "This computer supports SABI==%x\n",
731 loca + 0xf0000 - 6);
732 printk(KERN_DEBUG "SABI header:\n");
733 printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
734 readw(sabi + sabi_config->header_offsets.port));
735 printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
736 readb(sabi + sabi_config->header_offsets.iface_func));
737 printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
738 readb(sabi + sabi_config->header_offsets.en_mem));
739 printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
740 readb(sabi + sabi_config->header_offsets.re_mem));
741 printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
742 readw(sabi + sabi_config->header_offsets.data_offset));
743 printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
744 readw(sabi + sabi_config->header_offsets.data_segment));
745 }
746
747 /* Get a pointer to the SABI Interface */
748 ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
749 ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
750 sabi_iface = ioremap_nocache(ifaceP, 16);
751 if (!sabi_iface) {
752 pr_err("Can't remap %x\n", ifaceP);
753 goto exit;
754 }
755 if (debug) {
756 printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
757 printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
758
759 test_backlight();
760 test_wireless();
761
762 retval = sabi_get_command(sabi_config->commands.get_brightness,
763 &sretval);
764 printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
765 }
766
767 /* Turn on "Linux" mode in the BIOS */
768 if (sabi_config->commands.set_linux != 0xff) {
769 retval = sabi_set_command(sabi_config->commands.set_linux,
770 0x81);
771 if (retval) {
772 pr_warn("Linux mode was not set!\n");
773 goto error_no_platform;
774 }
775 }
776
777 /* knock up a platform device to hang stuff off of */
778 sdev = platform_device_register_simple("samsung", -1, NULL, 0);
779 if (IS_ERR(sdev))
780 goto error_no_platform;
781
782 /* create a backlight device to talk to this one */
783 memset(&props, 0, sizeof(struct backlight_properties));
784 props.type = BACKLIGHT_PLATFORM;
785 props.max_brightness = sabi_config->max_brightness;
786 backlight_device = backlight_device_register("samsung", &sdev->dev,
787 NULL, &backlight_ops,
788 &props);
789 if (IS_ERR(backlight_device))
790 goto error_no_backlight;
791
792 backlight_device->props.brightness = read_brightness();
793 backlight_device->props.power = FB_BLANK_UNBLANK;
794 backlight_update_status(backlight_device);
795
796 retval = init_wireless(sdev);
797 if (retval)
798 goto error_no_rfk;
799
800 retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
801 if (retval)
802 goto error_file_create;
803
804exit:
805 return 0;
806
807error_file_create:
808 destroy_wireless();
809
810error_no_rfk:
811 backlight_device_unregister(backlight_device);
812
813error_no_backlight:
814 platform_device_unregister(sdev);
815
816error_no_platform:
817 iounmap(sabi_iface);
818
819error_no_signature:
820 iounmap(f0000_segment);
821 return -EINVAL;
822}
823
824static void __exit samsung_exit(void)
825{
826 /* Turn off "Linux" mode in the BIOS */
827 if (sabi_config->commands.set_linux != 0xff)
828 sabi_set_command(sabi_config->commands.set_linux, 0x80);
829
830 device_remove_file(&sdev->dev, &dev_attr_performance_level);
831 backlight_device_unregister(backlight_device);
832 destroy_wireless();
833 iounmap(sabi_iface);
834 iounmap(f0000_segment);
835 platform_device_unregister(sdev);
836}
837
838module_init(samsung_init);
839module_exit(samsung_exit);
840
841MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
842MODULE_DESCRIPTION("Samsung Backlight driver");
843MODULE_LICENSE("GPL");