diff options
author | Seth Forshee | 2011-09-20 16:55:49 -0500 |
---|---|---|
committer | Matthew Garrett | 2011-10-24 16:52:36 +0200 |
commit | 135740de77641b4180c8a1f19abcfcd5e4351b15 (patch) | |
tree | b8c1421f005dbaa8f95079c53eeb30cd18becf36 /drivers/platform | |
parent | f689c875c13c9d62b3c4de09cd5dad66549f700d (diff) |
toshiba_acpi: Convert to use acpi_driver
Changes toshiba_acpi to register an acpi driver and eliminates the
platform device it was using. Also eliminates most global
variables, moving them into toshiba_acpi_dev, along with some
other miscellaneous fixes and cleanup.
Signed-off-by: Azael Avalos <coproscefalo@gmail.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 506 |
1 files changed, 261 insertions, 245 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index cb009b2629ee..d74c97cde0f1 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -47,7 +47,6 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/backlight.h> -#include <linux/platform_device.h> #include <linux/rfkill.h> #include <linux/input.h> #include <linux/input/sparse-keymap.h> @@ -111,6 +110,22 @@ MODULE_LICENSE("GPL"); #define HCI_WIRELESS_BT_ATTACH 0x40 #define HCI_WIRELESS_BT_POWER 0x80 +struct toshiba_acpi_dev { + struct acpi_device *acpi_dev; + const char *method_hci; + struct rfkill *bt_rfk; + struct input_dev *hotkey_dev; + struct backlight_device *backlight_dev; + struct led_classdev led_dev; + int illumination_installed; + int force_fan; + int last_key_event; + int key_event_valid; + acpi_handle handle; + + struct mutex mutex; +}; + static const struct acpi_device_id toshiba_device_ids[] = { {"TOS6200", 0}, {"TOS6208", 0}, @@ -119,7 +134,7 @@ static const struct acpi_device_id toshiba_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); -static const struct key_entry toshiba_acpi_keymap[] __initconst = { +static const struct key_entry toshiba_acpi_keymap[] __devinitconst = { { KE_KEY, 0x101, { KEY_MUTE } }, { KE_KEY, 0x102, { KEY_ZOOMOUT } }, { KE_KEY, 0x103, { KEY_ZOOMIN } }, @@ -179,29 +194,11 @@ static int write_acpi_int(const char *methodName, int val) return (status == AE_OK); } -#if 0 -static int read_acpi_int(const char *methodName, int *pVal) -{ - struct acpi_buffer results; - union acpi_object out_objs[1]; - acpi_status status; - - results.length = sizeof(out_objs); - results.pointer = out_objs; - - status = acpi_evaluate_object(0, (char *)methodName, 0, &results); - *pVal = out_objs[0].integer.value; - - return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER); -} -#endif - -static const char *method_hci /*= 0*/ ; - /* Perform a raw HCI call. Here we don't care about input or output buffer * format. */ -static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) +static acpi_status hci_raw(struct toshiba_acpi_dev *dev, + const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) { struct acpi_object_list params; union acpi_object in_objs[HCI_WORDS]; @@ -220,7 +217,7 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) results.length = sizeof(out_objs); results.pointer = out_objs; - status = acpi_evaluate_object(NULL, (char *)method_hci, ¶ms, + status = acpi_evaluate_object(NULL, (char *)dev->method_hci, ¶ms, &results); if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) { for (i = 0; i < out_objs->package.count; ++i) { @@ -237,85 +234,79 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) * may be useful (such as "not supported"). */ -static acpi_status hci_write1(u32 reg, u32 in1, u32 * result) +static acpi_status hci_write1(struct toshiba_acpi_dev *dev, u32 reg, + u32 in1, u32 *result) { u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; u32 out[HCI_WORDS]; - acpi_status status = hci_raw(in, out); + acpi_status status = hci_raw(dev, in, out); *result = (status == AE_OK) ? out[0] : HCI_FAILURE; return status; } -static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result) +static acpi_status hci_read1(struct toshiba_acpi_dev *dev, u32 reg, + u32 *out1, u32 *result) { u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; u32 out[HCI_WORDS]; - acpi_status status = hci_raw(in, out); + acpi_status status = hci_raw(dev, in, out); *out1 = out[2]; *result = (status == AE_OK) ? out[0] : HCI_FAILURE; return status; } -static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result) +static acpi_status hci_write2(struct toshiba_acpi_dev *dev, u32 reg, + u32 in1, u32 in2, u32 *result) { u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 }; u32 out[HCI_WORDS]; - acpi_status status = hci_raw(in, out); + acpi_status status = hci_raw(dev, in, out); *result = (status == AE_OK) ? out[0] : HCI_FAILURE; return status; } -static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) +static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg, + u32 *out1, u32 *out2, u32 *result) { u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; u32 out[HCI_WORDS]; - acpi_status status = hci_raw(in, out); + acpi_status status = hci_raw(dev, in, out); *out1 = out[2]; *out2 = out[3]; *result = (status == AE_OK) ? out[0] : HCI_FAILURE; return status; } -struct toshiba_acpi_dev { - struct platform_device *p_dev; - struct rfkill *bt_rfk; - struct input_dev *hotkey_dev; - int illumination_installed; - acpi_handle handle; - - const char *bt_name; - - struct mutex mutex; -}; - /* Illumination support */ -static int toshiba_illumination_available(void) +static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) { u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; u32 out[HCI_WORDS]; acpi_status status; in[0] = 0xf100; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_info("Illumination device not available\n"); return 0; } in[0] = 0xf400; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); return 1; } static void toshiba_illumination_set(struct led_classdev *cdev, enum led_brightness brightness) { + struct toshiba_acpi_dev *dev = container_of(cdev, + struct toshiba_acpi_dev, led_dev); u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; u32 out[HCI_WORDS]; acpi_status status; /* First request : initialize communication. */ in[0] = 0xf100; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_info("Illumination device not available\n"); return; @@ -326,7 +317,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev, in[0] = 0xf400; in[1] = 0x14e; in[2] = 1; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_info("ACPI call for illumination failed\n"); return; @@ -336,7 +327,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev, in[0] = 0xf400; in[1] = 0x14e; in[2] = 0; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_info("ACPI call for illumination failed.\n"); return; @@ -347,11 +338,13 @@ static void toshiba_illumination_set(struct led_classdev *cdev, in[0] = 0xf200; in[1] = 0; in[2] = 0; - hci_raw(in, out); + hci_raw(dev, in, out); } static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) { + struct toshiba_acpi_dev *dev = container_of(cdev, + struct toshiba_acpi_dev, led_dev); u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; u32 out[HCI_WORDS]; acpi_status status; @@ -359,7 +352,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) /* First request : initialize communication. */ in[0] = 0xf100; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_info("Illumination device not available\n"); return LED_OFF; @@ -368,7 +361,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) /* Check the illumination */ in[0] = 0xf300; in[1] = 0x14e; - status = hci_raw(in, out); + status = hci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_info("ACPI call for illumination failed.\n"); return LED_OFF; @@ -380,46 +373,35 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) in[0] = 0xf200; in[1] = 0; in[2] = 0; - hci_raw(in, out); + hci_raw(dev, in, out); return result; } -static struct led_classdev toshiba_led = { - .name = "toshiba::illumination", - .max_brightness = 1, - .brightness_set = toshiba_illumination_set, - .brightness_get = toshiba_illumination_get, -}; - -static struct toshiba_acpi_dev toshiba_acpi = { - .bt_name = "Toshiba Bluetooth", -}; - /* Bluetooth rfkill handlers */ -static u32 hci_get_bt_present(bool *present) +static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) { u32 hci_result; u32 value, value2; value = 0; value2 = 0; - hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); + hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result); if (hci_result == HCI_SUCCESS) *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false; return hci_result; } -static u32 hci_get_radio_state(bool *radio_state) +static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state) { u32 hci_result; u32 value, value2; value = 0; value2 = 0x0001; - hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); + hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result); *radio_state = value & HCI_WIRELESS_KILL_SWITCH; return hci_result; @@ -436,7 +418,7 @@ static int bt_rfkill_set_block(void *data, bool blocked) value = (blocked == false); mutex_lock(&dev->mutex); - if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) { + if (hci_get_radio_state(dev, &radio_state) != HCI_SUCCESS) { err = -EBUSY; goto out; } @@ -446,8 +428,8 @@ static int bt_rfkill_set_block(void *data, bool blocked) goto out; } - hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); - hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); + hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); + hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) err = -EBUSY; @@ -467,7 +449,7 @@ static void bt_rfkill_poll(struct rfkill *rfkill, void *data) mutex_lock(&dev->mutex); - hci_result = hci_get_radio_state(&value); + hci_result = hci_get_radio_state(dev, &value); if (hci_result != HCI_SUCCESS) { /* Can't do anything useful */ mutex_unlock(&dev->mutex); @@ -488,17 +470,14 @@ static const struct rfkill_ops toshiba_rfk_ops = { }; static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; -static struct backlight_device *toshiba_backlight_device; -static int force_fan; -static int last_key_event; -static int key_event_valid; static int get_lcd(struct backlight_device *bd) { + struct toshiba_acpi_dev *dev = bl_get_data(bd); u32 hci_result; u32 value; - hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); + hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); if (hci_result == HCI_SUCCESS) { return (value >> HCI_LCD_BRIGHTNESS_SHIFT); } else @@ -507,8 +486,13 @@ static int get_lcd(struct backlight_device *bd) static int lcd_proc_show(struct seq_file *m, void *v) { - int value = get_lcd(NULL); + struct toshiba_acpi_dev *dev = m->private; + int value; + + if (!dev->backlight_dev) + return -ENODEV; + value = get_lcd(dev->backlight_dev); if (value >= 0) { seq_printf(m, "brightness: %d\n", value); seq_printf(m, "brightness_levels: %d\n", @@ -522,15 +506,15 @@ static int lcd_proc_show(struct seq_file *m, void *v) static int lcd_proc_open(struct inode *inode, struct file *file) { - return single_open(file, lcd_proc_show, NULL); + return single_open(file, lcd_proc_show, PDE(inode)->data); } -static int set_lcd(int value) +static int set_lcd(struct toshiba_acpi_dev *dev, int value) { u32 hci_result; value = value << HCI_LCD_BRIGHTNESS_SHIFT; - hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); + hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); if (hci_result != HCI_SUCCESS) return -EFAULT; @@ -539,12 +523,14 @@ static int set_lcd(int value) static int set_lcd_status(struct backlight_device *bd) { - return set_lcd(bd->props.brightness); + struct toshiba_acpi_dev *dev = bl_get_data(bd); + return set_lcd(dev, bd->props.brightness); } static ssize_t lcd_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { + struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data; char cmd[42]; size_t len; int value; @@ -557,7 +543,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, if (sscanf(cmd, " brightness : %i", &value) == 1 && value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { - ret = set_lcd(value); + ret = set_lcd(dev, value); if (ret == 0) ret = count; } else { @@ -577,10 +563,11 @@ static const struct file_operations lcd_proc_fops = { static int video_proc_show(struct seq_file *m, void *v) { + struct toshiba_acpi_dev *dev = m->private; u32 hci_result; u32 value; - hci_read1(HCI_VIDEO_OUT, &value, &hci_result); + hci_read1(dev, HCI_VIDEO_OUT, &value, &hci_result); if (hci_result == HCI_SUCCESS) { int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; @@ -597,12 +584,13 @@ static int video_proc_show(struct seq_file *m, void *v) static int video_proc_open(struct inode *inode, struct file *file) { - return single_open(file, video_proc_show, NULL); + return single_open(file, video_proc_show, PDE(inode)->data); } static ssize_t video_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { + struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data; char *cmd, *buffer; int value; int remain = count; @@ -644,7 +632,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, kfree(cmd); - hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); + hci_read1(dev, HCI_VIDEO_OUT, &video_out, &hci_result); if (hci_result == HCI_SUCCESS) { unsigned int new_video_out = video_out; if (lcd_out != -1) @@ -675,13 +663,14 @@ static const struct file_operations video_proc_fops = { static int fan_proc_show(struct seq_file *m, void *v) { + struct toshiba_acpi_dev *dev = m->private; u32 hci_result; u32 value; - hci_read1(HCI_FAN, &value, &hci_result); + hci_read1(dev, HCI_FAN, &value, &hci_result); if (hci_result == HCI_SUCCESS) { seq_printf(m, "running: %d\n", (value > 0)); - seq_printf(m, "force_on: %d\n", force_fan); + seq_printf(m, "force_on: %d\n", dev->force_fan); } else { pr_err("Error reading fan status\n"); } @@ -691,12 +680,13 @@ static int fan_proc_show(struct seq_file *m, void *v) static int fan_proc_open(struct inode *inode, struct file *file) { - return single_open(file, fan_proc_show, NULL); + return single_open(file, fan_proc_show, PDE(inode)->data); } static ssize_t fan_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { + struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data; char cmd[42]; size_t len; int value; @@ -709,11 +699,11 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf, if (sscanf(cmd, " force_on : %i", &value) == 1 && value >= 0 && value <= 1) { - hci_write1(HCI_FAN, value, &hci_result); + hci_write1(dev, HCI_FAN, value, &hci_result); if (hci_result != HCI_SUCCESS) return -EFAULT; else - force_fan = value; + dev->force_fan = value; } else { return -EINVAL; } @@ -732,21 +722,22 @@ static const struct file_operations fan_proc_fops = { static int keys_proc_show(struct seq_file *m, void *v) { + struct toshiba_acpi_dev *dev = m->private; u32 hci_result; u32 value; - if (!key_event_valid) { - hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (!dev->key_event_valid) { + hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result); if (hci_result == HCI_SUCCESS) { - key_event_valid = 1; - last_key_event = value; + dev->key_event_valid = 1; + dev->last_key_event = value; } else if (hci_result == HCI_EMPTY) { /* better luck next time */ } else if (hci_result == HCI_NOT_SUPPORTED) { /* This is a workaround for an unresolved issue on * some machines where system events sporadically * become disabled. */ - hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result); pr_notice("Re-enabled hotkeys\n"); } else { pr_err("Error reading hotkey status\n"); @@ -754,20 +745,21 @@ static int keys_proc_show(struct seq_file *m, void *v) } } - seq_printf(m, "hotkey_ready: %d\n", key_event_valid); - seq_printf(m, "hotkey: 0x%04x\n", last_key_event); + seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); + seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); end: return 0; } static int keys_proc_open(struct inode *inode, struct file *file) { - return single_open(file, keys_proc_show, NULL); + return single_open(file, keys_proc_show, PDE(inode)->data); } static ssize_t keys_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { + struct toshiba_acpi_dev *dev = PDE(file->f_path.dentry->d_inode)->data; char cmd[42]; size_t len; int value; @@ -778,7 +770,7 @@ static ssize_t keys_proc_write(struct file *file, const char __user *buf, cmd[len] = '\0'; if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) { - key_event_valid = 0; + dev->key_event_valid = 0; } else { return -EINVAL; } @@ -820,13 +812,19 @@ static const struct file_operations version_proc_fops = { #define PROC_TOSHIBA "toshiba" -static void __init create_toshiba_proc_entries(void) +static void __devinit +create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) { - proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops); - proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops); - proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops); - proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops); - proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops); + proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, + &lcd_proc_fops, dev); + proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, + &video_proc_fops, dev); + proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, + &fan_proc_fops, dev); + proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, + &keys_proc_fops, dev); + proc_create_data("version", S_IRUGO, toshiba_proc_dir, + &version_proc_fops, dev); } static void remove_toshiba_proc_entries(void) @@ -843,224 +841,242 @@ static const struct backlight_ops toshiba_backlight_data = { .update_status = set_lcd_status, }; -static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context) -{ - u32 hci_result, value; - - if (event != 0x80) - return; - do { - hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); - if (hci_result == HCI_SUCCESS) { - if (value == 0x100) - continue; - /* act on key press; ignore key release */ - if (value & 0x80) - continue; - - if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev, - value, 1, true)) { - pr_info("Unknown key %x\n", - value); - } - } else if (hci_result == HCI_NOT_SUPPORTED) { - /* This is a workaround for an unresolved issue on - * some machines where system events sporadically - * become disabled. */ - hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); - pr_notice("Re-enabled hotkeys\n"); - } - } while (hci_result != HCI_EMPTY); -} - -static int __init toshiba_acpi_setup_keyboard(char *device) +static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev, + char *device_path) { acpi_status status; int error; - status = acpi_get_handle(NULL, device, &toshiba_acpi.handle); + status = acpi_get_handle(NULL, device_path, &dev->handle); if (ACPI_FAILURE(status)) { pr_info("Unable to get notification device\n"); return -ENODEV; } - toshiba_acpi.hotkey_dev = input_allocate_device(); - if (!toshiba_acpi.hotkey_dev) { + dev->hotkey_dev = input_allocate_device(); + if (!dev->hotkey_dev) { pr_info("Unable to register input device\n"); return -ENOMEM; } - toshiba_acpi.hotkey_dev->name = "Toshiba input device"; - toshiba_acpi.hotkey_dev->phys = device; - toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST; + dev->hotkey_dev->name = "Toshiba input device"; + dev->hotkey_dev->phys = device_path; + dev->hotkey_dev->id.bustype = BUS_HOST; - error = sparse_keymap_setup(toshiba_acpi.hotkey_dev, - toshiba_acpi_keymap, NULL); + error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL); if (error) goto err_free_dev; - status = acpi_install_notify_handler(toshiba_acpi.handle, - ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL); - if (ACPI_FAILURE(status)) { - pr_info("Unable to install hotkey notification\n"); - error = -ENODEV; - goto err_free_keymap; - } - - status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL); + status = acpi_evaluate_object(dev->handle, "ENAB", NULL, NULL); if (ACPI_FAILURE(status)) { pr_info("Unable to enable hotkeys\n"); error = -ENODEV; - goto err_remove_notify; + goto err_free_keymap; } - error = input_register_device(toshiba_acpi.hotkey_dev); + error = input_register_device(dev->hotkey_dev); if (error) { pr_info("Unable to register input device\n"); - goto err_remove_notify; + goto err_free_keymap; } return 0; - err_remove_notify: - acpi_remove_notify_handler(toshiba_acpi.handle, - ACPI_DEVICE_NOTIFY, toshiba_acpi_notify); err_free_keymap: - sparse_keymap_free(toshiba_acpi.hotkey_dev); + sparse_keymap_free(dev->hotkey_dev); err_free_dev: - input_free_device(toshiba_acpi.hotkey_dev); - toshiba_acpi.hotkey_dev = NULL; + input_free_device(dev->hotkey_dev); + dev->hotkey_dev = NULL; return error; } -static void toshiba_acpi_exit(void) +static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) { - if (toshiba_acpi.hotkey_dev) { - acpi_remove_notify_handler(toshiba_acpi.handle, - ACPI_DEVICE_NOTIFY, toshiba_acpi_notify); - sparse_keymap_free(toshiba_acpi.hotkey_dev); - input_unregister_device(toshiba_acpi.hotkey_dev); - } + struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); - if (toshiba_acpi.bt_rfk) { - rfkill_unregister(toshiba_acpi.bt_rfk); - rfkill_destroy(toshiba_acpi.bt_rfk); - } + remove_toshiba_proc_entries(); - if (toshiba_backlight_device) - backlight_device_unregister(toshiba_backlight_device); + if (dev->hotkey_dev) { + input_unregister_device(dev->hotkey_dev); + sparse_keymap_free(dev->hotkey_dev); + } - remove_toshiba_proc_entries(); + if (dev->bt_rfk) { + rfkill_unregister(dev->bt_rfk); + rfkill_destroy(dev->bt_rfk); + } - if (toshiba_proc_dir) - remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + if (dev->backlight_dev) + backlight_device_unregister(dev->backlight_dev); - if (toshiba_acpi.illumination_installed) - led_classdev_unregister(&toshiba_led); + if (dev->illumination_installed) + led_classdev_unregister(&dev->led_dev); - platform_device_unregister(toshiba_acpi.p_dev); + kfree(dev); - return; + return 0; } -static int __init toshiba_acpi_init(void) +static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev) { + struct toshiba_acpi_dev *dev; u32 hci_result; bool bt_present; int ret = 0; struct backlight_properties props; - if (acpi_disabled) - return -ENODEV; + pr_info("Toshiba Laptop ACPI Extras version %s\n", + TOSHIBA_ACPI_VERSION); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->acpi_dev = acpi_dev; + acpi_dev->driver_data = dev; /* simple device detection: look for HCI method */ if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) { - method_hci = TOSH_INTERFACE_1 GHCI_METHOD; - if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1)) + dev->method_hci = TOSH_INTERFACE_1 GHCI_METHOD; + if (toshiba_acpi_setup_keyboard(dev, TOSH_INTERFACE_1)) pr_info("Unable to activate hotkeys\n"); } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) { - method_hci = TOSH_INTERFACE_2 GHCI_METHOD; - if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2)) + dev->method_hci = TOSH_INTERFACE_2 GHCI_METHOD; + if (toshiba_acpi_setup_keyboard(dev, TOSH_INTERFACE_2)) pr_info("Unable to activate hotkeys\n"); - } else - return -ENODEV; - - pr_info("Toshiba Laptop ACPI Extras version %s\n", - TOSHIBA_ACPI_VERSION); - pr_info(" HCI method: %s\n", method_hci); - - mutex_init(&toshiba_acpi.mutex); - - toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi", - -1, NULL, 0); - if (IS_ERR(toshiba_acpi.p_dev)) { - ret = PTR_ERR(toshiba_acpi.p_dev); - pr_err("unable to register platform device\n"); - toshiba_acpi.p_dev = NULL; - toshiba_acpi_exit(); - return ret; + } else { + ret = -ENODEV; + goto error; } - force_fan = 0; - key_event_valid = 0; + pr_info("HCI method: %s\n", dev->method_hci); + + mutex_init(&dev->mutex); /* enable event fifo */ - hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result); - toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); - if (!toshiba_proc_dir) { - toshiba_acpi_exit(); - return -ENODEV; - } else { - create_toshiba_proc_entries(); - } + create_toshiba_proc_entries(dev); props.type = BACKLIGHT_PLATFORM; props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; - toshiba_backlight_device = backlight_device_register("toshiba", - &toshiba_acpi.p_dev->dev, - NULL, - &toshiba_backlight_data, - &props); - if (IS_ERR(toshiba_backlight_device)) { - ret = PTR_ERR(toshiba_backlight_device); + dev->backlight_dev = backlight_device_register("toshiba", + &acpi_dev->dev, + dev, + &toshiba_backlight_data, + &props); + if (IS_ERR(dev->backlight_dev)) { + ret = PTR_ERR(dev->backlight_dev); pr_err("Could not register toshiba backlight device\n"); - toshiba_backlight_device = NULL; - toshiba_acpi_exit(); - return ret; + dev->backlight_dev = NULL; + goto error; } /* Register rfkill switch for Bluetooth */ - if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { - toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name, - &toshiba_acpi.p_dev->dev, - RFKILL_TYPE_BLUETOOTH, - &toshiba_rfk_ops, - &toshiba_acpi); - if (!toshiba_acpi.bt_rfk) { + if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) { + dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth", + &acpi_dev->dev, + RFKILL_TYPE_BLUETOOTH, + &toshiba_rfk_ops, + dev); + if (!dev->bt_rfk) { pr_err("unable to allocate rfkill device\n"); - toshiba_acpi_exit(); - return -ENOMEM; + ret = -ENOMEM; + goto error; } - ret = rfkill_register(toshiba_acpi.bt_rfk); + ret = rfkill_register(dev->bt_rfk); if (ret) { pr_err("unable to register rfkill device\n"); - rfkill_destroy(toshiba_acpi.bt_rfk); - toshiba_acpi_exit(); - return ret; + rfkill_destroy(dev->bt_rfk); + goto error; } } - toshiba_acpi.illumination_installed = 0; - if (toshiba_illumination_available()) { - if (!led_classdev_register(&(toshiba_acpi.p_dev->dev), - &toshiba_led)) - toshiba_acpi.illumination_installed = 1; + if (toshiba_illumination_available(dev)) { + dev->led_dev.name = "toshiba::illumination"; + dev->led_dev.max_brightness = 1; + dev->led_dev.brightness_set = toshiba_illumination_set; + dev->led_dev.brightness_get = toshiba_illumination_get; + if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) + dev->illumination_installed = 1; } return 0; + +error: + toshiba_acpi_remove(acpi_dev, 0); + return ret; +} + +static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) +{ + struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); + u32 hci_result, value; + + if (event != 0x80) + return; + do { + hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + if (value == 0x100) + continue; + /* act on key press; ignore key release */ + if (value & 0x80) + continue; + + if (!sparse_keymap_report_event(dev->hotkey_dev, + value, 1, true)) { + pr_info("Unknown key %x\n", + value); + } + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an unresolved issue on + * some machines where system events sporadically + * become disabled. */ + hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result); + pr_notice("Re-enabled hotkeys\n"); + } + } while (hci_result != HCI_EMPTY); +} + + +static struct acpi_driver toshiba_acpi_driver = { + .name = "Toshiba ACPI driver", + .owner = THIS_MODULE, + .ids = toshiba_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, + .ops = { + .add = toshiba_acpi_add, + .remove = toshiba_acpi_remove, + .notify = toshiba_acpi_notify, + }, +}; + +static int __init toshiba_acpi_init(void) +{ + int ret; + + toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); + if (!toshiba_proc_dir) { + pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); + return -ENODEV; + } + + ret = acpi_bus_register_driver(&toshiba_acpi_driver); + if (ret) { + pr_err("Failed to register ACPI driver: %d\n", ret); + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + } + + return ret; +} + +static void __exit toshiba_acpi_exit(void) +{ + acpi_bus_unregister_driver(&toshiba_acpi_driver); + if (toshiba_proc_dir) + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); } module_init(toshiba_acpi_init); |