diff options
Diffstat (limited to 'drivers/acpi')
45 files changed, 1412 insertions, 1115 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index da49b006bcc5..eab04e957285 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -160,15 +160,8 @@ config ACPI_DOCK tristate "Dock" depends on EXPERIMENTAL help - This driver adds support for ACPI controlled docking stations - -config ACPI_BAY - tristate "Removable Drive Bay (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on ACPI_DOCK - help - This driver adds support for ACPI controlled removable drive - bays such as the IBM ultrabay or the Dell Module Bay. + This driver adds support for ACPI controlled docking stations and removable + drive bays such as the IBM ultrabay or the Dell Module Bay. config ACPI_PROCESSOR tristate "Processor" diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 52a4cd4b81d0..ad4bfd558ff3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o -obj-$(CONFIG_ACPI_BAY) += bay.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 831883b7d6c9..d72a1b6c8a94 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -85,7 +85,7 @@ struct acpi_ac { struct power_supply charger; #endif struct acpi_device * device; - unsigned long state; + unsigned long long state; }; #define to_acpi_ac(x) container_of(x, struct acpi_ac, charger); @@ -269,7 +269,7 @@ static int acpi_ac_add(struct acpi_device *device) ac->device = device; strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_AC_CLASS); - acpi_driver_data(device) = ac; + device->driver_data = ac; result = acpi_ac_get_state(ac); if (result) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 5f1127ad5a95..5a122b98aad8 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -194,8 +194,7 @@ acpi_memory_get_device(acpi_handle handle, static int acpi_memory_check_device(struct acpi_memory_device *mem_device) { - unsigned long current_status; - + unsigned long long current_status; /* Get device present/absent information from the _STA */ if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA", @@ -264,7 +263,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) acpi_status status; struct acpi_object_list arg_list; union acpi_object arg; - unsigned long current_status; + unsigned long long current_status; /* Issue the _EJ0 command */ @@ -403,7 +402,7 @@ static int acpi_memory_device_add(struct acpi_device *device) mem_device->device = device; sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); - acpi_driver_data(device) = mem_device; + device->driver_data = mem_device; /* Get the range from the _CRS */ result = acpi_memory_get_device_resources(mem_device); @@ -454,8 +453,8 @@ static int acpi_memory_device_start (struct acpi_device *device) /* call add_memory func */ result = acpi_memory_enable_device(mem_device); if (result) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error in acpi_memory_enable_device\n")); + printk(KERN_ERR "Error in acpi_memory_enable_device [%d]\n", + result); } return result; } diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index d3d0886d637f..1e74988c7b2d 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -42,7 +42,7 @@ #define ASUS_ACPI_VERSION "0.30" -#define PROC_ASUS "asus" //the directory +#define PROC_ASUS "asus" /* The directory */ #define PROC_MLED "mled" #define PROC_WLED "wled" #define PROC_TLED "tled" @@ -66,10 +66,10 @@ /* * Flags for hotk status */ -#define MLED_ON 0x01 //mail LED -#define WLED_ON 0x02 //wireless LED -#define TLED_ON 0x04 //touchpad LED -#define BT_ON 0x08 //internal Bluetooth +#define MLED_ON 0x01 /* Mail LED */ +#define WLED_ON 0x02 /* Wireless LED */ +#define TLED_ON 0x04 /* Touchpad LED */ +#define BT_ON 0x08 /* Internal Bluetooth */ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); MODULE_DESCRIPTION(ACPI_HOTK_NAME); @@ -82,28 +82,28 @@ MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus"); module_param(asus_gid, uint, 0); MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus"); -/* For each model, all features implemented, +/* For each model, all features implemented, * those marked with R are relative to HOTK, A for absolute */ struct model_data { - char *name; //name of the laptop________________A - char *mt_mled; //method to handle mled_____________R - char *mled_status; //node to handle mled reading_______A - char *mt_wled; //method to handle wled_____________R - char *wled_status; //node to handle wled reading_______A - char *mt_tled; //method to handle tled_____________R - char *tled_status; //node to handle tled reading_______A - char *mt_ledd; //method to handle LED display______R - char *mt_bt_switch; //method to switch Bluetooth on/off_R - char *bt_status; //no model currently supports this__? - char *mt_lcd_switch; //method to turn LCD on/off_________A - char *lcd_status; //node to read LCD panel state______A - char *brightness_up; //method to set brightness up_______A - char *brightness_down; //guess what ?______________________A - char *brightness_set; //method to set absolute brightness_R - char *brightness_get; //method to get absolute brightness_R - char *brightness_status; //node to get brightness____________A - char *display_set; //method to set video output________R - char *display_get; //method to get video output________R + char *name; /* name of the laptop________________A */ + char *mt_mled; /* method to handle mled_____________R */ + char *mled_status; /* node to handle mled reading_______A */ + char *mt_wled; /* method to handle wled_____________R */ + char *wled_status; /* node to handle wled reading_______A */ + char *mt_tled; /* method to handle tled_____________R */ + char *tled_status; /* node to handle tled reading_______A */ + char *mt_ledd; /* method to handle LED display______R */ + char *mt_bt_switch; /* method to switch Bluetooth on/off_R */ + char *bt_status; /* no model currently supports this__? */ + char *mt_lcd_switch; /* method to turn LCD on/off_________A */ + char *lcd_status; /* node to read LCD panel state______A */ + char *brightness_up; /* method to set brightness up_______A */ + char *brightness_down; /* method to set brightness down ____A */ + char *brightness_set; /* method to set absolute brightness_R */ + char *brightness_get; /* method to get absolute brightness_R */ + char *brightness_status;/* node to get brightness____________A */ + char *display_set; /* method to set video output________R */ + char *display_get; /* method to get video output________R */ }; /* @@ -111,41 +111,41 @@ struct model_data { * about the hotk device */ struct asus_hotk { - struct acpi_device *device; //the device we are in - acpi_handle handle; //the handle of the hotk device - char status; //status of the hotk, for LEDs, ... - u32 ledd_status; //status of the LED display - struct model_data *methods; //methods available on the laptop - u8 brightness; //brightness level + struct acpi_device *device; /* the device we are in */ + acpi_handle handle; /* the handle of the hotk device */ + char status; /* status of the hotk, for LEDs */ + u32 ledd_status; /* status of the LED display */ + struct model_data *methods; /* methods available on the laptop */ + u8 brightness; /* brightness level */ enum { - A1x = 0, //A1340D, A1300F - A2x, //A2500H - A4G, //A4700G - D1x, //D1 - L2D, //L2000D - L3C, //L3800C - L3D, //L3400D - L3H, //L3H, L2000E, L5D - L4R, //L4500R - L5x, //L5800C - L8L, //L8400L - M1A, //M1300A - M2E, //M2400E, L4400L - M6N, //M6800N, W3400N - M6R, //M6700R, A3000G - P30, //Samsung P30 - S1x, //S1300A, but also L1400B and M2400A (L84F) - S2x, //S200 (J1 reported), Victor MP-XP7210 - W1N, //W1000N - W5A, //W5A - W3V, //W3030V - xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N - A4S, //Z81sp - //(Centrino) - F3Sa, + A1x = 0, /* A1340D, A1300F */ + A2x, /* A2500H */ + A4G, /* A4700G */ + D1x, /* D1 */ + L2D, /* L2000D */ + L3C, /* L3800C */ + L3D, /* L3400D */ + L3H, /* L3H, L2000E, L5D */ + L4R, /* L4500R */ + L5x, /* L5800C */ + L8L, /* L8400L */ + M1A, /* M1300A */ + M2E, /* M2400E, L4400L */ + M6N, /* M6800N, W3400N */ + M6R, /* M6700R, A3000G */ + P30, /* Samsung P30 */ + S1x, /* S1300A, but also L1400B and M2400A (L84F) */ + S2x, /* S200 (J1 reported), Victor MP-XP7210 */ + W1N, /* W1000N */ + W5A, /* W5A */ + W3V, /* W3030V */ + xxN, /* M2400N, M3700N, M5200N, M6800N, + S1300N, S5200N*/ + A4S, /* Z81sp */ + F3Sa, /* (Centrino) */ END_MODEL - } model; //Models currently supported - u16 event_count[128]; //count for each event TODO make this better + } model; /* Models currently supported */ + u16 event_count[128]; /* Count for each event TODO make this better */ }; /* Here we go */ @@ -459,18 +459,18 @@ static struct acpi_driver asus_hotk_driver = { }, }; -/* +/* * This function evaluates an ACPI method, given an int as parameter, the * method is searched within the scope of the handle, can be NULL. The output * of the method is written is output, which can also be NULL * - * returns 1 if write is successful, 0 else. + * returns 1 if write is successful, 0 else. */ static int write_acpi_int(acpi_handle handle, const char *method, int val, struct acpi_buffer *output) { - struct acpi_object_list params; //list of input parameters (an int here) - union acpi_object in_obj; //the only param we use + struct acpi_object_list params; /* list of input parameters (int) */ + union acpi_object in_obj; /* the only param we use */ acpi_status status; params.count = 1; @@ -507,18 +507,18 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, { int len = 0; int temp; - char buf[16]; //enough for all info + char buf[16]; /* enough for all info */ /* - * We use the easy way, we don't care of off and count, so we don't set eof - * to 1 + * We use the easy way, we don't care of off and count, + * so we don't set eof to 1 */ len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); len += sprintf(page + len, "Model reference : %s\n", hotk->methods->name); - /* - * The SFUN method probably allows the original driver to get the list - * of features supported by a given model. For now, 0x0100 or 0x0800 + /* + * The SFUN method probably allows the original driver to get the list + * of features supported by a given model. For now, 0x0100 or 0x0800 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. * The significance of others is yet to be found. */ @@ -528,7 +528,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof, /* * Another value for userspace: the ASYM method returns 0x02 for * battery low and 0x04 for battery critical, its readings tend to be - * more accurate than those provided by _BST. + * more accurate than those provided by _BST. * Note: since not all the laptops provide this method, errors are * silently ignored. */ @@ -579,7 +579,7 @@ static int read_led(const char *ledname, int ledmask) return (hotk->status & ledmask) ? 1 : 0; } -static int parse_arg(const char __user * buf, unsigned long count, int *val) +static int parse_arg(const char __user *buf, unsigned long count, int *val) { char s[32]; if (!count) @@ -596,7 +596,7 @@ static int parse_arg(const char __user * buf, unsigned long count, int *val) /* FIXME: kill extraneous args so it can be called independently */ static int -write_led(const char __user * buffer, unsigned long count, +write_led(const char __user *buffer, unsigned long count, char *ledname, int ledmask, int invert) { int rv, value; @@ -631,7 +631,7 @@ proc_read_mled(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_mled(struct file *file, const char __user * buffer, +proc_write_mled(struct file *file, const char __user *buffer, unsigned long count, void *data) { return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1); @@ -648,7 +648,7 @@ proc_read_ledd(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_ledd(struct file *file, const char __user * buffer, +proc_write_ledd(struct file *file, const char __user *buffer, unsigned long count, void *data) { int rv, value; @@ -677,7 +677,7 @@ proc_read_wled(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_wled(struct file *file, const char __user * buffer, +proc_write_wled(struct file *file, const char __user *buffer, unsigned long count, void *data) { return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0); @@ -694,10 +694,10 @@ proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_bluetooth(struct file *file, const char __user * buffer, +proc_write_bluetooth(struct file *file, const char __user *buffer, unsigned long count, void *data) { - /* Note: mt_bt_switch controls both internal Bluetooth adapter's + /* Note: mt_bt_switch controls both internal Bluetooth adapter's presence and its LED */ return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0); } @@ -714,7 +714,7 @@ proc_read_tled(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_tled(struct file *file, const char __user * buffer, +proc_write_tled(struct file *file, const char __user *buffer, unsigned long count, void *data) { return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0); @@ -734,7 +734,7 @@ static int get_lcd_state(void) input.count = 2; input.pointer = mt_params; - /* Note: the following values are partly guessed up, but + /* Note: the following values are partly guessed up, but otherwise they seem to work */ mt_params[0].type = ACPI_TYPE_INTEGER; mt_params[0].integer.value = 0x02; @@ -753,7 +753,7 @@ static int get_lcd_state(void) /* That's what the AML code does */ lcd = out_obj.integer.value >> 8; } else if (hotk->model == F3Sa) { - unsigned long tmp; + unsigned long long tmp; union acpi_object param; struct acpi_object_list input; acpi_status status; @@ -796,12 +796,13 @@ static int set_lcd_state(int value) acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch, NULL, NULL); - } else { /* L3H and the like have to be handled differently */ + } else { + /* L3H and the like must be handled differently */ if (!write_acpi_int (hotk->handle, hotk->methods->mt_lcd_switch, 0x07, NULL)) status = AE_ERROR; - /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress, + /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress, the exact behaviour is simulated here */ } if (ACPI_FAILURE(status)) @@ -819,7 +820,7 @@ proc_read_lcd(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_lcd(struct file *file, const char __user * buffer, +proc_write_lcd(struct file *file, const char __user *buffer, unsigned long count, void *data) { int rv, value; @@ -897,7 +898,7 @@ proc_read_brn(char *page, char **start, off_t off, int count, int *eof, } static int -proc_write_brn(struct file *file, const char __user * buffer, +proc_write_brn(struct file *file, const char __user *buffer, unsigned long count, void *data) { int rv, value; @@ -921,7 +922,7 @@ static void set_display(int value) } /* - * Now, *this* one could be more user-friendly, but so far, no-one has + * Now, *this* one could be more user-friendly, but so far, no-one has * complained. The significance of bits is the same as in proc_write_disp() */ static int @@ -933,18 +934,18 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof, if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value)) printk(KERN_WARNING "Asus ACPI: Error reading display status\n"); - value &= 0x07; /* needed for some models, shouldn't hurt others */ + value &= 0x07; /* needed for some models, shouldn't hurt others */ return sprintf(page, "%d\n", value); } /* - * Experimental support for display switching. As of now: 1 should activate - * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination - * (bitwise) of these will suffice. I never actually tested 3 displays hooked up - * simultaneously, so be warned. See the acpi4asus README for more info. + * Experimental support for display switching. As of now: 1 should activate + * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination + * (bitwise) of these will suffice. I never actually tested 3 displays hooked + * up simultaneously, so be warned. See the acpi4asus README for more info. */ static int -proc_write_disp(struct file *file, const char __user * buffer, +proc_write_disp(struct file *file, const char __user *buffer, unsigned long count, void *data) { int rv, value; @@ -957,12 +958,12 @@ proc_write_disp(struct file *file, const char __user * buffer, typedef int (proc_readfunc) (char *page, char **start, off_t off, int count, int *eof, void *data); -typedef int (proc_writefunc) (struct file * file, const char __user * buffer, +typedef int (proc_writefunc) (struct file *file, const char __user *buffer, unsigned long count, void *data); static int -asus_proc_add(char *name, proc_writefunc * writefunc, - proc_readfunc * readfunc, mode_t mode, +asus_proc_add(char *name, proc_writefunc *writefunc, + proc_readfunc *readfunc, mode_t mode, struct acpi_device *device) { struct proc_dir_entry *proc = @@ -1040,9 +1041,9 @@ static int asus_hotk_add_fs(struct acpi_device *device) &proc_read_bluetooth, mode, device); } - /* - * We need both read node and write method as LCD switch is also accessible - * from keyboard + /* + * We need both read node and write method as LCD switch is also + * accessible from the keyboard */ if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode, @@ -1096,11 +1097,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) if (!hotk) return; - if ((event & ~((u32) BR_UP)) < 16) { + if ((event & ~((u32) BR_UP)) < 16) hotk->brightness = (event & ~((u32) BR_UP)); - } else if ((event & ~((u32) BR_DOWN)) < 16) { + else if ((event & ~((u32) BR_DOWN)) < 16) hotk->brightness = (event & ~((u32) BR_DOWN)); - } acpi_bus_generate_proc_event(hotk->device, event, hotk->event_count[event % 128]++); @@ -1186,8 +1186,8 @@ static int asus_hotk_get_info(void) acpi_status status; /* - * Get DSDT headers early enough to allow for differentiating between - * models, but late enough to allow acpi_bus_register_driver() to fail + * Get DSDT headers early enough to allow for differentiating between + * models, but late enough to allow acpi_bus_register_driver() to fail * before doing anything ACPI-specific. Should we encounter a machine, * which needs special handling (i.e. its hotkey device has a different * HID), this bit will be moved. A global variable asus_info contains @@ -1212,8 +1212,8 @@ static int asus_hotk_get_info(void) /* * Try to match the object returned by INIT to the specific model. - * Handle every possible object (or the lack of thereof) the DSDT - * writers might throw at us. When in trouble, we pass NULL to + * Handle every possible object (or the lack of thereof) the DSDT + * writers might throw at us. When in trouble, we pass NULL to * asus_model_match() and try something completely different. */ if (buffer.pointer) { @@ -1244,6 +1244,8 @@ static int asus_hotk_get_info(void) "default values\n", string); printk(KERN_NOTICE " send /proc/acpi/dsdt to the developers\n"); + kfree(model); + return -ENODEV; } hotk->methods = &model_conf[hotk->model]; return AE_OK; @@ -1254,7 +1256,7 @@ static int asus_hotk_get_info(void) /* Sort of per-model blacklist */ if (strncmp(string, "L2B", 3) == 0) hotk->methods->lcd_status = NULL; - /* L2B is similar enough to L3C to use its settings, with this only + /* L2B is similar enough to L3C to use its settings, with this only exception */ else if (strncmp(string, "A3G", 3) == 0) hotk->methods->lcd_status = "\\BLFG"; @@ -1321,7 +1323,7 @@ static int asus_hotk_add(struct acpi_device *device) hotk->handle = device->handle; strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_HOTK_CLASS); - acpi_driver_data(device) = hotk; + device->driver_data = hotk; hotk->device = device; result = asus_hotk_check(); @@ -1366,10 +1368,9 @@ static int asus_hotk_add(struct acpi_device *device) /* LED display is off by default */ hotk->ledd_status = 0xFFF; - end: - if (result) { +end: + if (result) kfree(hotk); - } return result; } @@ -1394,8 +1395,8 @@ static int asus_hotk_remove(struct acpi_device *device, int type) } static struct backlight_ops asus_backlight_data = { - .get_brightness = read_brightness, - .update_status = set_brightness_status, + .get_brightness = read_brightness, + .update_status = set_brightness_status, }; static void asus_acpi_exit(void) @@ -1442,15 +1443,15 @@ static int __init asus_acpi_init(void) return -ENODEV; } - asus_backlight_device = backlight_device_register("asus",NULL,NULL, + asus_backlight_device = backlight_device_register("asus", NULL, NULL, &asus_backlight_data); - if (IS_ERR(asus_backlight_device)) { + if (IS_ERR(asus_backlight_device)) { printk(KERN_ERR "Could not register asus backlight device\n"); asus_backlight_device = NULL; asus_acpi_exit(); return -ENODEV; } - asus_backlight_device->props.max_brightness = 15; + asus_backlight_device->props.max_brightness = 15; return 0; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b1c723f9f58d..de8046933bce 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -804,7 +804,7 @@ static int acpi_battery_add(struct acpi_device *device) battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); - acpi_driver_data(device) = battery; + device->driver_data = battery; mutex_init(&battery->lock); acpi_battery_update(battery); #ifdef CONFIG_ACPI_PROCFS_POWER diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c deleted file mode 100644 index 61b6c5beb2d3..000000000000 --- a/drivers/acpi/bay.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * bay.c - ACPI removable drive bay driver - * - * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/notifier.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> -#include <linux/seq_file.h> -#include <asm/uaccess.h> -#include <linux/platform_device.h> - -ACPI_MODULE_NAME("bay"); -MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver"); -MODULE_LICENSE("GPL"); -#define ACPI_BAY_CLASS "bay" -#define ACPI_BAY_COMPONENT 0x10000000 -#define _COMPONENT ACPI_BAY_COMPONENT -#define bay_dprintk(h,s) {\ - char prefix[80] = {'\0'};\ - struct acpi_buffer buffer = {sizeof(prefix), prefix};\ - acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ - printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } -static void bay_notify(acpi_handle handle, u32 event, void *data); - -static const struct acpi_device_id bay_device_ids[] = { - {"LNXIOBAY", 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, bay_device_ids); - -struct bay { - acpi_handle handle; - char *name; - struct list_head list; - struct platform_device *pdev; -}; - -static LIST_HEAD(drive_bays); - - -/***************************************************************************** - * Drive Bay functions * - *****************************************************************************/ -/** - * is_ejectable - see if a device is ejectable - * @handle: acpi handle of the device - * - * If an acpi object has a _EJ0 method, then it is ejectable - */ -static int is_ejectable(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) - return 0; - return 1; -} - -/** - * bay_present - see if the bay device is present - * @bay: the drive bay - * - * execute the _STA method. - */ -static int bay_present(struct bay *bay) -{ - unsigned long sta; - acpi_status status; - - if (bay) { - status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta) - return 1; - } - return 0; -} - -/** - * eject_device - respond to an eject request - * @handle - the device to eject - * - * Call this devices _EJ0 method. - */ -static void eject_device(acpi_handle handle) -{ - struct acpi_object_list arg_list; - union acpi_object arg; - - bay_dprintk(handle, "Ejecting device"); - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", - &arg_list, NULL))) - pr_debug("Failed to evaluate _EJ0!\n"); -} - -/* - * show_present - read method for "present" file in sysfs - */ -static ssize_t show_present(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bay *bay = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); - -} -static DEVICE_ATTR(present, S_IRUGO, show_present, NULL); - -/* - * write_eject - write method for "eject" file in sysfs - */ -static ssize_t write_eject(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bay *bay = dev_get_drvdata(dev); - - if (!count) - return -EINVAL; - - eject_device(bay->handle); - return count; -} -static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); - -/** - * is_ata - see if a device is an ata device - * @handle: acpi handle of the device - * - * If an acpi object has one of 4 ATA ACPI methods defined, - * then it is an ATA device - */ -static int is_ata(acpi_handle handle) -{ - acpi_handle tmp; - - if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) - return 1; - - return 0; -} - -/** - * parent_is_ata(acpi_handle handle) - * - */ -static int parent_is_ata(acpi_handle handle) -{ - acpi_handle phandle; - - if (acpi_get_parent(handle, &phandle)) - return 0; - - return is_ata(phandle); -} - -/** - * is_ejectable_bay - see if a device is an ejectable drive bay - * @handle: acpi handle of the device - * - * If an acpi object is ejectable and has one of the ACPI ATA - * methods defined, then we can safely call it an ejectable - * drive bay - */ -static int is_ejectable_bay(acpi_handle handle) -{ - if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle)) - return 1; - return 0; -} - -#if 0 -/** - * eject_removable_drive - try to eject this drive - * @dev : the device structure of the drive - * - * If a device is a removable drive that requires an _EJ0 method - * to be executed in order to safely remove from the system, do - * it. ATM - always returns success - */ -int eject_removable_drive(struct device *dev) -{ - acpi_handle handle = DEVICE_ACPI_HANDLE(dev); - - if (handle) { - bay_dprintk(handle, "Got device handle"); - if (is_ejectable_bay(handle)) - eject_device(handle); - } else { - printk("No acpi handle for device\n"); - } - - /* should I return an error code? */ - return 0; -} -EXPORT_SYMBOL_GPL(eject_removable_drive); -#endif /* 0 */ - -static int acpi_bay_add_fs(struct bay *bay) -{ - int ret; - struct device *dev = &bay->pdev->dev; - - ret = device_create_file(dev, &dev_attr_present); - if (ret) - goto add_fs_err; - ret = device_create_file(dev, &dev_attr_eject); - if (ret) { - device_remove_file(dev, &dev_attr_present); - goto add_fs_err; - } - return 0; - - add_fs_err: - bay_dprintk(bay->handle, "Error adding sysfs files\n"); - return ret; -} - -static void acpi_bay_remove_fs(struct bay *bay) -{ - struct device *dev = &bay->pdev->dev; - - /* cleanup sysfs */ - device_remove_file(dev, &dev_attr_present); - device_remove_file(dev, &dev_attr_eject); -} - -static int bay_is_dock_device(acpi_handle handle) -{ - acpi_handle parent; - - acpi_get_parent(handle, &parent); - - /* if the device or it's parent is dependent on the - * dock, then we are a dock device - */ - return (is_dock_device(handle) || is_dock_device(parent)); -} - -static int bay_add(acpi_handle handle, int id) -{ - acpi_status status; - struct bay *new_bay; - struct platform_device *pdev; - struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer); - - bay_dprintk(handle, "Adding notify handler"); - - /* - * Initialize bay device structure - */ - new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC); - INIT_LIST_HEAD(&new_bay->list); - new_bay->handle = handle; - new_bay->name = (char *)nbuffer.pointer; - - /* initialize platform device stuff */ - pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); - if (IS_ERR(pdev)) { - printk(KERN_ERR PREFIX "Error registering bay device\n"); - goto bay_add_err; - } - new_bay->pdev = pdev; - platform_set_drvdata(pdev, new_bay); - - /* - * we want the bay driver to be able to send uevents - */ - pdev->dev.uevent_suppress = 0; - - /* register for events on this device */ - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - bay_notify, new_bay); - if (ACPI_FAILURE(status)) { - printk(KERN_INFO PREFIX "Error installing bay notify handler\n"); - platform_device_unregister(new_bay->pdev); - goto bay_add_err; - } - - if (acpi_bay_add_fs(new_bay)) { - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - bay_notify); - platform_device_unregister(new_bay->pdev); - goto bay_add_err; - } - - /* if we are on a dock station, we should register for dock - * notifications. - */ - if (bay_is_dock_device(handle)) { - bay_dprintk(handle, "Is dependent on dock\n"); - register_hotplug_dock_device(handle, bay_notify, new_bay); - } - list_add(&new_bay->list, &drive_bays); - printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name); - return 0; - -bay_add_err: - kfree(new_bay->name); - kfree(new_bay); - return -ENODEV; -} - -/** - * bay_notify - act upon an acpi bay notification - * @handle: the bay handle - * @event: the acpi event - * @data: our driver data struct - * - */ -static void bay_notify(acpi_handle handle, u32 event, void *data) -{ - struct bay *bay_dev = (struct bay *)data; - struct device *dev = &bay_dev->pdev->dev; - char event_string[12]; - char *envp[] = { event_string, NULL }; - - bay_dprintk(handle, "Bay event"); - sprintf(event_string, "BAY_EVENT=%d", event); - kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); -} - -static acpi_status -find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - /* - * there could be more than one ejectable bay. - * so, just return AE_OK always so that every object - * will be checked. - */ - if (is_ejectable_bay(handle)) { - bay_dprintk(handle, "found ejectable bay"); - if (!bay_add(handle, *count)) - (*count)++; - } - return AE_OK; -} - -static int __init bay_init(void) -{ - int bays = 0; - - INIT_LIST_HEAD(&drive_bays); - - if (acpi_disabled) - return -ENODEV; - - /* look for dockable drive bays */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_bay, &bays, NULL); - - if (!bays) - return -ENODEV; - - return 0; -} - -static void __exit bay_exit(void) -{ - struct bay *bay, *tmp; - - list_for_each_entry_safe(bay, tmp, &drive_bays, list) { - if (is_dock_device(bay->handle)) - unregister_hotplug_dock_device(bay->handle); - acpi_bay_remove_fs(bay); - acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY, - bay_notify); - platform_device_unregister(bay->pdev); - kfree(bay->name); - kfree(bay); - } -} - -postcore_initcall(bay_init); -module_exit(bay_exit); - diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ccae305ee55d..c797c6473f31 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir); #define STRUCT_TO_INT(s) (*((int*)&s)) +static int set_power_nocheck(const struct dmi_system_id *id) +{ + printk(KERN_NOTICE PREFIX "%s detected - " + "disable power check in power transistion\n", id->ident); + acpi_power_nocheck = 1; + return 0; +} +static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = { + { + set_power_nocheck, "HP Pavilion 05", { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"), + DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL}, + {}, +}; + + /* -------------------------------------------------------------------------- Device Management -------------------------------------------------------------------------- */ @@ -77,7 +94,7 @@ EXPORT_SYMBOL(acpi_bus_get_device); int acpi_bus_get_status(struct acpi_device *device) { acpi_status status = AE_OK; - unsigned long sta = 0; + unsigned long long sta = 0; if (!device) @@ -95,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device) } /* - * Otherwise we assume the status of our parent (unless we don't - * have one, in which case status is implied). + * According to ACPI spec some device can be present and functional + * even if the parent is not present but functional. + * In such conditions the child device should not inherit the status + * from the parent. */ - else if (device->parent) - device->status = device->parent->status; else STRUCT_TO_INT(device->status) = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; if (device->status.functional && !device->status.present) { - printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " - "functional but not present; setting present\n", - device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)); - device->status.present = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " + "functional but not present;\n", + device->pnp.bus_id, + (u32) STRUCT_TO_INT(device->status))); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", @@ -155,7 +172,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state) int result = 0; acpi_status status = 0; struct acpi_device *device = NULL; - unsigned long psc = 0; + unsigned long long psc = 0; result = acpi_bus_get_device(handle, &device); @@ -223,7 +240,19 @@ int acpi_bus_set_power(acpi_handle handle, int state) /* * Get device's current power state */ - acpi_bus_get_power(device->handle, &device->power.state); + if (!acpi_power_nocheck) { + /* + * Maybe the incorrect power state is returned on the bogus + * bios, which is different with the real power state. + * For example: the bios returns D0 state and the real power + * state is D3. OS expects to set the device to D0 state. In + * such case if OS uses the power state returned by the BIOS, + * the device can't be transisted to the correct power state. + * So if the acpi_power_nocheck is set, it is unnecessary to + * get the power state by calling acpi_bus_get_power. + */ + acpi_bus_get_power(device->handle, &device->power.state); + } if ((state == device->power.state) && !device->flags.force_power_state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); @@ -496,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device) return 0; } +static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); +int register_acpi_bus_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&acpi_bus_notify_list, nb); +} +EXPORT_SYMBOL_GPL(register_acpi_bus_notifier); + +void unregister_acpi_bus_notifier(struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); + /** * acpi_bus_notify * --------------- @@ -506,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) int result = 0; struct acpi_device *device = NULL; + blocking_notifier_call_chain(&acpi_bus_notify_list, + type, (void *)handle); if (acpi_bus_get_device(handle, &device)) return; @@ -749,6 +793,12 @@ static int __init acpi_bus_init(void) goto error1; } + /* + * Maybe EC region is required at bus_scan/acpi_get_devices. So it + * is necessary to enable it as early as possible. + */ + acpi_boot_ec_enable(); + printk(KERN_INFO PREFIX "Interpreter enabled\n"); /* Initialize sleep structures */ @@ -818,7 +868,11 @@ static int __init acpi_init(void) } } else disable_acpi(); - + /* + * If the laptop falls into the DMI check table, the power state check + * will be disabled in the course of device power transistion. + */ + dmi_check_system(power_nocheck_dmi_table); return result; } diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 1dfec413588c..9d568d417eaa 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -145,7 +145,7 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) { struct acpi_button *button = seq->private; acpi_status status; - unsigned long state; + unsigned long long state; if (!button || !button->device) return 0; @@ -253,7 +253,7 @@ static int acpi_button_remove_fs(struct acpi_device *device) -------------------------------------------------------------------------- */ static int acpi_lid_send_state(struct acpi_button *button) { - unsigned long state; + unsigned long long state; acpi_status status; status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, @@ -384,7 +384,7 @@ static int acpi_button_add(struct acpi_device *device) return -ENOMEM; button->device = device; - acpi_driver_data(device) = button; + device->driver_data = button; button->input = input = input_allocate_device(); if (!input) { diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index f9db4f444bd0..58dc367aabc6 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -52,8 +52,7 @@ struct proc_dir_entry *acpi_lock_ac_dir(void) if (acpi_ac_dir) { lock_ac_dir_cnt++; } else { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Cannot create %s\n", ACPI_AC_CLASS)); + printk(KERN_ERR "Cannot create %s\n", ACPI_AC_CLASS); } mutex_unlock(&cm_sbs_mutex); return acpi_ac_dir; @@ -83,8 +82,7 @@ struct proc_dir_entry *acpi_lock_battery_dir(void) if (acpi_battery_dir) { lock_battery_dir_cnt++; } else { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Cannot create %s\n", ACPI_BATTERY_CLASS)); + printk(KERN_ERR "Cannot create %s\n", ACPI_BATTERY_CLASS); } mutex_unlock(&cm_sbs_mutex); return acpi_battery_dir; diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 3c25ec7a1871..134818b265a9 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -76,7 +76,7 @@ static int is_device_present(acpi_handle handle) { acpi_handle temp; acpi_status status; - unsigned long sta; + unsigned long long sta; status = acpi_get_handle(handle, "_STA", &temp); @@ -108,7 +108,7 @@ static int acpi_container_add(struct acpi_device *device) container->handle = device->handle; strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS); - acpi_driver_data(device) = container; + device->driver_data = container; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n", acpi_device_name(device), acpi_device_bid(device))); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7d2edf143f16..5b30b8d91d71 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " " before undocking"); static struct atomic_notifier_head dock_notifier_list; -static struct platform_device *dock_device; static char dock_device_name[] = "dock"; static const struct acpi_device_id dock_device_ids[] = { @@ -65,23 +64,29 @@ struct dock_station { struct mutex hp_lock; struct list_head dependent_devices; struct list_head hotplug_devices; + + struct list_head sibiling; + struct platform_device *dock_device; }; +static LIST_HEAD(dock_stations); +static int dock_station_count; struct dock_dependent_device { struct list_head list; struct list_head hotplug_list; acpi_handle handle; - acpi_notify_handler handler; + struct acpi_dock_ops *ops; void *context; }; #define DOCK_DOCKING 0x00000001 #define DOCK_UNDOCKING 0x00000002 +#define DOCK_IS_DOCK 0x00000010 +#define DOCK_IS_ATA 0x00000020 +#define DOCK_IS_BAT 0x00000040 #define DOCK_EVENT 3 #define UNDOCK_EVENT 2 -static struct dock_station *dock_station; - /***************************************************************************** * Dock Dependent device functions * *****************************************************************************/ @@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle) return 1; } +static int is_ejectable(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return 0; + return 1; +} + +static int is_ata(acpi_handle handle) +{ + acpi_handle tmp; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 1; + + return 0; +} + +static int is_battery(acpi_handle handle) +{ + struct acpi_device_info *info; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + int ret = 1; + + if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) + return 0; + info = buffer.pointer; + if (!(info->valid & ACPI_VALID_HID)) + ret = 0; + else + ret = !strcmp("PNP0C0A", info->hardware_id.value); + + kfree(buffer.pointer); + return ret; +} + +static int is_ejectable_bay(acpi_handle handle) +{ + acpi_handle phandle; + if (!is_ejectable(handle)) + return 0; + if (is_battery(handle) || is_ata(handle)) + return 1; + if (!acpi_get_parent(handle, &phandle) && is_ata(phandle)) + return 1; + return 0; +} + /** * is_dock_device - see if a device is on a dock station * @handle: acpi handle of the device @@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle) */ int is_dock_device(acpi_handle handle) { - if (!dock_station) + struct dock_station *dock_station; + + if (!dock_station_count) return 0; - if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) + if (is_dock(handle)) return 1; + list_for_each_entry(dock_station, &dock_stations, sibiling) { + if (find_dock_dependent_device(dock_station, handle)) + return 1; + } return 0; } @@ -229,7 +294,7 @@ EXPORT_SYMBOL_GPL(is_dock_device); */ static int dock_present(struct dock_station *ds) { - unsigned long sta; + unsigned long long sta; acpi_status status; if (ds) { @@ -320,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) * First call driver specific hotplug functions */ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { - if (dd->handler) - dd->handler(dd->handle, event, dd->context); + if (dd->ops && dd->ops->handler) + dd->ops->handler(dd->handle, event, dd->context); } /* @@ -341,9 +406,10 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) static void dock_event(struct dock_station *ds, u32 event, int num) { - struct device *dev = &dock_device->dev; + struct device *dev = &ds->dock_device->dev; char event_string[13]; char *envp[] = { event_string, NULL }; + struct dock_dependent_device *dd; if (num == UNDOCK_EVENT) sprintf(event_string, "EVENT=undock"); @@ -354,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num) * Indicate that the status of the dock station has * changed. */ - kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); + if (num == DOCK_EVENT) + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); + + list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) + if (dd->ops && dd->ops->uevent) + dd->ops->uevent(dd->handle, event, dd->context); + if (num != DOCK_EVENT) + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } /** @@ -414,9 +487,10 @@ static void handle_dock(struct dock_station *ds, int dock) arg.type = ACPI_TYPE_INTEGER; arg.integer.value = dock; status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); - if (ACPI_FAILURE(status)) - printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", - (char *)name_buffer.pointer); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute" + " _DCK\n", (char *)name_buffer.pointer)); + kfree(buffer.pointer); kfree(name_buffer.pointer); } @@ -452,6 +526,25 @@ static inline void complete_undock(struct dock_station *ds) ds->flags &= ~(DOCK_UNDOCKING); } +static void dock_lock(struct dock_station *ds, int lock) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = !!lock; + status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + if (lock) + printk(KERN_WARNING PREFIX "Locking device failed\n"); + else + printk(KERN_WARNING PREFIX "Unlocking device failed\n"); + } +} + /** * dock_in_progress - see if we are in the middle of handling a dock event * @ds: the dock station @@ -479,7 +572,7 @@ static int dock_in_progress(struct dock_station *ds) */ int register_dock_notifier(struct notifier_block *nb) { - if (!dock_station) + if (!dock_station_count) return -ENODEV; return atomic_notifier_chain_register(&dock_notifier_list, nb); @@ -493,7 +586,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier); */ void unregister_dock_notifier(struct notifier_block *nb) { - if (!dock_station) + if (!dock_station_count) return; atomic_notifier_chain_unregister(&dock_notifier_list, nb); @@ -504,7 +597,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); /** * register_hotplug_dock_device - register a hotplug function * @handle: the handle of the device - * @handler: the acpi_notifier_handler to call after docking + * @ops: handlers to call after docking * @context: device specific data * * If a driver would like to perform a hotplug operation after a dock @@ -512,27 +605,36 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); * the dock driver after _DCK is executed. */ int -register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, +register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, void *context) { struct dock_dependent_device *dd; + struct dock_station *dock_station; + int ret = -EINVAL; - if (!dock_station) + if (!dock_station_count) return -ENODEV; /* * make sure this handle is for a device dependent on the dock, * this would include the dock station itself */ - dd = find_dock_dependent_device(dock_station, handle); - if (dd) { - dd->handler = handler; - dd->context = context; - dock_add_hotplug_device(dock_station, dd); - return 0; + list_for_each_entry(dock_station, &dock_stations, sibiling) { + /* + * An ATA bay can be in a dock and itself can be ejected + * seperately, so there are two 'dock stations' which need the + * ops + */ + dd = find_dock_dependent_device(dock_station, handle); + if (dd) { + dd->ops = ops; + dd->context = context; + dock_add_hotplug_device(dock_station, dd); + ret = 0; + } } - return -EINVAL; + return ret; } EXPORT_SYMBOL_GPL(register_hotplug_dock_device); @@ -544,13 +646,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_device); void unregister_hotplug_dock_device(acpi_handle handle) { struct dock_dependent_device *dd; + struct dock_station *dock_station; - if (!dock_station) + if (!dock_station_count) return; - dd = find_dock_dependent_device(dock_station, handle); - if (dd) - dock_del_hotplug_device(dock_station, dd); + list_for_each_entry(dock_station, &dock_stations, sibiling) { + dd = find_dock_dependent_device(dock_station, handle); + if (dd) + dock_del_hotplug_device(dock_station, dd); + } } EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); @@ -575,13 +680,9 @@ static int handle_eject_request(struct dock_station *ds, u32 event) */ dock_event(ds, event, UNDOCK_EVENT); - if (!dock_present(ds)) { - complete_undock(ds); - return -ENODEV; - } - hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); undock(ds); + dock_lock(ds, 0); eject_dock(ds); if (dock_present(ds)) { printk(KERN_ERR PREFIX "Unable to undock!\n"); @@ -604,14 +705,36 @@ static int handle_eject_request(struct dock_station *ds, u32 event) static void dock_notify(acpi_handle handle, u32 event, void *data) { struct dock_station *ds = data; + struct acpi_device *tmp; + int surprise_removal = 0; + + /* + * According to acpi spec 3.0a, if a DEVICE_CHECK notification + * is sent and _DCK is present, it is assumed to mean an undock + * request. + */ + if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK) + event = ACPI_NOTIFY_EJECT_REQUEST; + /* + * dock station: BUS_CHECK - docked or surprise removal + * DEVICE_CHECK - undocked + * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal + * + * To simplify event handling, dock dependent device handler always + * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and + * ACPI_NOTIFY_EJECT_REQUEST for removal + */ switch (event) { case ACPI_NOTIFY_BUS_CHECK: - if (!dock_in_progress(ds) && dock_present(ds)) { + case ACPI_NOTIFY_DEVICE_CHECK: + if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, + &tmp)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { printk(KERN_ERR PREFIX "Unable to dock!\n"); + complete_dock(ds); break; } atomic_notifier_call_chain(&dock_notifier_list, @@ -619,20 +742,19 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) hotplug_dock_devices(ds, event); complete_dock(ds); dock_event(ds, event, DOCK_EVENT); + dock_lock(ds, 1); + break; } - break; - case ACPI_NOTIFY_DEVICE_CHECK: - /* - * According to acpi spec 3.0a, if a DEVICE_CHECK notification - * is sent and _DCK is present, it is assumed to mean an - * undock request. This notify routine will only be called - * for objects defining _DCK, so we will fall through to eject - * request here. However, we will pass an eject request through - * to the driver who wish to hotplug. - */ + if (dock_present(ds) || dock_in_progress(ds)) + break; + /* This is a surprise removal */ + surprise_removal = 1; + event = ACPI_NOTIFY_EJECT_REQUEST; + /* Fall back */ case ACPI_NOTIFY_EJECT_REQUEST: begin_undock(ds); - if (immediate_undock) + if ((immediate_undock && !(ds->flags & DOCK_IS_ATA)) + || surprise_removal) handle_eject_request(ds, event); else dock_event(ds, event, UNDOCK_EVENT); @@ -642,6 +764,51 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) } } +struct dock_data { + acpi_handle handle; + unsigned long event; + struct dock_station *ds; +}; + +static void acpi_dock_deferred_cb(void *context) +{ + struct dock_data *data = (struct dock_data *)context; + + dock_notify(data->handle, data->event, data->ds); + kfree(data); +} + +static int acpi_dock_notifier_call(struct notifier_block *this, + unsigned long event, void *data) +{ + struct dock_station *dock_station; + acpi_handle handle = (acpi_handle)data; + + if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK + && event != ACPI_NOTIFY_EJECT_REQUEST) + return 0; + list_for_each_entry(dock_station, &dock_stations, sibiling) { + if (dock_station->handle == handle) { + struct dock_data *dock_data; + + dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); + if (!dock_data) + return 0; + dock_data->handle = handle; + dock_data->event = event; + dock_data->ds = dock_station; + acpi_os_hotplug_execute(acpi_dock_deferred_cb, + dock_data); + return 0 ; + } + } + return 0; +} + +static struct notifier_block dock_acpi_notifier = { + .notifier_call = acpi_dock_notifier_call, +}; + /** * find_dock_devices - find devices on the dock station * @handle: the handle of the device we are examining @@ -688,6 +855,8 @@ fdd_out: static ssize_t show_docked(struct device *dev, struct device_attribute *attr, char *buf) { + struct dock_station *dock_station = *((struct dock_station **) + dev->platform_data); return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); } @@ -699,6 +868,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf) { + struct dock_station *dock_station = *((struct dock_station **) + dev->platform_data); return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); } @@ -711,6 +882,8 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; + struct dock_station *dock_station = *((struct dock_station **) + dev->platform_data); if (!count) return -EINVAL; @@ -727,16 +900,38 @@ static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); static ssize_t show_dock_uid(struct device *dev, struct device_attribute *attr, char *buf) { - unsigned long lbuf; + unsigned long long lbuf; + struct dock_station *dock_station = *((struct dock_station **) + dev->platform_data); acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); if (ACPI_FAILURE(status)) return 0; - return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); + return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf); } static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); +static ssize_t show_dock_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dock_station *dock_station = *((struct dock_station **) + dev->platform_data); + char *type; + + if (dock_station->flags & DOCK_IS_DOCK) + type = "dock_station"; + else if (dock_station->flags & DOCK_IS_ATA) + type = "ata_bay"; + else if (dock_station->flags & DOCK_IS_BAT) + type = "battery_bay"; + else + type = "unknown"; + + return snprintf(buf, PAGE_SIZE, "%s\n", type); +} +static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); + /** * dock_add - add a new dock station * @handle: the dock station handle @@ -747,8 +942,9 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); static int dock_add(acpi_handle handle) { int ret; - acpi_status status; struct dock_dependent_device *dd; + struct dock_station *dock_station; + struct platform_device *dock_device; /* allocate & initialize the dock_station private data */ dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); @@ -758,22 +954,34 @@ static int dock_add(acpi_handle handle) dock_station->last_dock_time = jiffies - HZ; INIT_LIST_HEAD(&dock_station->dependent_devices); INIT_LIST_HEAD(&dock_station->hotplug_devices); + INIT_LIST_HEAD(&dock_station->sibiling); spin_lock_init(&dock_station->dd_lock); mutex_init(&dock_station->hp_lock); ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); /* initialize platform device stuff */ - dock_device = - platform_device_register_simple(dock_device_name, 0, NULL, 0); + dock_station->dock_device = + platform_device_register_simple(dock_device_name, + dock_station_count, NULL, 0); + dock_device = dock_station->dock_device; if (IS_ERR(dock_device)) { kfree(dock_station); dock_station = NULL; return PTR_ERR(dock_device); } + platform_device_add_data(dock_device, &dock_station, + sizeof(struct dock_station *)); /* we want the dock device to send uevents */ dock_device->dev.uevent_suppress = 0; + if (is_dock(handle)) + dock_station->flags |= DOCK_IS_DOCK; + if (is_ata(handle)) + dock_station->flags |= DOCK_IS_ATA; + if (is_battery(handle)) + dock_station->flags |= DOCK_IS_BAT; + ret = device_create_file(&dock_device->dev, &dev_attr_docked); if (ret) { printk("Error %d adding sysfs file\n", ret); @@ -812,6 +1020,9 @@ static int dock_add(acpi_handle handle) dock_station = NULL; return ret; } + ret = device_create_file(&dock_device->dev, &dev_attr_type); + if (ret) + printk(KERN_ERR"Error %d adding sysfs file\n", ret); /* Find dependent devices */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, @@ -828,24 +1039,12 @@ static int dock_add(acpi_handle handle) } add_dock_dependent_device(dock_station, dd); - /* register for dock events */ - status = acpi_install_notify_handler(dock_station->handle, - ACPI_SYSTEM_NOTIFY, - dock_notify, dock_station); - - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Error installing notify handler\n"); - ret = -ENODEV; - goto dock_add_err; - } - - printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION); - + dock_station_count++; + list_add(&dock_station->sibiling, &dock_stations); return 0; -dock_add_err: - kfree(dd); dock_add_err_unregister: + device_remove_file(&dock_device->dev, &dev_attr_type); device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_uid); @@ -859,12 +1058,12 @@ dock_add_err_unregister: /** * dock_remove - free up resources related to the dock station */ -static int dock_remove(void) +static int dock_remove(struct dock_station *dock_station) { struct dock_dependent_device *dd, *tmp; - acpi_status status; + struct platform_device *dock_device = dock_station->dock_device; - if (!dock_station) + if (!dock_station_count) return 0; /* remove dependent devices */ @@ -872,14 +1071,8 @@ static int dock_remove(void) list) kfree(dd); - /* remove dock notify handler */ - status = acpi_remove_notify_handler(dock_station->handle, - ACPI_SYSTEM_NOTIFY, - dock_notify); - if (ACPI_FAILURE(status)) - printk(KERN_ERR "Error removing notify handler\n"); - /* cleanup sysfs */ + device_remove_file(&dock_device->dev, &dev_attr_type); device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_uid); @@ -904,41 +1097,60 @@ static int dock_remove(void) static acpi_status find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) { - int *count = context; acpi_status status = AE_OK; if (is_dock(handle)) { if (dock_add(handle) >= 0) { - (*count)++; status = AE_CTRL_TERMINATE; } } return status; } -static int __init dock_init(void) +static acpi_status +find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) { - int num = 0; - - dock_station = NULL; + /* If bay is a dock, it's already handled */ + if (is_ejectable_bay(handle) && !is_dock(handle)) + dock_add(handle); + return AE_OK; +} +static int __init dock_init(void) +{ if (acpi_disabled) return 0; /* look for a dock station */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock, &num, NULL); + ACPI_UINT32_MAX, find_dock, NULL, NULL); - if (!num) - printk(KERN_INFO "No dock devices found.\n"); + /* look for bay */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_bay, NULL, NULL); + if (!dock_station_count) { + printk(KERN_INFO PREFIX "No dock devices found.\n"); + return 0; + } + register_acpi_bus_notifier(&dock_acpi_notifier); + printk(KERN_INFO PREFIX "%s: %d docks/bays found\n", + ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); return 0; } static void __exit dock_exit(void) { - dock_remove(); + struct dock_station *dock_station; + + unregister_acpi_bus_notifier(&dock_acpi_notifier); + list_for_each_entry(dock_station, &dock_stations, sibiling) + dock_remove(dock_station); } -postcore_initcall(dock_init); +/* + * Must be called before drivers of devices in dock, otherwise we can't know + * which devices are in a dock + */ +subsys_initcall(dock_init); module_exit(dock_exit); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 13593f9f2197..ef42316f89f5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1,7 +1,7 @@ /* - * ec.c - ACPI Embedded Controller Driver (v2.0) + * ec.c - ACPI Embedded Controller Driver (v2.1) * - * Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> + * Copyright (C) 2006-2008 Alexey Starikovskiy <astarikovskiy@suse.de> * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com> * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> @@ -26,7 +26,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/* Uncomment next line to get verbose print outs*/ +/* Uncomment next line to get verbose printout */ /* #define DEBUG */ #include <linux/kernel.h> @@ -38,6 +38,7 @@ #include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/list.h> +#include <linux/spinlock.h> #include <asm/io.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -65,22 +66,21 @@ enum ec_command { ACPI_EC_COMMAND_QUERY = 0x84, }; -/* EC events */ -enum ec_event { - ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ - ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ -}; - #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ +#define ACPI_EC_STORM_THRESHOLD 20 /* number of false interrupts + per one transaction */ + enum { - EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ EC_FLAGS_QUERY_PENDING, /* Query is pending */ - EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ + EC_FLAGS_GPE_MODE, /* Expect GPE to be sent + * for status change */ EC_FLAGS_NO_GPE, /* Don't use GPE mode */ - EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */ + EC_FLAGS_GPE_STORM, /* GPE storm detected */ + EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and + * OpReg are installed */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -95,6 +95,15 @@ struct acpi_ec_query_handler { u8 query_bit; }; +struct transaction { + const u8 *wdata; + u8 *rdata; + unsigned short irq_count; + u8 command; + u8 wlen; + u8 rlen; +}; + static struct acpi_ec { acpi_handle handle; unsigned long gpe; @@ -105,9 +114,8 @@ static struct acpi_ec { struct mutex lock; wait_queue_head_t wait; struct list_head list; - struct delayed_work work; - atomic_t irq_count; - u8 handlers_installed; + struct transaction *curr; + spinlock_t curr_lock; } *boot_ec, *first_ec; /* @@ -150,7 +158,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { u8 x = inb(ec->data_addr); pr_debug(PREFIX "---> data = 0x%2.2x\n", x); - return inb(ec->data_addr); + return x; } static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) @@ -165,158 +173,172 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) outb(data, ec->data_addr); } -static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) +static int ec_transaction_done(struct acpi_ec *ec) { - if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) - return 0; - if (event == ACPI_EC_EVENT_OBF_1) { - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) - return 1; - } else if (event == ACPI_EC_EVENT_IBF_0) { - if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) - return 1; - } - - return 0; + unsigned long flags; + int ret = 0; + spin_lock_irqsave(&ec->curr_lock, flags); + if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen)) + ret = 1; + spin_unlock_irqrestore(&ec->curr_lock, flags); + return ret; } -static void ec_schedule_ec_poll(struct acpi_ec *ec) +static void gpe_transaction(struct acpi_ec *ec, u8 status) { - if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) - schedule_delayed_work(&ec->work, - msecs_to_jiffies(ACPI_EC_DELAY)); + unsigned long flags; + spin_lock_irqsave(&ec->curr_lock, flags); + if (!ec->curr) + goto unlock; + if (ec->curr->wlen > 0) { + if ((status & ACPI_EC_FLAG_IBF) == 0) { + acpi_ec_write_data(ec, *(ec->curr->wdata++)); + --ec->curr->wlen; + } else + /* false interrupt, state didn't change */ + ++ec->curr->irq_count; + + } else if (ec->curr->rlen > 0) { + if ((status & ACPI_EC_FLAG_OBF) == 1) { + *(ec->curr->rdata++) = acpi_ec_read_data(ec); + --ec->curr->rlen; + } else + /* false interrupt, state didn't change */ + ++ec->curr->irq_count; + } +unlock: + spin_unlock_irqrestore(&ec->curr_lock, flags); } -static void ec_switch_to_poll_mode(struct acpi_ec *ec) +static int acpi_ec_wait(struct acpi_ec *ec) { + if (wait_event_timeout(ec->wait, ec_transaction_done(ec), + msecs_to_jiffies(ACPI_EC_DELAY))) + return 0; + /* missing GPEs, switch back to poll mode */ + if (printk_ratelimit()) + pr_info(PREFIX "missing confirmations, " + "switch off interrupt mode.\n"); set_bit(EC_FLAGS_NO_GPE, &ec->flags); clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); - acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); - set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); + return 1; } -static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) +static void acpi_ec_gpe_query(void *ec_cxt); + +static int ec_check_sci(struct acpi_ec *ec, u8 state) { - atomic_set(&ec->irq_count, 0); - if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && - likely(!force_poll)) { - if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), - msecs_to_jiffies(ACPI_EC_DELAY))) - return 0; - clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - if (acpi_ec_check_status(ec, event)) { - /* missing GPEs, switch back to poll mode */ - if (printk_ratelimit()) - pr_info(PREFIX "missing confirmations, " - "switch off interrupt mode.\n"); - ec_switch_to_poll_mode(ec); - ec_schedule_ec_poll(ec); - return 0; - } - } else { - unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); - clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - while (time_before(jiffies, delay)) { - if (acpi_ec_check_status(ec, event)) - return 0; - msleep(1); - } - if (acpi_ec_check_status(ec,event)) + if (state & ACPI_EC_FLAG_SCI) { + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) + return acpi_os_execute(OSL_EC_BURST_HANDLER, + acpi_ec_gpe_query, ec); + } + return 0; +} + +static int ec_poll(struct acpi_ec *ec) +{ + unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); + msleep(1); + while (time_before(jiffies, delay)) { + gpe_transaction(ec, acpi_ec_read_status(ec)); + msleep(1); + if (ec_transaction_done(ec)) return 0; } - pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", - acpi_ec_read_status(ec), - (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\""); return -ETIME; } -static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, - const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len, +static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, + struct transaction *t, int force_poll) { - int result = 0; - set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); + unsigned long tmp; + int ret = 0; pr_debug(PREFIX "transaction start\n"); - acpi_ec_write_cmd(ec, command); - for (; wdata_len > 0; --wdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); - if (result) { - pr_err(PREFIX - "write_cmd timeout, command = %d\n", command); - goto end; - } - set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - acpi_ec_write_data(ec, *(wdata++)); + /* disable GPE during transaction if storm is detected */ + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); + acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); } - - if (!rdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); - if (result) { - pr_err(PREFIX - "finish-write timeout, command = %d\n", command); - goto end; - } - } else if (command == ACPI_EC_COMMAND_QUERY) + /* start transaction */ + spin_lock_irqsave(&ec->curr_lock, tmp); + /* following two actions should be kept atomic */ + t->irq_count = 0; + ec->curr = t; + acpi_ec_write_cmd(ec, ec->curr->command); + if (ec->curr->command == ACPI_EC_COMMAND_QUERY) clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - - for (; rdata_len > 0; --rdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); - if (result) { - pr_err(PREFIX "read timeout, command = %d\n", command); - goto end; - } - /* Don't expect GPE after last read */ - if (rdata_len > 1) - set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - *(rdata++) = acpi_ec_read_data(ec); - } - end: + spin_unlock_irqrestore(&ec->curr_lock, tmp); + /* if we selected poll mode or failed in GPE-mode do a poll loop */ + if (force_poll || + !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) || + acpi_ec_wait(ec)) + ret = ec_poll(ec); pr_debug(PREFIX "transaction end\n"); - return result; + spin_lock_irqsave(&ec->curr_lock, tmp); + ec->curr = NULL; + spin_unlock_irqrestore(&ec->curr_lock, tmp); + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + /* check if we received SCI during transaction */ + ec_check_sci(ec, acpi_ec_read_status(ec)); + /* it is safe to enable GPE outside of transaction */ + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && + t->irq_count > ACPI_EC_STORM_THRESHOLD) { + pr_debug(PREFIX "GPE storm detected\n"); + set_bit(EC_FLAGS_GPE_STORM, &ec->flags); + } + return ret; +} + +static int ec_check_ibf0(struct acpi_ec *ec) +{ + u8 status = acpi_ec_read_status(ec); + return (status & ACPI_EC_FLAG_IBF) == 0; } -static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, - const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len, +static int ec_wait_ibf0(struct acpi_ec *ec) +{ + unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); + /* interrupt wait manually if GPE mode is not active */ + unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ? + msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1); + while (time_before(jiffies, delay)) + if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout)) + return 0; + return -ETIME; +} + +static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t, int force_poll) { int status; u32 glk; - - if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) + if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) return -EINVAL; - - if (rdata) - memset(rdata, 0, rdata_len); - + if (t->rdata) + memset(t->rdata, 0, t->rlen); mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) { - mutex_unlock(&ec->lock); - return -ENODEV; + status = -ENODEV; + goto unlock; } } - - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); - if (status) { + if (ec_wait_ibf0(ec)) { pr_err(PREFIX "input buffer is not empty, " "aborting transaction\n"); + status = -ETIME; goto end; } - - status = acpi_ec_transaction_unlocked(ec, command, - wdata, wdata_len, - rdata, rdata_len, - force_poll); - - end: - + status = acpi_ec_transaction_unlocked(ec, t, force_poll); +end: if (ec->global_lock) acpi_release_global_lock(glk); +unlock: mutex_unlock(&ec->lock); - return status; } @@ -327,21 +349,32 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, int acpi_ec_burst_enable(struct acpi_ec *ec) { u8 d; - return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0); + struct transaction t = {.command = ACPI_EC_BURST_ENABLE, + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; + + return acpi_ec_transaction(ec, &t, 0); } int acpi_ec_burst_disable(struct acpi_ec *ec) { - return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0); + struct transaction t = {.command = ACPI_EC_BURST_DISABLE, + .wdata = NULL, .rdata = NULL, + .wlen = 0, .rlen = 0}; + + return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? + acpi_ec_transaction(ec, &t, 0) : 0; } static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) { int result; u8 d; + struct transaction t = {.command = ACPI_EC_COMMAND_READ, + .wdata = &address, .rdata = &d, + .wlen = 1, .rlen = 1}; - result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, - &address, 1, &d, 1, 0); + result = acpi_ec_transaction(ec, &t, 0); *data = d; return result; } @@ -349,8 +382,11 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { u8 wdata[2] = { address, data }; - return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, - wdata, 2, NULL, 0, 0); + struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, + .wdata = wdata, .rdata = NULL, + .wlen = 2, .rlen = 0}; + + return acpi_ec_transaction(ec, &t, 0); } /* @@ -412,12 +448,13 @@ int ec_transaction(u8 command, u8 * rdata, unsigned rdata_len, int force_poll) { + struct transaction t = {.command = command, + .wdata = wdata, .rdata = rdata, + .wlen = wdata_len, .rlen = rdata_len}; if (!first_ec) return -ENODEV; - return acpi_ec_transaction(first_ec, command, wdata, - wdata_len, rdata, rdata_len, - force_poll); + return acpi_ec_transaction(first_ec, &t, force_poll); } EXPORT_SYMBOL(ec_transaction); @@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) { int result; u8 d; - + struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; if (!ec || !data) return -EINVAL; @@ -436,7 +475,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) * bit to be cleared (and thus clearing the interrupt source). */ - result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0); + result = acpi_ec_transaction(ec, &t, 0); if (result) return result; @@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt) static u32 acpi_ec_gpe_handler(void *data) { - acpi_status status = AE_OK; struct acpi_ec *ec = data; - u8 state = acpi_ec_read_status(ec); + u8 status; pr_debug(PREFIX "~~~> interrupt\n"); - atomic_inc(&ec->irq_count); - if (atomic_read(&ec->irq_count) > 5) { - pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); - ec_switch_to_poll_mode(ec); - goto end; - } - clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) + status = acpi_ec_read_status(ec); + + gpe_transaction(ec, status); + if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) wake_up(&ec->wait); - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - status = acpi_os_execute(OSL_EC_BURST_HANDLER, - acpi_ec_gpe_query, ec); - } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && - !test_bit(EC_FLAGS_NO_GPE, &ec->flags) && - in_interrupt()) { + ec_check_sci(ec, status); + if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && + !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) { /* this is non-query, must be confirmation */ if (printk_ratelimit()) pr_info(PREFIX "non-query interrupt received," " switching to interrupt mode\n"); set_bit(EC_FLAGS_GPE_MODE, &ec->flags); - clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); } -end: - ec_schedule_ec_poll(ec); - return ACPI_SUCCESS(status) ? - ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; -} - -static void do_ec_poll(struct work_struct *work) -{ - struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); - atomic_set(&ec->irq_count, 0); - (void)acpi_ec_gpe_handler(ec); + return ACPI_INTERRUPT_HANDLED; } /* -------------------------------------------------------------------------- @@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void) mutex_init(&ec->lock); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); - INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); - atomic_set(&ec->irq_count, 0); + spin_lock_init(&ec->curr_lock); return ec; } @@ -718,6 +736,7 @@ static acpi_status ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) { acpi_status status; + unsigned long long tmp; struct acpi_ec *ec = context; status = acpi_walk_resources(handle, METHOD_NAME__CRS, @@ -727,31 +746,26 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) /* Get GPE bit assignment (EC events). */ /* TODO: Add support for _GPE returning a package */ - status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); if (ACPI_FAILURE(status)) return status; + ec->gpe = tmp; /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); + acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); + ec->global_lock = tmp; ec->handle = handle; return AE_CTRL_TERMINATE; } -static void ec_poll_stop(struct acpi_ec *ec) -{ - clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); - cancel_delayed_work(&ec->work); -} - static void ec_remove_handlers(struct acpi_ec *ec) { - ec_poll_stop(ec); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err(PREFIX "failed to remove space handler\n"); if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler))) pr_err(PREFIX "failed to remove gpe handler\n"); - ec->handlers_installed = 0; + clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); } static int acpi_ec_add(struct acpi_device *device) @@ -788,7 +802,7 @@ static int acpi_ec_add(struct acpi_device *device) if (!first_ec) first_ec = ec; - acpi_driver_data(device) = ec; + device->driver_data = ec; acpi_ec_add_fs(device); pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); @@ -813,7 +827,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type) } mutex_unlock(&ec->lock); acpi_ec_remove_fs(device); - acpi_driver_data(device) = NULL; + device->driver_data = NULL; if (ec == first_ec) first_ec = NULL; kfree(ec); @@ -846,27 +860,36 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) static int ec_install_handlers(struct acpi_ec *ec) { acpi_status status; - if (ec->handlers_installed) + if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return 0; status = acpi_install_gpe_handler(NULL, ec->gpe, - ACPI_GPE_EDGE_TRIGGERED, - &acpi_ec_gpe_handler, ec); + ACPI_GPE_EDGE_TRIGGERED, + &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) return -ENODEV; - acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); - status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, NULL, ec); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); - return -ENODEV; + if (status == AE_NOT_FOUND) { + /* + * Maybe OS fails in evaluating the _REG object. + * The AE_NOT_FOUND error will be ignored and OS + * continue to initialize EC. + */ + printk(KERN_ERR "Fail in evaluating the _REG object" + " of EC device. Broken bios is suspected.\n"); + } else { + acpi_remove_gpe_handler(NULL, ec->gpe, + &acpi_ec_gpe_handler); + return -ENODEV; + } } - ec->handlers_installed = 1; + set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); return 0; } @@ -887,7 +910,6 @@ static int acpi_ec_start(struct acpi_device *device) /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - ec_schedule_ec_poll(ec); return ret; } @@ -906,7 +928,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) int __init acpi_boot_ec_enable(void) { - if (!boot_ec || boot_ec->handlers_installed) + if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) return 0; if (!ec_install_handlers(boot_ec)) { first_ec = boot_ec; diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 8892b9824fae..4c512c2990e5 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -96,8 +96,7 @@ acpi_ex_add_table(u32 table_index, /* Install the new table into the local data structures */ - obj_desc->reference.object = ACPI_CAST_PTR(void, - (unsigned long)table_index); + obj_desc->reference.object = ACPI_TO_POINTER(table_index); /* Add the table to the namespace */ @@ -280,6 +279,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *ddb_handle; + struct acpi_table_header *table; struct acpi_table_desc table_desc; u32 table_index; acpi_status status; @@ -294,9 +294,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", - obj_desc, - acpi_ut_get_object_type_name(obj_desc))); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Load table from Region %p\n", obj_desc)); /* Region must be system_memory (from ACPI spec) */ @@ -316,61 +315,112 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } /* - * We will simply map the memory region for the table. However, the - * memory region is technically not guaranteed to remain stable and - * we may eventually have to copy the table to a local buffer. + * Map the table header and get the actual table length. The region + * length is not guaranteed to be the same as the table length. + */ + table = acpi_os_map_memory(obj_desc->region.address, + sizeof(struct acpi_table_header)); + if (!table) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + length = table->length; + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + + /* Must have at least an ACPI table header */ + + if (length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } + + /* + * The memory region is not guaranteed to remain stable and we must + * copy the table to a local buffer. For example, the memory region + * is corrupted after suspend on some machines. Dynamically loaded + * tables are usually small, so this overhead is minimal. */ + + /* Allocate a buffer for the table */ + + table_desc.pointer = ACPI_ALLOCATE(length); + if (!table_desc.pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Map the entire table and copy it */ + + table = acpi_os_map_memory(obj_desc->region.address, length); + if (!table) { + ACPI_FREE(table_desc.pointer); + return_ACPI_STATUS(AE_NO_MEMORY); + } + + ACPI_MEMCPY(table_desc.pointer, table, length); + acpi_os_unmap_memory(table, length); + table_desc.address = obj_desc->region.address; - table_desc.length = obj_desc->region.length; - table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; break; case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Load from Buffer or Field %p %s\n", obj_desc, - acpi_ut_get_object_type_name(obj_desc))); - - length = obj_desc->buffer.length; + "Load table from Buffer or Field %p\n", + obj_desc)); /* Must have at least an ACPI table header */ - if (length < sizeof(struct acpi_table_header)) { + if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) { return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); } - /* Validate checksum here. It won't get validated in tb_add_table */ + /* Get the actual table length from the table header */ - status = - acpi_tb_verify_checksum(ACPI_CAST_PTR - (struct acpi_table_header, - obj_desc->buffer.pointer), length); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + table = + ACPI_CAST_PTR(struct acpi_table_header, + obj_desc->buffer.pointer); + length = table->length; + + /* Table cannot extend beyond the buffer */ + + if (length > obj_desc->buffer.length) { + return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); + } + if (length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); } /* - * We need to copy the buffer since the original buffer could be - * changed or deleted in the future + * Copy the table from the buffer because the buffer could be modified + * or even deleted in the future */ table_desc.pointer = ACPI_ALLOCATE(length); if (!table_desc.pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer, - length); - table_desc.length = length; - table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; + ACPI_MEMCPY(table_desc.pointer, table, length); + table_desc.address = ACPI_TO_INTEGER(table_desc.pointer); break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* - * Install the new table into the local data structures - */ + /* Validate table checksum (will not get validated in tb_add_table) */ + + status = acpi_tb_verify_checksum(table_desc.pointer, length); + if (ACPI_FAILURE(status)) { + ACPI_FREE(table_desc.pointer); + return_ACPI_STATUS(status); + } + + /* Complete the table descriptor */ + + table_desc.length = length; + table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; + + /* Install the new table into the local data structures */ + status = acpi_tb_add_table(&table_desc, &table_index); if (ACPI_FAILURE(status)) { goto cleanup; @@ -379,7 +429,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* * Add the table to the namespace. * - * Note: We load the table objects relative to the root of the namespace. + * Note: Load the table objects relative to the root of the namespace. * This appears to go against the ACPI specification, but we do it for * compatibility with other ACPI implementations. */ @@ -415,7 +465,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, cleanup: if (ACPI_FAILURE(status)) { - /* Delete allocated buffer or mapping */ + /* Delete allocated table buffer */ acpi_tb_delete_table(&table_desc); } diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 2655bc1b4eeb..1800aa09ff61 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -265,7 +265,7 @@ static int acpi_fan_add(struct acpi_device *device) dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id); - acpi_driver_data(device) = cdev; + device->driver_data = cdev; result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, "thermal_cooling"); @@ -327,8 +327,8 @@ static int acpi_fan_resume(struct acpi_device *device) result = acpi_bus_get_power(device->handle, &power_state); if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error reading fan power state\n")); + printk(KERN_ERR "Error reading fan power state [%d]\n", + result); return result; } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index dba3cfbe8cba..25dccdf179b9 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -78,19 +78,17 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address) return_ACPI_STATUS(status); } - /* Set the vector */ + /* + * According to the ACPI specification 2.0c and later, the 64-bit + * waking vector should be cleared and the 32-bit waking vector should + * be used, unless we want the wake-up code to be called by the BIOS in + * Protected Mode. Some systems (for example HP dv5-1004nr) are known + * to fail to resume if the 64-bit vector is used. + */ + if (facs->version >= 1) + facs->xfirmware_waking_vector = 0; - if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { - /* - * ACPI 1.0 FACS or short table or optional X_ field is zero - */ - facs->firmware_waking_vector = (u32) physical_address; - } else { - /* - * ACPI 2.0 FACS with valid X_ field - */ - facs->xfirmware_waking_vector = physical_address; - } + facs->firmware_waking_vector = (u32)physical_address; return_ACPI_STATUS(AE_OK); } @@ -134,20 +132,7 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) } /* Get the vector */ - - if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { - /* - * ACPI 1.0 FACS or short table or optional X_ field is zero - */ - *physical_address = - (acpi_physical_address) facs->firmware_waking_vector; - } else { - /* - * ACPI 2.0 FACS with valid X_ field - */ - *physical_address = - (acpi_physical_address) facs->xfirmware_waking_vector; - } + *physical_address = (acpi_physical_address)facs->firmware_waking_vector; return_ACPI_STATUS(AE_OK); } @@ -627,6 +612,13 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) } /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ + /* + * Some BIOSes assume that WAK_STS will be cleared on resume and use + * it to determine whether the system is rebooting or resuming. Clear + * it for compatibility. + */ + acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + acpi_gbl_system_awake_and_running = TRUE; /* Enable power button */ diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 38be5865d95d..f3cc37624537 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -45,9 +45,14 @@ #include <acpi/acpi.h> #include <acpi/acnamesp.h> #include <acpi/acinterp.h> +#include <acpi/amlcode.h> #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfeval") + +/* Local prototypes */ +static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); + #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -69,6 +74,7 @@ ACPI_MODULE_NAME("nsxfeval") * be valid (non-null) * ******************************************************************************/ + acpi_status acpi_evaluate_object_typed(acpi_handle handle, acpi_string pathname, @@ -283,6 +289,10 @@ acpi_evaluate_object(acpi_handle handle, if (ACPI_SUCCESS(status)) { + /* Dereference Index and ref_of references */ + + acpi_ns_resolve_references(info); + /* Get the size of the returned object */ status = @@ -352,6 +362,74 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object) /******************************************************************************* * + * FUNCTION: acpi_ns_resolve_references + * + * PARAMETERS: Info - Evaluation info block + * + * RETURN: Info->return_object is replaced with the dereferenced object + * + * DESCRIPTION: Dereference certain reference objects. Called before an + * internal return object is converted to an external union acpi_object. + * + * Performs an automatic dereference of Index and ref_of reference objects. + * These reference objects are not supported by the union acpi_object, so this is a + * last resort effort to return something useful. Also, provides compatibility + * with other ACPI implementations. + * + * NOTE: does not handle references within returned package objects or nested + * references, but this support could be added later if found to be necessary. + * + ******************************************************************************/ +static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) +{ + union acpi_operand_object *obj_desc = NULL; + struct acpi_namespace_node *node; + + /* We are interested in reference objects only */ + + if (ACPI_GET_OBJECT_TYPE(info->return_object) != + ACPI_TYPE_LOCAL_REFERENCE) { + return; + } + + /* + * Two types of references are supported - those created by Index and + * ref_of operators. A name reference (AML_NAMEPATH_OP) can be converted + * to an union acpi_object, so it is not dereferenced here. A ddb_handle + * (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to + * an union acpi_object. + */ + switch (info->return_object->reference.opcode) { + case AML_INDEX_OP: + + obj_desc = *(info->return_object->reference.where); + break; + + case AML_REF_OF_OP: + + node = info->return_object->reference.object; + if (node) { + obj_desc = node->object; + } + break; + + default: + return; + } + + /* Replace the existing reference object */ + + if (obj_desc) { + acpi_ut_add_reference(obj_desc); + acpi_ut_remove_reference(info->return_object); + info->return_object = obj_desc; + } + + return; +} + +/******************************************************************************* + * * FUNCTION: acpi_walk_namespace * * PARAMETERS: Type - acpi_object_type to search for @@ -379,6 +457,7 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object) * function, etc. * ******************************************************************************/ + acpi_status acpi_walk_namespace(acpi_object_type type, acpi_handle start_object, diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index a287ed550f54..5efa4e7ddb0b 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -253,6 +253,7 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + status = AE_BAD_PARAMETER; goto cleanup; } @@ -264,6 +265,10 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) info->name = node->name.integer; info->valid = 0; + if (node->type == ACPI_TYPE_METHOD) { + info->param_count = node->object->method.param_count; + } + status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index cb9864e39bae..25ceae9191ef 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -258,7 +258,7 @@ int __init acpi_numa_init(void) int acpi_get_pxm(acpi_handle h) { - unsigned long pxm; + unsigned long long pxm; acpi_status status; acpi_handle handle; acpi_handle phandle = h; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 235a1386888a..a384155c3143 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -608,7 +608,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ acpi_handle handle; struct acpi_pci_id *pci_id = *id; acpi_status status; - unsigned long temp; + unsigned long long temp; acpi_object_type type; acpi_get_parent(chandle, &handle); @@ -620,8 +620,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE)) return; - status = - acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &temp); if (ACPI_SUCCESS(status)) { u32 val; @@ -682,6 +681,22 @@ static void acpi_os_execute_deferred(struct work_struct *work) return; } +static void acpi_os_execute_hp_deferred(struct work_struct *work) +{ + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); + if (!dpc) { + printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); + return; + } + + acpi_os_wait_events_complete(NULL); + + dpc->function(dpc->context); + kfree(dpc); + + return; +} + /******************************************************************************* * * FUNCTION: acpi_os_execute @@ -697,12 +712,13 @@ static void acpi_os_execute_deferred(struct work_struct *work) * ******************************************************************************/ -acpi_status acpi_os_execute(acpi_execute_type type, - acpi_osd_exec_callback function, void *context) +static acpi_status __acpi_os_execute(acpi_execute_type type, + acpi_osd_exec_callback function, void *context, int hp) { acpi_status status = AE_OK; struct acpi_os_dpc *dpc; struct workqueue_struct *queue; + int ret; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); @@ -726,19 +742,38 @@ acpi_status acpi_os_execute(acpi_execute_type type, dpc->function = function; dpc->context = context; - INIT_WORK(&dpc->work, acpi_os_execute_deferred); - queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq; - if (!queue_work(queue, &dpc->work)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Call to queue_work() failed.\n")); + if (!hp) { + INIT_WORK(&dpc->work, acpi_os_execute_deferred); + queue = (type == OSL_NOTIFY_HANDLER) ? + kacpi_notify_wq : kacpid_wq; + ret = queue_work(queue, &dpc->work); + } else { + INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred); + ret = schedule_work(&dpc->work); + } + + if (!ret) { + printk(KERN_ERR "Call to queue_work() failed.\n"); status = AE_ERROR; kfree(dpc); } return_ACPI_STATUS(status); } +acpi_status acpi_os_execute(acpi_execute_type type, + acpi_osd_exec_callback function, void *context) +{ + return __acpi_os_execute(type, function, context, 0); +} EXPORT_SYMBOL(acpi_os_execute); +acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, + void *context) +{ + return __acpi_os_execute(0, function, context, 1); +} +EXPORT_SYMBOL(acpi_os_hotplug_execute); + void acpi_os_wait_events_complete(void *context) { flush_workqueue(kacpid_wq); diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index c06238e55d98..4647039a0d8a 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -719,6 +719,8 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, *op = NULL; } + ACPI_PREEMPTION_POINT(); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index cf47805a7448..fcfdef7b4fdd 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -709,7 +709,7 @@ int acpi_pci_link_free_irq(acpi_handle handle) acpi_device_bid(link->device))); if (link->refcnt == 0) { - acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL); + acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL); } mutex_unlock(&acpi_link_lock); return (link->irq.active); @@ -737,7 +737,7 @@ static int acpi_pci_link_add(struct acpi_device *device) link->device = device; strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); - acpi_driver_data(device) = link; + device->driver_data = link; mutex_lock(&acpi_link_lock); result = acpi_pci_link_get_possible(link); @@ -773,7 +773,7 @@ static int acpi_pci_link_add(struct acpi_device *device) end: /* disable all links -- to be activated on use */ - acpi_ut_evaluate_object(device->handle, "_DIS", 0, NULL); + acpi_evaluate_object(device->handle, "_DIS", NULL, NULL); mutex_unlock(&acpi_link_lock); if (result) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c3fed31166b5..1b8f67d21d53 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -190,7 +190,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) struct acpi_pci_root *root = NULL; struct acpi_pci_root *tmp; acpi_status status = AE_OK; - unsigned long value = 0; + unsigned long long value = 0; acpi_handle handle = NULL; struct acpi_device *child; @@ -206,7 +206,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) root->device = device; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); - acpi_driver_data(device) = root; + device->driver_data = root; device->ops.bind = acpi_pci_bind; diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index d5b4ef898879..9bb84d4596be 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -76,10 +76,10 @@ static struct acpi_pci_driver acpi_pci_slot_driver = { }; static int -check_slot(acpi_handle handle, unsigned long *sun) +check_slot(acpi_handle handle, unsigned long long *sun) { int device = -1; - unsigned long adr, sta; + unsigned long long adr, sta; acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -132,7 +132,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) { int device; - unsigned long sun; + unsigned long long sun; char name[SLOT_NAME_SIZE]; struct acpi_pci_slot *slot; struct pci_slot *pci_slot; @@ -182,7 +182,7 @@ static acpi_status walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) { int device, function; - unsigned long adr; + unsigned long long adr; acpi_status status; acpi_handle dummy_handle; acpi_walk_callback user_function; @@ -239,7 +239,7 @@ static int walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) { int seg, bus; - unsigned long tmp; + unsigned long long tmp; acpi_status status; acpi_handle dummy_handle; struct pci_bus *pci_bus; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 4ab21cb1c8c7..a1718e56103b 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -54,6 +54,14 @@ ACPI_MODULE_NAME("power"); #define ACPI_POWER_RESOURCE_STATE_OFF 0x00 #define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "acpi." +int acpi_power_nocheck; +module_param_named(power_nocheck, acpi_power_nocheck, bool, 000); + static int acpi_power_add(struct acpi_device *device); static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_resume(struct acpi_device *device); @@ -128,16 +136,16 @@ acpi_power_get_context(acpi_handle handle, return 0; } -static int acpi_power_get_state(struct acpi_power_resource *resource, int *state) +static int acpi_power_get_state(acpi_handle handle, int *state) { acpi_status status = AE_OK; - unsigned long sta = 0; + unsigned long long sta = 0; - if (!resource || !state) + if (!handle || !state) return -EINVAL; - status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); if (ACPI_FAILURE(status)) return -ENODEV; @@ -145,7 +153,7 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state ACPI_POWER_RESOURCE_STATE_OFF; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", - resource->name, state ? "on" : "off")); + acpi_ut_get_node_name(handle), state ? "on" : "off")); return 0; } @@ -153,7 +161,6 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) { int result = 0, state1; - struct acpi_power_resource *resource = NULL; u32 i = 0; @@ -161,12 +168,15 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) return -EINVAL; /* The state of the list is 'on' IFF all resources are 'on'. */ + /* */ for (i = 0; i < list->count; i++) { - result = acpi_power_get_context(list->handles[i], &resource); - if (result) - return result; - result = acpi_power_get_state(resource, &state1); + /* + * The state of the power resource can be obtained by + * using the ACPI handle. In such case it is unnecessary to + * get the Power resource first and then get its state again. + */ + result = acpi_power_get_state(list->handles[i], &state1); if (result) return result; @@ -226,12 +236,18 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) if (ACPI_FAILURE(status)) return -ENODEV; - result = acpi_power_get_state(resource, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_ON) - return -ENOEXEC; - + if (!acpi_power_nocheck) { + /* + * If acpi_power_nocheck is set, it is unnecessary to check + * the power state after power transition. + */ + result = acpi_power_get_state(resource->device->handle, + &state); + if (result) + return result; + if (state != ACPI_POWER_RESOURCE_STATE_ON) + return -ENOEXEC; + } /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D0; @@ -277,11 +293,17 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) if (ACPI_FAILURE(status)) return -ENODEV; - result = acpi_power_get_state(resource, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_OFF) - return -ENOEXEC; + if (!acpi_power_nocheck) { + /* + * If acpi_power_nocheck is set, it is unnecessary to check + * the power state after power transition. + */ + result = acpi_power_get_state(handle, &state); + if (result) + return result; + if (state != ACPI_POWER_RESOURCE_STATE_OFF) + return -ENOEXEC; + } /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D3; @@ -555,7 +577,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) if (!resource) goto end; - result = acpi_power_get_state(resource, &state); + result = acpi_power_get_state(resource->device->handle, &state); if (result) goto end; @@ -657,7 +679,7 @@ static int acpi_power_add(struct acpi_device *device) strcpy(resource->name, device->pnp.bus_id); strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_POWER_CLASS); - acpi_driver_data(device) = resource; + device->driver_data = resource; /* Evalute the object to get the system level and resource order. */ status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer); @@ -668,7 +690,7 @@ static int acpi_power_add(struct acpi_device *device) resource->system_level = acpi_object.power_resource.system_level; resource->order = acpi_object.power_resource.resource_order; - result = acpi_power_get_state(resource, &state); + result = acpi_power_get_state(device->handle, &state); if (result) goto end; @@ -733,9 +755,9 @@ static int acpi_power_resume(struct acpi_device *device) if (!device || !acpi_driver_data(device)) return -EINVAL; - resource = (struct acpi_power_resource *)acpi_driver_data(device); + resource = acpi_driver_data(device); - result = acpi_power_get_state(resource, &state); + result = acpi_power_get_state(device->handle, &state); if (result) return result; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index ee68ac54c0d4..24a362f8034c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -563,7 +563,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid) /* Check if it is a Device with HID and UID */ if (has_uid) { - unsigned long value; + unsigned long long value; status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, NULL, &value); if (ACPI_FAILURE(status)) { @@ -818,7 +818,7 @@ static int acpi_processor_add(struct acpi_device *device) pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); - acpi_driver_data(device) = pr; + device->driver_data = pr; return 0; } @@ -875,7 +875,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type) static int is_processor_present(acpi_handle handle) { acpi_status status; - unsigned long sta = 0; + unsigned long long sta = 0; status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index cf5b1b7b684f..81b40ed5379e 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1587,6 +1587,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (acpi_idle_bm_check()) { if (dev->safe_state) { + dev->last_state = dev->safe_state; return dev->safe_state->enter(dev, dev->safe_state); } else { local_irq_disable(); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 80c251ec6d2a..751f9b3d39d9 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -38,6 +38,7 @@ #include <asm/uaccess.h> #endif +#include <asm/cpufeature.h> #include <acpi/acpi_bus.h> #include <acpi/processor.h> @@ -126,7 +127,7 @@ static struct notifier_block acpi_ppc_notifier_block = { static int acpi_processor_get_platform_limit(struct acpi_processor *pr) { acpi_status status = 0; - unsigned long ppc = 0; + unsigned long long ppc = 0; if (!pr) @@ -334,7 +335,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) acpi_status status = AE_OK; acpi_handle handle = NULL; - if (!pr || !pr->performance || !pr->handle) return -EINVAL; @@ -347,13 +347,25 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) result = acpi_processor_get_performance_control(pr); if (result) - return result; + goto update_bios; result = acpi_processor_get_performance_states(pr); if (result) - return result; + goto update_bios; return 0; + + /* + * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that + * the BIOS is older than the CPU and does not know its frequencies + */ + update_bios: + if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){ + if(boot_cpu_has(X86_FEATURE_EST)) + printk(KERN_WARNING FW_BUG "BIOS needs update for CPU " + "frequency support\n"); + } + return result; } int acpi_processor_notify_smm(struct module *calling_module) @@ -523,14 +535,9 @@ static int acpi_processor_get_psd(struct acpi_processor *pr) } psd = buffer.pointer; - if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); - result = -EFAULT; - goto end; - } - - if (psd->package.count != 1) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); + if (!psd || (psd->type != ACPI_TYPE_PACKAGE) + || psd->package.count != 1) { + printk(KERN_ERR "Invalid _PSD data\n"); result = -EFAULT; goto end; } @@ -543,19 +550,19 @@ static int acpi_processor_get_psd(struct acpi_processor *pr) status = acpi_extract_package(&(psd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); + ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSD data")); result = -EFAULT; goto end; } if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); + printk(KERN_ERR "Unknown _PSD:num_entries\n"); result = -EFAULT; goto end; } if (pdomain->revision != ACPI_PSD_REV0_REVISION) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); + printk(KERN_ERR "Unknown _PSD:revision\n"); result = -EFAULT; goto end; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index a56fc6c4394b..29608372aed8 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -274,7 +274,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data) static int acpi_processor_get_platform_limit(struct acpi_processor *pr) { acpi_status status = 0; - unsigned long tpc = 0; + unsigned long long tpc = 0; if (!pr) return -EINVAL; @@ -527,14 +527,9 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr) } tsd = buffer.pointer; - if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); - result = -EFAULT; - goto end; - } - - if (tsd->package.count != 1) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); + if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE) + || tsd->package.count != 1) { + printk(KERN_INFO "Invalid _TSD data\n"); result = -EFAULT; goto end; } @@ -547,19 +542,19 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr) status = acpi_extract_package(&(tsd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); + ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSD data")); result = -EFAULT; goto end; } if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n")); + printk(KERN_ERR "Unknown _TSD:num_entries\n"); result = -EFAULT; goto end; } if (pdomain->revision != ACPI_TSD_REV0_REVISION) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n")); + printk(KERN_ERR "Unknown _TSD:revision\n"); result = -EFAULT; goto end; } diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6b662c00b67..755baf2ca70a 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -15,9 +15,28 @@ void acpi_reboot(void) rr = &acpi_gbl_FADT.reset_register; - /* Is the reset register supported? */ - if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || - rr->bit_width != 8 || rr->bit_offset != 0) + /* + * Is the ACPI reset register supported? + * + * According to ACPI 3.0, FADT.flags.RESET_REG_SUP indicates + * whether the ACPI reset mechanism is supported. + * + * However, some boxes have this bit clear, yet a valid + * ACPI_RESET_REG & RESET_VALUE, and ACPI reboot is the only + * mechanism that works for them after S3. + * + * This suggests that other operating systems may not be checking + * the RESET_REG_SUP bit, and are using other means to decide + * whether to use the ACPI reboot mechanism or not. + * + * So when acpi reboot is requested, + * only the reset_register is checked. If the following + * conditions are met, it indicates that the reset register is supported. + * a. reset_register is not zero + * b. the access width is eight + * c. the bit_offset is zero + */ + if (!(rr->address) || rr->bit_width != 8 || rr->bit_offset != 0) return; reset_value = acpi_gbl_FADT.reset_value; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 10a36512647c..d0033250b5a9 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -931,7 +931,7 @@ static int acpi_sbs_add(struct acpi_device *device) sbs->device = device; strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_SBS_CLASS); - acpi_driver_data(device) = sbs; + device->driver_data = sbs; result = acpi_charger_add(sbs); if (result) diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index a4e3767b8c64..e53e590252c0 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -258,7 +258,7 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, static int acpi_smbus_hc_add(struct acpi_device *device) { int status; - unsigned long val; + unsigned long long val; struct acpi_smb_hc *hc; if (!device) @@ -282,7 +282,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device) hc->ec = acpi_driver_data(device->parent); hc->offset = (val >> 8) & 0xff; hc->query_bit = val & 0xff; - acpi_driver_data(device) = hc; + device->driver_data = hc; acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", @@ -303,7 +303,7 @@ static int acpi_smbus_hc_remove(struct acpi_device *device, int type) hc = acpi_driver_data(device); acpi_ec_remove_query_handler(hc->ec, hc->query_bit); kfree(hc); - acpi_driver_data(device) = NULL; + device->driver_data = NULL; return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e7b8853c310b..f209a2ee21c4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -113,16 +113,16 @@ static int acpi_bus_hot_remove_device(void *context) if (acpi_bus_trim(device, 1)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Removing device failed\n")); + printk(KERN_ERR "Removing device [%s] failed\n", + acpi_device_bid(device)); return -1; } /* power off device */ status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Power-off device failed\n")); + ACPI_EXCEPTION((AE_INFO, status, + "Power-off device failed")); if (device->flags.lockable) { arg_list.count = 1; @@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device, { const struct acpi_device_id *id; + /* + * If the device is not present, it is unnecessary to load device + * driver for it. + */ + if (!device->status.present) + return -ENODEV; + if (device->flags.hardware_id) { for (id = ids; id->id[0]; id++) { if (!strcmp((char*)id->id, device->pnp.hardware_id)) @@ -384,7 +391,7 @@ static int acpi_device_remove(struct device * dev) acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); } acpi_dev->driver = NULL; - acpi_driver_data(acpi_dev) = NULL; + acpi_dev->driver_data = NULL; put_device(dev); return 0; @@ -477,7 +484,8 @@ static int acpi_device_register(struct acpi_device *device, result = acpi_device_setup_files(device); if(result) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id)); + printk(KERN_ERR "Error creating sysfs interface for device" + " %s [%d]\n", device->dev.bus_id, result); device->removal_type = ACPI_BUS_REMOVAL_NORMAL; return 0; @@ -537,7 +545,7 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) result = driver->ops.add(device); if (result) { device->driver = NULL; - acpi_driver_data(device) = NULL; + device->driver_data = NULL; return result; } @@ -744,6 +752,16 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) if (!acpi_match_device_ids(device, button_device_ids)) device->wakeup.flags.run_wake = 1; + /* + * Don't set Power button GPE as run_wake + * if Fixed Power button is used + */ + if (!strcmp(device->pnp.hardware_id, "PNP0C0C") && + !(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) { + device->wakeup.flags.run_wake = 0; + device->wakeup.flags.valid = 0; + } + end: if (ACPI_FAILURE(status)) device->flags.wake_capable = 0; @@ -807,6 +825,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) /* TBD: System wake support and resource requirements. */ device->power.state = ACPI_STATE_UNKNOWN; + acpi_bus_get_power(device->handle, &(device->power.state)); return 0; } @@ -1153,20 +1172,6 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) } static int -acpi_is_child_device(struct acpi_device *device, - int (*matcher)(struct acpi_device *)) -{ - int result = -ENODEV; - - do { - if (ACPI_SUCCESS(matcher(device))) - return AE_OK; - } while ((device = device->parent)); - - return result; -} - -static int acpi_add_single_object(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type, struct acpi_bus_ops *ops) @@ -1221,15 +1226,18 @@ acpi_add_single_object(struct acpi_device **child, result = -ENODEV; goto end; } - if (!device->status.present) { - /* Bay and dock should be handled even if absent */ - if (!ACPI_SUCCESS( - acpi_is_child_device(device, acpi_bay_match)) && - !ACPI_SUCCESS( - acpi_is_child_device(device, acpi_dock_match))) { - result = -ENODEV; - goto end; - } + /* + * When the device is neither present nor functional, the + * device should not be added to Linux ACPI device tree. + * When the status of the device is not present but functinal, + * it should be added to Linux ACPI tree. For example : bay + * device , dock device. + * In such conditions it is unncessary to check whether it is + * bay device or dock device. + */ + if (!device->status.present && !device->status.functional) { + result = -ENODEV; + goto end; } break; default: @@ -1252,6 +1260,16 @@ acpi_add_single_object(struct acpi_device **child, acpi_device_set_id(device, parent, handle, type); /* + * The ACPI device is attached to acpi handle before getting + * the power/wakeup/peformance flags. Otherwise OS can't get + * the corresponding ACPI device by the acpi handle in the course + * of getting the power/wakeup/performance flags. + */ + result = acpi_device_set_context(device, type); + if (result) + goto end; + + /* * Power Management * ---------------- */ @@ -1281,8 +1299,6 @@ acpi_add_single_object(struct acpi_device **child, goto end; } - if ((result = acpi_device_set_context(device, type))) - goto end; result = acpi_device_register(device, parent); @@ -1402,7 +1418,12 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) * TBD: Need notifications and other detection mechanisms * in place before we can fully implement this. */ - if (child->status.present) { + /* + * When the device is not present but functional, it is also + * necessary to scan the children of this device. + */ + if (child->status.present || (!child->status.present && + child->status.functional)) { status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, NULL, NULL); if (ACPI_SUCCESS(status)) { @@ -1545,7 +1566,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) return result; } -int __init acpi_boot_ec_enable(void); static int __init acpi_scan_init(void) { @@ -1579,9 +1599,6 @@ static int __init acpi_scan_init(void) */ result = acpi_bus_scan_fixed(acpi_root); - /* EC region might be needed at bus_scan, so enable it now */ - acpi_boot_ec_enable(); - if (!result) result = acpi_bus_scan(acpi_root, &ops); diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index d13194a031bf..a0f887f37600 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -15,6 +15,7 @@ #include <linux/dmi.h> #include <linux/device.h> #include <linux/suspend.h> +#include <linux/reboot.h> #include <asm/io.h> @@ -24,6 +25,36 @@ u8 sleep_states[ACPI_S_STATE_COUNT]; +static void acpi_sleep_tts_switch(u32 acpi_state) +{ + union acpi_object in_arg = { ACPI_TYPE_INTEGER }; + struct acpi_object_list arg_list = { 1, &in_arg }; + acpi_status status = AE_OK; + + in_arg.integer.value = acpi_state; + status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + /* + * OS can't evaluate the _TTS object correctly. Some warning + * message will be printed. But it won't break anything. + */ + printk(KERN_NOTICE "Failure in evaluating _TTS object\n"); + } +} + +static int tts_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) +{ + acpi_sleep_tts_switch(ACPI_STATE_S5); + return NOTIFY_DONE; +} + +static struct notifier_block tts_notifier = { + .notifier_call = tts_notify_reboot, + .next = NULL, + .priority = 0, +}; + static int acpi_sleep_prepare(u32 acpi_state) { #ifdef CONFIG_ACPI_SLEEP @@ -131,6 +162,7 @@ static void acpi_pm_end(void) * failing transition to a sleep state. */ acpi_target_sleep_state = ACPI_STATE_S0; + acpi_sleep_tts_switch(acpi_target_sleep_state); } #endif /* CONFIG_PM_SLEEP */ @@ -155,6 +187,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state) if (sleep_states[acpi_state]) { acpi_target_sleep_state = acpi_state; + acpi_sleep_tts_switch(acpi_target_sleep_state); } else { printk(KERN_ERR "ACPI does not support this state: %d\n", pm_state); @@ -200,6 +233,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state) break; } + /* If ACPI is not enabled by the BIOS, we need to enable it here. */ + acpi_enable(); /* Reprogram control registers and execute _BFS */ acpi_leave_sleep_state_prep(acpi_state); @@ -296,6 +331,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), }, }, + { + .callback = init_old_suspend_ordering, + .ident = "HP xw4600 Workstation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ @@ -313,6 +356,7 @@ void __init acpi_no_s4_hw_signature(void) static int acpi_hibernation_begin(void) { acpi_target_sleep_state = ACPI_STATE_S4; + acpi_sleep_tts_switch(acpi_target_sleep_state); return 0; } @@ -376,7 +420,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = { */ static int acpi_hibernation_begin_old(void) { - int error = acpi_sleep_prepare(ACPI_STATE_S4); + int error; + /* + * The _TTS object should always be evaluated before the _PTS object. + * When the old_suspended_ordering is true, the _PTS object is + * evaluated in the acpi_sleep_prepare. + */ + acpi_sleep_tts_switch(ACPI_STATE_S4); + + error = acpi_sleep_prepare(ACPI_STATE_S4); if (!error) acpi_target_sleep_state = ACPI_STATE_S4; @@ -444,7 +496,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) acpi_handle handle = DEVICE_ACPI_HANDLE(dev); struct acpi_device *adev; char acpi_method[] = "_SxD"; - unsigned long d_min, d_max; + unsigned long long d_min, d_max; if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { printk(KERN_DEBUG "ACPI handle has no context!\n"); @@ -596,5 +648,10 @@ int __init acpi_sleep_init(void) pm_power_off = acpi_power_off; } printk(")\n"); + /* + * Register the tts_notifier to reboot notifier list so that the _TTS + * object can also be evaluated when the system enters S5. + */ + register_reboot_notifier(&tts_notifier); return 0; } diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 91dec448b3ed..58a1d89e232f 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -387,8 +387,8 @@ static ssize_t counter_set(struct kobject *kobj, goto end; if (!(all_counters[index].flags & ACPI_EVENT_VALID)) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Can not change Invalid GPE/Fixed Event status\n")); + printk(KERN_WARNING + "Can not change Invalid GPE/Fixed Event status\n"); return -EINVAL; } diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index a4a41ba2484b..2c7885e7ffba 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c @@ -50,7 +50,7 @@ ACPI_MODULE_NAME("tbfadt") /* Local prototypes */ static void inline acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, - u8 bit_width, u64 address); + u8 byte_width, u64 address); static void acpi_tb_convert_fadt(void); @@ -111,7 +111,7 @@ static struct acpi_fadt_info fadt_info_table[] = { * FUNCTION: acpi_tb_init_generic_address * * PARAMETERS: generic_address - GAS struct to be initialized - * bit_width - Width of this register + * byte_width - Width of this register * Address - Address of the register * * RETURN: None @@ -124,7 +124,7 @@ static struct acpi_fadt_info fadt_info_table[] = { static void inline acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, - u8 bit_width, u64 address) + u8 byte_width, u64 address) { /* @@ -136,7 +136,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, /* All other fields are byte-wide */ generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; - generic_address->bit_width = bit_width; + generic_address->bit_width = byte_width << 3; generic_address->bit_offset = 0; generic_address->access_width = 0; } @@ -342,9 +342,20 @@ static void acpi_tb_convert_fadt(void) * useful to calculate them once, here. * * The PM event blocks are split into two register blocks, first is the - * PM Status Register block, followed immediately by the PM Enable Register - * block. Each is of length (pm1_event_length/2) + * PM Status Register block, followed immediately by the PM Enable + * Register block. Each is of length (xpm1x_event_block.bit_width/2). + * + * On various systems the v2 fields (and particularly the bit widths) + * cannot be relied upon, though. Hence resort to using the v1 length + * here (and warn about the inconsistency). */ + if (acpi_gbl_FADT.xpm1a_event_block.bit_width + != acpi_gbl_FADT.pm1_event_length * 8) + printk(KERN_WARNING "FADT: " + "X_PM1a_EVT_BLK.bit_width (%u) does not match" + " PM1_EVT_LEN (%u)\n", + acpi_gbl_FADT.xpm1a_event_block.bit_width, + acpi_gbl_FADT.pm1_event_length); pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); /* The PM1A register block is required */ @@ -360,13 +371,20 @@ static void acpi_tb_convert_fadt(void) /* The PM1B register block is optional, ignore if not present */ if (acpi_gbl_FADT.xpm1b_event_block.address) { + if (acpi_gbl_FADT.xpm1b_event_block.bit_width + != acpi_gbl_FADT.pm1_event_length * 8) + printk(KERN_WARNING "FADT: " + "X_PM1b_EVT_BLK.bit_width (%u) does not match" + " PM1_EVT_LEN (%u)\n", + acpi_gbl_FADT.xpm1b_event_block.bit_width, + acpi_gbl_FADT.pm1_event_length); acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, pm1_register_length, (acpi_gbl_FADT.xpm1b_event_block. address + pm1_register_length)); /* Don't forget to copy space_id of the GAS */ acpi_gbl_xpm1b_enable.space_id = - acpi_gbl_FADT.xpm1a_event_block.space_id; + acpi_gbl_FADT.xpm1b_event_block.space_id; } } diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index b22185f55a16..18747ce8dd2f 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -110,7 +110,6 @@ acpi_status acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) { u32 i; - u32 length; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(tb_add_table); @@ -145,25 +144,64 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) } } - length = ACPI_MIN(table_desc->length, - acpi_gbl_root_table_list.tables[i].length); + /* + * Check for a table match on the entire table length, + * not just the header. + */ + if (table_desc->length != + acpi_gbl_root_table_list.tables[i].length) { + continue; + } + if (ACPI_MEMCMP(table_desc->pointer, acpi_gbl_root_table_list.tables[i].pointer, - length)) { + acpi_gbl_root_table_list.tables[i].length)) { continue; } - /* Table is already registered */ - + /* + * Note: the current mechanism does not unregister a table if it is + * dynamically unloaded. The related namespace entries are deleted, + * but the table remains in the root table list. + * + * The assumption here is that the number of different tables that + * will be loaded is actually small, and there is minimal overhead + * in just keeping the table in case it is needed again. + * + * If this assumption changes in the future (perhaps on large + * machines with many table load/unload operations), tables will + * need to be unregistered when they are unloaded, and slots in the + * root table list should be reused when empty. + */ + + /* + * Table is already registered. + * We can delete the table that was passed as a parameter. + */ acpi_tb_delete_table(table_desc); *table_index = i; - status = AE_ALREADY_EXISTS; - goto release; + + if (acpi_gbl_root_table_list.tables[i]. + flags & ACPI_TABLE_IS_LOADED) { + + /* Table is still loaded, this is an error */ + + status = AE_ALREADY_EXISTS; + goto release; + } else { + /* Table was unloaded, allow it to be reloaded */ + + table_desc->pointer = + acpi_gbl_root_table_list.tables[i].pointer; + table_desc->address = + acpi_gbl_root_table_list.tables[i].address; + status = AE_OK; + goto print_header; + } } - /* - * Add the table to the global table list - */ + /* Add the table to the global root table list */ + status = acpi_tb_store_table(table_desc->address, table_desc->pointer, table_desc->length, table_desc->flags, table_index); @@ -171,6 +209,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) goto release; } + print_header: acpi_tb_print_table_header(table_desc->address, table_desc->pointer); release: diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 912703691d36..ba184629fb33 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -246,18 +246,18 @@ static const struct file_operations acpi_thermal_polling_fops = { static int acpi_thermal_get_temperature(struct acpi_thermal *tz) { acpi_status status = AE_OK; - + unsigned long long tmp; if (!tz) return -EINVAL; tz->last_temperature = tz->temperature; - status = - acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature); + status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp); if (ACPI_FAILURE(status)) return -ENODEV; + tz->temperature = tmp; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", tz->temperature)); @@ -267,17 +267,16 @@ static int acpi_thermal_get_temperature(struct acpi_thermal *tz) static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) { acpi_status status = AE_OK; - + unsigned long long tmp; if (!tz) return -EINVAL; - status = - acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, - &tz->polling_frequency); + status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp); if (ACPI_FAILURE(status)) return -ENODEV; + tz->polling_frequency = tmp; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", tz->polling_frequency)); @@ -356,6 +355,7 @@ do { \ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) { acpi_status status = AE_OK; + unsigned long long tmp; struct acpi_handle_list devices; int valid = 0; int i; @@ -363,7 +363,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) /* Critical Shutdown (required) */ if (flag & ACPI_TRIPS_CRITICAL) { status = acpi_evaluate_integer(tz->device->handle, - "_CRT", NULL, &tz->trips.critical.temperature); + "_CRT", NULL, &tmp); + tz->trips.critical.temperature = tmp; /* * Treat freezing temperatures as invalid as well; some * BIOSes return really low values and cause reboots at startup. @@ -388,10 +389,12 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } else if (crt > 0) { unsigned long crt_k = CELSIUS_TO_KELVIN(crt); /* - * Allow override to lower critical threshold + * Allow override critical threshold */ - if (crt_k < tz->trips.critical.temperature) - tz->trips.critical.temperature = crt_k; + if (crt_k > tz->trips.critical.temperature) + printk(KERN_WARNING PREFIX + "Critical threshold %d C\n", crt); + tz->trips.critical.temperature = crt_k; } } } @@ -399,12 +402,13 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) /* Critical Sleep (optional) */ if (flag & ACPI_TRIPS_HOT) { status = acpi_evaluate_integer(tz->device->handle, - "_HOT", NULL, &tz->trips.hot.temperature); + "_HOT", NULL, &tmp); if (ACPI_FAILURE(status)) { tz->trips.hot.flags.valid = 0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n")); } else { + tz->trips.hot.temperature = tmp; tz->trips.hot.flags.valid = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", @@ -418,33 +422,40 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) if (psv == -1) { status = AE_SUPPORT; } else if (psv > 0) { - tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); + tmp = CELSIUS_TO_KELVIN(psv); status = AE_OK; } else { status = acpi_evaluate_integer(tz->device->handle, - "_PSV", NULL, &tz->trips.passive.temperature); + "_PSV", NULL, &tmp); } if (ACPI_FAILURE(status)) tz->trips.passive.flags.valid = 0; else { + tz->trips.passive.temperature = tmp; tz->trips.passive.flags.valid = 1; if (flag == ACPI_TRIPS_INIT) { status = acpi_evaluate_integer( tz->device->handle, "_TC1", - NULL, &tz->trips.passive.tc1); + NULL, &tmp); if (ACPI_FAILURE(status)) tz->trips.passive.flags.valid = 0; + else + tz->trips.passive.tc1 = tmp; status = acpi_evaluate_integer( tz->device->handle, "_TC2", - NULL, &tz->trips.passive.tc2); + NULL, &tmp); if (ACPI_FAILURE(status)) tz->trips.passive.flags.valid = 0; + else + tz->trips.passive.tc2 = tmp; status = acpi_evaluate_integer( tz->device->handle, "_TSP", - NULL, &tz->trips.passive.tsp); + NULL, &tmp); if (ACPI_FAILURE(status)) tz->trips.passive.flags.valid = 0; + else + tz->trips.passive.tsp = tmp; } } } @@ -479,7 +490,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) if (flag & ACPI_TRIPS_ACTIVE) { status = acpi_evaluate_integer(tz->device->handle, - name, NULL, &tz->trips.active[i].temperature); + name, NULL, &tmp); if (ACPI_FAILURE(status)) { tz->trips.active[i].flags.valid = 0; if (i == 0) @@ -500,8 +511,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) tz->trips.active[i - 2].temperature : CELSIUS_TO_KELVIN(act)); break; - } else + } else { + tz->trips.active[i].temperature = tmp; tz->trips.active[i].flags.valid = 1; + } } name[2] = 'L'; @@ -1213,8 +1226,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) acpi_bus_private_data_handler, tz->thermal_zone); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error attaching device data\n")); + ACPI_EXCEPTION((AE_INFO, status, + "Error attaching device data")); return -ENODEV; } @@ -1647,7 +1660,7 @@ static int acpi_thermal_add(struct acpi_device *device) strcpy(tz->name, device->pnp.bus_id); strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); - acpi_driver_data(device) = tz; + device->driver_data = tz; mutex_init(&tz->lock); diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index 8a649f40d162..2a632f8b7a05 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -548,7 +548,7 @@ static unsigned long write_video(const char *buffer, unsigned long count) hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); if (hci_result == HCI_SUCCESS) { - int new_video_out = video_out; + unsigned int new_video_out = video_out; if (lcd_out != -1) _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); if (crt_out != -1) diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index a6e71b801d2d..bcace577183b 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -45,6 +45,7 @@ #include <acpi/acpi.h> #include <acpi/acnamesp.h> +#include <acpi/amlcode.h> ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) #define _COMPONENT ACPI_UTILITIES @@ -575,6 +576,41 @@ char *acpi_ut_get_descriptor_name(void *object) } +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_reference_name + * + * PARAMETERS: Object - An ACPI reference object + * + * RETURN: Pointer to a string + * + * DESCRIPTION: Decode a reference object sub-type to a string. + * + ******************************************************************************/ + +/* Printable names of reference object sub-types */ + +const char *acpi_ut_get_reference_name(union acpi_operand_object *object) +{ + + switch (object->reference.opcode) { + case AML_INT_NAMEPATH_OP: + return "Name"; + + case AML_LOAD_OP: + return "DDB-Handle"; + + case AML_REF_OF_OP: + return "RefOf"; + + case AML_INDEX_OP: + return "Index"; + + default: + return "Unknown"; + } +} + #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /* * Strings and procedures used for debug only @@ -677,14 +713,14 @@ u8 acpi_ut_valid_object_type(acpi_object_type type) * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Init library globals. All globals that require specific * initialization should be initialized here! * ******************************************************************************/ -void acpi_ut_init_globals(void) +acpi_status acpi_ut_init_globals(void) { acpi_status status; u32 i; @@ -695,7 +731,7 @@ void acpi_ut_init_globals(void) status = acpi_ut_create_caches(); if (ACPI_FAILURE(status)) { - return; + return_ACPI_STATUS(status); } /* Mutex locked flags */ @@ -772,7 +808,7 @@ void acpi_ut_init_globals(void) acpi_gbl_display_final_mem_stats = FALSE; #endif - return_VOID; + return_ACPI_STATUS(AE_OK); } ACPI_EXPORT_SYMBOL(acpi_dbg_level) diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 916eff399eb3..924d05af94d2 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -503,7 +503,9 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, * required eventually. */ ACPI_ERROR((AE_INFO, - "Unsupported Reference opcode=%X in object %p", + "Cannot convert to external object - " + "unsupported Reference type [%s] %X in object %p", + acpi_ut_get_reference_name(internal_object), internal_object->reference.opcode, internal_object)); status = AE_TYPE; @@ -513,7 +515,9 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, default: - ACPI_ERROR((AE_INFO, "Unsupported type=%X in object %p", + ACPI_ERROR((AE_INFO, "Cannot convert to external object - " + "unsupported type [%s] %X in object %p", + acpi_ut_get_object_type_name(internal_object), ACPI_GET_OBJECT_TYPE(internal_object), internal_object)); status = AE_TYPE; diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index f8bdadf3c32f..c198a4d40583 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -81,7 +81,12 @@ acpi_status __init acpi_initialize_subsystem(void) /* Initialize all globals used by the subsystem */ - acpi_ut_init_globals(); + status = acpi_ut_init_globals(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "During initialization of globals")); + return_ACPI_STATUS(status); + } /* Create the default mutex objects */ diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 100926143818..e827be36ee8d 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -256,7 +256,7 @@ EXPORT_SYMBOL(acpi_extract_package); acpi_status acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, - struct acpi_object_list *arguments, unsigned long *data) + struct acpi_object_list *arguments, unsigned long long *data) { acpi_status status = AE_OK; union acpi_object *element; @@ -288,7 +288,7 @@ acpi_evaluate_integer(acpi_handle handle, *data = element->integer.value; kfree(element); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); return AE_OK; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index e8a51a1700f7..6c011476ff28 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -291,20 +291,20 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level); static int acpi_video_device_lcd_get_level_current( struct acpi_video_device *device, - unsigned long *level); + unsigned long long *level); static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); static void acpi_video_switch_brightness(struct acpi_video_device *device, int event); static int acpi_video_device_get_state(struct acpi_video_device *device, - unsigned long *state); + unsigned long long *state); static int acpi_video_output_get(struct output_device *od); static int acpi_video_device_set_state(struct acpi_video_device *device, int state); /*backlight device sysfs support*/ static int acpi_video_get_brightness(struct backlight_device *bd) { - unsigned long cur_level; + unsigned long long cur_level; int i; struct acpi_video_device *vd = (struct acpi_video_device *)bl_get_data(bd); @@ -336,7 +336,7 @@ static struct backlight_ops acpi_backlight_ops = { /*video output device sysfs support*/ static int acpi_video_output_get(struct output_device *od) { - unsigned long state; + unsigned long long state; struct acpi_video_device *vd = (struct acpi_video_device *)dev_get_drvdata(&od->dev); acpi_video_device_get_state(vd, &state); @@ -370,7 +370,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) { struct acpi_device *device = cdev->devdata; struct acpi_video_device *video = acpi_driver_data(device); - unsigned long level; + unsigned long long level; int state; acpi_video_device_lcd_get_level_current(video, &level); @@ -410,7 +410,7 @@ static struct thermal_cooling_device_ops video_cooling_ops = { /* device */ static int -acpi_video_device_query(struct acpi_video_device *device, unsigned long *state) +acpi_video_device_query(struct acpi_video_device *device, unsigned long long *state) { int status; @@ -421,7 +421,7 @@ acpi_video_device_query(struct acpi_video_device *device, unsigned long *state) static int acpi_video_device_get_state(struct acpi_video_device *device, - unsigned long *state) + unsigned long long *state) { int status; @@ -436,7 +436,7 @@ acpi_video_device_set_state(struct acpi_video_device *device, int state) int status; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; - unsigned long ret; + unsigned long long ret; arg0.integer.value = state; @@ -495,7 +495,7 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) static int acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, - unsigned long *level) + unsigned long long *level) { if (device->cap._BQC) return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, @@ -549,7 +549,7 @@ static int acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option) { int status; - unsigned long tmp; + unsigned long long tmp; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; @@ -564,7 +564,7 @@ acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option) } static int -acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id) +acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id) { int status; @@ -575,7 +575,7 @@ acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id) static int acpi_video_bus_POST_options(struct acpi_video_bus *video, - unsigned long *options) + unsigned long long *options) { int status; @@ -918,7 +918,7 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset) { int status; struct acpi_video_device *dev = seq->private; - unsigned long state; + unsigned long long state; if (!dev) @@ -927,14 +927,14 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset) status = acpi_video_device_get_state(dev, &state); seq_printf(seq, "state: "); if (ACPI_SUCCESS(status)) - seq_printf(seq, "0x%02lx\n", state); + seq_printf(seq, "0x%02llx\n", state); else seq_printf(seq, "<not supported>\n"); status = acpi_video_device_query(dev, &state); seq_printf(seq, "query: "); if (ACPI_SUCCESS(status)) - seq_printf(seq, "0x%02lx\n", state); + seq_printf(seq, "0x%02llx\n", state); else seq_printf(seq, "<not supported>\n"); @@ -1217,7 +1217,7 @@ static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file) static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset) { struct acpi_video_bus *video = seq->private; - unsigned long options; + unsigned long long options; int status; @@ -1232,7 +1232,7 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset) printk(KERN_WARNING PREFIX "This indicates a BIOS bug. Please contact the manufacturer.\n"); } - printk("%lx\n", options); + printk("%llx\n", options); seq_printf(seq, "can POST: <integrated video>"); if (options & 2) seq_printf(seq, " <PCI video>"); @@ -1256,7 +1256,7 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset) { struct acpi_video_bus *video = seq->private; int status; - unsigned long id; + unsigned long long id; if (!video) @@ -1303,7 +1303,7 @@ acpi_video_bus_write_POST(struct file *file, struct seq_file *m = file->private_data; struct acpi_video_bus *video = m->private; char str[12] = { 0 }; - unsigned long opt, options; + unsigned long long opt, options; if (!video || count + 1 > sizeof str) @@ -1473,7 +1473,7 @@ static int acpi_video_bus_get_one_device(struct acpi_device *device, struct acpi_video_bus *video) { - unsigned long device_id; + unsigned long long device_id; int status; struct acpi_video_device *data; struct acpi_video_device_attrib* attribute; @@ -1491,7 +1491,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device, strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); - acpi_driver_data(device) = data; + device->driver_data = data; data->device_id = device_id; data->video = video; @@ -1530,8 +1530,8 @@ acpi_video_bus_get_one_device(struct acpi_device *device, acpi_video_device_notify, data); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error installing notify handler\n")); + ACPI_EXCEPTION((AE_INFO, status, + "Error installing notify handler")); if(data->brightness) kfree(data->brightness->levels); kfree(data->brightness); @@ -1724,7 +1724,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, static void acpi_video_switch_brightness(struct acpi_video_device *device, int event) { - unsigned long level_current, level_next; + unsigned long long level_current, level_next; if (!device->brightness) return; acpi_video_device_lcd_get_level_current(device, &level_current); @@ -1745,8 +1745,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video, status = acpi_video_bus_get_one_device(dev, video); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Cant attach device")); + printk(KERN_ERR "Cant attach device [%d]\n", status); continue; } } @@ -1982,7 +1981,7 @@ static int acpi_video_bus_add(struct acpi_device *device) video->device = device; strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); - acpi_driver_data(device) = video; + device->driver_data = video; acpi_video_bus_find_cap(video); error = acpi_video_bus_check(video); @@ -2003,8 +2002,8 @@ static int acpi_video_bus_add(struct acpi_device *device) ACPI_DEVICE_NOTIFY, acpi_video_bus_notify, video); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Error installing notify handler\n")); + ACPI_EXCEPTION((AE_INFO, status, + "Error installing notify handler")); error = -ENODEV; goto err_stop_video; } @@ -2058,7 +2057,7 @@ static int acpi_video_bus_add(struct acpi_device *device) acpi_video_bus_remove_fs(device); err_free_video: kfree(video); - acpi_driver_data(device) = NULL; + device->driver_data = NULL; return error; } diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c index cfe2c833474d..47cd7baf9b1b 100644 --- a/drivers/acpi/wmi.c +++ b/drivers/acpi/wmi.c @@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) return 0; } +static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) +{ + struct guid_block *block = NULL; + char method[5]; + struct acpi_object_list input; + union acpi_object params[1]; + acpi_status status; + acpi_handle handle; + + block = &wblock->gblock; + handle = wblock->handle; + + if (!block) + return AE_NOT_EXIST; + + input.count = 1; + input.pointer = params; + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = enable; + + snprintf(method, 5, "WE%02X", block->notify_id); + status = acpi_evaluate_object(handle, method, &input, NULL); + + if (status != AE_OK && status != AE_NOT_FOUND) + return status; + else + return AE_OK; +} + /* * Exported WMI functions */ @@ -242,7 +271,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) char method[4] = "WM"; if (!find_guid(guid_string, &wblock)) - return AE_BAD_ADDRESS; + return AE_ERROR; block = &wblock->gblock; handle = wblock->handle; @@ -304,7 +333,7 @@ struct acpi_buffer *out) return AE_BAD_PARAMETER; if (!find_guid(guid_string, &wblock)) - return AE_BAD_ADDRESS; + return AE_ERROR; block = &wblock->gblock; handle = wblock->handle; @@ -314,7 +343,7 @@ struct acpi_buffer *out) /* Check GUID is a data block */ if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) - return AE_BAD_ADDRESS; + return AE_ERROR; input.count = 1; input.pointer = wq_params; @@ -385,7 +414,7 @@ const struct acpi_buffer *in) return AE_BAD_DATA; if (!find_guid(guid_string, &wblock)) - return AE_BAD_ADDRESS; + return AE_ERROR; block = &wblock->gblock; handle = wblock->handle; @@ -395,7 +424,7 @@ const struct acpi_buffer *in) /* Check GUID is a data block */ if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) - return AE_BAD_ADDRESS; + return AE_ERROR; input.count = 2; input.pointer = params; @@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid, wmi_notify_handler handler, void *data) { struct wmi_block *block; + acpi_status status; if (!guid || !handler) return AE_BAD_PARAMETER; @@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data) block->handler = handler; block->handler_data = data; - return AE_OK; + status = wmi_method_enable(block, 1); + + return status; } EXPORT_SYMBOL_GPL(wmi_install_notify_handler); @@ -453,6 +485,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler); acpi_status wmi_remove_notify_handler(const char *guid) { struct wmi_block *block; + acpi_status status; if (!guid) return AE_BAD_PARAMETER; @@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid) if (!block->handler) return AE_NULL_ENTRY; + status = wmi_method_enable(block, 0); + block->handler = NULL; block->handler_data = NULL; - return AE_OK; + return status; } EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); |