From 158bc69effbf96f59c01cdeb20f8d4c184e59f8e Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Thu, 15 Jan 2009 13:50:57 -0800 Subject: sgi-xp: eliminate false detection of no heartbeat After XPC has been up and running on multiple partitions for any length of time, if XPC on one of the partitions is stopped and restarted (either by a rmmod/insmod or a system restart), it is possible for the XPCs running on the other partitions to falsely detect a lack of heartbeat from the XPC that was just restarted. This false detection will occur if the restarted XPC comes up within the five-seconds preceding one of the other XPC's heartbeat check (which occurs once every twenty seconds). The detection of no heartbeat results in the detecting XPC deactivating from the just restarted XPC. The only remedy is to restart one of the XPCs and hope that one doesn't hit this five-second window on any of the other partitions. Signed-off-by: Dean Nelson Signed-off-by: Robin Holt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc_sn2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 73b7fb8de47a..82fb9958f22f 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -899,7 +899,7 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", part_sn2->remote_vars_pa); - part->last_heartbeat = remote_vars->heartbeat; + part->last_heartbeat = remote_vars->heartbeat - 1; dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", part->last_heartbeat); -- cgit v1.2.3 From cad73120ab0dfd484682229346de8c16073577e1 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 9 Jan 2009 17:23:38 -0500 Subject: dell-laptop: move to drivers/platform/x86/ from drivers/misc/ Signed-off-by: Len Brown --- drivers/misc/Makefile | 1 - drivers/misc/dell-laptop.c | 436 ------------------------------------- drivers/platform/x86/Kconfig | 12 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/dell-laptop.c | 436 +++++++++++++++++++++++++++++++++++++ 5 files changed, 449 insertions(+), 437 deletions(-) delete mode 100644 drivers/misc/dell-laptop.c create mode 100644 drivers/platform/x86/dell-laptop.c (limited to 'drivers/misc') diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 9cf8ae6e4b39..d5749a7bc777 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o obj-$(CONFIG_ICS932S401) += ics932s401.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o -obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SGI_IOC4) += ioc4.o diff --git a/drivers/misc/dell-laptop.c b/drivers/misc/dell-laptop.c deleted file mode 100644 index 4d33a2068b7a..000000000000 --- a/drivers/misc/dell-laptop.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Driver for Dell laptop extras - * - * Copyright (c) Red Hat - * - * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell - * Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../firmware/dcdbas.h" - -#define BRIGHTNESS_TOKEN 0x7d - -/* This structure will be modified by the firmware when we enter - * system management mode, hence the volatiles */ - -struct calling_interface_buffer { - u16 class; - u16 select; - volatile u32 input[4]; - volatile u32 output[4]; -} __packed; - -struct calling_interface_token { - u16 tokenID; - u16 location; - union { - u16 value; - u16 stringlength; - }; -}; - -struct calling_interface_structure { - struct dmi_header header; - u16 cmdIOAddress; - u8 cmdIOCode; - u32 supportedCmds; - struct calling_interface_token tokens[]; -} __packed; - -static int da_command_address; -static int da_command_code; -static int da_num_tokens; -static struct calling_interface_token *da_tokens; - -static struct backlight_device *dell_backlight_device; -static struct rfkill *wifi_rfkill; -static struct rfkill *bluetooth_rfkill; -static struct rfkill *wwan_rfkill; - -static const struct dmi_system_id __initdata dell_device_table[] = { - { - .ident = "Dell laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_CHASSIS_TYPE, "8"), - }, - }, - { } -}; - -static void parse_da_table(const struct dmi_header *dm) -{ - /* Final token is a terminator, so we don't want to copy it */ - int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; - struct calling_interface_structure *table = - container_of(dm, struct calling_interface_structure, header); - - /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least - 6 bytes of entry */ - - if (dm->length < 17) - return; - - da_command_address = table->cmdIOAddress; - da_command_code = table->cmdIOCode; - - da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * - sizeof(struct calling_interface_token), - GFP_KERNEL); - - if (!da_tokens) - return; - - memcpy(da_tokens+da_num_tokens, table->tokens, - sizeof(struct calling_interface_token) * tokens); - - da_num_tokens += tokens; -} - -static void find_tokens(const struct dmi_header *dm) -{ - switch (dm->type) { - case 0xd4: /* Indexed IO */ - break; - case 0xd5: /* Protected Area Type 1 */ - break; - case 0xd6: /* Protected Area Type 2 */ - break; - case 0xda: /* Calling interface */ - parse_da_table(dm); - break; - } -} - -static int find_token_location(int tokenid) -{ - int i; - for (i = 0; i < da_num_tokens; i++) { - if (da_tokens[i].tokenID == tokenid) - return da_tokens[i].location; - } - - return -1; -} - -static struct calling_interface_buffer * -dell_send_request(struct calling_interface_buffer *buffer, int class, - int select) -{ - struct smi_cmd command; - - command.magic = SMI_CMD_MAGIC; - command.command_address = da_command_address; - command.command_code = da_command_code; - command.ebx = virt_to_phys(buffer); - command.ecx = 0x42534931; - - buffer->class = class; - buffer->select = select; - - dcdbas_smi_request(&command); - - return buffer; -} - -/* Derived from information in DellWirelessCtl.cpp: - Class 17, select 11 is radio control. It returns an array of 32-bit values. - - result[0]: return code - result[1]: - Bit 0: Hardware switch supported - Bit 1: Wifi locator supported - Bit 2: Wifi is supported - Bit 3: Bluetooth is supported - Bit 4: WWAN is supported - Bit 5: Wireless keyboard supported - Bits 6-7: Reserved - Bit 8: Wifi is installed - Bit 9: Bluetooth is installed - Bit 10: WWAN is installed - Bits 11-15: Reserved - Bit 16: Hardware switch is on - Bit 17: Wifi is blocked - Bit 18: Bluetooth is blocked - Bit 19: WWAN is blocked - Bits 20-31: Reserved - result[2]: NVRAM size in bytes - result[3]: NVRAM format version number -*/ - -static int dell_rfkill_set(int radio, enum rfkill_state state) -{ - struct calling_interface_buffer buffer; - int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; - - memset(&buffer, 0, sizeof(struct calling_interface_buffer)); - buffer.input[0] = (1 | (radio<<8) | (disable << 16)); - dell_send_request(&buffer, 17, 11); - - return 0; -} - -static int dell_wifi_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(1, state); -} - -static int dell_bluetooth_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(2, state); -} - -static int dell_wwan_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(3, state); -} - -static int dell_rfkill_get(int bit, enum rfkill_state *state) -{ - struct calling_interface_buffer buffer; - int status; - int new_state = RFKILL_STATE_HARD_BLOCKED; - - memset(&buffer, 0, sizeof(struct calling_interface_buffer)); - dell_send_request(&buffer, 17, 11); - status = buffer.output[1]; - - if (status & (1<<16)) - new_state = RFKILL_STATE_SOFT_BLOCKED; - - if (status & (1<name = "dell-wifi"; - wifi_rfkill->toggle_radio = dell_wifi_set; - wifi_rfkill->get_state = dell_wifi_get; - ret = rfkill_register(wifi_rfkill); - if (ret) - goto err_wifi; - } - - if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { - bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); - if (!bluetooth_rfkill) - goto err_bluetooth; - bluetooth_rfkill->name = "dell-bluetooth"; - bluetooth_rfkill->toggle_radio = dell_bluetooth_set; - bluetooth_rfkill->get_state = dell_bluetooth_get; - ret = rfkill_register(bluetooth_rfkill); - if (ret) - goto err_bluetooth; - } - - if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { - wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); - if (!wwan_rfkill) - goto err_wwan; - wwan_rfkill->name = "dell-wwan"; - wwan_rfkill->toggle_radio = dell_wwan_set; - wwan_rfkill->get_state = dell_wwan_get; - ret = rfkill_register(wwan_rfkill); - if (ret) - goto err_wwan; - } - - return 0; -err_wwan: - if (wwan_rfkill) - rfkill_free(wwan_rfkill); - if (bluetooth_rfkill) { - rfkill_unregister(bluetooth_rfkill); - bluetooth_rfkill = NULL; - } -err_bluetooth: - if (bluetooth_rfkill) - rfkill_free(bluetooth_rfkill); - if (wifi_rfkill) { - rfkill_unregister(wifi_rfkill); - wifi_rfkill = NULL; - } -err_wifi: - if (wifi_rfkill) - rfkill_free(wifi_rfkill); - - return ret; -} - -static int dell_send_intensity(struct backlight_device *bd) -{ - struct calling_interface_buffer buffer; - - memset(&buffer, 0, sizeof(struct calling_interface_buffer)); - buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); - buffer.input[1] = bd->props.brightness; - - if (buffer.input[0] == -1) - return -ENODEV; - - if (power_supply_is_system_supplied() > 0) - dell_send_request(&buffer, 1, 2); - else - dell_send_request(&buffer, 1, 1); - - return 0; -} - -static int dell_get_intensity(struct backlight_device *bd) -{ - struct calling_interface_buffer buffer; - - memset(&buffer, 0, sizeof(struct calling_interface_buffer)); - buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); - - if (buffer.input[0] == -1) - return -ENODEV; - - if (power_supply_is_system_supplied() > 0) - dell_send_request(&buffer, 0, 2); - else - dell_send_request(&buffer, 0, 1); - - return buffer.output[1]; -} - -static struct backlight_ops dell_ops = { - .get_brightness = dell_get_intensity, - .update_status = dell_send_intensity, -}; - -static int __init dell_init(void) -{ - struct calling_interface_buffer buffer; - int max_intensity = 0; - int ret; - - if (!dmi_check_system(dell_device_table)) - return -ENODEV; - - dmi_walk(find_tokens); - - if (!da_tokens) { - printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n"); - return -ENODEV; - } - - ret = dell_setup_rfkill(); - - if (ret) { - printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); - goto out; - } - -#ifdef CONFIG_ACPI - /* In the event of an ACPI backlight being available, don't - * register the platform controller. - */ - if (acpi_video_backlight_support()) - return 0; -#endif - - memset(&buffer, 0, sizeof(struct calling_interface_buffer)); - buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); - - if (buffer.input[0] != -1) { - dell_send_request(&buffer, 0, 2); - max_intensity = buffer.output[3]; - } - - if (max_intensity) { - dell_backlight_device = backlight_device_register( - "dell_backlight", - NULL, NULL, - &dell_ops); - - if (IS_ERR(dell_backlight_device)) { - ret = PTR_ERR(dell_backlight_device); - dell_backlight_device = NULL; - goto out; - } - - dell_backlight_device->props.max_brightness = max_intensity; - dell_backlight_device->props.brightness = - dell_get_intensity(dell_backlight_device); - backlight_update_status(dell_backlight_device); - } - - return 0; -out: - if (wifi_rfkill) - rfkill_unregister(wifi_rfkill); - if (bluetooth_rfkill) - rfkill_unregister(bluetooth_rfkill); - if (wwan_rfkill) - rfkill_unregister(wwan_rfkill); - kfree(da_tokens); - return ret; -} - -static void __exit dell_exit(void) -{ - backlight_device_unregister(dell_backlight_device); - if (wifi_rfkill) - rfkill_unregister(wifi_rfkill); - if (bluetooth_rfkill) - rfkill_unregister(bluetooth_rfkill); - if (wwan_rfkill) - rfkill_unregister(wwan_rfkill); -} - -module_init(dell_init); -module_exit(dell_exit); - -MODULE_AUTHOR("Matthew Garrett "); -MODULE_DESCRIPTION("Dell laptop driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e65448e99b48..9e8f9485f9c9 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -54,6 +54,18 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. +config DELL_LAPTOP + tristate "Dell Laptop Extras (EXPERIMENTAL)" + depends on X86 + depends on DCDBAS + depends on EXPERIMENTAL + depends on BACKLIGHT_CLASS_DEVICE + depends on RFKILL + default n + ---help--- + This driver adds support for rfkill and backlight control to Dell + laptops. + config FUJITSU_LAPTOP tristate "Fujitsu Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 1e9de2ae0de5..e29065120be9 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o +obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c new file mode 100644 index 000000000000..16e11c2ee19a --- /dev/null +++ b/drivers/platform/x86/dell-laptop.c @@ -0,0 +1,436 @@ +/* + * Driver for Dell laptop extras + * + * Copyright (c) Red Hat + * + * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell + * Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../firmware/dcdbas.h" + +#define BRIGHTNESS_TOKEN 0x7d + +/* This structure will be modified by the firmware when we enter + * system management mode, hence the volatiles */ + +struct calling_interface_buffer { + u16 class; + u16 select; + volatile u32 input[4]; + volatile u32 output[4]; +} __packed; + +struct calling_interface_token { + u16 tokenID; + u16 location; + union { + u16 value; + u16 stringlength; + }; +}; + +struct calling_interface_structure { + struct dmi_header header; + u16 cmdIOAddress; + u8 cmdIOCode; + u32 supportedCmds; + struct calling_interface_token tokens[]; +} __packed; + +static int da_command_address; +static int da_command_code; +static int da_num_tokens; +static struct calling_interface_token *da_tokens; + +static struct backlight_device *dell_backlight_device; +static struct rfkill *wifi_rfkill; +static struct rfkill *bluetooth_rfkill; +static struct rfkill *wwan_rfkill; + +static const struct dmi_system_id __initdata dell_device_table[] = { + { + .ident = "Dell laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "8"), + }, + }, + { } +}; + +static void parse_da_table(const struct dmi_header *dm) +{ + /* Final token is a terminator, so we don't want to copy it */ + int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; + struct calling_interface_structure *table = + container_of(dm, struct calling_interface_structure, header); + + /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least + 6 bytes of entry */ + + if (dm->length < 17) + return; + + da_command_address = table->cmdIOAddress; + da_command_code = table->cmdIOCode; + + da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * + sizeof(struct calling_interface_token), + GFP_KERNEL); + + if (!da_tokens) + return; + + memcpy(da_tokens+da_num_tokens, table->tokens, + sizeof(struct calling_interface_token) * tokens); + + da_num_tokens += tokens; +} + +static void find_tokens(const struct dmi_header *dm) +{ + switch (dm->type) { + case 0xd4: /* Indexed IO */ + break; + case 0xd5: /* Protected Area Type 1 */ + break; + case 0xd6: /* Protected Area Type 2 */ + break; + case 0xda: /* Calling interface */ + parse_da_table(dm); + break; + } +} + +static int find_token_location(int tokenid) +{ + int i; + for (i = 0; i < da_num_tokens; i++) { + if (da_tokens[i].tokenID == tokenid) + return da_tokens[i].location; + } + + return -1; +} + +static struct calling_interface_buffer * +dell_send_request(struct calling_interface_buffer *buffer, int class, + int select) +{ + struct smi_cmd command; + + command.magic = SMI_CMD_MAGIC; + command.command_address = da_command_address; + command.command_code = da_command_code; + command.ebx = virt_to_phys(buffer); + command.ecx = 0x42534931; + + buffer->class = class; + buffer->select = select; + + dcdbas_smi_request(&command); + + return buffer; +} + +/* Derived from information in DellWirelessCtl.cpp: + Class 17, select 11 is radio control. It returns an array of 32-bit values. + + result[0]: return code + result[1]: + Bit 0: Hardware switch supported + Bit 1: Wifi locator supported + Bit 2: Wifi is supported + Bit 3: Bluetooth is supported + Bit 4: WWAN is supported + Bit 5: Wireless keyboard supported + Bits 6-7: Reserved + Bit 8: Wifi is installed + Bit 9: Bluetooth is installed + Bit 10: WWAN is installed + Bits 11-15: Reserved + Bit 16: Hardware switch is on + Bit 17: Wifi is blocked + Bit 18: Bluetooth is blocked + Bit 19: WWAN is blocked + Bits 20-31: Reserved + result[2]: NVRAM size in bytes + result[3]: NVRAM format version number +*/ + +static int dell_rfkill_set(int radio, enum rfkill_state state) +{ + struct calling_interface_buffer buffer; + int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = (1 | (radio<<8) | (disable << 16)); + dell_send_request(&buffer, 17, 11); + + return 0; +} + +static int dell_wifi_set(void *data, enum rfkill_state state) +{ + return dell_rfkill_set(1, state); +} + +static int dell_bluetooth_set(void *data, enum rfkill_state state) +{ + return dell_rfkill_set(2, state); +} + +static int dell_wwan_set(void *data, enum rfkill_state state) +{ + return dell_rfkill_set(3, state); +} + +static int dell_rfkill_get(int bit, enum rfkill_state *state) +{ + struct calling_interface_buffer buffer; + int status; + int new_state = RFKILL_STATE_HARD_BLOCKED; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + dell_send_request(&buffer, 17, 11); + status = buffer.output[1]; + + if (status & (1<<16)) + new_state = RFKILL_STATE_SOFT_BLOCKED; + + if (status & (1<name = "dell-wifi"; + wifi_rfkill->toggle_radio = dell_wifi_set; + wifi_rfkill->get_state = dell_wifi_get; + ret = rfkill_register(wifi_rfkill); + if (ret) + goto err_wifi; + } + + if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { + bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); + if (!bluetooth_rfkill) + goto err_bluetooth; + bluetooth_rfkill->name = "dell-bluetooth"; + bluetooth_rfkill->toggle_radio = dell_bluetooth_set; + bluetooth_rfkill->get_state = dell_bluetooth_get; + ret = rfkill_register(bluetooth_rfkill); + if (ret) + goto err_bluetooth; + } + + if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { + wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); + if (!wwan_rfkill) + goto err_wwan; + wwan_rfkill->name = "dell-wwan"; + wwan_rfkill->toggle_radio = dell_wwan_set; + wwan_rfkill->get_state = dell_wwan_get; + ret = rfkill_register(wwan_rfkill); + if (ret) + goto err_wwan; + } + + return 0; +err_wwan: + if (wwan_rfkill) + rfkill_free(wwan_rfkill); + if (bluetooth_rfkill) { + rfkill_unregister(bluetooth_rfkill); + bluetooth_rfkill = NULL; + } +err_bluetooth: + if (bluetooth_rfkill) + rfkill_free(bluetooth_rfkill); + if (wifi_rfkill) { + rfkill_unregister(wifi_rfkill); + wifi_rfkill = NULL; + } +err_wifi: + if (wifi_rfkill) + rfkill_free(wifi_rfkill); + + return ret; +} + +static int dell_send_intensity(struct backlight_device *bd) +{ + struct calling_interface_buffer buffer; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); + buffer.input[1] = bd->props.brightness; + + if (buffer.input[0] == -1) + return -ENODEV; + + if (power_supply_is_system_supplied() > 0) + dell_send_request(&buffer, 1, 2); + else + dell_send_request(&buffer, 1, 1); + + return 0; +} + +static int dell_get_intensity(struct backlight_device *bd) +{ + struct calling_interface_buffer buffer; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); + + if (buffer.input[0] == -1) + return -ENODEV; + + if (power_supply_is_system_supplied() > 0) + dell_send_request(&buffer, 0, 2); + else + dell_send_request(&buffer, 0, 1); + + return buffer.output[1]; +} + +static struct backlight_ops dell_ops = { + .get_brightness = dell_get_intensity, + .update_status = dell_send_intensity, +}; + +static int __init dell_init(void) +{ + struct calling_interface_buffer buffer; + int max_intensity = 0; + int ret; + + if (!dmi_check_system(dell_device_table)) + return -ENODEV; + + dmi_walk(find_tokens); + + if (!da_tokens) { + printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n"); + return -ENODEV; + } + + ret = dell_setup_rfkill(); + + if (ret) { + printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); + goto out; + } + +#ifdef CONFIG_ACPI + /* In the event of an ACPI backlight being available, don't + * register the platform controller. + */ + if (acpi_video_backlight_support()) + return 0; +#endif + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); + + if (buffer.input[0] != -1) { + dell_send_request(&buffer, 0, 2); + max_intensity = buffer.output[3]; + } + + if (max_intensity) { + dell_backlight_device = backlight_device_register( + "dell_backlight", + NULL, NULL, + &dell_ops); + + if (IS_ERR(dell_backlight_device)) { + ret = PTR_ERR(dell_backlight_device); + dell_backlight_device = NULL; + goto out; + } + + dell_backlight_device->props.max_brightness = max_intensity; + dell_backlight_device->props.brightness = + dell_get_intensity(dell_backlight_device); + backlight_update_status(dell_backlight_device); + } + + return 0; +out: + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); + if (wwan_rfkill) + rfkill_unregister(wwan_rfkill); + kfree(da_tokens); + return ret; +} + +static void __exit dell_exit(void) +{ + backlight_device_unregister(dell_backlight_device); + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); + if (wwan_rfkill) + rfkill_unregister(wwan_rfkill); +} + +module_init(dell_init); +module_exit(dell_exit); + +MODULE_AUTHOR("Matthew Garrett "); +MODULE_DESCRIPTION("Dell laptop driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); -- cgit v1.2.3