diff options
-rw-r--r-- | drivers/acpi/Kconfig | 3 | ||||
-rw-r--r-- | drivers/acpi/toshiba_acpi.c | 261 |
2 files changed, 256 insertions, 8 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 735f5ea17473..12cf5d491f0d 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -260,6 +260,9 @@ config ACPI_ASUS | |||
260 | config ACPI_TOSHIBA | 260 | config ACPI_TOSHIBA |
261 | tristate "Toshiba Laptop Extras" | 261 | tristate "Toshiba Laptop Extras" |
262 | depends on X86 | 262 | depends on X86 |
263 | select INPUT_POLLDEV | ||
264 | select NET | ||
265 | select RFKILL | ||
263 | select BACKLIGHT_CLASS_DEVICE | 266 | select BACKLIGHT_CLASS_DEVICE |
264 | ---help--- | 267 | ---help--- |
265 | This driver adds support for access to certain system settings | 268 | This driver adds support for access to certain system settings |
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index 0a43c8e0eff3..8a649f40d162 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Copyright (C) 2002-2004 John Belmonte | 5 | * Copyright (C) 2002-2004 John Belmonte |
6 | * Copyright (C) 2008 Philip Langdale | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -33,7 +34,7 @@ | |||
33 | * | 34 | * |
34 | */ | 35 | */ |
35 | 36 | ||
36 | #define TOSHIBA_ACPI_VERSION "0.18" | 37 | #define TOSHIBA_ACPI_VERSION "0.19" |
37 | #define PROC_INTERFACE_VERSION 1 | 38 | #define PROC_INTERFACE_VERSION 1 |
38 | 39 | ||
39 | #include <linux/kernel.h> | 40 | #include <linux/kernel.h> |
@@ -42,6 +43,9 @@ | |||
42 | #include <linux/types.h> | 43 | #include <linux/types.h> |
43 | #include <linux/proc_fs.h> | 44 | #include <linux/proc_fs.h> |
44 | #include <linux/backlight.h> | 45 | #include <linux/backlight.h> |
46 | #include <linux/platform_device.h> | ||
47 | #include <linux/rfkill.h> | ||
48 | #include <linux/input-polldev.h> | ||
45 | 49 | ||
46 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
47 | 51 | ||
@@ -90,6 +94,7 @@ MODULE_LICENSE("GPL"); | |||
90 | #define HCI_VIDEO_OUT 0x001c | 94 | #define HCI_VIDEO_OUT 0x001c |
91 | #define HCI_HOTKEY_EVENT 0x001e | 95 | #define HCI_HOTKEY_EVENT 0x001e |
92 | #define HCI_LCD_BRIGHTNESS 0x002a | 96 | #define HCI_LCD_BRIGHTNESS 0x002a |
97 | #define HCI_WIRELESS 0x0056 | ||
93 | 98 | ||
94 | /* field definitions */ | 99 | /* field definitions */ |
95 | #define HCI_LCD_BRIGHTNESS_BITS 3 | 100 | #define HCI_LCD_BRIGHTNESS_BITS 3 |
@@ -98,9 +103,14 @@ MODULE_LICENSE("GPL"); | |||
98 | #define HCI_VIDEO_OUT_LCD 0x1 | 103 | #define HCI_VIDEO_OUT_LCD 0x1 |
99 | #define HCI_VIDEO_OUT_CRT 0x2 | 104 | #define HCI_VIDEO_OUT_CRT 0x2 |
100 | #define HCI_VIDEO_OUT_TV 0x4 | 105 | #define HCI_VIDEO_OUT_TV 0x4 |
106 | #define HCI_WIRELESS_KILL_SWITCH 0x01 | ||
107 | #define HCI_WIRELESS_BT_PRESENT 0x0f | ||
108 | #define HCI_WIRELESS_BT_ATTACH 0x40 | ||
109 | #define HCI_WIRELESS_BT_POWER 0x80 | ||
101 | 110 | ||
102 | static const struct acpi_device_id toshiba_device_ids[] = { | 111 | static const struct acpi_device_id toshiba_device_ids[] = { |
103 | {"TOS6200", 0}, | 112 | {"TOS6200", 0}, |
113 | {"TOS6208", 0}, | ||
104 | {"TOS1900", 0}, | 114 | {"TOS1900", 0}, |
105 | {"", 0}, | 115 | {"", 0}, |
106 | }; | 116 | }; |
@@ -193,7 +203,7 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) | |||
193 | return status; | 203 | return status; |
194 | } | 204 | } |
195 | 205 | ||
196 | /* common hci tasks (get or set one value) | 206 | /* common hci tasks (get or set one or two value) |
197 | * | 207 | * |
198 | * In addition to the ACPI status, the HCI system returns a result which | 208 | * In addition to the ACPI status, the HCI system returns a result which |
199 | * may be useful (such as "not supported"). | 209 | * may be useful (such as "not supported"). |
@@ -218,6 +228,152 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result) | |||
218 | return status; | 228 | return status; |
219 | } | 229 | } |
220 | 230 | ||
231 | static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result) | ||
232 | { | ||
233 | u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 }; | ||
234 | u32 out[HCI_WORDS]; | ||
235 | acpi_status status = hci_raw(in, out); | ||
236 | *result = (status == AE_OK) ? out[0] : HCI_FAILURE; | ||
237 | return status; | ||
238 | } | ||
239 | |||
240 | static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) | ||
241 | { | ||
242 | u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; | ||
243 | u32 out[HCI_WORDS]; | ||
244 | acpi_status status = hci_raw(in, out); | ||
245 | *out1 = out[2]; | ||
246 | *out2 = out[3]; | ||
247 | *result = (status == AE_OK) ? out[0] : HCI_FAILURE; | ||
248 | return status; | ||
249 | } | ||
250 | |||
251 | struct toshiba_acpi_dev { | ||
252 | struct platform_device *p_dev; | ||
253 | struct rfkill *rfk_dev; | ||
254 | struct input_polled_dev *poll_dev; | ||
255 | |||
256 | const char *bt_name; | ||
257 | const char *rfk_name; | ||
258 | |||
259 | bool last_rfk_state; | ||
260 | |||
261 | struct mutex mutex; | ||
262 | }; | ||
263 | |||
264 | static struct toshiba_acpi_dev toshiba_acpi = { | ||
265 | .bt_name = "Toshiba Bluetooth", | ||
266 | .rfk_name = "Toshiba RFKill Switch", | ||
267 | .last_rfk_state = false, | ||
268 | }; | ||
269 | |||
270 | /* Bluetooth rfkill handlers */ | ||
271 | |||
272 | static u32 hci_get_bt_present(bool *present) | ||
273 | { | ||
274 | u32 hci_result; | ||
275 | u32 value, value2; | ||
276 | |||
277 | value = 0; | ||
278 | value2 = 0; | ||
279 | hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); | ||
280 | if (hci_result == HCI_SUCCESS) | ||
281 | *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false; | ||
282 | |||
283 | return hci_result; | ||
284 | } | ||
285 | |||
286 | static u32 hci_get_bt_on(bool *on) | ||
287 | { | ||
288 | u32 hci_result; | ||
289 | u32 value, value2; | ||
290 | |||
291 | value = 0; | ||
292 | value2 = 0x0001; | ||
293 | hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); | ||
294 | if (hci_result == HCI_SUCCESS) | ||
295 | *on = (value & HCI_WIRELESS_BT_POWER) && | ||
296 | (value & HCI_WIRELESS_BT_ATTACH); | ||
297 | |||
298 | return hci_result; | ||
299 | } | ||
300 | |||
301 | static u32 hci_get_radio_state(bool *radio_state) | ||
302 | { | ||
303 | u32 hci_result; | ||
304 | u32 value, value2; | ||
305 | |||
306 | value = 0; | ||
307 | value2 = 0x0001; | ||
308 | hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); | ||
309 | |||
310 | *radio_state = value & HCI_WIRELESS_KILL_SWITCH; | ||
311 | return hci_result; | ||
312 | } | ||
313 | |||
314 | static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) | ||
315 | { | ||
316 | u32 result1, result2; | ||
317 | u32 value; | ||
318 | bool radio_state; | ||
319 | struct toshiba_acpi_dev *dev = data; | ||
320 | |||
321 | value = (state == RFKILL_STATE_UNBLOCKED); | ||
322 | |||
323 | if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) | ||
324 | return -EFAULT; | ||
325 | |||
326 | switch (state) { | ||
327 | case RFKILL_STATE_UNBLOCKED: | ||
328 | if (!radio_state) | ||
329 | return -EPERM; | ||
330 | break; | ||
331 | case RFKILL_STATE_SOFT_BLOCKED: | ||
332 | break; | ||
333 | default: | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | mutex_lock(&dev->mutex); | ||
338 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); | ||
339 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); | ||
340 | mutex_unlock(&dev->mutex); | ||
341 | |||
342 | if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) | ||
343 | return -EFAULT; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void bt_poll_rfkill(struct input_polled_dev *poll_dev) | ||
349 | { | ||
350 | bool state_changed; | ||
351 | bool new_rfk_state; | ||
352 | bool value; | ||
353 | u32 hci_result; | ||
354 | struct toshiba_acpi_dev *dev = poll_dev->private; | ||
355 | |||
356 | hci_result = hci_get_radio_state(&value); | ||
357 | if (hci_result != HCI_SUCCESS) | ||
358 | return; /* Can't do anything useful */ | ||
359 | |||
360 | new_rfk_state = value; | ||
361 | |||
362 | mutex_lock(&dev->mutex); | ||
363 | state_changed = new_rfk_state != dev->last_rfk_state; | ||
364 | dev->last_rfk_state = new_rfk_state; | ||
365 | mutex_unlock(&dev->mutex); | ||
366 | |||
367 | if (unlikely(state_changed)) { | ||
368 | rfkill_force_state(dev->rfk_dev, | ||
369 | new_rfk_state ? | ||
370 | RFKILL_STATE_SOFT_BLOCKED : | ||
371 | RFKILL_STATE_HARD_BLOCKED); | ||
372 | input_report_switch(poll_dev->input, SW_RFKILL_ALL, | ||
373 | new_rfk_state); | ||
374 | } | ||
375 | } | ||
376 | |||
221 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; | 377 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; |
222 | static struct backlight_device *toshiba_backlight_device; | 378 | static struct backlight_device *toshiba_backlight_device; |
223 | static int force_fan; | 379 | static int force_fan; |
@@ -547,6 +703,14 @@ static struct backlight_ops toshiba_backlight_data = { | |||
547 | 703 | ||
548 | static void toshiba_acpi_exit(void) | 704 | static void toshiba_acpi_exit(void) |
549 | { | 705 | { |
706 | if (toshiba_acpi.poll_dev) { | ||
707 | input_unregister_polled_device(toshiba_acpi.poll_dev); | ||
708 | input_free_polled_device(toshiba_acpi.poll_dev); | ||
709 | } | ||
710 | |||
711 | if (toshiba_acpi.rfk_dev) | ||
712 | rfkill_unregister(toshiba_acpi.rfk_dev); | ||
713 | |||
550 | if (toshiba_backlight_device) | 714 | if (toshiba_backlight_device) |
551 | backlight_device_unregister(toshiba_backlight_device); | 715 | backlight_device_unregister(toshiba_backlight_device); |
552 | 716 | ||
@@ -555,6 +719,8 @@ static void toshiba_acpi_exit(void) | |||
555 | if (toshiba_proc_dir) | 719 | if (toshiba_proc_dir) |
556 | remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); | 720 | remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); |
557 | 721 | ||
722 | platform_device_unregister(toshiba_acpi.p_dev); | ||
723 | |||
558 | return; | 724 | return; |
559 | } | 725 | } |
560 | 726 | ||
@@ -562,6 +728,10 @@ static int __init toshiba_acpi_init(void) | |||
562 | { | 728 | { |
563 | acpi_status status = AE_OK; | 729 | acpi_status status = AE_OK; |
564 | u32 hci_result; | 730 | u32 hci_result; |
731 | bool bt_present; | ||
732 | bool bt_on; | ||
733 | bool radio_on; | ||
734 | int ret = 0; | ||
565 | 735 | ||
566 | if (acpi_disabled) | 736 | if (acpi_disabled) |
567 | return -ENODEV; | 737 | return -ENODEV; |
@@ -578,6 +748,18 @@ static int __init toshiba_acpi_init(void) | |||
578 | TOSHIBA_ACPI_VERSION); | 748 | TOSHIBA_ACPI_VERSION); |
579 | printk(MY_INFO " HCI method: %s\n", method_hci); | 749 | printk(MY_INFO " HCI method: %s\n", method_hci); |
580 | 750 | ||
751 | mutex_init(&toshiba_acpi.mutex); | ||
752 | |||
753 | toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi", | ||
754 | -1, NULL, 0); | ||
755 | if (IS_ERR(toshiba_acpi.p_dev)) { | ||
756 | ret = PTR_ERR(toshiba_acpi.p_dev); | ||
757 | printk(MY_ERR "unable to register platform device\n"); | ||
758 | toshiba_acpi.p_dev = NULL; | ||
759 | toshiba_acpi_exit(); | ||
760 | return ret; | ||
761 | } | ||
762 | |||
581 | force_fan = 0; | 763 | force_fan = 0; |
582 | key_event_valid = 0; | 764 | key_event_valid = 0; |
583 | 765 | ||
@@ -586,19 +768,23 @@ static int __init toshiba_acpi_init(void) | |||
586 | 768 | ||
587 | toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); | 769 | toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); |
588 | if (!toshiba_proc_dir) { | 770 | if (!toshiba_proc_dir) { |
589 | status = AE_ERROR; | 771 | toshiba_acpi_exit(); |
772 | return -ENODEV; | ||
590 | } else { | 773 | } else { |
591 | toshiba_proc_dir->owner = THIS_MODULE; | 774 | toshiba_proc_dir->owner = THIS_MODULE; |
592 | status = add_device(); | 775 | status = add_device(); |
593 | if (ACPI_FAILURE(status)) | 776 | if (ACPI_FAILURE(status)) { |
594 | remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); | 777 | toshiba_acpi_exit(); |
778 | return -ENODEV; | ||
779 | } | ||
595 | } | 780 | } |
596 | 781 | ||
597 | toshiba_backlight_device = backlight_device_register("toshiba",NULL, | 782 | toshiba_backlight_device = backlight_device_register("toshiba", |
783 | &toshiba_acpi.p_dev->dev, | ||
598 | NULL, | 784 | NULL, |
599 | &toshiba_backlight_data); | 785 | &toshiba_backlight_data); |
600 | if (IS_ERR(toshiba_backlight_device)) { | 786 | if (IS_ERR(toshiba_backlight_device)) { |
601 | int ret = PTR_ERR(toshiba_backlight_device); | 787 | ret = PTR_ERR(toshiba_backlight_device); |
602 | 788 | ||
603 | printk(KERN_ERR "Could not register toshiba backlight device\n"); | 789 | printk(KERN_ERR "Could not register toshiba backlight device\n"); |
604 | toshiba_backlight_device = NULL; | 790 | toshiba_backlight_device = NULL; |
@@ -607,7 +793,66 @@ static int __init toshiba_acpi_init(void) | |||
607 | } | 793 | } |
608 | toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; | 794 | toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; |
609 | 795 | ||
610 | return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; | 796 | /* Register rfkill switch for Bluetooth */ |
797 | if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { | ||
798 | toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, | ||
799 | RFKILL_TYPE_BLUETOOTH); | ||
800 | if (!toshiba_acpi.rfk_dev) { | ||
801 | printk(MY_ERR "unable to allocate rfkill device\n"); | ||
802 | toshiba_acpi_exit(); | ||
803 | return -ENOMEM; | ||
804 | } | ||
805 | |||
806 | toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; | ||
807 | toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; | ||
808 | toshiba_acpi.rfk_dev->user_claim_unsupported = 1; | ||
809 | toshiba_acpi.rfk_dev->data = &toshiba_acpi; | ||
810 | |||
811 | if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { | ||
812 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED; | ||
813 | } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS && | ||
814 | radio_on) { | ||
815 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED; | ||
816 | } else { | ||
817 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED; | ||
818 | } | ||
819 | |||
820 | ret = rfkill_register(toshiba_acpi.rfk_dev); | ||
821 | if (ret) { | ||
822 | printk(MY_ERR "unable to register rfkill device\n"); | ||
823 | toshiba_acpi_exit(); | ||
824 | return -ENOMEM; | ||
825 | } | ||
826 | } | ||
827 | |||
828 | /* Register input device for kill switch */ | ||
829 | toshiba_acpi.poll_dev = input_allocate_polled_device(); | ||
830 | if (!toshiba_acpi.poll_dev) { | ||
831 | printk(MY_ERR "unable to allocate kill-switch input device\n"); | ||
832 | toshiba_acpi_exit(); | ||
833 | return -ENOMEM; | ||
834 | } | ||
835 | toshiba_acpi.poll_dev->private = &toshiba_acpi; | ||
836 | toshiba_acpi.poll_dev->poll = bt_poll_rfkill; | ||
837 | toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */ | ||
838 | |||
839 | toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name; | ||
840 | toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST; | ||
841 | toshiba_acpi.poll_dev->input->id.vendor = 0x0930; /* Toshiba USB ID */ | ||
842 | set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit); | ||
843 | set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit); | ||
844 | input_report_switch(toshiba_acpi.poll_dev->input, SW_RFKILL_ALL, TRUE); | ||
845 | |||
846 | ret = input_register_polled_device(toshiba_acpi.poll_dev); | ||
847 | if (ret) { | ||
848 | printk(MY_ERR "unable to register kill-switch input device\n"); | ||
849 | rfkill_free(toshiba_acpi.rfk_dev); | ||
850 | toshiba_acpi.rfk_dev = NULL; | ||
851 | toshiba_acpi_exit(); | ||
852 | return ret; | ||
853 | } | ||
854 | |||
855 | return 0; | ||
611 | } | 856 | } |
612 | 857 | ||
613 | module_init(toshiba_acpi_init); | 858 | module_init(toshiba_acpi_init); |