2 * Samsung Laptop driver
4 * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
5 * Copyright (C) 2009,2011 Novell Inc.
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.
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
21 #include <linux/dmi.h>
22 #include <linux/platform_device.h>
23 #include <linux/rfkill.h>
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.
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
36 #define MAX_BRIGHT 0x07
39 #define SABI_IFACE_MAIN 0x00
40 #define SABI_IFACE_SUB 0x02
41 #define SABI_IFACE_COMPLETE 0x04
42 #define SABI_IFACE_DATA 0x05
44 /* Structure to get data back to the calling function */
49 struct sabi_header_offsets {
58 struct sabi_commands {
60 * Brightness is 0 - 8, as described above.
61 * Value 0 is for the BIOS to use
68 * 0x00 - wireless is off
69 * 0x01 - wireless is on
73 * TODO, verify 3G is correct, that doesn't seem right...
75 u8 get_wireless_button;
76 u8 set_wireless_button;
78 /* 0 is off, 1 is on */
83 * 0x80 or 0x00 - no action
84 * 0x81 - recovery key pressed
90 * on seclinux: 0 is low, 1 is high,
91 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
93 u8 get_performance_level;
94 u8 set_performance_level;
97 * Tell the BIOS that Linux is running on this machine.
103 struct sabi_performance_level {
109 const char *test_string;
111 const struct sabi_header_offsets header_offsets;
112 const struct sabi_commands commands;
113 const struct sabi_performance_level performance_levels[4];
118 static const struct sabi_config sabi_configs[] = {
120 .test_string = "SECLINUX",
122 .main_function = 0x4c49,
130 .data_segment = 0x07,
134 .get_brightness = 0x00,
135 .set_brightness = 0x01,
137 .get_wireless_button = 0x02,
138 .set_wireless_button = 0x03,
140 .get_backlight = 0x04,
141 .set_backlight = 0x05,
143 .get_recovery_mode = 0x06,
144 .set_recovery_mode = 0x07,
146 .get_performance_level = 0x08,
147 .set_performance_level = 0x09,
152 .performance_levels = {
167 .test_string = "SwSmi@",
169 .main_function = 0x5843,
177 .data_segment = 0x07,
181 .get_brightness = 0x10,
182 .set_brightness = 0x11,
184 .get_wireless_button = 0x12,
185 .set_wireless_button = 0x13,
187 .get_backlight = 0x2d,
188 .set_backlight = 0x2e,
190 .get_recovery_mode = 0xff,
191 .set_recovery_mode = 0xff,
193 .get_performance_level = 0x31,
194 .set_performance_level = 0x32,
199 .performance_levels = {
220 struct samsung_laptop {
221 const struct sabi_config *config;
224 void __iomem *sabi_iface;
225 void __iomem *f0000_segment;
227 struct mutex sabi_mutex;
229 struct platform_device *platform_device;
230 struct backlight_device *backlight_device;
233 bool has_stepping_quirk;
239 module_param(force, bool, 0);
240 MODULE_PARM_DESC(force,
241 "Disable the DMI check and forces the driver to be loaded");
244 module_param(debug, bool, S_IRUGO | S_IWUSR);
245 MODULE_PARM_DESC(debug, "Debug enabled or not");
247 static int sabi_get_command(struct samsung_laptop *samsung,
248 u8 command, struct sabi_retval *sretval)
250 const struct sabi_config *config = samsung->config;
252 u16 port = readw(samsung->sabi + config->header_offsets.port);
253 u8 complete, iface_data;
255 mutex_lock(&samsung->sabi_mutex);
257 /* enable memory to be able to write to it */
258 outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
260 /* write out the command */
261 writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
262 writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
263 writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
264 outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
266 /* write protect memory to make it safe */
267 outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
269 /* see if the command actually succeeded */
270 complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
271 iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
272 if (complete != 0xaa || iface_data == 0xff) {
273 pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
274 command, complete, iface_data);
279 * Save off the data into a structure so the caller use it.
280 * Right now we only want the first 4 bytes,
281 * There are commands that need more, but not for the ones we
282 * currently care about.
284 sretval->retval[0] = readb(samsung->sabi_iface + SABI_IFACE_DATA);
285 sretval->retval[1] = readb(samsung->sabi_iface + SABI_IFACE_DATA + 1);
286 sretval->retval[2] = readb(samsung->sabi_iface + SABI_IFACE_DATA + 2);
287 sretval->retval[3] = readb(samsung->sabi_iface + SABI_IFACE_DATA + 3);
290 mutex_unlock(&samsung->sabi_mutex);
295 static int sabi_set_command(struct samsung_laptop *samsung,
298 const struct sabi_config *config = samsung->config;
300 u16 port = readw(samsung->sabi + config->header_offsets.port);
301 u8 complete, iface_data;
303 mutex_lock(&samsung->sabi_mutex);
305 /* enable memory to be able to write to it */
306 outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
308 /* write out the command */
309 writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
310 writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
311 writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
312 writeb(data, samsung->sabi_iface + SABI_IFACE_DATA);
313 outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
315 /* write protect memory to make it safe */
316 outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
318 /* see if the command actually succeeded */
319 complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
320 iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
321 if (complete != 0xaa || iface_data == 0xff) {
322 pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
323 command, complete, iface_data);
327 mutex_unlock(&samsung->sabi_mutex);
331 static void test_backlight(struct samsung_laptop *samsung)
333 const struct sabi_commands *commands = &samsung->config->commands;
334 struct sabi_retval sretval;
336 sabi_get_command(samsung, commands->get_backlight, &sretval);
337 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
339 sabi_set_command(samsung, commands->set_backlight, 0);
340 printk(KERN_DEBUG "backlight should be off\n");
342 sabi_get_command(samsung, commands->get_backlight, &sretval);
343 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
347 sabi_set_command(samsung, commands->set_backlight, 1);
348 printk(KERN_DEBUG "backlight should be on\n");
350 sabi_get_command(samsung, commands->get_backlight, &sretval);
351 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
354 static void test_wireless(struct samsung_laptop *samsung)
356 const struct sabi_commands *commands = &samsung->config->commands;
357 struct sabi_retval sretval;
359 sabi_get_command(samsung, commands->get_wireless_button, &sretval);
360 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
362 sabi_set_command(samsung, commands->set_wireless_button, 0);
363 printk(KERN_DEBUG "wireless led should be off\n");
365 sabi_get_command(samsung, commands->get_wireless_button, &sretval);
366 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
370 sabi_set_command(samsung, commands->set_wireless_button, 1);
371 printk(KERN_DEBUG "wireless led should be on\n");
373 sabi_get_command(samsung, commands->get_wireless_button, &sretval);
374 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
377 static int read_brightness(struct samsung_laptop *samsung)
379 const struct sabi_config *config = samsung->config;
380 const struct sabi_commands *commands = &samsung->config->commands;
381 struct sabi_retval sretval;
382 int user_brightness = 0;
385 retval = sabi_get_command(samsung, commands->get_brightness,
388 user_brightness = sretval.retval[0];
389 if (user_brightness > config->min_brightness)
390 user_brightness -= config->min_brightness;
394 return user_brightness;
397 static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness)
399 const struct sabi_config *config = samsung->config;
400 const struct sabi_commands *commands = &samsung->config->commands;
401 u8 user_level = user_brightness + config->min_brightness;
403 if (samsung->has_stepping_quirk && user_level != 0) {
405 * short circuit if the specified level is what's already set
406 * to prevent the screen from flickering needlessly
408 if (user_brightness == read_brightness(samsung))
411 sabi_set_command(samsung, commands->set_brightness, 0);
414 sabi_set_command(samsung, commands->set_brightness, user_level);
417 static int get_brightness(struct backlight_device *bd)
419 struct samsung_laptop *samsung = bl_get_data(bd);
421 return read_brightness(samsung);
424 static void check_for_stepping_quirk(struct samsung_laptop *samsung)
428 int orig_level = read_brightness(samsung);
431 * Some laptops exhibit the strange behaviour of stepping toward
432 * (rather than setting) the brightness except when changing to/from
433 * brightness level 0. This behaviour is checked for here and worked
434 * around in set_brightness.
438 set_brightness(samsung, 1);
440 initial_level = read_brightness(samsung);
442 if (initial_level <= 2)
443 check_level = initial_level + 2;
445 check_level = initial_level - 2;
447 samsung->has_stepping_quirk = false;
448 set_brightness(samsung, check_level);
450 if (read_brightness(samsung) != check_level) {
451 samsung->has_stepping_quirk = true;
452 pr_info("enabled workaround for brightness stepping quirk\n");
455 set_brightness(samsung, orig_level);
458 static int update_status(struct backlight_device *bd)
460 struct samsung_laptop *samsung = bl_get_data(bd);
461 const struct sabi_commands *commands = &samsung->config->commands;
463 set_brightness(samsung, bd->props.brightness);
465 if (bd->props.power == FB_BLANK_UNBLANK)
466 sabi_set_command(samsung, commands->set_backlight, 1);
468 sabi_set_command(samsung, commands->set_backlight, 0);
473 static const struct backlight_ops backlight_ops = {
474 .get_brightness = get_brightness,
475 .update_status = update_status,
478 static int rfkill_set(void *data, bool blocked)
480 struct samsung_laptop *samsung = data;
481 const struct sabi_commands *commands = &samsung->config->commands;
483 /* Do something with blocked...*/
485 * blocked == false is on
486 * blocked == true is off
489 sabi_set_command(samsung, commands->set_wireless_button, 0);
491 sabi_set_command(samsung, commands->set_wireless_button, 1);
496 static struct rfkill_ops rfkill_ops = {
497 .set_block = rfkill_set,
500 static ssize_t get_performance_level(struct device *dev,
501 struct device_attribute *attr, char *buf)
503 struct samsung_laptop *samsung = dev_get_drvdata(dev);
504 const struct sabi_config *config = samsung->config;
505 const struct sabi_commands *commands = &config->commands;
506 struct sabi_retval sretval;
511 retval = sabi_get_command(samsung, commands->get_performance_level,
516 /* The logic is backwards, yeah, lots of fun... */
517 for (i = 0; config->performance_levels[i].name; ++i) {
518 if (sretval.retval[0] == config->performance_levels[i].value)
519 return sprintf(buf, "%s\n", config->performance_levels[i].name);
521 return sprintf(buf, "%s\n", "unknown");
524 static ssize_t set_performance_level(struct device *dev,
525 struct device_attribute *attr, const char *buf,
528 struct samsung_laptop *samsung = dev_get_drvdata(dev);
529 const struct sabi_config *config = samsung->config;
530 const struct sabi_commands *commands = &config->commands;
536 for (i = 0; config->performance_levels[i].name; ++i) {
537 const struct sabi_performance_level *level =
538 &config->performance_levels[i];
539 if (!strncasecmp(level->name, buf, strlen(level->name))) {
540 sabi_set_command(samsung,
541 commands->set_performance_level,
547 if (!config->performance_levels[i].name)
553 static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
554 get_performance_level, set_performance_level);
557 static int find_signature(void __iomem *memcheck, const char *testStr)
562 for (loca = 0; loca < 0xffff; loca++) {
563 char temp = readb(memcheck + loca);
565 if (temp == testStr[i]) {
566 if (i == strlen(testStr)-1)
576 static void samsung_rfkill_exit(struct samsung_laptop *samsung)
579 rfkill_unregister(samsung->rfk);
580 rfkill_destroy(samsung->rfk);
585 static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
589 samsung->rfk = rfkill_alloc("samsung-wifi",
590 &samsung->platform_device->dev,
592 &rfkill_ops, samsung);
596 retval = rfkill_register(samsung->rfk);
598 rfkill_destroy(samsung->rfk);
606 static void samsung_backlight_exit(struct samsung_laptop *samsung)
608 if (samsung->backlight_device) {
609 backlight_device_unregister(samsung->backlight_device);
610 samsung->backlight_device = NULL;
614 static int __init samsung_backlight_init(struct samsung_laptop *samsung)
616 struct backlight_device *bd;
617 struct backlight_properties props;
619 memset(&props, 0, sizeof(struct backlight_properties));
620 props.type = BACKLIGHT_PLATFORM;
621 props.max_brightness = samsung->config->max_brightness -
622 samsung->config->min_brightness;
624 bd = backlight_device_register("samsung",
625 &samsung->platform_device->dev,
626 samsung, &backlight_ops,
631 samsung->backlight_device = bd;
632 samsung->backlight_device->props.brightness = read_brightness(samsung);
633 samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
634 backlight_update_status(samsung->backlight_device);
639 static void samsung_sysfs_exit(struct samsung_laptop *samsung)
641 device_remove_file(&samsung->platform_device->dev,
642 &dev_attr_performance_level);
645 static int __init samsung_sysfs_init(struct samsung_laptop *samsung)
647 return device_create_file(&samsung->platform_device->dev,
648 &dev_attr_performance_level);
651 static void samsung_sabi_exit(struct samsung_laptop *samsung)
653 const struct sabi_config *config = samsung->config;
655 /* Turn off "Linux" mode in the BIOS */
656 if (config && config->commands.set_linux != 0xff)
657 sabi_set_command(samsung, config->commands.set_linux, 0x80);
659 if (samsung->sabi_iface) {
660 iounmap(samsung->sabi_iface);
661 samsung->sabi_iface = NULL;
663 if (samsung->f0000_segment) {
664 iounmap(samsung->f0000_segment);
665 samsung->f0000_segment = NULL;
668 samsung->config = NULL;
671 static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca)
673 const struct sabi_config *config = samsung->config;
675 printk(KERN_DEBUG "This computer supports SABI==%x\n",
677 printk(KERN_DEBUG "SABI header:\n");
678 printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
679 readw(samsung->sabi + config->header_offsets.port));
680 printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
681 readb(samsung->sabi + config->header_offsets.iface_func));
682 printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
683 readb(samsung->sabi + config->header_offsets.en_mem));
684 printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
685 readb(samsung->sabi + config->header_offsets.re_mem));
686 printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
687 readw(samsung->sabi + config->header_offsets.data_offset));
688 printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
689 readw(samsung->sabi + config->header_offsets.data_segment));
692 static void __init samsung_sabi_selftest(struct samsung_laptop *samsung,
695 const struct sabi_config *config = samsung->config;
696 struct sabi_retval sretval;
698 printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
699 printk(KERN_DEBUG "sabi_iface = %p\n", samsung->sabi_iface);
701 test_backlight(samsung);
702 test_wireless(samsung);
704 sabi_get_command(samsung, config->commands.get_brightness, &sretval);
705 printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
708 static int __init samsung_sabi_init(struct samsung_laptop *samsung)
710 const struct sabi_config *config = NULL;
711 const struct sabi_commands *commands;
717 samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
718 if (!samsung->f0000_segment) {
719 pr_err("Can't map the segment at 0xf0000\n");
724 /* Try to find one of the signatures in memory to find the header */
725 for (i = 0; sabi_configs[i].test_string != 0; ++i) {
726 samsung->config = &sabi_configs[i];
727 loca = find_signature(samsung->f0000_segment,
728 samsung->config->test_string);
733 if (loca == 0xffff) {
734 pr_err("This computer does not support SABI\n");
739 config = samsung->config;
740 commands = &config->commands;
742 /* point to the SMI port Number */
744 samsung->sabi = (samsung->f0000_segment + loca);
747 samsung_sabi_infos(samsung, loca);
749 /* Get a pointer to the SABI Interface */
750 ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4;
751 ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff;
752 samsung->sabi_iface = ioremap_nocache(ifaceP, 16);
753 if (!samsung->sabi_iface) {
754 pr_err("Can't remap %x\n", ifaceP);
760 samsung_sabi_selftest(samsung, ifaceP);
762 /* Turn on "Linux" mode in the BIOS */
763 if (commands->set_linux != 0xff) {
764 int retval = sabi_set_command(samsung,
765 commands->set_linux, 0x81);
767 pr_warn("Linux mode was not set!\n");
773 /* Check for stepping quirk */
774 check_for_stepping_quirk(samsung);
778 samsung_sabi_exit(samsung);
783 static void samsung_platform_exit(struct samsung_laptop *samsung)
785 if (samsung->platform_device) {
786 platform_device_unregister(samsung->platform_device);
787 samsung->platform_device = NULL;
791 static int __init samsung_platform_init(struct samsung_laptop *samsung)
793 struct platform_device *pdev;
795 pdev = platform_device_register_simple("samsung", -1, NULL, 0);
797 return PTR_ERR(pdev);
799 samsung->platform_device = pdev;
800 platform_set_drvdata(samsung->platform_device, samsung);
804 static int __init dmi_check_cb(const struct dmi_system_id *id)
806 pr_info("found laptop model '%s'\n", id->ident);
810 static struct dmi_system_id __initdata samsung_dmi_table[] = {
814 DMI_MATCH(DMI_SYS_VENDOR,
815 "SAMSUNG ELECTRONICS CO., LTD."),
816 DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
817 DMI_MATCH(DMI_BOARD_NAME, "N128"),
819 .callback = dmi_check_cb,
824 DMI_MATCH(DMI_SYS_VENDOR,
825 "SAMSUNG ELECTRONICS CO., LTD."),
826 DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
827 DMI_MATCH(DMI_BOARD_NAME, "N130"),
829 .callback = dmi_check_cb,
834 DMI_MATCH(DMI_SYS_VENDOR,
835 "SAMSUNG ELECTRONICS CO., LTD."),
836 DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
837 DMI_MATCH(DMI_BOARD_NAME, "N510"),
839 .callback = dmi_check_cb,
844 DMI_MATCH(DMI_SYS_VENDOR,
845 "SAMSUNG ELECTRONICS CO., LTD."),
846 DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
847 DMI_MATCH(DMI_BOARD_NAME, "X125"),
849 .callback = dmi_check_cb,
852 .ident = "X120/X170",
854 DMI_MATCH(DMI_SYS_VENDOR,
855 "SAMSUNG ELECTRONICS CO., LTD."),
856 DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
857 DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
859 .callback = dmi_check_cb,
864 DMI_MATCH(DMI_SYS_VENDOR,
865 "SAMSUNG ELECTRONICS CO., LTD."),
866 DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
867 DMI_MATCH(DMI_BOARD_NAME, "NC10"),
869 .callback = dmi_check_cb,
874 DMI_MATCH(DMI_SYS_VENDOR,
875 "SAMSUNG ELECTRONICS CO., LTD."),
876 DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
877 DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
879 .callback = dmi_check_cb,
884 DMI_MATCH(DMI_SYS_VENDOR,
885 "SAMSUNG ELECTRONICS CO., LTD."),
886 DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
887 DMI_MATCH(DMI_BOARD_NAME, "X360"),
889 .callback = dmi_check_cb,
892 .ident = "R410 Plus",
894 DMI_MATCH(DMI_SYS_VENDOR,
895 "SAMSUNG ELECTRONICS CO., LTD."),
896 DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
897 DMI_MATCH(DMI_BOARD_NAME, "R460"),
899 .callback = dmi_check_cb,
904 DMI_MATCH(DMI_SYS_VENDOR,
905 "SAMSUNG ELECTRONICS CO., LTD."),
906 DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
907 DMI_MATCH(DMI_BOARD_NAME, "R518"),
909 .callback = dmi_check_cb,
912 .ident = "R519/R719",
914 DMI_MATCH(DMI_SYS_VENDOR,
915 "SAMSUNG ELECTRONICS CO., LTD."),
916 DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
917 DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
919 .callback = dmi_check_cb,
922 .ident = "N150/N210/N220",
924 DMI_MATCH(DMI_SYS_VENDOR,
925 "SAMSUNG ELECTRONICS CO., LTD."),
926 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
927 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
929 .callback = dmi_check_cb,
934 DMI_MATCH(DMI_SYS_VENDOR,
935 "SAMSUNG ELECTRONICS CO., LTD."),
936 DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
937 DMI_MATCH(DMI_BOARD_NAME, "N220"),
939 .callback = dmi_check_cb,
942 .ident = "N150/N210/N220/N230",
944 DMI_MATCH(DMI_SYS_VENDOR,
945 "SAMSUNG ELECTRONICS CO., LTD."),
946 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
947 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
949 .callback = dmi_check_cb,
952 .ident = "N150P/N210P/N220P",
954 DMI_MATCH(DMI_SYS_VENDOR,
955 "SAMSUNG ELECTRONICS CO., LTD."),
956 DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
957 DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
959 .callback = dmi_check_cb,
964 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
965 DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
966 DMI_MATCH(DMI_BOARD_NAME, "SR700"),
968 .callback = dmi_check_cb,
971 .ident = "R530/R730",
973 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
974 DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
975 DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
977 .callback = dmi_check_cb,
980 .ident = "NF110/NF210/NF310",
982 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
983 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
984 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
986 .callback = dmi_check_cb,
989 .ident = "N145P/N250P/N260P",
991 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
992 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
993 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
995 .callback = dmi_check_cb,
1000 DMI_MATCH(DMI_SYS_VENDOR,
1001 "SAMSUNG ELECTRONICS CO., LTD."),
1002 DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
1003 DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
1005 .callback = dmi_check_cb,
1010 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1011 DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
1012 DMI_MATCH(DMI_BOARD_NAME, "P460"),
1014 .callback = dmi_check_cb,
1017 .ident = "R528/R728",
1019 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1020 DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
1021 DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
1023 .callback = dmi_check_cb,
1026 .ident = "NC210/NC110",
1028 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1029 DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
1030 DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
1032 .callback = dmi_check_cb,
1037 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1038 DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
1039 DMI_MATCH(DMI_BOARD_NAME, "X520"),
1041 .callback = dmi_check_cb,
1045 MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
1047 static struct platform_device *samsung_platform_device;
1049 static int __init samsung_init(void)
1051 struct samsung_laptop *samsung;
1054 if (!force && !dmi_check_system(samsung_dmi_table))
1057 samsung = kzalloc(sizeof(*samsung), GFP_KERNEL);
1061 mutex_init(&samsung->sabi_mutex);
1063 ret = samsung_platform_init(samsung);
1065 goto error_platform;
1067 ret = samsung_sabi_init(samsung);
1071 ret = samsung_sysfs_init(samsung);
1075 ret = samsung_backlight_init(samsung);
1077 goto error_backlight;
1079 ret = samsung_rfkill_init(samsung);
1083 samsung_platform_device = samsung->platform_device;
1087 samsung_backlight_exit(samsung);
1089 samsung_sysfs_exit(samsung);
1091 samsung_sabi_exit(samsung);
1093 samsung_platform_exit(samsung);
1099 static void __exit samsung_exit(void)
1101 struct samsung_laptop *samsung;
1103 samsung = platform_get_drvdata(samsung_platform_device);
1105 samsung_rfkill_exit(samsung);
1106 samsung_backlight_exit(samsung);
1107 samsung_sysfs_exit(samsung);
1108 samsung_sabi_exit(samsung);
1109 samsung_platform_exit(samsung);
1112 samsung_platform_device = NULL;
1115 module_init(samsung_init);
1116 module_exit(samsung_exit);
1118 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
1119 MODULE_DESCRIPTION("Samsung Backlight driver");
1120 MODULE_LICENSE("GPL");