aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/sony-laptop.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index f6cdc8929fd7..f458870c30b6 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -64,6 +64,7 @@
64#include <asm/uaccess.h> 64#include <asm/uaccess.h>
65#include <linux/sonypi.h> 65#include <linux/sonypi.h>
66#include <linux/sony-laptop.h> 66#include <linux/sony-laptop.h>
67#include <linux/rfkill.h>
67#ifdef CONFIG_SONYPI_COMPAT 68#ifdef CONFIG_SONYPI_COMPAT
68#include <linux/poll.h> 69#include <linux/poll.h>
69#include <linux/miscdevice.h> 70#include <linux/miscdevice.h>
@@ -123,6 +124,18 @@ MODULE_PARM_DESC(minor,
123 "default is -1 (automatic)"); 124 "default is -1 (automatic)");
124#endif 125#endif
125 126
127enum sony_nc_rfkill {
128 SONY_WIFI,
129 SONY_BLUETOOTH,
130 SONY_WWAN,
131 SONY_WIMAX,
132 SONY_RFKILL_MAX,
133};
134
135static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
136static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
137static void sony_nc_rfkill_update(void);
138
126/*********** Input Devices ***********/ 139/*********** Input Devices ***********/
127 140
128#define SONY_LAPTOP_BUF_SIZE 128 141#define SONY_LAPTOP_BUF_SIZE 128
@@ -134,6 +147,7 @@ struct sony_laptop_input_s {
134 spinlock_t fifo_lock; 147 spinlock_t fifo_lock;
135 struct workqueue_struct *wq; 148 struct workqueue_struct *wq;
136}; 149};
150
137static struct sony_laptop_input_s sony_laptop_input = { 151static struct sony_laptop_input_s sony_laptop_input = {
138 .users = ATOMIC_INIT(0), 152 .users = ATOMIC_INIT(0),
139}; 153};
@@ -891,6 +905,9 @@ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
891 if (!sony_nc_events[i].data) 905 if (!sony_nc_events[i].data)
892 printk(KERN_INFO DRV_PFX 906 printk(KERN_INFO DRV_PFX
893 "Unknown event: %x %x\n", origev, ev); 907 "Unknown event: %x %x\n", origev, ev);
908 } else if (sony_find_snc_handle(0x124) == ev) {
909 sony_nc_rfkill_update();
910 return;
894 } 911 }
895 } 912 }
896 913
@@ -973,6 +990,172 @@ static int sony_nc_resume(struct acpi_device *device)
973 return 0; 990 return 0;
974} 991}
975 992
993static void sony_nc_rfkill_cleanup(void)
994{
995 int i;
996
997 for (i = 0; i < SONY_RFKILL_MAX; i++) {
998 if (sony_rfkill_devices[i])
999 rfkill_unregister(sony_rfkill_devices[i]);
1000 }
1001}
1002
1003static int sony_nc_rfkill_get(void *data, enum rfkill_state *state)
1004{
1005 int result;
1006 int argument = sony_rfkill_address[(long) data];
1007
1008 sony_call_snc_handle(0x124, 0x200, &result);
1009 if (result & 0x1) {
1010 sony_call_snc_handle(0x124, argument, &result);
1011 if (result & 0xf)
1012 *state = RFKILL_STATE_UNBLOCKED;
1013 else
1014 *state = RFKILL_STATE_SOFT_BLOCKED;
1015 } else {
1016 *state = RFKILL_STATE_HARD_BLOCKED;
1017 }
1018
1019 return 0;
1020}
1021
1022static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
1023{
1024 int result;
1025 int argument = sony_rfkill_address[(long) data] + 0x100;
1026
1027 if (state == RFKILL_STATE_UNBLOCKED)
1028 argument |= 0xff0000;
1029
1030 return sony_call_snc_handle(0x124, argument, &result);
1031}
1032
1033static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
1034{
1035 int err = 0;
1036 struct rfkill *sony_wifi_rfkill;
1037
1038 sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
1039 if (!sony_wifi_rfkill)
1040 return -1;
1041 sony_wifi_rfkill->name = "sony-wifi";
1042 sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
1043 sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
1044 sony_wifi_rfkill->user_claim_unsupported = 1;
1045 sony_wifi_rfkill->data = (void *)SONY_WIFI;
1046 err = rfkill_register(sony_wifi_rfkill);
1047 if (err)
1048 rfkill_free(sony_wifi_rfkill);
1049 else
1050 sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
1051 return err;
1052}
1053
1054static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
1055{
1056 int err = 0;
1057 struct rfkill *sony_bluetooth_rfkill;
1058
1059 sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
1060 RFKILL_TYPE_BLUETOOTH);
1061 if (!sony_bluetooth_rfkill)
1062 return -1;
1063 sony_bluetooth_rfkill->name = "sony-bluetooth";
1064 sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
1065 sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
1066 sony_bluetooth_rfkill->user_claim_unsupported = 1;
1067 sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
1068 err = rfkill_register(sony_bluetooth_rfkill);
1069 if (err)
1070 rfkill_free(sony_bluetooth_rfkill);
1071 else
1072 sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill;
1073 return err;
1074}
1075
1076static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
1077{
1078 int err = 0;
1079 struct rfkill *sony_wwan_rfkill;
1080
1081 sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
1082 if (!sony_wwan_rfkill)
1083 return -1;
1084 sony_wwan_rfkill->name = "sony-wwan";
1085 sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
1086 sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
1087 sony_wwan_rfkill->user_claim_unsupported = 1;
1088 sony_wwan_rfkill->data = (void *)SONY_WWAN;
1089 err = rfkill_register(sony_wwan_rfkill);
1090 if (err)
1091 rfkill_free(sony_wwan_rfkill);
1092 else
1093 sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill;
1094 return err;
1095}
1096
1097static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
1098{
1099 int err = 0;
1100 struct rfkill *sony_wimax_rfkill;
1101
1102 sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
1103 if (!sony_wimax_rfkill)
1104 return -1;
1105 sony_wimax_rfkill->name = "sony-wimax";
1106 sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
1107 sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
1108 sony_wimax_rfkill->user_claim_unsupported = 1;
1109 sony_wimax_rfkill->data = (void *)SONY_WIMAX;
1110 err = rfkill_register(sony_wimax_rfkill);
1111 if (err)
1112 rfkill_free(sony_wimax_rfkill);
1113 else
1114 sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill;
1115 return err;
1116}
1117
1118static void sony_nc_rfkill_update()
1119{
1120 int i;
1121 enum rfkill_state state;
1122
1123 for (i = 0; i < SONY_RFKILL_MAX; i++) {
1124 if (sony_rfkill_devices[i]) {
1125 sony_rfkill_devices[i]->
1126 get_state(sony_rfkill_devices[i]->data,
1127 &state);
1128 rfkill_force_state(sony_rfkill_devices[i], state);
1129 }
1130 }
1131}
1132
1133static int sony_nc_rfkill_setup(struct acpi_device *device)
1134{
1135 int result, ret;
1136
1137 if (sony_find_snc_handle(0x124) == -1)
1138 return -1;
1139
1140 ret = sony_call_snc_handle(0x124, 0xb00, &result);
1141 if (ret) {
1142 printk(KERN_INFO DRV_PFX
1143 "Unable to enumerate rfkill devices: %x\n", ret);
1144 return ret;
1145 }
1146
1147 if (result & 0x1)
1148 sony_nc_setup_wifi_rfkill(device);
1149 if (result & 0x2)
1150 sony_nc_setup_bluetooth_rfkill(device);
1151 if (result & 0x1c)
1152 sony_nc_setup_wwan_rfkill(device);
1153 if (result & 0x20)
1154 sony_nc_setup_wimax_rfkill(device);
1155
1156 return 0;
1157}
1158
976static int sony_nc_add(struct acpi_device *device) 1159static int sony_nc_add(struct acpi_device *device)
977{ 1160{
978 acpi_status status; 1161 acpi_status status;
@@ -1026,6 +1209,7 @@ static int sony_nc_add(struct acpi_device *device)
1026 &handle))) { 1209 &handle))) {
1027 dprintk("Doing SNC setup\n"); 1210 dprintk("Doing SNC setup\n");
1028 sony_nc_function_setup(device); 1211 sony_nc_function_setup(device);
1212 sony_nc_rfkill_setup(device);
1029 } 1213 }
1030 1214
1031 /* setup input devices and helper fifo */ 1215 /* setup input devices and helper fifo */
@@ -1132,6 +1316,7 @@ static int sony_nc_add(struct acpi_device *device)
1132 sony_laptop_remove_input(); 1316 sony_laptop_remove_input();
1133 1317
1134 outwalk: 1318 outwalk:
1319 sony_nc_rfkill_cleanup();
1135 return result; 1320 return result;
1136} 1321}
1137 1322
@@ -1157,6 +1342,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1157 1342
1158 sony_pf_remove(); 1343 sony_pf_remove();
1159 sony_laptop_remove_input(); 1344 sony_laptop_remove_input();
1345 sony_nc_rfkill_cleanup();
1160 dprintk(SONY_NC_DRIVER_NAME " removed.\n"); 1346 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
1161 1347
1162 return 0; 1348 return 0;