aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-06-02 07:01:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 14:06:13 -0400
commit19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 (patch)
tree33326eeb09cb9664cc8427a5dc7cd2b08b5a57c3 /drivers/net/wireless/b43legacy
parent0f6399c4c525b518644a9b09f8d6fb125a418c4d (diff)
rfkill: rewrite
This patch completely rewrites the rfkill core to address the following deficiencies: * all rfkill drivers need to implement polling where necessary rather than having one central implementation * updating the rfkill state cannot be done from arbitrary contexts, forcing drivers to use schedule_work and requiring lots of code * rfkill drivers need to keep track of soft/hard blocked internally -- the core should do this * the rfkill API has many unexpected quirks, for example being asymmetric wrt. alloc/free and register/unregister * rfkill can call back into a driver from within a function the driver called -- this is prone to deadlocks and generally should be avoided * rfkill-input pointlessly is a separate module * drivers need to #ifdef rfkill functions (unless they want to depend on or select RFKILL) -- rfkill should provide inlines that do nothing if it isn't compiled in * the rfkill structure is not opaque -- drivers need to initialise it correctly (lots of sanity checking code required) -- instead force drivers to pass the right variables to rfkill_alloc() * the documentation is hard to read because it always assumes the reader is completely clueless and contains way TOO MANY CAPS * the rfkill code needlessly uses a lot of locks and atomic operations in locked sections * fix LED trigger to actually change the LED when the radio state changes -- this wasn't done before Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad] Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43legacy')
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig2
-rw-r--r--drivers/net/wireless/b43legacy/leds.c3
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c123
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.h6
4 files changed, 43 insertions, 91 deletions
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
index d4f628a74bbd..6893f439df70 100644
--- a/drivers/net/wireless/b43legacy/Kconfig
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -47,7 +47,7 @@ config B43LEGACY_LEDS
47# if it's possible. 47# if it's possible.
48config B43LEGACY_RFKILL 48config B43LEGACY_RFKILL
49 bool 49 bool
50 depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) 50 depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY)
51 default y 51 default y
52 52
53# This config option automatically enables b43 HW-RNG support, 53# This config option automatically enables b43 HW-RNG support,
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
index 3ea55b18c700..538d3117594b 100644
--- a/drivers/net/wireless/b43legacy/leds.c
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
86 86
87static int b43legacy_register_led(struct b43legacy_wldev *dev, 87static int b43legacy_register_led(struct b43legacy_wldev *dev,
88 struct b43legacy_led *led, 88 struct b43legacy_led *led,
89 const char *name, char *default_trigger, 89 const char *name,
90 const char *default_trigger,
90 u8 led_index, bool activelow) 91 u8 led_index, bool activelow)
91{ 92{
92 int err; 93 int err;
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index 4b0c7d27a51f..c6230a64505a 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
45} 45}
46 46
47/* The poll callback for the hardware button. */ 47/* The poll callback for the hardware button. */
48static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) 48static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data)
49{ 49{
50 struct b43legacy_wldev *dev = poll_dev->private; 50 struct b43legacy_wldev *dev = data;
51 struct b43legacy_wl *wl = dev->wl; 51 struct b43legacy_wl *wl = dev->wl;
52 bool enabled; 52 bool enabled;
53 bool report_change = 0;
54 53
55 mutex_lock(&wl->mutex); 54 mutex_lock(&wl->mutex);
56 if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { 55 if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
@@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
60 enabled = b43legacy_is_hw_radio_enabled(dev); 59 enabled = b43legacy_is_hw_radio_enabled(dev);
61 if (unlikely(enabled != dev->radio_hw_enable)) { 60 if (unlikely(enabled != dev->radio_hw_enable)) {
62 dev->radio_hw_enable = enabled; 61 dev->radio_hw_enable = enabled;
63 report_change = 1;
64 b43legacyinfo(wl, "Radio hardware status changed to %s\n", 62 b43legacyinfo(wl, "Radio hardware status changed to %s\n",
65 enabled ? "ENABLED" : "DISABLED"); 63 enabled ? "ENABLED" : "DISABLED");
64 enabled = !rfkill_set_hw_state(rfkill, !enabled);
65 if (enabled != dev->phy.radio_on) {
66 if (enabled)
67 b43legacy_radio_turn_on(dev);
68 else
69 b43legacy_radio_turn_off(dev, 0);
70 }
66 } 71 }
67 mutex_unlock(&wl->mutex); 72 mutex_unlock(&wl->mutex);
68
69 /* send the radio switch event to the system - note both a key press
70 * and a release are required */
71 if (unlikely(report_change)) {
72 input_report_key(poll_dev->input, KEY_WLAN, 1);
73 input_report_key(poll_dev->input, KEY_WLAN, 0);
74 }
75} 73}
76 74
77/* Called when the RFKILL toggled in software. 75/* Called when the RFKILL toggled in software.
78 * This is called without locking. */ 76 * This is called without locking. */
79static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) 77static int b43legacy_rfkill_soft_set(void *data, bool blocked)
80{ 78{
81 struct b43legacy_wldev *dev = data; 79 struct b43legacy_wldev *dev = data;
82 struct b43legacy_wl *wl = dev->wl; 80 struct b43legacy_wl *wl = dev->wl;
83 int err = -EBUSY; 81 int ret = -EINVAL;
84 82
85 if (!wl->rfkill.registered) 83 if (!wl->rfkill.registered)
86 return 0; 84 return -EINVAL;
87 85
88 mutex_lock(&wl->mutex); 86 mutex_lock(&wl->mutex);
89 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) 87 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
90 goto out_unlock; 88 goto out_unlock;
91 err = 0; 89
92 switch (state) { 90 if (!dev->radio_hw_enable)
93 case RFKILL_STATE_UNBLOCKED: 91 goto out_unlock;
94 if (!dev->radio_hw_enable) { 92
95 /* No luck. We can't toggle the hardware RF-kill 93 if (!blocked != dev->phy.radio_on) {
96 * button from software. */ 94 if (!blocked)
97 err = -EBUSY;
98 goto out_unlock;
99 }
100 if (!dev->phy.radio_on)
101 b43legacy_radio_turn_on(dev); 95 b43legacy_radio_turn_on(dev);
102 break; 96 else
103 case RFKILL_STATE_SOFT_BLOCKED:
104 if (dev->phy.radio_on)
105 b43legacy_radio_turn_off(dev, 0); 97 b43legacy_radio_turn_off(dev, 0);
106 break;
107 default:
108 b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
109 state);
110 break;
111 } 98 }
99 ret = 0;
112 100
113out_unlock: 101out_unlock:
114 mutex_unlock(&wl->mutex); 102 mutex_unlock(&wl->mutex);
115 103 return ret;
116 return err;
117} 104}
118 105
119char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) 106const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
120{ 107{
121 struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); 108 struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
122 109
123 if (!rfk->registered) 110 if (!rfk->registered)
124 return NULL; 111 return NULL;
125 return rfkill_get_led_name(rfk->rfkill); 112 return rfkill_get_led_trigger_name(rfk->rfkill);
126} 113}
127 114
115static const struct rfkill_ops b43legacy_rfkill_ops = {
116 .set_block = b43legacy_rfkill_soft_set,
117 .poll = b43legacy_rfkill_poll,
118};
119
128void b43legacy_rfkill_init(struct b43legacy_wldev *dev) 120void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
129{ 121{
130 struct b43legacy_wl *wl = dev->wl; 122 struct b43legacy_wl *wl = dev->wl;
@@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
133 125
134 rfk->registered = 0; 126 rfk->registered = 0;
135 127
136 rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
137 if (!rfk->rfkill)
138 goto out_error;
139 snprintf(rfk->name, sizeof(rfk->name), 128 snprintf(rfk->name, sizeof(rfk->name),
140 "b43legacy-%s", wiphy_name(wl->hw->wiphy)); 129 "b43legacy-%s", wiphy_name(wl->hw->wiphy));
141 rfk->rfkill->name = rfk->name; 130 rfk->rfkill = rfkill_alloc(rfk->name,
142 rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; 131 dev->dev->dev,
143 rfk->rfkill->data = dev; 132 RFKILL_TYPE_WLAN,
144 rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; 133 &b43legacy_rfkill_ops, dev);
145 134 if (!rfk->rfkill)
146 rfk->poll_dev = input_allocate_polled_device(); 135 goto out_error;
147 if (!rfk->poll_dev) {
148 rfkill_free(rfk->rfkill);
149 goto err_freed_rfk;
150 }
151
152 rfk->poll_dev->private = dev;
153 rfk->poll_dev->poll = b43legacy_rfkill_poll;
154 rfk->poll_dev->poll_interval = 1000; /* msecs */
155
156 rfk->poll_dev->input->name = rfk->name;
157 rfk->poll_dev->input->id.bustype = BUS_HOST;
158 rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
159 rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
160 set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
161 136
162 err = rfkill_register(rfk->rfkill); 137 err = rfkill_register(rfk->rfkill);
163 if (err) 138 if (err)
164 goto err_free_polldev; 139 goto err_free;
165
166#ifdef CONFIG_RFKILL_INPUT_MODULE
167 /* B43legacy RF-kill isn't useful without the rfkill-input subsystem.
168 * Try to load the module. */
169 err = request_module("rfkill-input");
170 if (err)
171 b43legacywarn(wl, "Failed to load the rfkill-input module."
172 "The built-in radio LED will not work.\n");
173#endif /* CONFIG_RFKILL_INPUT */
174
175 err = input_register_polled_device(rfk->poll_dev);
176 if (err)
177 goto err_unreg_rfk;
178 140
179 rfk->registered = 1; 141 rfk->registered = 1;
180 142
181 return; 143 return;
182err_unreg_rfk: 144 err_free:
183 rfkill_unregister(rfk->rfkill); 145 rfkill_destroy(rfk->rfkill);
184err_free_polldev: 146 out_error:
185 input_free_polled_device(rfk->poll_dev);
186 rfk->poll_dev = NULL;
187err_freed_rfk:
188 rfk->rfkill = NULL;
189out_error:
190 rfk->registered = 0; 147 rfk->registered = 0;
191 b43legacywarn(wl, "RF-kill button init failed\n"); 148 b43legacywarn(wl, "RF-kill button init failed\n");
192} 149}
@@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
199 return; 156 return;
200 rfk->registered = 0; 157 rfk->registered = 0;
201 158
202 input_unregister_polled_device(rfk->poll_dev);
203 rfkill_unregister(rfk->rfkill); 159 rfkill_unregister(rfk->rfkill);
204 input_free_polled_device(rfk->poll_dev); 160 rfkill_destroy(rfk->rfkill);
205 rfk->poll_dev = NULL;
206 rfk->rfkill = NULL; 161 rfk->rfkill = NULL;
207} 162}
208 163
diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h
index 11150a8032f0..adffc503a6a1 100644
--- a/drivers/net/wireless/b43legacy/rfkill.h
+++ b/drivers/net/wireless/b43legacy/rfkill.h
@@ -6,16 +6,12 @@ struct b43legacy_wldev;
6#ifdef CONFIG_B43LEGACY_RFKILL 6#ifdef CONFIG_B43LEGACY_RFKILL
7 7
8#include <linux/rfkill.h> 8#include <linux/rfkill.h>
9#include <linux/workqueue.h>
10#include <linux/input-polldev.h>
11 9
12 10
13 11
14struct b43legacy_rfkill { 12struct b43legacy_rfkill {
15 /* The RFKILL subsystem data structure */ 13 /* The RFKILL subsystem data structure */
16 struct rfkill *rfkill; 14 struct rfkill *rfkill;
17 /* The poll device for the RFKILL input button */
18 struct input_polled_dev *poll_dev;
19 /* Did initialization succeed? Used for freeing. */ 15 /* Did initialization succeed? Used for freeing. */
20 bool registered; 16 bool registered;
21 /* The unique name of this rfkill switch */ 17 /* The unique name of this rfkill switch */
@@ -27,7 +23,7 @@ struct b43legacy_rfkill {
27void b43legacy_rfkill_init(struct b43legacy_wldev *dev); 23void b43legacy_rfkill_init(struct b43legacy_wldev *dev);
28void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); 24void b43legacy_rfkill_exit(struct b43legacy_wldev *dev);
29 25
30char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); 26const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev);
31 27
32 28
33#else /* CONFIG_B43LEGACY_RFKILL */ 29#else /* CONFIG_B43LEGACY_RFKILL */