aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-09-27 15:35:34 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:54:12 -0400
commit8e9f7529fdfe34ed519f048682eb404fbd8004e8 (patch)
treec0ca2c07e9f4124be2bc46c35823f4fb79e99d9d /drivers
parent21954c367e4088c491122edd263964345bc1d3bf (diff)
[B43]: RF-kill support
This adds full support for the RFKILL button and the RFKILL LED trigger. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/b43/Kconfig8
-rw-r--r--drivers/net/wireless/b43/Makefile2
-rw-r--r--drivers/net/wireless/b43/b43.h5
-rw-r--r--drivers/net/wireless/b43/leds.c8
-rw-r--r--drivers/net/wireless/b43/main.c18
-rw-r--r--drivers/net/wireless/b43/phy.c13
-rw-r--r--drivers/net/wireless/b43/phy.h2
-rw-r--r--drivers/net/wireless/b43/rfkill.c155
-rw-r--r--drivers/net/wireless/b43/rfkill.h49
9 files changed, 245 insertions, 15 deletions
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 1575654556b0..968f0611ed49 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -64,7 +64,13 @@ config B43_PCMCIA
64# LED support 64# LED support
65config B43_LEDS 65config B43_LEDS
66 bool 66 bool
67 depends on MAC80211_LEDS 67 depends on B43 && MAC80211_LEDS
68 default y
69
70# RFKILL support
71config B43_RFKILL
72 bool
73 depends on B43 && RFKILL
68 default y 74 default y
69 75
70config B43_DEBUG 76config B43_DEBUG
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index e6331414c4ca..485e59e2dfab 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -5,6 +5,8 @@ b43-y += phy.o
5b43-y += sysfs.o 5b43-y += sysfs.o
6b43-y += xmit.o 6b43-y += xmit.o
7b43-y += lo.o 7b43-y += lo.o
8# b43 RFKILL button support
9b43-$(CONFIG_B43_RFKILL) += rfkill.o
8# b43 LED support 10# b43 LED support
9b43-$(CONFIG_B43_LEDS) += leds.o 11b43-$(CONFIG_B43_LEDS) += leds.o
10# b43 PCMCIA support 12# b43 PCMCIA support
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 6e6b59227e16..a28ad230d63e 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -10,6 +10,7 @@
10 10
11#include "debugfs.h" 11#include "debugfs.h"
12#include "leds.h" 12#include "leds.h"
13#include "rfkill.h"
13#include "lo.h" 14#include "lo.h"
14#include "phy.h" 15#include "phy.h"
15 16
@@ -625,6 +626,9 @@ struct b43_wl {
625 u8 rng_initialized; 626 u8 rng_initialized;
626 char rng_name[30 + 1]; 627 char rng_name[30 + 1];
627 628
629 /* The RF-kill button */
630 struct b43_rfkill rfkill;
631
628 /* List of all wireless devices on this chip */ 632 /* List of all wireless devices on this chip */
629 struct list_head devlist; 633 struct list_head devlist;
630 u8 nr_devs; 634 u8 nr_devs;
@@ -700,6 +704,7 @@ struct b43_wldev {
700 struct b43_led led_tx; 704 struct b43_led led_tx;
701 struct b43_led led_rx; 705 struct b43_led led_rx;
702 struct b43_led led_assoc; 706 struct b43_led led_assoc;
707 struct b43_led led_radio;
703 708
704 /* Reason code of the last interrupt. */ 709 /* Reason code of the last interrupt. */
705 u32 irq_reason; 710 u32 irq_reason;
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index ddab856f1140..19e588582c7c 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -154,12 +154,16 @@ static void b43_map_led(struct b43_wldev *dev,
154 ieee80211_get_rx_led_name(hw), 154 ieee80211_get_rx_led_name(hw),
155 led_index, activelow); 155 led_index, activelow);
156 break; 156 break;
157 /*FIXME: We need another trigger for the "radio-on" LEDs below.
158 * Wiggle that somehow into the rfkill subsystem. */
159 case B43_LED_RADIO_ALL: 157 case B43_LED_RADIO_ALL:
160 case B43_LED_RADIO_A: 158 case B43_LED_RADIO_A:
161 case B43_LED_RADIO_B: 159 case B43_LED_RADIO_B:
162 case B43_LED_MODE_BG: 160 case B43_LED_MODE_BG:
161 snprintf(name, sizeof(name),
162 "b43-%s:radio", wiphy_name(hw->wiphy));
163 b43_register_led(dev, &dev->led_radio, name,
164 b43_rfkill_led_name(dev),
165 led_index, activelow);
166 break;
163 case B43_LED_WEIRD: 167 case B43_LED_WEIRD:
164 case B43_LED_ASSOC: 168 case B43_LED_ASSOC:
165 snprintf(name, sizeof(name), 169 snprintf(name, sizeof(name),
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 2b81bd6165d8..a9f7148493f7 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2161,7 +2161,7 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
2161/* This is the opposite of b43_chip_init() */ 2161/* This is the opposite of b43_chip_init() */
2162static void b43_chip_exit(struct b43_wldev *dev) 2162static void b43_chip_exit(struct b43_wldev *dev)
2163{ 2163{
2164 b43_radio_turn_off(dev); 2164 b43_radio_turn_off(dev, 1);
2165 b43_leds_exit(dev); 2165 b43_leds_exit(dev);
2166 b43_gpio_cleanup(dev); 2166 b43_gpio_cleanup(dev);
2167 /* firmware is released later */ 2167 /* firmware is released later */
@@ -2269,7 +2269,7 @@ out:
2269 return err; 2269 return err;
2270 2270
2271err_radio_off: 2271err_radio_off:
2272 b43_radio_turn_off(dev); 2272 b43_radio_turn_off(dev, 1);
2273err_leds_exit: 2273err_leds_exit:
2274 b43_leds_exit(dev); 2274 b43_leds_exit(dev);
2275 b43_gpio_cleanup(dev); 2275 b43_gpio_cleanup(dev);
@@ -2358,8 +2358,7 @@ static void b43_periodic_every1sec(struct b43_wldev *dev)
2358 radio_hw_enable = b43_is_hw_radio_enabled(dev); 2358 radio_hw_enable = b43_is_hw_radio_enabled(dev);
2359 if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { 2359 if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
2360 dev->radio_hw_enable = radio_hw_enable; 2360 dev->radio_hw_enable = radio_hw_enable;
2361 b43info(dev->wl, "Radio hardware status changed to %s\n", 2361 b43_rfkill_toggled(dev, radio_hw_enable);
2362 radio_hw_enable ? "ENABLED" : "DISABLED");
2363 } 2362 }
2364} 2363}
2365 2364
@@ -2850,7 +2849,7 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
2850 "Press the button to turn it on.\n"); 2849 "Press the button to turn it on.\n");
2851 } 2850 }
2852 } else { 2851 } else {
2853 b43_radio_turn_off(dev); 2852 b43_radio_turn_off(dev, 0);
2854 b43info(dev->wl, "Radio turned off by software\n"); 2853 b43info(dev->wl, "Radio turned off by software\n");
2855 } 2854 }
2856 } 2855 }
@@ -3330,11 +3329,15 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
3330 return; 3329 return;
3331 b43_set_status(dev, B43_STAT_UNINIT); 3330 b43_set_status(dev, B43_STAT_UNINIT);
3332 3331
3332 mutex_unlock(&dev->wl->mutex);
3333 b43_rfkill_exit(dev);
3334 mutex_lock(&dev->wl->mutex);
3335
3333 b43_rng_exit(dev->wl); 3336 b43_rng_exit(dev->wl);
3334 b43_pio_free(dev); 3337 b43_pio_free(dev);
3335 b43_dma_free(dev); 3338 b43_dma_free(dev);
3336 b43_chip_exit(dev); 3339 b43_chip_exit(dev);
3337 b43_radio_turn_off(dev); 3340 b43_radio_turn_off(dev, 1);
3338 b43_switch_analog(dev, 0); 3341 b43_switch_analog(dev, 0);
3339 if (phy->dyn_tssi_tbl) 3342 if (phy->dyn_tssi_tbl)
3340 kfree(phy->tssi2dbm); 3343 kfree(phy->tssi2dbm);
@@ -3458,6 +3461,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
3458 memset(wl->mac_addr, 0, ETH_ALEN); 3461 memset(wl->mac_addr, 0, ETH_ALEN);
3459 b43_upload_card_macaddress(dev); 3462 b43_upload_card_macaddress(dev);
3460 b43_security_init(dev); 3463 b43_security_init(dev);
3464 b43_rfkill_init(dev);
3461 b43_rng_init(wl); 3465 b43_rng_init(wl);
3462 3466
3463 b43_set_status(dev, B43_STAT_INITIALIZED); 3467 b43_set_status(dev, B43_STAT_INITIALIZED);
@@ -3802,7 +3806,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
3802 wl->current_dev = dev; 3806 wl->current_dev = dev;
3803 INIT_WORK(&dev->restart_work, b43_chip_reset); 3807 INIT_WORK(&dev->restart_work, b43_chip_reset);
3804 3808
3805 b43_radio_turn_off(dev); 3809 b43_radio_turn_off(dev, 1);
3806 b43_switch_analog(dev, 0); 3810 b43_switch_analog(dev, 0);
3807 ssb_device_disable(dev->dev, 0); 3811 ssb_device_disable(dev->dev, 0);
3808 ssb_bus_may_powerdown(bus); 3812 ssb_bus_may_powerdown(bus);
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index 354d18238752..5f7ffa0a76c0 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -4349,10 +4349,13 @@ void b43_radio_turn_on(struct b43_wldev *dev)
4349 phy->radio_on = 1; 4349 phy->radio_on = 1;
4350} 4350}
4351 4351
4352void b43_radio_turn_off(struct b43_wldev *dev) 4352void b43_radio_turn_off(struct b43_wldev *dev, bool force)
4353{ 4353{
4354 struct b43_phy *phy = &dev->phy; 4354 struct b43_phy *phy = &dev->phy;
4355 4355
4356 if (!phy->radio_on && !force)
4357 return;
4358
4356 if (phy->type == B43_PHYTYPE_A) { 4359 if (phy->type == B43_PHYTYPE_A) {
4357 b43_radio_write16(dev, 0x0004, 0x00FF); 4360 b43_radio_write16(dev, 0x0004, 0x00FF);
4358 b43_radio_write16(dev, 0x0005, 0x00FB); 4361 b43_radio_write16(dev, 0x0005, 0x00FB);
@@ -4364,9 +4367,11 @@ void b43_radio_turn_off(struct b43_wldev *dev)
4364 4367
4365 rfover = b43_phy_read(dev, B43_PHY_RFOVER); 4368 rfover = b43_phy_read(dev, B43_PHY_RFOVER);
4366 rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); 4369 rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
4367 phy->radio_off_context.rfover = rfover; 4370 if (!force) {
4368 phy->radio_off_context.rfoverval = rfoverval; 4371 phy->radio_off_context.rfover = rfover;
4369 phy->radio_off_context.valid = 1; 4372 phy->radio_off_context.rfoverval = rfoverval;
4373 phy->radio_off_context.valid = 1;
4374 }
4370 b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); 4375 b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
4371 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); 4376 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
4372 } else 4377 } else
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
index d1f623cb9b34..c64d74504fc0 100644
--- a/drivers/net/wireless/b43/phy.h
+++ b/drivers/net/wireless/b43/phy.h
@@ -267,7 +267,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev);
267void b43_radio_init2060(struct b43_wldev *dev); 267void b43_radio_init2060(struct b43_wldev *dev);
268 268
269void b43_radio_turn_on(struct b43_wldev *dev); 269void b43_radio_turn_on(struct b43_wldev *dev);
270void b43_radio_turn_off(struct b43_wldev *dev); 270void b43_radio_turn_off(struct b43_wldev *dev, bool force);
271 271
272int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, 272int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
273 int synthetic_pu_workaround); 273 int synthetic_pu_workaround);
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
new file mode 100644
index 000000000000..c25fd9956a9c
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -0,0 +1,155 @@
1/*
2
3 Broadcom B43 wireless driver
4 RFKILL support
5
6 Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22
23*/
24
25#include "rfkill.h"
26#include "b43.h"
27
28
29static void b43_notify_rfkill_press(struct work_struct *work)
30{
31 struct b43_rfkill *rfk = container_of(work, struct b43_rfkill,
32 notify_work);
33 struct b43_wl *wl = container_of(rfk, struct b43_wl, rfkill);
34 struct b43_wldev *dev;
35 enum rfkill_state state;
36
37 mutex_lock(&wl->mutex);
38 dev = wl->current_dev;
39 if (b43_status(dev) < B43_STAT_INITIALIZED) {
40 mutex_unlock(&wl->mutex);
41 return;
42 }
43 if (dev->radio_hw_enable)
44 state = RFKILL_STATE_ON;
45 else
46 state = RFKILL_STATE_OFF;
47 b43info(wl, "Radio hardware status changed to %s\n",
48 dev->radio_hw_enable ? "ENABLED" : "DISABLED");
49 mutex_unlock(&wl->mutex);
50
51 if (rfk->rfkill) {
52 /* Be careful. This calls back into the software toggle routines.
53 * So we must unlock before calling. */
54 rfkill_switch_all(rfk->rfkill->type, state);
55 }
56}
57
58/* Called when the RFKILL toggled in hardware.
59 * This is called with the mutex locked. */
60void b43_rfkill_toggled(struct b43_wldev *dev, bool on)
61{
62 struct b43_wl *wl = dev->wl;
63
64 B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
65 /* Update the RF status asynchronously, as rfkill will
66 * call back into the software toggle handler.
67 * This would deadlock if done synchronously. */
68 queue_work(wl->hw->workqueue, &wl->rfkill.notify_work);
69}
70
71/* Called when the RFKILL toggled in software.
72 * This is called without locking. */
73static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
74{
75 struct b43_wldev *dev = data;
76 struct b43_wl *wl = dev->wl;
77 int err = 0;
78
79 mutex_lock(&wl->mutex);
80 if (b43_status(dev) < B43_STAT_INITIALIZED)
81 goto out_unlock;
82
83 switch (state) {
84 case RFKILL_STATE_ON:
85 if (!dev->radio_hw_enable) {
86 /* No luck. We can't toggle the hardware RF-kill
87 * button from software. */
88 err = -EBUSY;
89 goto out_unlock;
90 }
91 if (!dev->phy.radio_on)
92 b43_radio_turn_on(dev);
93 break;
94 case RFKILL_STATE_OFF:
95 if (dev->phy.radio_on)
96 b43_radio_turn_off(dev, 0);
97 break;
98 }
99
100out_unlock:
101 mutex_unlock(&wl->mutex);
102
103 return err;
104}
105
106char * b43_rfkill_led_name(struct b43_wldev *dev)
107{
108 struct b43_wl *wl = dev->wl;
109
110 if (!wl->rfkill.rfkill)
111 return NULL;
112 return rfkill_get_led_name(wl->rfkill.rfkill);
113}
114
115void b43_rfkill_init(struct b43_wldev *dev)
116{
117 struct b43_wl *wl = dev->wl;
118 struct b43_rfkill *rfk = &(wl->rfkill);
119 int err;
120
121 snprintf(rfk->name, sizeof(rfk->name),
122 "b43-%s", wiphy_name(wl->hw->wiphy));
123 rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
124 if (!rfk->rfkill)
125 goto error;
126 rfk->rfkill->name = rfk->name;
127 rfk->rfkill->state = RFKILL_STATE_ON;
128 rfk->rfkill->data = dev;
129 rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
130 rfk->rfkill->user_claim_unsupported = 1;
131
132 INIT_WORK(&rfk->notify_work, b43_notify_rfkill_press);
133
134 err = rfkill_register(rfk->rfkill);
135 if (err)
136 goto error;
137
138 return;
139error:
140 b43warn(dev->wl, "Failed to initialize the RF-kill button\n");
141 rfkill_free(rfk->rfkill);
142 rfk->rfkill = NULL;
143}
144
145void b43_rfkill_exit(struct b43_wldev *dev)
146{
147 struct b43_rfkill *rfk = &(dev->wl->rfkill);
148
149 if (!rfk->rfkill)
150 return;
151 cancel_work_sync(&rfk->notify_work);
152 rfkill_unregister(rfk->rfkill);
153 rfkill_free(rfk->rfkill);
154 rfk->rfkill = NULL;
155}
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h
new file mode 100644
index 000000000000..05db0d67a92e
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.h
@@ -0,0 +1,49 @@
1#ifndef B43_RFKILL_H_
2#define B43_RFKILL_H_
3
4struct b43_wldev;
5
6
7#ifdef CONFIG_B43_RFKILL
8
9#include <linux/rfkill.h>
10
11struct b43_rfkill {
12 /* The RFKILL subsystem data structure */
13 struct rfkill *rfkill;
14 /* The unique name of this rfkill switch */
15 char name[32];
16 /* Workqueue for asynchronous notification. */
17 struct work_struct notify_work;
18};
19
20void b43_rfkill_init(struct b43_wldev *dev);
21void b43_rfkill_exit(struct b43_wldev *dev);
22void b43_rfkill_toggled(struct b43_wldev *dev, bool on);
23char * b43_rfkill_led_name(struct b43_wldev *dev);
24
25
26#else /* CONFIG_B43_RFKILL */
27/* No RFKILL support. */
28
29struct b43_rfkill {
30 /* empty */
31};
32
33static inline void b43_rfkill_init(struct b43_wldev *dev)
34{
35}
36static inline void b43_rfkill_exit(struct b43_wldev *dev)
37{
38}
39static inline void b43_rfkill_toggled(struct b43_wldev *dev, bool on)
40{
41}
42static inline char * b43_rfkill_led_name(struct b43_wldev *dev)
43{
44 return NULL;
45}
46
47#endif /* CONFIG_B43_RFKILL */
48
49#endif /* B43_RFKILL_H_ */