diff options
Diffstat (limited to 'drivers/platform/x86/sony-laptop.c')
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 191 |
1 files changed, 71 insertions, 120 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f1963b05175b..aec0b27fd774 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -128,11 +128,11 @@ enum sony_nc_rfkill { | |||
128 | SONY_BLUETOOTH, | 128 | SONY_BLUETOOTH, |
129 | SONY_WWAN, | 129 | SONY_WWAN, |
130 | SONY_WIMAX, | 130 | SONY_WIMAX, |
131 | SONY_RFKILL_MAX, | 131 | N_SONY_RFKILL, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; | 134 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
135 | static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; | 135 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
136 | static void sony_nc_rfkill_update(void); | 136 | static void sony_nc_rfkill_update(void); |
137 | 137 | ||
138 | /*********** Input Devices ***********/ | 138 | /*********** Input Devices ***********/ |
@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void) | |||
1051 | { | 1051 | { |
1052 | int i; | 1052 | int i; |
1053 | 1053 | ||
1054 | for (i = 0; i < SONY_RFKILL_MAX; i++) { | 1054 | for (i = 0; i < N_SONY_RFKILL; i++) { |
1055 | if (sony_rfkill_devices[i]) | 1055 | if (sony_rfkill_devices[i]) { |
1056 | rfkill_unregister(sony_rfkill_devices[i]); | 1056 | rfkill_unregister(sony_rfkill_devices[i]); |
1057 | rfkill_destroy(sony_rfkill_devices[i]); | ||
1058 | } | ||
1057 | } | 1059 | } |
1058 | } | 1060 | } |
1059 | 1061 | ||
1060 | static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) | 1062 | static int sony_nc_rfkill_set(void *data, bool blocked) |
1061 | { | ||
1062 | int result; | ||
1063 | int argument = sony_rfkill_address[(long) data]; | ||
1064 | |||
1065 | sony_call_snc_handle(0x124, 0x200, &result); | ||
1066 | if (result & 0x1) { | ||
1067 | sony_call_snc_handle(0x124, argument, &result); | ||
1068 | if (result & 0xf) | ||
1069 | *state = RFKILL_STATE_UNBLOCKED; | ||
1070 | else | ||
1071 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
1072 | } else { | ||
1073 | *state = RFKILL_STATE_HARD_BLOCKED; | ||
1074 | } | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int sony_nc_rfkill_set(void *data, enum rfkill_state state) | ||
1080 | { | 1063 | { |
1081 | int result; | 1064 | int result; |
1082 | int argument = sony_rfkill_address[(long) data] + 0x100; | 1065 | int argument = sony_rfkill_address[(long) data] + 0x100; |
1083 | 1066 | ||
1084 | if (state == RFKILL_STATE_UNBLOCKED) | 1067 | if (!blocked) |
1085 | argument |= 0xff0000; | 1068 | argument |= 0xff0000; |
1086 | 1069 | ||
1087 | return sony_call_snc_handle(0x124, argument, &result); | 1070 | return sony_call_snc_handle(0x124, argument, &result); |
1088 | } | 1071 | } |
1089 | 1072 | ||
1090 | static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) | 1073 | static const struct rfkill_ops sony_rfkill_ops = { |
1091 | { | 1074 | .set_block = sony_nc_rfkill_set, |
1092 | int err = 0; | 1075 | }; |
1093 | struct rfkill *sony_wifi_rfkill; | ||
1094 | |||
1095 | sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | ||
1096 | if (!sony_wifi_rfkill) | ||
1097 | return -1; | ||
1098 | sony_wifi_rfkill->name = "sony-wifi"; | ||
1099 | sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1100 | sony_wifi_rfkill->get_state = sony_nc_rfkill_get; | ||
1101 | sony_wifi_rfkill->data = (void *)SONY_WIFI; | ||
1102 | err = rfkill_register(sony_wifi_rfkill); | ||
1103 | if (err) | ||
1104 | rfkill_free(sony_wifi_rfkill); | ||
1105 | else { | ||
1106 | sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill; | ||
1107 | sony_nc_rfkill_set(sony_wifi_rfkill->data, | ||
1108 | RFKILL_STATE_UNBLOCKED); | ||
1109 | } | ||
1110 | return err; | ||
1111 | } | ||
1112 | 1076 | ||
1113 | static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) | 1077 | static int sony_nc_setup_rfkill(struct acpi_device *device, |
1078 | enum sony_nc_rfkill nc_type) | ||
1114 | { | 1079 | { |
1115 | int err = 0; | 1080 | int err = 0; |
1116 | struct rfkill *sony_bluetooth_rfkill; | 1081 | struct rfkill *rfk; |
1117 | 1082 | enum rfkill_type type; | |
1118 | sony_bluetooth_rfkill = rfkill_allocate(&device->dev, | 1083 | const char *name; |
1119 | RFKILL_TYPE_BLUETOOTH); | 1084 | |
1120 | if (!sony_bluetooth_rfkill) | 1085 | switch (nc_type) { |
1121 | return -1; | 1086 | case SONY_WIFI: |
1122 | sony_bluetooth_rfkill->name = "sony-bluetooth"; | 1087 | type = RFKILL_TYPE_WLAN; |
1123 | sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; | 1088 | name = "sony-wifi"; |
1124 | sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; | 1089 | break; |
1125 | sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; | 1090 | case SONY_BLUETOOTH: |
1126 | err = rfkill_register(sony_bluetooth_rfkill); | 1091 | type = RFKILL_TYPE_BLUETOOTH; |
1127 | if (err) | 1092 | name = "sony-bluetooth"; |
1128 | rfkill_free(sony_bluetooth_rfkill); | 1093 | break; |
1129 | else { | 1094 | case SONY_WWAN: |
1130 | sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; | 1095 | type = RFKILL_TYPE_WWAN; |
1131 | sony_nc_rfkill_set(sony_bluetooth_rfkill->data, | 1096 | name = "sony-wwan"; |
1132 | RFKILL_STATE_UNBLOCKED); | 1097 | break; |
1098 | case SONY_WIMAX: | ||
1099 | type = RFKILL_TYPE_WIMAX; | ||
1100 | name = "sony-wimax"; | ||
1101 | break; | ||
1102 | default: | ||
1103 | return -EINVAL; | ||
1133 | } | 1104 | } |
1134 | return err; | ||
1135 | } | ||
1136 | 1105 | ||
1137 | static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) | 1106 | rfk = rfkill_alloc(name, &device->dev, type, |
1138 | { | 1107 | &sony_rfkill_ops, (void *)nc_type); |
1139 | int err = 0; | 1108 | if (!rfk) |
1140 | struct rfkill *sony_wwan_rfkill; | 1109 | return -ENOMEM; |
1141 | 1110 | ||
1142 | sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); | 1111 | err = rfkill_register(rfk); |
1143 | if (!sony_wwan_rfkill) | 1112 | if (err) { |
1144 | return -1; | 1113 | rfkill_destroy(rfk); |
1145 | sony_wwan_rfkill->name = "sony-wwan"; | 1114 | return err; |
1146 | sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1147 | sony_wwan_rfkill->get_state = sony_nc_rfkill_get; | ||
1148 | sony_wwan_rfkill->data = (void *)SONY_WWAN; | ||
1149 | err = rfkill_register(sony_wwan_rfkill); | ||
1150 | if (err) | ||
1151 | rfkill_free(sony_wwan_rfkill); | ||
1152 | else { | ||
1153 | sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill; | ||
1154 | sony_nc_rfkill_set(sony_wwan_rfkill->data, | ||
1155 | RFKILL_STATE_UNBLOCKED); | ||
1156 | } | 1115 | } |
1116 | sony_rfkill_devices[nc_type] = rfk; | ||
1117 | sony_nc_rfkill_set((void *)nc_type, false); | ||
1157 | return err; | 1118 | return err; |
1158 | } | 1119 | } |
1159 | 1120 | ||
1160 | static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) | 1121 | static void sony_nc_rfkill_update() |
1161 | { | 1122 | { |
1162 | int err = 0; | 1123 | enum sony_nc_rfkill i; |
1163 | struct rfkill *sony_wimax_rfkill; | 1124 | int result; |
1125 | bool hwblock; | ||
1164 | 1126 | ||
1165 | sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); | 1127 | sony_call_snc_handle(0x124, 0x200, &result); |
1166 | if (!sony_wimax_rfkill) | 1128 | hwblock = !(result & 0x1); |
1167 | return -1; | ||
1168 | sony_wimax_rfkill->name = "sony-wimax"; | ||
1169 | sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1170 | sony_wimax_rfkill->get_state = sony_nc_rfkill_get; | ||
1171 | sony_wimax_rfkill->data = (void *)SONY_WIMAX; | ||
1172 | err = rfkill_register(sony_wimax_rfkill); | ||
1173 | if (err) | ||
1174 | rfkill_free(sony_wimax_rfkill); | ||
1175 | else { | ||
1176 | sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill; | ||
1177 | sony_nc_rfkill_set(sony_wimax_rfkill->data, | ||
1178 | RFKILL_STATE_UNBLOCKED); | ||
1179 | } | ||
1180 | return err; | ||
1181 | } | ||
1182 | 1129 | ||
1183 | static void sony_nc_rfkill_update() | 1130 | for (i = 0; i < N_SONY_RFKILL; i++) { |
1184 | { | 1131 | int argument = sony_rfkill_address[i]; |
1185 | int i; | ||
1186 | enum rfkill_state state; | ||
1187 | 1132 | ||
1188 | for (i = 0; i < SONY_RFKILL_MAX; i++) { | 1133 | if (!sony_rfkill_devices[i]) |
1189 | if (sony_rfkill_devices[i]) { | 1134 | continue; |
1190 | sony_rfkill_devices[i]-> | 1135 | |
1191 | get_state(sony_rfkill_devices[i]->data, | 1136 | if (hwblock) { |
1192 | &state); | 1137 | if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) |
1193 | rfkill_force_state(sony_rfkill_devices[i], state); | 1138 | sony_nc_rfkill_set(sony_rfkill_devices[i], |
1139 | true); | ||
1140 | continue; | ||
1194 | } | 1141 | } |
1142 | |||
1143 | sony_call_snc_handle(0x124, argument, &result); | ||
1144 | rfkill_set_states(sony_rfkill_devices[i], | ||
1145 | !(result & 0xf), false); | ||
1195 | } | 1146 | } |
1196 | } | 1147 | } |
1197 | 1148 | ||
@@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) | |||
1210 | } | 1161 | } |
1211 | 1162 | ||
1212 | if (result & 0x1) | 1163 | if (result & 0x1) |
1213 | sony_nc_setup_wifi_rfkill(device); | 1164 | sony_nc_setup_rfkill(device, SONY_WIFI); |
1214 | if (result & 0x2) | 1165 | if (result & 0x2) |
1215 | sony_nc_setup_bluetooth_rfkill(device); | 1166 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); |
1216 | if (result & 0x1c) | 1167 | if (result & 0x1c) |
1217 | sony_nc_setup_wwan_rfkill(device); | 1168 | sony_nc_setup_rfkill(device, SONY_WWAN); |
1218 | if (result & 0x20) | 1169 | if (result & 0x20) |
1219 | sony_nc_setup_wimax_rfkill(device); | 1170 | sony_nc_setup_rfkill(device, SONY_WIMAX); |
1220 | 1171 | ||
1221 | return 0; | 1172 | return 0; |
1222 | } | 1173 | } |