|
@@ -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);
|
|
@@ -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
|
|
@@ -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;
|
|
|
}
|
|
@@ -265,6 +286,7 @@ 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);
|
|
@@ -272,7 +294,9 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
|
|
|
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 = {
|
|
@@ -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)) {
|