Skip to content

Commit

Permalink
dell-laptop: Pay attention to which devices the hardware switch controls
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matthew Garrett committed Feb 25, 2010
1 parent 116ee77 commit c6760ac
Showing 1 changed file with 29 additions and 2 deletions.
31 changes: 29 additions & 2 deletions drivers/platform/x86/dell-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ static struct calling_interface_buffer *buffer;
struct page *bufferpage;
DEFINE_MUTEX(buffer_mutex);

static int hwswitch_state;

static void get_buffer(void)
{
mutex_lock(&buffer_mutex);
Expand Down Expand Up @@ -217,6 +219,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
/* Derived from information in DellWirelessCtl.cpp:
Class 17, select 11 is radio control. It returns an array of 32-bit values.
Input byte 0 = 0: Wireless information
result[0]: return code
result[1]:
Bit 0: Hardware switch supported
Expand All @@ -237,18 +241,35 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
Bits 20-31: Reserved
result[2]: NVRAM size in bytes
result[3]: NVRAM format version number
Input byte 0 = 2: Wireless switch configuration
result[0]: return code
result[1]:
Bit 0: Wifi controlled by switch
Bit 1: Bluetooth controlled by switch
Bit 2: WWAN controlled by switch
Bits 3-6: Reserved
Bit 7: Wireless switch config locked
Bit 8: Wifi locator enabled
Bits 9-14: Reserved
Bit 15: Wifi locator setting locked
Bits 16-31: Reserved
*/

static int dell_rfkill_set(void *data, bool blocked)
{
int disable = blocked ? 1 : 0;
unsigned long radio = (unsigned long)data;
int hwswitch_bit = (unsigned long)data - 1;
int ret = 0;

get_buffer();
dell_send_request(buffer, 17, 11);

if (!(buffer->output[1] & BIT(16))) {
/* If the hardware switch controls this radio, and the hardware
switch is disabled, don't allow changing the software state */
if ((hwswitch_state & BIT(hwswitch_bit)) &&
!(buffer->output[1] & BIT(16))) {
ret = -EINVAL;
goto out;
}
Expand All @@ -265,14 +286,17 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
int status;
int bit = (unsigned long)data + 16;
int hwswitch_bit = (unsigned long)data - 1;

get_buffer();
dell_send_request(buffer, 17, 11);
status = buffer->output[1];
release_buffer();

rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
rfkill_set_hw_state(rfkill, !(status & BIT(16)));

if (hwswitch_state & (BIT(hwswitch_bit)))
rfkill_set_hw_state(rfkill, !(status & BIT(16)));
}

static const struct rfkill_ops dell_rfkill_ops = {
Expand Down Expand Up @@ -306,6 +330,9 @@ static int __init dell_setup_rfkill(void)
get_buffer();
dell_send_request(buffer, 17, 11);
status = buffer->output[1];
buffer->input[0] = 0x2;
dell_send_request(buffer, 17, 11);
hwswitch_state = buffer->output[1];
release_buffer();

if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
Expand Down

0 comments on commit c6760ac

Please sign in to comment.