diff options
Diffstat (limited to 'drivers/platform/x86/samsung-laptop.c')
-rw-r--r-- | drivers/platform/x86/samsung-laptop.c | 272 |
1 files changed, 83 insertions, 189 deletions
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index ec85987..64e1f2d 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -21,6 +21,8 @@ #include <linux/dmi.h> #include <linux/platform_device.h> #include <linux/rfkill.h> +#include <linux/acpi.h> +#include <linux/efi.h> /* * This driver is needed because a number of Samsung laptops do not hook @@ -226,6 +228,8 @@ static struct backlight_device *backlight_device; static struct mutex sabi_mutex; static struct platform_device *sdev; static struct rfkill *rfk; +static bool handle_backlight; +static bool has_stepping_quirk; static int force; module_param(force, bool, 0); @@ -382,6 +386,17 @@ static void set_brightness(u8 user_brightness) { u8 user_level = user_brightness + sabi_config->min_brightness; + if (has_stepping_quirk && user_level != 0) { + /* + * short circuit if the specified level is what's already set + * to prevent the screen from flickering needlessly + */ + if (user_brightness == read_brightness()) + return; + + sabi_set_command(sabi_config->commands.set_brightness, 0); + } + sabi_set_command(sabi_config->commands.set_brightness, user_level); } @@ -390,6 +405,40 @@ static int get_brightness(struct backlight_device *bd) return (int)read_brightness(); } +static void check_for_stepping_quirk(void) +{ + u8 initial_level; + u8 check_level; + u8 orig_level = read_brightness(); + + /* + * Some laptops exhibit the strange behaviour of stepping toward + * (rather than setting) the brightness except when changing to/from + * brightness level 0. This behaviour is checked for here and worked + * around in set_brightness. + */ + + if (orig_level == 0) + set_brightness(1); + + initial_level = read_brightness(); + + if (initial_level <= 2) + check_level = initial_level + 2; + else + check_level = initial_level - 2; + + has_stepping_quirk = false; + set_brightness(check_level); + + if (read_brightness() != check_level) { + has_stepping_quirk = true; + pr_info("enabled workaround for brightness stepping quirk\n"); + } + + set_brightness(orig_level); +} + static int update_status(struct backlight_device *bd) { set_brightness(bd->props.brightness); @@ -494,216 +543,34 @@ static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, get_performance_level, set_performance_level); -static int __init dmi_check_cb(const struct dmi_system_id *id) -{ - pr_info("found laptop model '%s'\n", - id->ident); - return 1; -} - static struct dmi_system_id __initdata samsung_dmi_table[] = { { - .ident = "N128", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N128"), - DMI_MATCH(DMI_BOARD_NAME, "N128"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N130", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N130"), - DMI_MATCH(DMI_BOARD_NAME, "N130"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X125", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X125"), - DMI_MATCH(DMI_BOARD_NAME, "X125"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X120/X170", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), - DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NC10", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), - DMI_MATCH(DMI_BOARD_NAME, "NC10"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NP-Q45", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), - DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X360"), - DMI_MATCH(DMI_BOARD_NAME, "X360"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R410 Plus", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), - DMI_MATCH(DMI_BOARD_NAME, "R460"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R518", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R518"), - DMI_MATCH(DMI_BOARD_NAME, "R518"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R519/R719", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), - DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N150/N210/N220", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ }, - .callback = dmi_check_cb, }, { - .ident = "N150/N210/N220/N230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), + DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ }, - .callback = dmi_check_cb, }, { - .ident = "N150P/N210P/N220P", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), - DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "SR700"), - DMI_MATCH(DMI_BOARD_NAME, "SR700"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R530/R730", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), - DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NF110/NF210/NF310", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), - DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), + DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ }, - .callback = dmi_check_cb, }, { - .ident = "N145P/N250P/N260P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), - DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R70/R71", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), - DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "P460", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "P460"), - DMI_MATCH(DMI_BOARD_NAME, "P460"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X520", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X520"), - DMI_MATCH(DMI_BOARD_NAME, "X520"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R528/R728", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"), - DMI_MATCH(DMI_BOARD_NAME, "R528/R728"), + DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ }, - .callback = dmi_check_cb, }, { }, }; @@ -737,14 +604,25 @@ static int __init samsung_init(void) int loca; int retval; + if (efi_enabled(EFI_BOOT)) + return -ENODEV; + mutex_init(&sabi_mutex); + handle_backlight = true; + +#ifdef CONFIG_ACPI + /* Don't handle backlight here if the acpi video already handle it */ + if (acpi_video_backlight_support()) + handle_backlight = false; +#endif if (!force && !dmi_check_system(samsung_dmi_table)) return -ENODEV; f0000_segment = ioremap_nocache(0xf0000, 0xffff); if (!f0000_segment) { - pr_err("Can't map the segment at 0xf0000\n"); + if (debug || force) + pr_err("Can't map the segment at 0xf0000\n"); return -EINVAL; } @@ -757,7 +635,8 @@ static int __init samsung_init(void) } if (loca == 0xffff) { - pr_err("This computer does not support SABI\n"); + if (debug || force) + pr_err("This computer does not support SABI\n"); goto error_no_signature; } @@ -795,7 +674,8 @@ static int __init samsung_init(void) printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); - test_backlight(); + if (handle_backlight) + test_backlight(); test_wireless(); retval = sabi_get_command(sabi_config->commands.get_brightness, @@ -813,11 +693,24 @@ static int __init samsung_init(void) } } + /* Check for stepping quirk */ + if (handle_backlight) + check_for_stepping_quirk(); + +#ifdef CONFIG_ACPI + /* Only log that if we are really on a sabi platform */ + if (acpi_video_backlight_support()) + pr_info("Backlight controlled by ACPI video driver\n"); +#endif + /* knock up a platform device to hang stuff off of */ sdev = platform_device_register_simple("samsung", -1, NULL, 0); if (IS_ERR(sdev)) goto error_no_platform; + if (!handle_backlight) + goto skip_backlight; + /* create a backlight device to talk to this one */ memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; @@ -833,6 +726,7 @@ static int __init samsung_init(void) backlight_device->props.power = FB_BLANK_UNBLANK; backlight_update_status(backlight_device); +skip_backlight: retval = init_wireless(sdev); if (retval) goto error_no_rfk; |