diff options
Diffstat (limited to 'drivers/net/wireless/b43legacy/rfkill.c')
-rw-r--r-- | drivers/net/wireless/b43legacy/rfkill.c | 133 |
1 files changed, 74 insertions, 59 deletions
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index b9d38a4f286d..520910fd5c45 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include "radio.h" | 26 | #include "radio.h" |
27 | #include "b43legacy.h" | 27 | #include "b43legacy.h" |
28 | 28 | ||
29 | #include <linux/kmod.h> | ||
30 | |||
29 | 31 | ||
30 | /* Returns TRUE, if the radio is enabled in hardware. */ | 32 | /* Returns TRUE, if the radio is enabled in hardware. */ |
31 | static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) | 33 | static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) |
@@ -51,7 +53,10 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) | |||
51 | bool report_change = 0; | 53 | bool report_change = 0; |
52 | 54 | ||
53 | mutex_lock(&wl->mutex); | 55 | mutex_lock(&wl->mutex); |
54 | B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); | 56 | if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { |
57 | mutex_unlock(&wl->mutex); | ||
58 | return; | ||
59 | } | ||
55 | enabled = b43legacy_is_hw_radio_enabled(dev); | 60 | enabled = b43legacy_is_hw_radio_enabled(dev); |
56 | if (unlikely(enabled != dev->radio_hw_enable)) { | 61 | if (unlikely(enabled != dev->radio_hw_enable)) { |
57 | dev->radio_hw_enable = enabled; | 62 | dev->radio_hw_enable = enabled; |
@@ -61,8 +66,12 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) | |||
61 | } | 66 | } |
62 | mutex_unlock(&wl->mutex); | 67 | mutex_unlock(&wl->mutex); |
63 | 68 | ||
64 | if (unlikely(report_change)) | 69 | /* send the radio switch event to the system - note both a key press |
65 | input_report_key(poll_dev->input, KEY_WLAN, enabled); | 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 | } | ||
66 | } | 75 | } |
67 | 76 | ||
68 | /* Called when the RFKILL toggled in software. | 77 | /* Called when the RFKILL toggled in software. |
@@ -71,13 +80,15 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) | |||
71 | { | 80 | { |
72 | struct b43legacy_wldev *dev = data; | 81 | struct b43legacy_wldev *dev = data; |
73 | struct b43legacy_wl *wl = dev->wl; | 82 | struct b43legacy_wl *wl = dev->wl; |
74 | int err = 0; | 83 | int err = -EBUSY; |
75 | 84 | ||
76 | if (!wl->rfkill.registered) | 85 | if (!wl->rfkill.registered) |
77 | return 0; | 86 | return 0; |
78 | 87 | ||
79 | mutex_lock(&wl->mutex); | 88 | mutex_lock(&wl->mutex); |
80 | B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); | 89 | if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) |
90 | goto out_unlock; | ||
91 | err = 0; | ||
81 | switch (state) { | 92 | switch (state) { |
82 | case RFKILL_STATE_ON: | 93 | case RFKILL_STATE_ON: |
83 | if (!dev->radio_hw_enable) { | 94 | if (!dev->radio_hw_enable) { |
@@ -103,11 +114,11 @@ out_unlock: | |||
103 | 114 | ||
104 | char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) | 115 | char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) |
105 | { | 116 | { |
106 | struct b43legacy_wl *wl = dev->wl; | 117 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); |
107 | 118 | ||
108 | if (!wl->rfkill.rfkill) | 119 | if (!rfk->registered) |
109 | return NULL; | 120 | return NULL; |
110 | return rfkill_get_led_name(wl->rfkill.rfkill); | 121 | return rfkill_get_led_name(rfk->rfkill); |
111 | } | 122 | } |
112 | 123 | ||
113 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev) | 124 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev) |
@@ -116,53 +127,13 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) | |||
116 | struct b43legacy_rfkill *rfk = &(wl->rfkill); | 127 | struct b43legacy_rfkill *rfk = &(wl->rfkill); |
117 | int err; | 128 | int err; |
118 | 129 | ||
119 | if (rfk->rfkill) { | 130 | rfk->registered = 0; |
120 | err = rfkill_register(rfk->rfkill); | ||
121 | if (err) { | ||
122 | b43legacywarn(wl, "Failed to register RF-kill button\n"); | ||
123 | goto err_free_rfk; | ||
124 | } | ||
125 | } | ||
126 | if (rfk->poll_dev) { | ||
127 | err = input_register_polled_device(rfk->poll_dev); | ||
128 | if (err) { | ||
129 | b43legacywarn(wl, "Failed to register RF-kill polldev\n"); | ||
130 | goto err_free_polldev; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | return; | ||
135 | err_free_rfk: | ||
136 | rfkill_free(rfk->rfkill); | ||
137 | rfk->rfkill = NULL; | ||
138 | err_free_polldev: | ||
139 | input_free_polled_device(rfk->poll_dev); | ||
140 | rfk->poll_dev = NULL; | ||
141 | } | ||
142 | |||
143 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) | ||
144 | { | ||
145 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); | ||
146 | |||
147 | if (rfk->poll_dev) | ||
148 | input_unregister_polled_device(rfk->poll_dev); | ||
149 | if (rfk->rfkill) | ||
150 | rfkill_unregister(rfk->rfkill); | ||
151 | } | ||
152 | |||
153 | void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) | ||
154 | { | ||
155 | struct b43legacy_wl *wl = dev->wl; | ||
156 | struct b43legacy_rfkill *rfk = &(wl->rfkill); | ||
157 | 131 | ||
132 | rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); | ||
133 | if (!rfk->rfkill) | ||
134 | goto out_error; | ||
158 | snprintf(rfk->name, sizeof(rfk->name), | 135 | snprintf(rfk->name, sizeof(rfk->name), |
159 | "b43legacy-%s", wiphy_name(wl->hw->wiphy)); | 136 | "b43legacy-%s", wiphy_name(wl->hw->wiphy)); |
160 | |||
161 | rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); | ||
162 | if (!rfk->rfkill) { | ||
163 | b43legacywarn(wl, "Failed to allocate RF-kill button\n"); | ||
164 | return; | ||
165 | } | ||
166 | rfk->rfkill->name = rfk->name; | 137 | rfk->rfkill->name = rfk->name; |
167 | rfk->rfkill->state = RFKILL_STATE_ON; | 138 | rfk->rfkill->state = RFKILL_STATE_ON; |
168 | rfk->rfkill->data = dev; | 139 | rfk->rfkill->data = dev; |
@@ -170,20 +141,64 @@ void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) | |||
170 | rfk->rfkill->user_claim_unsupported = 1; | 141 | rfk->rfkill->user_claim_unsupported = 1; |
171 | 142 | ||
172 | rfk->poll_dev = input_allocate_polled_device(); | 143 | rfk->poll_dev = input_allocate_polled_device(); |
173 | if (rfk->poll_dev) { | 144 | if (!rfk->poll_dev) |
174 | rfk->poll_dev->private = dev; | 145 | goto err_free_rfk; |
175 | rfk->poll_dev->poll = b43legacy_rfkill_poll; | 146 | rfk->poll_dev->private = dev; |
176 | rfk->poll_dev->poll_interval = 1000; /* msecs */ | 147 | rfk->poll_dev->poll = b43legacy_rfkill_poll; |
177 | } else | 148 | rfk->poll_dev->poll_interval = 1000; /* msecs */ |
178 | b43legacywarn(wl, "Failed to allocate RF-kill polldev\n"); | 149 | |
150 | rfk->poll_dev->input->name = rfk->name; | ||
151 | rfk->poll_dev->input->id.bustype = BUS_HOST; | ||
152 | rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; | ||
153 | rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); | ||
154 | set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); | ||
155 | |||
156 | err = rfkill_register(rfk->rfkill); | ||
157 | if (err) | ||
158 | goto err_free_polldev; | ||
159 | |||
160 | #ifdef CONFIG_RFKILL_INPUT_MODULE | ||
161 | /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. | ||
162 | * Try to load the module. */ | ||
163 | err = request_module("rfkill-input"); | ||
164 | if (err) | ||
165 | b43legacywarn(wl, "Failed to load the rfkill-input module." | ||
166 | "The built-in radio LED will not work.\n"); | ||
167 | #endif /* CONFIG_RFKILL_INPUT */ | ||
168 | |||
169 | err = input_register_polled_device(rfk->poll_dev); | ||
170 | if (err) | ||
171 | goto err_unreg_rfk; | ||
172 | |||
173 | rfk->registered = 1; | ||
174 | |||
175 | return; | ||
176 | err_unreg_rfk: | ||
177 | rfkill_unregister(rfk->rfkill); | ||
178 | err_free_polldev: | ||
179 | input_free_polled_device(rfk->poll_dev); | ||
180 | rfk->poll_dev = NULL; | ||
181 | err_free_rfk: | ||
182 | rfkill_free(rfk->rfkill); | ||
183 | rfk->rfkill = NULL; | ||
184 | out_error: | ||
185 | rfk->registered = 0; | ||
186 | b43legacywarn(wl, "RF-kill button init failed\n"); | ||
179 | } | 187 | } |
180 | 188 | ||
181 | void b43legacy_rfkill_free(struct b43legacy_wldev *dev) | 189 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) |
182 | { | 190 | { |
183 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); | 191 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); |
184 | 192 | ||
193 | if (!rfk->registered) | ||
194 | return; | ||
195 | rfk->registered = 0; | ||
196 | |||
197 | input_unregister_polled_device(rfk->poll_dev); | ||
198 | rfkill_unregister(rfk->rfkill); | ||
185 | input_free_polled_device(rfk->poll_dev); | 199 | input_free_polled_device(rfk->poll_dev); |
186 | rfk->poll_dev = NULL; | 200 | rfk->poll_dev = NULL; |
187 | rfkill_free(rfk->rfkill); | 201 | rfkill_free(rfk->rfkill); |
188 | rfk->rfkill = NULL; | 202 | rfk->rfkill = NULL; |
189 | } | 203 | } |
204 | |||