Skip to content

Commit 22565ba

Browse files
palidvhart
authored andcommitted
dell-laptop: Do not cache hwswitch state
The hwswitch state can be changed at runtime, so make sure dell-laptop always knows the current state. It can be modified by the userspace utility smbios-wireless-ctl. Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Signed-off-by: Darren Hart <dvhart@linux.intel.com>
1 parent 715d0cd commit 22565ba

File tree

1 file changed

+61
-24
lines changed

1 file changed

+61
-24
lines changed

drivers/platform/x86/dell-laptop.c

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
309309
static struct calling_interface_buffer *buffer;
310310
static DEFINE_MUTEX(buffer_mutex);
311311

312-
static int hwswitch_state;
313-
314312
static void clear_buffer(void)
315313
{
316314
memset(buffer, 0, sizeof(struct calling_interface_buffer));
@@ -553,20 +551,30 @@ static int dell_rfkill_set(void *data, bool blocked)
553551
int disable = blocked ? 1 : 0;
554552
unsigned long radio = (unsigned long)data;
555553
int hwswitch_bit = (unsigned long)data - 1;
554+
int hwswitch;
555+
int status;
556556
int ret;
557557

558558
get_buffer();
559559

560560
dell_send_request(buffer, 17, 11);
561561
ret = buffer->output[0];
562+
status = buffer->output[1];
562563

563564
if (ret != 0)
564565
goto out;
565566

567+
clear_buffer();
568+
569+
buffer->input[0] = 0x2;
570+
dell_send_request(buffer, 17, 11);
571+
ret = buffer->output[0];
572+
hwswitch = buffer->output[1];
573+
566574
/* If the hardware switch controls this radio, and the hardware
567575
switch is disabled, always disable the radio */
568-
if ((hwswitch_state & BIT(hwswitch_bit)) &&
569-
!(buffer->output[1] & BIT(16)))
576+
if (ret == 0 && (hwswitch & BIT(hwswitch_bit)) &&
577+
(status & BIT(0)) && !(status & BIT(16)))
570578
disable = 1;
571579

572580
clear_buffer();
@@ -597,27 +605,43 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
597605
}
598606

599607
static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
600-
int status)
608+
int status, int hwswitch)
601609
{
602-
if (hwswitch_state & (BIT(radio - 1)))
610+
if (hwswitch & (BIT(radio - 1)))
603611
rfkill_set_hw_state(rfkill, !(status & BIT(16)));
604612
}
605613

606614
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
607615
{
616+
int radio = ((unsigned long)data & 0xF);
617+
int hwswitch;
608618
int status;
609619
int ret;
610620

611621
get_buffer();
622+
612623
dell_send_request(buffer, 17, 11);
613624
ret = buffer->output[0];
614625
status = buffer->output[1];
626+
627+
if (ret != 0 || !(status & BIT(0))) {
628+
release_buffer();
629+
return;
630+
}
631+
632+
clear_buffer();
633+
634+
buffer->input[0] = 0x2;
635+
dell_send_request(buffer, 17, 11);
636+
ret = buffer->output[0];
637+
hwswitch = buffer->output[1];
638+
615639
release_buffer();
616640

617641
if (ret != 0)
618642
return;
619643

620-
dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status);
644+
dell_rfkill_update_hw_state(rfkill, radio, status, hwswitch);
621645
}
622646

623647
static const struct rfkill_ops dell_rfkill_ops = {
@@ -629,13 +653,24 @@ static struct dentry *dell_laptop_dir;
629653

630654
static int dell_debugfs_show(struct seq_file *s, void *data)
631655
{
656+
int hwswitch_state;
657+
int hwswitch_ret;
632658
int status;
633659
int ret;
634660

635661
get_buffer();
662+
636663
dell_send_request(buffer, 17, 11);
637664
ret = buffer->output[0];
638665
status = buffer->output[1];
666+
667+
clear_buffer();
668+
669+
buffer->input[0] = 0x2;
670+
dell_send_request(buffer, 17, 11);
671+
hwswitch_ret = buffer->output[0];
672+
hwswitch_state = buffer->output[1];
673+
639674
release_buffer();
640675

641676
seq_printf(s, "return:\t%d\n", ret);
@@ -680,7 +715,8 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
680715
seq_printf(s, "Bit 21: WiGig is blocked: %lu\n",
681716
(status & BIT(21)) >> 21);
682717

683-
seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state);
718+
seq_printf(s, "\nhwswitch_return:\t%d\n", hwswitch_ret);
719+
seq_printf(s, "hwswitch_state:\t0x%X\n", hwswitch_state);
684720
seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n",
685721
hwswitch_state & BIT(0));
686722
seq_printf(s, "Bit 1 : Bluetooth controlled by switch: %lu\n",
@@ -716,6 +752,7 @@ static const struct file_operations dell_debugfs_fops = {
716752

717753
static void dell_update_rfkill(struct work_struct *ignored)
718754
{
755+
int hwswitch = 0;
719756
int status;
720757
int ret;
721758

@@ -728,16 +765,26 @@ static void dell_update_rfkill(struct work_struct *ignored)
728765
if (ret != 0)
729766
goto out;
730767

768+
clear_buffer();
769+
770+
buffer->input[0] = 0x2;
771+
dell_send_request(buffer, 17, 11);
772+
ret = buffer->output[0];
773+
774+
if (ret == 0 && (status & BIT(0)))
775+
hwswitch = buffer->output[1];
776+
731777
if (wifi_rfkill) {
732-
dell_rfkill_update_hw_state(wifi_rfkill, 1, status);
778+
dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
733779
dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
734780
}
735781
if (bluetooth_rfkill) {
736-
dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status);
782+
dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status,
783+
hwswitch);
737784
dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
738785
}
739786
if (wwan_rfkill) {
740-
dell_rfkill_update_hw_state(wwan_rfkill, 3, status);
787+
dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch);
741788
dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
742789
}
743790

@@ -805,25 +852,15 @@ static int __init dell_setup_rfkill(void)
805852
dell_send_request(buffer, 17, 11);
806853
ret = buffer->output[0];
807854
status = buffer->output[1];
808-
clear_buffer();
809-
buffer->input[0] = 0x2;
810-
dell_send_request(buffer, 17, 11);
811-
hwswitch_state = buffer->output[1];
812855
release_buffer();
813856

814857
/* dell wireless info smbios call is not supported */
815858
if (ret != 0)
816859
return 0;
817860

818-
if (!(status & BIT(0))) {
819-
if (force_rfkill) {
820-
/* No hwsitch, clear all hw-controlled bits */
821-
hwswitch_state &= ~7;
822-
} else {
823-
/* rfkill is only tested on laptops with a hwswitch */
824-
return 0;
825-
}
826-
}
861+
/* rfkill is only tested on laptops with a hwswitch */
862+
if (!(status & BIT(0)) && !force_rfkill)
863+
return 0;
827864

828865
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
829866
wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,

0 commit comments

Comments
 (0)