aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2010-02-10 14:44:03 -0500
committerMatthew Garrett <mjg@redhat.com>2010-02-25 11:50:50 -0500
commitc6760ac4268b6dbe03d74e5faef35bc862a82542 (patch)
tree85b244b524c7d9b3037840e723b1f85a18f6e964 /drivers/platform
parent116ee77b2858d9c89c0327f3a47c8ba864bf4a96 (diff)
dell-laptop: Pay attention to which devices the hardware switch controls
Right now, we assume that the hardware rfkill switch on Dells toggles all radio devices. In fact, this can be configured in the BIOS and so right now we may mark a device as hardware killed even when it isn't. Add code to query the devices controlled by the switch, and use this when determining the hardware kill state of a radio. Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/dell-laptop.c31
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;
128struct page *bufferpage; 128struct page *bufferpage;
129DEFINE_MUTEX(buffer_mutex); 129DEFINE_MUTEX(buffer_mutex);
130 130
131static int hwswitch_state;
132
131static void get_buffer(void) 133static 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
242static int dell_rfkill_set(void *data, bool blocked) 259static 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
278static const struct rfkill_ops dell_rfkill_ops = { 302static 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)) {