An updated version of the support for Fujitsu Lifebook S6410 in fujitsu-laptop. Fixes adding of the notification and the brightness button if no brightness change occured. To activate the different brightness-button handling use the use_alt_lcd_levels=1 module parameter. Signed-off-by: Peter Gruber <nokos@xxxxxxx> > This adds Support for Fujitsu Lifebook S6410 in fujitsu-laptop. The > module parameter use_alt_lcd_levels switches between different ACPI > brightness controls (The one in the original does not work for the > S6410, it only set the appropriate ACPI registerbut does not change the > brightness). With use_alt_lcd_levels=1 it has been testen on a Fujitsu > Lifebook S6410. Here it also provides an input device for the extra > buttons found on that laptop. > > The entry in blacklist.c is needed since the BIOS contains an ACPI Table > which has no signature (ie. "\0\0\0\0" ) which contains the brightness > adjustment functions if "Windows 2006" is detected by osi. With this > table the brightness buttons would be routed through the standard VIDEO > device but brightness adjustments would also not work. diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index ea92bac..8d02671 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -447,6 +447,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), }, + { + .callback = dmi_disable_osi_vista, + .ident = "Fujitsu Siemens", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), + }, + }, }, /* * Disable OSI(Linux) warnings on all "Hewlett-Packard" diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c index 1cfd7f3..4c871ba 100644 --- a/drivers/misc/fujitsu-laptop.c +++ b/drivers/misc/fujitsu-laptop.c @@ -2,6 +2,7 @@ /* Copyright (C) 2007 Jonathan Woithe <jwoithe@xxxxxxxxxxxxxxxxxxxxxxx> + Copyright (C) 2008 Peter Gruber <nokos@xxxxxxx> Based on earlier work: Copyright (C) 2003 Shane Spencer <shane@xxxxxxxxxxx> Adrian Yee <brewt-fujitsu@xxxxxxxxx> @@ -41,6 +42,12 @@ * * This driver has been tested on a Fujitsu Lifebook S7020. It should * work on most P-series and S-series Lifebooks, but YMMV. + * + * The moduleparameter use_alt_lcd_levels switches between different ACPI + * brightness controls. With use_alt_lcd_levels=1 it has been testen on + * a Fujitsu Lifebook S6410. Here it also provides an input device for the + * extra buttons found on that laptop. + * */ #include <linux/module.h> @@ -49,31 +56,82 @@ #include <linux/acpi.h> #include <linux/dmi.h> #include <linux/backlight.h> +#include <linux/input.h> +#include <linux/video_output.h> #include <linux/platform_device.h> +#include <linux/autoconf.h> #define FUJITSU_DRIVER_VERSION "0.3" #define FUJITSU_LCD_N_LEVELS 8 #define ACPI_FUJITSU_CLASS "fujitsu" -#define ACPI_FUJITSU_HID "FUJ02B1" -#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver" -#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" + +#define ACPI_FUJITSUB1_DRIVER_NAME "Fujitsu laptop ACPI extras driver B1" +#define ACPI_FUJITSUB1_HID "FUJ02B1" +#define ACPI_FUJITSUB1_DEVICE_NAME "Fujitsu FUJ02B1" + +#define ACPI_FUJITSUE3_DRIVER_NAME "Fujitsu laptop ACPI extras driver E3" +#define ACPI_FUJITSUE3_HID "FUJ02E3" +#define ACPI_FUJITSUE3_DEVICE_NAME "Fujitsu FUJ02E3" + +#define ACPI_FUJITSUB1_NOTIFY_CODE1 0x80 +#define ACPI_FUJITSUE3_NOTIFY_CODE1 0x80 + +#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 +#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 + +#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */ +#define DISPLAY_KEY 0x411 /* keys are mapped to KEY_SCREENLOCK (the key with the key symbol) */ +#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */ +#define REST_KEY 0x413 /* KEY_SUSPEND (R key)*/ struct fujitsu_t { - acpi_handle acpi_handle; + int usealt; /* use the alternative brightness interface */ + acpi_handle acpi_handle_b1; + acpi_handle acpi_handle_e3; + struct acpi_device *dev_b1; + struct acpi_device *dev_e3; + struct input_dev *input_b1; + struct input_dev *input_e3; + char phys_b1[32]; + char phys_e3[32]; struct backlight_device *bl_device; struct platform_device *pf_device; + int keycode_e3; /* remember keycode for release */ - unsigned long fuj02b1_state; + unsigned int max_brightness; unsigned int brightness_changed; unsigned int brightness_level; + unsigned int irb; /* info about the pressed buttons */ }; static struct fujitsu_t *fujitsu; +static int use_alt_lcd_levels; + +static void acpi_fujitsu_notify_b1(acpi_handle handle, u32 event, + void *data); +static void acpi_fujitsu_notify_e3(acpi_handle handle, u32 event, + void *data); /* Hardware access */ +static int get_irb(void) +{ + unsigned long state = 0; + acpi_status status = AE_OK; + + status = + acpi_evaluate_integer(fujitsu->acpi_handle_e3, "GIRB", NULL, + &state); + if (status < 0) + return status; + + fujitsu->irb = state; + + return fujitsu->irb; +} + static int set_lcd_level(int level) { acpi_status status = AE_OK; @@ -81,13 +139,13 @@ static int set_lcd_level(int level) struct acpi_object_list arg_list = { 1, &arg0 }; acpi_handle handle = NULL; - if (level < 0 || level >= FUJITSU_LCD_N_LEVELS) + if (level < 0 || level >= fujitsu->max_brightness) return -EINVAL; if (!fujitsu) return -EINVAL; - status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); + status = acpi_get_handle(fujitsu->acpi_handle_b1, "SBLL", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n")); return -ENODEV; @@ -102,18 +160,82 @@ static int set_lcd_level(int level) return 0; } +static int set_lcd_level_alt(int level) +{ + acpi_status status = AE_OK; + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list arg_list = { 1, &arg0 }; + acpi_handle handle = NULL; + + if (level < 0 || level >= fujitsu->max_brightness) + return -EINVAL; + + if (!fujitsu) + return -EINVAL; + + status = acpi_get_handle(fujitsu->acpi_handle_b1, "SBL2", &handle); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBL2 not present\n")); + return -ENODEV; + } + + arg0.integer.value = level; + + status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return 0; +} + static int get_lcd_level(void) { unsigned long state = 0; acpi_status status = AE_OK; - // Get the Brightness status = - acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); + acpi_evaluate_integer(fujitsu->acpi_handle_b1, "GBLL", NULL, + &state); + if (status < 0) + return status; + + fujitsu->brightness_level = state & 0x0fffffff; + + if (state & 0x80000000) + fujitsu->brightness_changed = 1; + else + fujitsu->brightness_changed = 0; + + return fujitsu->brightness_level; +} + +static int get_max_brightness(void) +{ + unsigned long state = 0; + acpi_status status = AE_OK; + + status = + acpi_evaluate_integer(fujitsu->acpi_handle_b1, "RBLL", NULL, + &state); + if (status < 0) + return status; + + fujitsu->max_brightness = state; + + return fujitsu->max_brightness; +} + +static int get_lcd_level_alt(void) +{ + unsigned long state = 0; + acpi_status status = AE_OK; + + status = + acpi_evaluate_integer(fujitsu->acpi_handle_b1, "GBLS", NULL, + &state); if (status < 0) return status; - fujitsu->fuj02b1_state = state; fujitsu->brightness_level = state & 0x0fffffff; if (state & 0x80000000) @@ -124,8 +246,24 @@ static int get_lcd_level(void) return fujitsu->brightness_level; } + /* Backlight device stuff */ +static int bl_get_brightness_alt(struct backlight_device *b) +{ + return get_lcd_level_alt(); +} + +static int bl_update_status_alt(struct backlight_device *b) +{ + return set_lcd_level_alt(b->props.brightness); +} + +static struct backlight_ops fujitsubl_ops_alt = { + .get_brightness = bl_get_brightness_alt, + .update_status = bl_update_status_alt, +}; + static int bl_get_brightness(struct backlight_device *b) { return get_lcd_level(); @@ -143,8 +281,56 @@ static struct backlight_ops fujitsubl_ops = { /* Platform device */ -static ssize_t show_lcd_level(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t +show_lcd_level_alt(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_lcd_level_alt(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t +store_lcd_level_alt(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + + int level, ret; + + if (sscanf(buf, "%i", &level) != 1 + || (level < 0 || level >= fujitsu->max_brightness)) + return -EINVAL; + + ret = set_lcd_level_alt(level); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t +show_max_brightness(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_max_brightness(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t +show_lcd_level(struct device *dev, struct device_attribute *attr, + char *buf) { int ret; @@ -156,15 +342,16 @@ static ssize_t show_lcd_level(struct device *dev, return sprintf(buf, "%i\n", ret); } -static ssize_t store_lcd_level(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t +store_lcd_level(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { int level, ret; if (sscanf(buf, "%i", &level) != 1 - || (level < 0 || level >= FUJITSU_LCD_N_LEVELS)) + || (level < 0 || level >= fujitsu->max_brightness)) return -EINVAL; ret = set_lcd_level(level); @@ -174,10 +361,23 @@ static ssize_t store_lcd_level(struct device *dev, return count; } +static ssize_t +ignore_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, + ignore_store); static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); +static DEVICE_ATTR(lcd_level_alt, 0644, show_lcd_level_alt, + store_lcd_level_alt); static struct attribute *fujitsupf_attributes[] = { + &dev_attr_max_brightness.attr, &dev_attr_lcd_level.attr, + &dev_attr_lcd_level_alt.attr, NULL }; @@ -194,22 +394,61 @@ static struct platform_driver fujitsupf_driver = { /* ACPI device */ -static int acpi_fujitsu_add(struct acpi_device *device) +static int acpi_fujitsu_add_b1(struct acpi_device *device) { + acpi_status status; int result = 0; int state = 0; + struct input_dev *input; + int error; - ACPI_FUNCTION_TRACE("acpi_fujitsu_add"); + ACPI_FUNCTION_TRACE("acpi_fujitsu_add_b1"); if (!device) return -EINVAL; - fujitsu->acpi_handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); + fujitsu->acpi_handle_b1 = device->handle; + sprintf(acpi_device_name(device), "%s", + ACPI_FUJITSUB1_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); acpi_driver_data(device) = fujitsu; - result = acpi_bus_get_power(fujitsu->acpi_handle, &state); + status = acpi_install_notify_handler(device->handle, + ACPI_DEVICE_NOTIFY, + acpi_fujitsu_notify_b1, + fujitsu); + + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + error = -ENODEV; + goto err_stop; + } + + fujitsu->input_b1 = input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto err_uninstall_notify; + } + + snprintf(fujitsu->phys_b1, sizeof(fujitsu->phys_b1), + "%s/video/input0", acpi_device_hid(device)); + + input->name = acpi_device_name(device); + input->phys = fujitsu->phys_b1; + input->id.bustype = BUS_HOST; + input->id.product = 0x06; + input->dev.parent = &device->dev; + input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_BRIGHTNESSUP, input->keybit); + set_bit(KEY_BRIGHTNESSDOWN, input->keybit); + set_bit(KEY_UNKNOWN, input->keybit); + + error = input_register_device(input); + if (error) + goto err_free_input_dev; + + result = acpi_bus_get_power(fujitsu->acpi_handle_b1, &state); if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error reading power state\n")); @@ -220,42 +459,311 @@ static int acpi_fujitsu_add(struct acpi_device *device) acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); + if (get_max_brightness() <= 0) + fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; + + fujitsu->dev_b1 = device; + + return result; + end: + err_free_input_dev: + input_free_device(input); + err_uninstall_notify: + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_fujitsu_notify_b1); + err_stop: return result; } -static int acpi_fujitsu_remove(struct acpi_device *device, int type) +static int acpi_fujitsu_remove_b1(struct acpi_device *device, int type) { - ACPI_FUNCTION_TRACE("acpi_fujitsu_remove"); + acpi_status status; + struct fujitsu_t *fujitsu = NULL; + + ACPI_FUNCTION_TRACE("acpi_fujitsu_remove_b1"); if (!device || !acpi_driver_data(device)) return -EINVAL; - fujitsu->acpi_handle = 0; + + fujitsu = acpi_driver_data(device); + + status = acpi_remove_notify_handler(fujitsu->acpi_handle_b1, + ACPI_DEVICE_NOTIFY, + acpi_fujitsu_notify_b1); + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + fujitsu->acpi_handle_b1 = 0; return 0; } -static const struct acpi_device_id fujitsu_device_ids[] = { - {ACPI_FUJITSU_HID, 0}, +static const struct acpi_device_id fujitsu_device_ids_b1[] = { + {ACPI_FUJITSUB1_HID, 0}, {"", 0}, }; -static struct acpi_driver acpi_fujitsu_driver = { - .name = ACPI_FUJITSU_DRIVER_NAME, +static struct acpi_driver acpi_fujitsu_driver_b1 = { + .name = ACPI_FUJITSUB1_DRIVER_NAME, .class = ACPI_FUJITSU_CLASS, - .ids = fujitsu_device_ids, + .ids = fujitsu_device_ids_b1, .ops = { - .add = acpi_fujitsu_add, - .remove = acpi_fujitsu_remove, + .add = acpi_fujitsu_add_b1, + .remove = acpi_fujitsu_remove_b1, + }, +}; + +static int acpi_fujitsu_add_e3(struct acpi_device *device) +{ + acpi_status status; + int result = 0; + int state = 0; + struct input_dev *input; + int error; + + ACPI_FUNCTION_TRACE("acpi_fujitsu_add_e3"); + + if (!device) + return -EINVAL; + + fujitsu->acpi_handle_e3 = device->handle; + sprintf(acpi_device_name(device), "%s", + ACPI_FUJITSUE3_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); + acpi_driver_data(device) = fujitsu; + + status = acpi_install_notify_handler(device->handle, + ACPI_DEVICE_NOTIFY, + acpi_fujitsu_notify_e3, + fujitsu); + + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + error = -ENODEV; + goto err_stop; + } + + fujitsu->input_e3 = input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto err_uninstall_notify; + } + + snprintf(fujitsu->phys_e3, sizeof(fujitsu->phys_e3), + "%s/video/input0", acpi_device_hid(device)); + + input->name = acpi_device_name(device); + input->phys = fujitsu->phys_e3; + input->id.bustype = BUS_HOST; + input->id.product = 0x06; + input->dev.parent = &device->dev; + input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_SCREENLOCK, input->keybit); + set_bit(KEY_MEDIA, input->keybit); + set_bit(KEY_EMAIL, input->keybit); + set_bit(KEY_SUSPEND, input->keybit); + set_bit(KEY_UNKNOWN, input->keybit); + + error = input_register_device(input); + if (error) + goto err_free_input_dev; + + result = acpi_bus_get_power(fujitsu->acpi_handle_e3, &state); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading power state\n")); + goto end; + } + + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + acpi_device_name(device), acpi_device_bid(device), + !device->power.state ? "on" : "off"); + + fujitsu->dev_e3 = device; + + return result; + + end: + err_free_input_dev: + input_free_device(input); + err_uninstall_notify: + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_fujitsu_notify_e3); + err_stop: + + return result; +} + +static int acpi_fujitsu_remove_e3(struct acpi_device *device, int type) +{ + acpi_status status; + struct fujitsu_t *fujitsu = NULL; + + ACPI_FUNCTION_TRACE("acpi_fujitsu_remove_e3"); + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + fujitsu = acpi_driver_data(device); + + status = acpi_remove_notify_handler(fujitsu->acpi_handle_e3, + ACPI_DEVICE_NOTIFY, + acpi_fujitsu_notify_e3); + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + fujitsu->acpi_handle_e3 = 0; + + return 0; +} + +static const struct acpi_device_id fujitsu_device_ids_e3[] = { + {ACPI_FUJITSUE3_HID, 0}, + {"", 0}, +}; + +static struct acpi_driver acpi_fujitsu_driver_e3 = { + .name = ACPI_FUJITSUE3_DRIVER_NAME, + .class = ACPI_FUJITSU_CLASS, + .ids = fujitsu_device_ids_e3, + .ops = { + .add = acpi_fujitsu_add_e3, + .remove = acpi_fujitsu_remove_e3, }, }; /* Initialization */ +static void +acpi_fujitsu_notify_b1(acpi_handle handle, u32 event, void *data) +{ + struct input_dev *input; + int keycode; + int oldb, newb; + + input = fujitsu->input_b1; + + switch (event) { + case ACPI_FUJITSUB1_NOTIFY_CODE1: + oldb = fujitsu->brightness_level; + get_lcd_level(); /* the alt version always yields changed */ + newb = fujitsu->brightness_level; + + if (oldb == newb && fujitsu->brightness_changed) { + keycode = 0; + if (oldb == 0) + keycode = KEY_BRIGHTNESSDOWN; + else if (oldb == (fujitsu->max_brightness)-1) + keycode = KEY_BRIGHTNESSUP; + } else if (oldb < newb) { + if (fujitsu->usealt) + set_lcd_level_alt(newb); + else + set_lcd_level(newb); + acpi_bus_generate_proc_event(fujitsu->dev_b1, + ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, + 0); + keycode = KEY_BRIGHTNESSUP; + } else if (oldb > newb) { + if (fujitsu->usealt) + set_lcd_level_alt(newb); + else + set_lcd_level(newb); + acpi_bus_generate_proc_event(fujitsu->dev_b1, + ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, + 0); + keycode = KEY_BRIGHTNESSDOWN; + } else { + keycode = KEY_UNKNOWN; + } + break; + default: + keycode = KEY_UNKNOWN; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + if (keycode != 0) { + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + } + + return; +} + +static void +acpi_fujitsu_notify_e3(acpi_handle handle, u32 event, void *data) +{ + struct input_dev *input; + int keycode; + unsigned int irb; + + input = fujitsu->input_e3; + + switch (event) { + case ACPI_FUJITSUE3_NOTIFY_CODE1: + irb = get_irb(); + + switch (irb & 0x4ff) { + case LOCK_KEY: + keycode = KEY_SCREENLOCK; + break; + case DISPLAY_KEY: + keycode = KEY_MEDIA; + break; + case ENERGY_KEY: + keycode = KEY_EMAIL; + break; + case REST_KEY: + keycode = KEY_SUSPEND; + break; + default: + keycode = 0; + break; + } + break; + default: + keycode = KEY_UNKNOWN; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + if (keycode == KEY_UNKNOWN) { + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + } else if (keycode == 0 && fujitsu->keycode_e3 != 0) { + input_report_key(input, fujitsu->keycode_e3, 0); + input_sync(input); + fujitsu->keycode_e3 = 0; + } else if (fujitsu->keycode_e3 != 0) { + input_report_key(input, fujitsu->keycode_e3, 0); + input_sync(input); + input_report_key(input, keycode, 1); + input_sync(input); + fujitsu->keycode_e3 = keycode; + } else { + input_report_key(input, keycode, 1); + input_sync(input); + fujitsu->keycode_e3 = keycode; + } + + return; +} + static int __init fujitsu_init(void) { - int ret, result; + int ret, result, max_brightness; if (acpi_disabled) return -ENODEV; @@ -265,21 +773,38 @@ static int __init fujitsu_init(void) return -ENOMEM; memset(fujitsu, 0, sizeof(struct fujitsu_t)); - result = acpi_bus_register_driver(&acpi_fujitsu_driver); + fujitsu->usealt = use_alt_lcd_levels != 0 ? 1 : 0; + + result = acpi_bus_register_driver(&acpi_fujitsu_driver_b1); + if (result < 0) { + ret = -ENODEV; + goto fail_acpi_b1; + } + + result = acpi_bus_register_driver(&acpi_fujitsu_driver_e3); if (result < 0) { ret = -ENODEV; - goto fail_acpi; + goto fail_acpi_e3; } /* Register backlight stuff */ - fujitsu->bl_device = - backlight_device_register("fujitsu-laptop", NULL, NULL, - &fujitsubl_ops); + if (fujitsu->usealt) { + fujitsu->bl_device = + backlight_device_register("fujitsu-laptop", NULL, NULL, + &fujitsubl_ops_alt); + } else { + fujitsu->bl_device = + backlight_device_register("fujitsu-laptop", NULL, NULL, + &fujitsubl_ops); + } if (IS_ERR(fujitsu->bl_device)) return PTR_ERR(fujitsu->bl_device); - fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1; + max_brightness = fujitsu->max_brightness; + + fujitsu->bl_device->props.max_brightness = max_brightness - 1; + ret = platform_driver_register(&fujitsupf_driver); if (ret) goto fail_backlight; @@ -323,7 +848,11 @@ static int __init fujitsu_init(void) backlight_device_unregister(fujitsu->bl_device); - fail_acpi: + fail_acpi_e3: + + acpi_bus_unregister_driver(&acpi_fujitsu_driver_b1); + + fail_acpi_b1: kfree(fujitsu); @@ -338,7 +867,8 @@ static void __exit fujitsu_cleanup(void) platform_driver_unregister(&fujitsupf_driver); backlight_device_unregister(fujitsu->bl_device); - acpi_bus_unregister_driver(&acpi_fujitsu_driver); + acpi_bus_unregister_driver(&acpi_fujitsu_driver_e3); + acpi_bus_unregister_driver(&acpi_fujitsu_driver_b1); kfree(fujitsu); @@ -348,6 +878,10 @@ static void __exit fujitsu_cleanup(void) module_init(fujitsu_init); module_exit(fujitsu_cleanup); +module_param(use_alt_lcd_levels, uint, 0644); +MODULE_PARM_DESC(use_alt_lcd_levels, + "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); + MODULE_AUTHOR("Jonathan Woithe"); MODULE_DESCRIPTION("Fujitsu laptop extras support"); MODULE_VERSION(FUJITSU_DRIVER_VERSION); -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html