diff options
| author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2008-07-21 08:15:51 -0400 |
|---|---|---|
| committer | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2008-07-21 08:15:51 -0400 |
| commit | 0e74dc2646db04b644faa8ea10ff4f408d55cf90 (patch) | |
| tree | d1729fca9b925ec972d1ad3c40295cc7740a31dd | |
| parent | 133ec3bd3ae409895eacdce326cdc8d73c249e8a (diff) | |
ACPI: thinkpad-acpi: add bluetooth and WWAN rfkill support
Add a read/write rfkill interface to the bluetooth radio switch on the
bluetooth submodule, and one for the wireless wan radio switch to the wan
submodule.
Since rfkill does care for when a switch changes state, use WLSW
notifications to also check if the WWAN or Bluetooth switches did not
change state (due to them being slaves of WLSW in firmware/hardware, but
that reality not being always properly exported by the thinkpad firmware).
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 22 | ||||
| -rw-r--r-- | drivers/misc/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/misc/thinkpad_acpi.c | 208 |
3 files changed, 200 insertions, 32 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 64b3f146e4b0..1c1c0217ebd1 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
| @@ -621,7 +621,8 @@ Bluetooth | |||
| 621 | --------- | 621 | --------- |
| 622 | 622 | ||
| 623 | procfs: /proc/acpi/ibm/bluetooth | 623 | procfs: /proc/acpi/ibm/bluetooth |
| 624 | sysfs device attribute: bluetooth_enable | 624 | sysfs device attribute: bluetooth_enable (deprecated) |
| 625 | sysfs rfkill class: switch "tpacpi_bluetooth_sw" | ||
| 625 | 626 | ||
| 626 | This feature shows the presence and current state of a ThinkPad | 627 | This feature shows the presence and current state of a ThinkPad |
| 627 | Bluetooth device in the internal ThinkPad CDC slot. | 628 | Bluetooth device in the internal ThinkPad CDC slot. |
| @@ -643,8 +644,12 @@ Sysfs notes: | |||
| 643 | 0: disables Bluetooth / Bluetooth is disabled | 644 | 0: disables Bluetooth / Bluetooth is disabled |
| 644 | 1: enables Bluetooth / Bluetooth is enabled. | 645 | 1: enables Bluetooth / Bluetooth is enabled. |
| 645 | 646 | ||
| 646 | Note: this interface will be probably be superseded by the | 647 | Note: this interface has been superseded by the generic rfkill |
| 647 | generic rfkill class, so it is NOT to be considered stable yet. | 648 | class. It has been deprecated, and it will be removed in year |
| 649 | 2010. | ||
| 650 | |||
| 651 | rfkill controller switch "tpacpi_bluetooth_sw": refer to | ||
| 652 | Documentation/rfkill.txt for details. | ||
| 648 | 653 | ||
| 649 | Video output control -- /proc/acpi/ibm/video | 654 | Video output control -- /proc/acpi/ibm/video |
| 650 | -------------------------------------------- | 655 | -------------------------------------------- |
| @@ -1374,7 +1379,8 @@ EXPERIMENTAL: WAN | |||
| 1374 | ----------------- | 1379 | ----------------- |
| 1375 | 1380 | ||
| 1376 | procfs: /proc/acpi/ibm/wan | 1381 | procfs: /proc/acpi/ibm/wan |
| 1377 | sysfs device attribute: wwan_enable | 1382 | sysfs device attribute: wwan_enable (deprecated) |
| 1383 | sysfs rfkill class: switch "tpacpi_wwan_sw" | ||
| 1378 | 1384 | ||
| 1379 | This feature is marked EXPERIMENTAL because the implementation | 1385 | This feature is marked EXPERIMENTAL because the implementation |
| 1380 | directly accesses hardware registers and may not work as expected. USE | 1386 | directly accesses hardware registers and may not work as expected. USE |
| @@ -1404,8 +1410,12 @@ Sysfs notes: | |||
| 1404 | 0: disables WWAN card / WWAN card is disabled | 1410 | 0: disables WWAN card / WWAN card is disabled |
| 1405 | 1: enables WWAN card / WWAN card is enabled. | 1411 | 1: enables WWAN card / WWAN card is enabled. |
| 1406 | 1412 | ||
| 1407 | Note: this interface will be probably be superseded by the | 1413 | Note: this interface has been superseded by the generic rfkill |
| 1408 | generic rfkill class, so it is NOT to be considered stable yet. | 1414 | class. It has been deprecated, and it will be removed in year |
| 1415 | 2010. | ||
| 1416 | |||
| 1417 | rfkill controller switch "tpacpi_wwan_sw": refer to | ||
| 1418 | Documentation/rfkill.txt for details. | ||
| 1409 | 1419 | ||
| 1410 | Multiple Commands, Module Parameters | 1420 | Multiple Commands, Module Parameters |
| 1411 | ------------------------------------ | 1421 | ------------------------------------ |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1921b8dbb242..b27ca91fd15e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -279,6 +279,8 @@ config THINKPAD_ACPI | |||
| 279 | select INPUT | 279 | select INPUT |
| 280 | select NEW_LEDS | 280 | select NEW_LEDS |
| 281 | select LEDS_CLASS | 281 | select LEDS_CLASS |
| 282 | select NET | ||
| 283 | select RFKILL | ||
| 282 | ---help--- | 284 | ---help--- |
| 283 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 285 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
| 284 | support for Fn-Fx key combinations, Bluetooth control, video | 286 | support for Fn-Fx key combinations, Bluetooth control, video |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 202d63e1b391..dc8d00a45701 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
| @@ -68,6 +68,7 @@ | |||
| 68 | #include <linux/hwmon-sysfs.h> | 68 | #include <linux/hwmon-sysfs.h> |
| 69 | #include <linux/input.h> | 69 | #include <linux/input.h> |
| 70 | #include <linux/leds.h> | 70 | #include <linux/leds.h> |
| 71 | #include <linux/rfkill.h> | ||
| 71 | #include <asm/uaccess.h> | 72 | #include <asm/uaccess.h> |
| 72 | 73 | ||
| 73 | #include <linux/dmi.h> | 74 | #include <linux/dmi.h> |
| @@ -144,6 +145,12 @@ enum { | |||
| 144 | 145 | ||
| 145 | #define TPACPI_MAX_ACPI_ARGS 3 | 146 | #define TPACPI_MAX_ACPI_ARGS 3 |
| 146 | 147 | ||
| 148 | /* rfkill switches */ | ||
| 149 | enum { | ||
| 150 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, | ||
| 151 | TPACPI_RFK_WWAN_SW_ID, | ||
| 152 | }; | ||
| 153 | |||
| 147 | /* Debugging */ | 154 | /* Debugging */ |
| 148 | #define TPACPI_LOG TPACPI_FILE ": " | 155 | #define TPACPI_LOG TPACPI_FILE ": " |
| 149 | #define TPACPI_ERR KERN_ERR TPACPI_LOG | 156 | #define TPACPI_ERR KERN_ERR TPACPI_LOG |
| @@ -905,6 +912,43 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) | |||
| 905 | return 0; | 912 | return 0; |
| 906 | } | 913 | } |
| 907 | 914 | ||
| 915 | static int __init tpacpi_new_rfkill(const unsigned int id, | ||
| 916 | struct rfkill **rfk, | ||
| 917 | const enum rfkill_type rfktype, | ||
| 918 | const char *name, | ||
| 919 | int (*toggle_radio)(void *, enum rfkill_state), | ||
| 920 | int (*get_state)(void *, enum rfkill_state *)) | ||
| 921 | { | ||
| 922 | int res; | ||
| 923 | enum rfkill_state initial_state; | ||
| 924 | |||
| 925 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); | ||
| 926 | if (!*rfk) { | ||
| 927 | printk(TPACPI_ERR | ||
| 928 | "failed to allocate memory for rfkill class\n"); | ||
| 929 | return -ENOMEM; | ||
| 930 | } | ||
| 931 | |||
| 932 | (*rfk)->name = name; | ||
| 933 | (*rfk)->get_state = get_state; | ||
| 934 | (*rfk)->toggle_radio = toggle_radio; | ||
| 935 | |||
| 936 | if (!get_state(NULL, &initial_state)) | ||
| 937 | (*rfk)->state = initial_state; | ||
| 938 | |||
| 939 | res = rfkill_register(*rfk); | ||
| 940 | if (res < 0) { | ||
| 941 | printk(TPACPI_ERR | ||
| 942 | "failed to register %s rfkill switch: %d\n", | ||
| 943 | name, res); | ||
| 944 | rfkill_free(*rfk); | ||
| 945 | *rfk = NULL; | ||
| 946 | return res; | ||
| 947 | } | ||
| 948 | |||
| 949 | return 0; | ||
| 950 | } | ||
| 951 | |||
| 908 | /************************************************************************* | 952 | /************************************************************************* |
| 909 | * thinkpad-acpi driver attributes | 953 | * thinkpad-acpi driver attributes |
| 910 | */ | 954 | */ |
| @@ -1906,10 +1950,18 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { | |||
| 1906 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | 1950 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, |
| 1907 | }; | 1951 | }; |
| 1908 | 1952 | ||
| 1953 | static void bluetooth_update_rfk(void); | ||
| 1954 | static void wan_update_rfk(void); | ||
| 1909 | static void tpacpi_send_radiosw_update(void) | 1955 | static void tpacpi_send_radiosw_update(void) |
| 1910 | { | 1956 | { |
| 1911 | int wlsw; | 1957 | int wlsw; |
| 1912 | 1958 | ||
| 1959 | /* Sync these BEFORE sending any rfkill events */ | ||
| 1960 | if (tp_features.bluetooth) | ||
| 1961 | bluetooth_update_rfk(); | ||
| 1962 | if (tp_features.wan) | ||
| 1963 | wan_update_rfk(); | ||
| 1964 | |||
| 1913 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | 1965 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { |
| 1914 | mutex_lock(&tpacpi_inputdev_send_mutex); | 1966 | mutex_lock(&tpacpi_inputdev_send_mutex); |
| 1915 | 1967 | ||
| @@ -2581,6 +2633,8 @@ enum { | |||
| 2581 | TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ | 2633 | TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ |
| 2582 | }; | 2634 | }; |
| 2583 | 2635 | ||
| 2636 | static struct rfkill *tpacpi_bluetooth_rfkill; | ||
| 2637 | |||
| 2584 | static int bluetooth_get_radiosw(void) | 2638 | static int bluetooth_get_radiosw(void) |
| 2585 | { | 2639 | { |
| 2586 | int status; | 2640 | int status; |
| @@ -2590,15 +2644,29 @@ static int bluetooth_get_radiosw(void) | |||
| 2590 | 2644 | ||
| 2591 | /* WLSW overrides bluetooth in firmware/hardware, reflect that */ | 2645 | /* WLSW overrides bluetooth in firmware/hardware, reflect that */ |
| 2592 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | 2646 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) |
| 2593 | return 0; | 2647 | return RFKILL_STATE_HARD_BLOCKED; |
| 2594 | 2648 | ||
| 2595 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 2649 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
| 2596 | return -EIO; | 2650 | return -EIO; |
| 2597 | 2651 | ||
| 2598 | return (status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0; | 2652 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? |
| 2653 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | ||
| 2599 | } | 2654 | } |
| 2600 | 2655 | ||
| 2601 | static int bluetooth_set_radiosw(int radio_on) | 2656 | static void bluetooth_update_rfk(void) |
| 2657 | { | ||
| 2658 | int status; | ||
| 2659 | |||
| 2660 | if (!tpacpi_bluetooth_rfkill) | ||
| 2661 | return; | ||
| 2662 | |||
| 2663 | status = bluetooth_get_radiosw(); | ||
| 2664 | if (status < 0) | ||
| 2665 | return; | ||
| 2666 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); | ||
| 2667 | } | ||
| 2668 | |||
| 2669 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) | ||
| 2602 | { | 2670 | { |
| 2603 | int status; | 2671 | int status; |
| 2604 | 2672 | ||
| @@ -2620,6 +2688,9 @@ static int bluetooth_set_radiosw(int radio_on) | |||
| 2620 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 2688 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
| 2621 | return -EIO; | 2689 | return -EIO; |
| 2622 | 2690 | ||
| 2691 | if (update_rfk) | ||
| 2692 | bluetooth_update_rfk(); | ||
| 2693 | |||
| 2623 | return 0; | 2694 | return 0; |
| 2624 | } | 2695 | } |
| 2625 | 2696 | ||
| @@ -2634,7 +2705,8 @@ static ssize_t bluetooth_enable_show(struct device *dev, | |||
| 2634 | if (status < 0) | 2705 | if (status < 0) |
| 2635 | return status; | 2706 | return status; |
| 2636 | 2707 | ||
| 2637 | return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); | 2708 | return snprintf(buf, PAGE_SIZE, "%d\n", |
| 2709 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | ||
| 2638 | } | 2710 | } |
| 2639 | 2711 | ||
| 2640 | static ssize_t bluetooth_enable_store(struct device *dev, | 2712 | static ssize_t bluetooth_enable_store(struct device *dev, |
| @@ -2647,7 +2719,7 @@ static ssize_t bluetooth_enable_store(struct device *dev, | |||
| 2647 | if (parse_strtoul(buf, 1, &t)) | 2719 | if (parse_strtoul(buf, 1, &t)) |
| 2648 | return -EINVAL; | 2720 | return -EINVAL; |
| 2649 | 2721 | ||
| 2650 | res = bluetooth_set_radiosw(t); | 2722 | res = bluetooth_set_radiosw(t, 1); |
| 2651 | 2723 | ||
| 2652 | return (res) ? res : count; | 2724 | return (res) ? res : count; |
| 2653 | } | 2725 | } |
| @@ -2667,8 +2739,27 @@ static const struct attribute_group bluetooth_attr_group = { | |||
| 2667 | .attrs = bluetooth_attributes, | 2739 | .attrs = bluetooth_attributes, |
| 2668 | }; | 2740 | }; |
| 2669 | 2741 | ||
| 2742 | static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) | ||
| 2743 | { | ||
| 2744 | int bts = bluetooth_get_radiosw(); | ||
| 2745 | |||
| 2746 | if (bts < 0) | ||
| 2747 | return bts; | ||
| 2748 | |||
| 2749 | *state = bts; | ||
| 2750 | return 0; | ||
| 2751 | } | ||
| 2752 | |||
| 2753 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) | ||
| 2754 | { | ||
| 2755 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
| 2756 | } | ||
| 2757 | |||
| 2670 | static void bluetooth_exit(void) | 2758 | static void bluetooth_exit(void) |
| 2671 | { | 2759 | { |
| 2760 | if (tpacpi_bluetooth_rfkill) | ||
| 2761 | rfkill_unregister(tpacpi_bluetooth_rfkill); | ||
| 2762 | |||
| 2672 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2763 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
| 2673 | &bluetooth_attr_group); | 2764 | &bluetooth_attr_group); |
| 2674 | } | 2765 | } |
| @@ -2699,14 +2790,26 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
| 2699 | "bluetooth hardware not installed\n"); | 2790 | "bluetooth hardware not installed\n"); |
| 2700 | } | 2791 | } |
| 2701 | 2792 | ||
| 2702 | if (tp_features.bluetooth) { | 2793 | if (!tp_features.bluetooth) |
| 2703 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2794 | return 1; |
| 2795 | |||
| 2796 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
| 2704 | &bluetooth_attr_group); | 2797 | &bluetooth_attr_group); |
| 2705 | if (res) | 2798 | if (res) |
| 2706 | return res; | 2799 | return res; |
| 2800 | |||
| 2801 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, | ||
| 2802 | &tpacpi_bluetooth_rfkill, | ||
| 2803 | RFKILL_TYPE_BLUETOOTH, | ||
| 2804 | "tpacpi_bluetooth_sw", | ||
| 2805 | tpacpi_bluetooth_rfk_set, | ||
| 2806 | tpacpi_bluetooth_rfk_get); | ||
| 2807 | if (res) { | ||
| 2808 | bluetooth_exit(); | ||
| 2809 | return res; | ||
| 2707 | } | 2810 | } |
| 2708 | 2811 | ||
| 2709 | return (tp_features.bluetooth)? 0 : 1; | 2812 | return 0; |
| 2710 | } | 2813 | } |
| 2711 | 2814 | ||
| 2712 | /* procfs -------------------------------------------------------------- */ | 2815 | /* procfs -------------------------------------------------------------- */ |
| @@ -2719,7 +2822,8 @@ static int bluetooth_read(char *p) | |||
| 2719 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 2822 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
| 2720 | else { | 2823 | else { |
| 2721 | len += sprintf(p + len, "status:\t\t%s\n", | 2824 | len += sprintf(p + len, "status:\t\t%s\n", |
| 2722 | (status)? "enabled" : "disabled"); | 2825 | (status == RFKILL_STATE_UNBLOCKED) ? |
| 2826 | "enabled" : "disabled"); | ||
| 2723 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 2827 | len += sprintf(p + len, "commands:\tenable, disable\n"); |
| 2724 | } | 2828 | } |
| 2725 | 2829 | ||
| @@ -2735,9 +2839,9 @@ static int bluetooth_write(char *buf) | |||
| 2735 | 2839 | ||
| 2736 | while ((cmd = next_cmd(&buf))) { | 2840 | while ((cmd = next_cmd(&buf))) { |
| 2737 | if (strlencmp(cmd, "enable") == 0) { | 2841 | if (strlencmp(cmd, "enable") == 0) { |
| 2738 | bluetooth_set_radiosw(1); | 2842 | bluetooth_set_radiosw(1, 1); |
| 2739 | } else if (strlencmp(cmd, "disable") == 0) { | 2843 | } else if (strlencmp(cmd, "disable") == 0) { |
| 2740 | bluetooth_set_radiosw(0); | 2844 | bluetooth_set_radiosw(0, 1); |
| 2741 | } else | 2845 | } else |
| 2742 | return -EINVAL; | 2846 | return -EINVAL; |
| 2743 | } | 2847 | } |
| @@ -2763,6 +2867,8 @@ enum { | |||
| 2763 | TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ | 2867 | TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ |
| 2764 | }; | 2868 | }; |
| 2765 | 2869 | ||
| 2870 | static struct rfkill *tpacpi_wan_rfkill; | ||
| 2871 | |||
| 2766 | static int wan_get_radiosw(void) | 2872 | static int wan_get_radiosw(void) |
| 2767 | { | 2873 | { |
| 2768 | int status; | 2874 | int status; |
| @@ -2772,15 +2878,29 @@ static int wan_get_radiosw(void) | |||
| 2772 | 2878 | ||
| 2773 | /* WLSW overrides WWAN in firmware/hardware, reflect that */ | 2879 | /* WLSW overrides WWAN in firmware/hardware, reflect that */ |
| 2774 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | 2880 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) |
| 2775 | return 0; | 2881 | return RFKILL_STATE_HARD_BLOCKED; |
| 2776 | 2882 | ||
| 2777 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 2883 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
| 2778 | return -EIO; | 2884 | return -EIO; |
| 2779 | 2885 | ||
| 2780 | return (status & TP_ACPI_WANCARD_RADIOSSW) != 0; | 2886 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? |
| 2887 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | ||
| 2781 | } | 2888 | } |
| 2782 | 2889 | ||
| 2783 | static int wan_set_radiosw(int radio_on) | 2890 | static void wan_update_rfk(void) |
| 2891 | { | ||
| 2892 | int status; | ||
| 2893 | |||
| 2894 | if (!tpacpi_wan_rfkill) | ||
| 2895 | return; | ||
| 2896 | |||
| 2897 | status = wan_get_radiosw(); | ||
| 2898 | if (status < 0) | ||
| 2899 | return; | ||
| 2900 | rfkill_force_state(tpacpi_wan_rfkill, status); | ||
| 2901 | } | ||
| 2902 | |||
| 2903 | static int wan_set_radiosw(int radio_on, int update_rfk) | ||
| 2784 | { | 2904 | { |
| 2785 | int status; | 2905 | int status; |
| 2786 | 2906 | ||
| @@ -2802,6 +2922,9 @@ static int wan_set_radiosw(int radio_on) | |||
| 2802 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 2922 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
| 2803 | return -EIO; | 2923 | return -EIO; |
| 2804 | 2924 | ||
| 2925 | if (update_rfk) | ||
| 2926 | wan_update_rfk(); | ||
| 2927 | |||
| 2805 | return 0; | 2928 | return 0; |
| 2806 | } | 2929 | } |
| 2807 | 2930 | ||
| @@ -2816,7 +2939,8 @@ static ssize_t wan_enable_show(struct device *dev, | |||
| 2816 | if (status < 0) | 2939 | if (status < 0) |
| 2817 | return status; | 2940 | return status; |
| 2818 | 2941 | ||
| 2819 | return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); | 2942 | return snprintf(buf, PAGE_SIZE, "%d\n", |
| 2943 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | ||
| 2820 | } | 2944 | } |
| 2821 | 2945 | ||
| 2822 | static ssize_t wan_enable_store(struct device *dev, | 2946 | static ssize_t wan_enable_store(struct device *dev, |
| @@ -2829,7 +2953,7 @@ static ssize_t wan_enable_store(struct device *dev, | |||
| 2829 | if (parse_strtoul(buf, 1, &t)) | 2953 | if (parse_strtoul(buf, 1, &t)) |
| 2830 | return -EINVAL; | 2954 | return -EINVAL; |
| 2831 | 2955 | ||
| 2832 | res = wan_set_radiosw(t); | 2956 | res = wan_set_radiosw(t, 1); |
| 2833 | 2957 | ||
| 2834 | return (res) ? res : count; | 2958 | return (res) ? res : count; |
| 2835 | } | 2959 | } |
| @@ -2849,8 +2973,27 @@ static const struct attribute_group wan_attr_group = { | |||
| 2849 | .attrs = wan_attributes, | 2973 | .attrs = wan_attributes, |
| 2850 | }; | 2974 | }; |
| 2851 | 2975 | ||
| 2976 | static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) | ||
| 2977 | { | ||
| 2978 | int wans = wan_get_radiosw(); | ||
| 2979 | |||
| 2980 | if (wans < 0) | ||
| 2981 | return wans; | ||
| 2982 | |||
| 2983 | *state = wans; | ||
| 2984 | return 0; | ||
| 2985 | } | ||
| 2986 | |||
| 2987 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) | ||
| 2988 | { | ||
| 2989 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
| 2990 | } | ||
| 2991 | |||
| 2852 | static void wan_exit(void) | 2992 | static void wan_exit(void) |
| 2853 | { | 2993 | { |
| 2994 | if (tpacpi_wan_rfkill) | ||
| 2995 | rfkill_unregister(tpacpi_wan_rfkill); | ||
| 2996 | |||
| 2854 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2997 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
| 2855 | &wan_attr_group); | 2998 | &wan_attr_group); |
| 2856 | } | 2999 | } |
| @@ -2879,14 +3022,26 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
| 2879 | "wan hardware not installed\n"); | 3022 | "wan hardware not installed\n"); |
| 2880 | } | 3023 | } |
| 2881 | 3024 | ||
| 2882 | if (tp_features.wan) { | 3025 | if (!tp_features.wan) |
| 2883 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 3026 | return 1; |
| 3027 | |||
| 3028 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
| 2884 | &wan_attr_group); | 3029 | &wan_attr_group); |
| 2885 | if (res) | 3030 | if (res) |
| 2886 | return res; | 3031 | return res; |
| 3032 | |||
| 3033 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, | ||
| 3034 | &tpacpi_wan_rfkill, | ||
| 3035 | RFKILL_TYPE_WWAN, | ||
| 3036 | "tpacpi_wwan_sw", | ||
| 3037 | tpacpi_wan_rfk_set, | ||
| 3038 | tpacpi_wan_rfk_get); | ||
| 3039 | if (res) { | ||
| 3040 | wan_exit(); | ||
| 3041 | return res; | ||
| 2887 | } | 3042 | } |
| 2888 | 3043 | ||
| 2889 | return (tp_features.wan)? 0 : 1; | 3044 | return 0; |
| 2890 | } | 3045 | } |
| 2891 | 3046 | ||
| 2892 | /* procfs -------------------------------------------------------------- */ | 3047 | /* procfs -------------------------------------------------------------- */ |
| @@ -2899,7 +3054,8 @@ static int wan_read(char *p) | |||
| 2899 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3054 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
| 2900 | else { | 3055 | else { |
| 2901 | len += sprintf(p + len, "status:\t\t%s\n", | 3056 | len += sprintf(p + len, "status:\t\t%s\n", |
| 2902 | (status)? "enabled" : "disabled"); | 3057 | (status == RFKILL_STATE_UNBLOCKED) ? |
| 3058 | "enabled" : "disabled"); | ||
| 2903 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 3059 | len += sprintf(p + len, "commands:\tenable, disable\n"); |
| 2904 | } | 3060 | } |
| 2905 | 3061 | ||
| @@ -2915,9 +3071,9 @@ static int wan_write(char *buf) | |||
| 2915 | 3071 | ||
| 2916 | while ((cmd = next_cmd(&buf))) { | 3072 | while ((cmd = next_cmd(&buf))) { |
| 2917 | if (strlencmp(cmd, "enable") == 0) { | 3073 | if (strlencmp(cmd, "enable") == 0) { |
| 2918 | wan_set_radiosw(1); | 3074 | wan_set_radiosw(1, 1); |
| 2919 | } else if (strlencmp(cmd, "disable") == 0) { | 3075 | } else if (strlencmp(cmd, "disable") == 0) { |
| 2920 | wan_set_radiosw(0); | 3076 | wan_set_radiosw(0, 1); |
| 2921 | } else | 3077 | } else |
| 2922 | return -EINVAL; | 3078 | return -EINVAL; |
| 2923 | } | 3079 | } |
