diff options
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 1a0bfd43f8f0..04b2ddbe63d2 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -128,6 +128,8 @@ static struct calling_interface_buffer *buffer; | |||
128 | struct page *bufferpage; | 128 | struct page *bufferpage; |
129 | DEFINE_MUTEX(buffer_mutex); | 129 | DEFINE_MUTEX(buffer_mutex); |
130 | 130 | ||
131 | static int hwswitch_state; | ||
132 | |||
131 | static void get_buffer(void) | 133 | static void get_buffer(void) |
132 | { | 134 | { |
133 | mutex_lock(&buffer_mutex); | 135 | mutex_lock(&buffer_mutex); |
@@ -217,6 +219,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
217 | /* Derived from information in DellWirelessCtl.cpp: | 219 | /* Derived from information in DellWirelessCtl.cpp: |
218 | Class 17, select 11 is radio control. It returns an array of 32-bit values. | 220 | Class 17, select 11 is radio control. It returns an array of 32-bit values. |
219 | 221 | ||
222 | Input byte 0 = 0: Wireless information | ||
223 | |||
220 | result[0]: return code | 224 | result[0]: return code |
221 | result[1]: | 225 | result[1]: |
222 | Bit 0: Hardware switch supported | 226 | Bit 0: Hardware switch supported |
@@ -237,18 +241,35 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
237 | Bits 20-31: Reserved | 241 | Bits 20-31: Reserved |
238 | result[2]: NVRAM size in bytes | 242 | result[2]: NVRAM size in bytes |
239 | result[3]: NVRAM format version number | 243 | result[3]: NVRAM format version number |
244 | |||
245 | Input byte 0 = 2: Wireless switch configuration | ||
246 | result[0]: return code | ||
247 | result[1]: | ||
248 | Bit 0: Wifi controlled by switch | ||
249 | Bit 1: Bluetooth controlled by switch | ||
250 | Bit 2: WWAN controlled by switch | ||
251 | Bits 3-6: Reserved | ||
252 | Bit 7: Wireless switch config locked | ||
253 | Bit 8: Wifi locator enabled | ||
254 | Bits 9-14: Reserved | ||
255 | Bit 15: Wifi locator setting locked | ||
256 | Bits 16-31: Reserved | ||
240 | */ | 257 | */ |
241 | 258 | ||
242 | static int dell_rfkill_set(void *data, bool blocked) | 259 | static int dell_rfkill_set(void *data, bool blocked) |
243 | { | 260 | { |
244 | int disable = blocked ? 1 : 0; | 261 | int disable = blocked ? 1 : 0; |
245 | unsigned long radio = (unsigned long)data; | 262 | unsigned long radio = (unsigned long)data; |
263 | int hwswitch_bit = (unsigned long)data - 1; | ||
246 | int ret = 0; | 264 | int ret = 0; |
247 | 265 | ||
248 | get_buffer(); | 266 | get_buffer(); |
249 | dell_send_request(buffer, 17, 11); | 267 | dell_send_request(buffer, 17, 11); |
250 | 268 | ||
251 | if (!(buffer->output[1] & BIT(16))) { | 269 | /* If the hardware switch controls this radio, and the hardware |
270 | switch is disabled, don't allow changing the software state */ | ||
271 | if ((hwswitch_state & BIT(hwswitch_bit)) && | ||
272 | !(buffer->output[1] & BIT(16))) { | ||
252 | ret = -EINVAL; | 273 | ret = -EINVAL; |
253 | goto out; | 274 | goto out; |
254 | } | 275 | } |
@@ -265,6 +286,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) | |||
265 | { | 286 | { |
266 | int status; | 287 | int status; |
267 | int bit = (unsigned long)data + 16; | 288 | int bit = (unsigned long)data + 16; |
289 | int hwswitch_bit = (unsigned long)data - 1; | ||
268 | 290 | ||
269 | get_buffer(); | 291 | get_buffer(); |
270 | dell_send_request(buffer, 17, 11); | 292 | dell_send_request(buffer, 17, 11); |
@@ -272,7 +294,9 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) | |||
272 | release_buffer(); | 294 | release_buffer(); |
273 | 295 | ||
274 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); | 296 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); |
275 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); | 297 | |
298 | if (hwswitch_state & (BIT(hwswitch_bit))) | ||
299 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); | ||
276 | } | 300 | } |
277 | 301 | ||
278 | static const struct rfkill_ops dell_rfkill_ops = { | 302 | static const struct rfkill_ops dell_rfkill_ops = { |
@@ -306,6 +330,9 @@ static int __init dell_setup_rfkill(void) | |||
306 | get_buffer(); | 330 | get_buffer(); |
307 | dell_send_request(buffer, 17, 11); | 331 | dell_send_request(buffer, 17, 11); |
308 | status = buffer->output[1]; | 332 | status = buffer->output[1]; |
333 | buffer->input[0] = 0x2; | ||
334 | dell_send_request(buffer, 17, 11); | ||
335 | hwswitch_state = buffer->output[1]; | ||
309 | release_buffer(); | 336 | release_buffer(); |
310 | 337 | ||
311 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 338 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |