diff options
author | David S. Miller <davem@davemloft.net> | 2009-06-07 07:24:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-07 07:24:21 -0400 |
commit | b1bc81a0ef86b86fa410dd303d84c8c7bd09a64d (patch) | |
tree | a0d2e6dd179e5d057776edd0ed865bc744dfa54d | |
parent | a93958ac980f0ce594ad90657ecbc595ff157a40 (diff) | |
parent | 0c0c9e7076b69f93678e4ec711e2bf237398e623 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
133 files changed, 4465 insertions, 4698 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index de491a3e2313..edb2f0b07616 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -437,3 +437,10 @@ Why: Superseded by tdfxfb. I2C/DDC support used to live in a separate | |||
437 | driver but this caused driver conflicts. | 437 | driver but this caused driver conflicts. |
438 | Who: Jean Delvare <khali@linux-fr.org> | 438 | Who: Jean Delvare <khali@linux-fr.org> |
439 | Krzysztof Helt <krzysztof.h1@wp.pl> | 439 | Krzysztof Helt <krzysztof.h1@wp.pl> |
440 | |||
441 | --------------------------- | ||
442 | |||
443 | What: CONFIG_RFKILL_INPUT | ||
444 | When: 2.6.33 | ||
445 | Why: Should be implemented in userspace, policy daemon. | ||
446 | Who: Johannes Berg <johannes@sipsolutions.net> | ||
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 40c3a3f10816..1b74b5f30af4 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt | |||
@@ -1,571 +1,136 @@ | |||
1 | rfkill - RF switch subsystem support | 1 | rfkill - RF kill switch support |
2 | ==================================== | 2 | =============================== |
3 | 3 | ||
4 | 1 Introduction | 4 | 1. Introduction |
5 | 2 Implementation details | 5 | 2. Implementation details |
6 | 3 Kernel driver guidelines | 6 | 3. Kernel driver guidelines |
7 | 3.1 wireless device drivers | 7 | 4. Kernel API |
8 | 3.2 platform/switch drivers | 8 | 5. Userspace support |
9 | 3.3 input device drivers | ||
10 | 4 Kernel API | ||
11 | 5 Userspace support | ||
12 | 9 | ||
13 | 10 | ||
14 | 1. Introduction: | 11 | 1. Introduction |
15 | 12 | ||
16 | The rfkill switch subsystem exists to add a generic interface to circuitry that | 13 | The rfkill subsystem provides a generic interface to disabling any radio |
17 | can enable or disable the signal output of a wireless *transmitter* of any | 14 | transmitter in the system. When a transmitter is blocked, it shall not |
18 | type. By far, the most common use is to disable radio-frequency transmitters. | 15 | radiate any power. |
19 | 16 | ||
20 | Note that disabling the signal output means that the the transmitter is to be | 17 | The subsystem also provides the ability to react on button presses and |
21 | made to not emit any energy when "blocked". rfkill is not about blocking data | 18 | disable all transmitters of a certain type (or all). This is intended for |
22 | transmissions, it is about blocking energy emission. | 19 | situations where transmitters need to be turned off, for example on |
20 | aircraft. | ||
23 | 21 | ||
24 | The rfkill subsystem offers support for keys and switches often found on | ||
25 | laptops to enable wireless devices like WiFi and Bluetooth, so that these keys | ||
26 | and switches actually perform an action in all wireless devices of a given type | ||
27 | attached to the system. | ||
28 | 22 | ||
29 | The buttons to enable and disable the wireless transmitters are important in | ||
30 | situations where the user is for example using his laptop on a location where | ||
31 | radio-frequency transmitters _must_ be disabled (e.g. airplanes). | ||
32 | 23 | ||
33 | Because of this requirement, userspace support for the keys should not be made | 24 | 2. Implementation details |
34 | mandatory. Because userspace might want to perform some additional smarter | ||
35 | tasks when the key is pressed, rfkill provides userspace the possibility to | ||
36 | take over the task to handle the key events. | ||
37 | |||
38 | =============================================================================== | ||
39 | 2: Implementation details | ||
40 | 25 | ||
41 | The rfkill subsystem is composed of various components: the rfkill class, the | 26 | The rfkill subsystem is composed of various components: the rfkill class, the |
42 | rfkill-input module (an input layer handler), and some specific input layer | 27 | rfkill-input module (an input layer handler), and some specific input layer |
43 | events. | 28 | events. |
44 | 29 | ||
45 | The rfkill class provides kernel drivers with an interface that allows them to | 30 | The rfkill class is provided for kernel drivers to register their radio |
46 | know when they should enable or disable a wireless network device transmitter. | 31 | transmitter with the kernel, provide methods for turning it on and off and, |
47 | This is enabled by the CONFIG_RFKILL Kconfig option. | 32 | optionally, letting the system know about hardware-disabled states that may |
48 | 33 | be implemented on the device. This code is enabled with the CONFIG_RFKILL | |
49 | The rfkill class support makes sure userspace will be notified of all state | 34 | Kconfig option, which drivers can "select". |
50 | changes on rfkill devices through uevents. It provides a notification chain | ||
51 | for interested parties in the kernel to also get notified of rfkill state | ||
52 | changes in other drivers. It creates several sysfs entries which can be used | ||
53 | by userspace. See section "Userspace support". | ||
54 | |||
55 | The rfkill-input module provides the kernel with the ability to implement a | ||
56 | basic response when the user presses a key or button (or toggles a switch) | ||
57 | related to rfkill functionality. It is an in-kernel implementation of default | ||
58 | policy of reacting to rfkill-related input events and neither mandatory nor | ||
59 | required for wireless drivers to operate. It is enabled by the | ||
60 | CONFIG_RFKILL_INPUT Kconfig option. | ||
61 | |||
62 | rfkill-input is a rfkill-related events input layer handler. This handler will | ||
63 | listen to all rfkill key events and will change the rfkill state of the | ||
64 | wireless devices accordingly. With this option enabled userspace could either | ||
65 | do nothing or simply perform monitoring tasks. | ||
66 | |||
67 | The rfkill-input module also provides EPO (emergency power-off) functionality | ||
68 | for all wireless transmitters. This function cannot be overridden, and it is | ||
69 | always active. rfkill EPO is related to *_RFKILL_ALL input layer events. | ||
70 | |||
71 | |||
72 | Important terms for the rfkill subsystem: | ||
73 | |||
74 | In order to avoid confusion, we avoid the term "switch" in rfkill when it is | ||
75 | referring to an electronic control circuit that enables or disables a | ||
76 | transmitter. We reserve it for the physical device a human manipulates | ||
77 | (which is an input device, by the way): | ||
78 | |||
79 | rfkill switch: | ||
80 | |||
81 | A physical device a human manipulates. Its state can be perceived by | ||
82 | the kernel either directly (through a GPIO pin, ACPI GPE) or by its | ||
83 | effect on a rfkill line of a wireless device. | ||
84 | |||
85 | rfkill controller: | ||
86 | |||
87 | A hardware circuit that controls the state of a rfkill line, which a | ||
88 | kernel driver can interact with *to modify* that state (i.e. it has | ||
89 | either write-only or read/write access). | ||
90 | |||
91 | rfkill line: | ||
92 | |||
93 | An input channel (hardware or software) of a wireless device, which | ||
94 | causes a wireless transmitter to stop emitting energy (BLOCK) when it | ||
95 | is active. Point of view is extremely important here: rfkill lines are | ||
96 | always seen from the PoV of a wireless device (and its driver). | ||
97 | |||
98 | soft rfkill line/software rfkill line: | ||
99 | |||
100 | A rfkill line the wireless device driver can directly change the state | ||
101 | of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED. | ||
102 | |||
103 | hard rfkill line/hardware rfkill line: | ||
104 | |||
105 | A rfkill line that works fully in hardware or firmware, and that cannot | ||
106 | be overridden by the kernel driver. The hardware device or the | ||
107 | firmware just exports its status to the driver, but it is read-only. | ||
108 | Related to rfkill_state RFKILL_STATE_HARD_BLOCKED. | ||
109 | |||
110 | The enum rfkill_state describes the rfkill state of a transmitter: | ||
111 | |||
112 | When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state, | ||
113 | the wireless transmitter (radio TX circuit for example) is *enabled*. When the | ||
114 | it is in the RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the | ||
115 | wireless transmitter is to be *blocked* from operating. | ||
116 | |||
117 | RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change | ||
118 | that state. RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio() | ||
119 | will not be able to change the state and will return with a suitable error if | ||
120 | attempts are made to set the state to RFKILL_STATE_UNBLOCKED. | ||
121 | |||
122 | RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is | ||
123 | locked in the BLOCKED state by a hardwire rfkill line (typically an input pin | ||
124 | that, when active, forces the transmitter to be disabled) which the driver | ||
125 | CANNOT override. | ||
126 | |||
127 | Full rfkill functionality requires two different subsystems to cooperate: the | ||
128 | input layer and the rfkill class. The input layer issues *commands* to the | ||
129 | entire system requesting that devices registered to the rfkill class change | ||
130 | state. The way this interaction happens is not complex, but it is not obvious | ||
131 | either: | ||
132 | |||
133 | Kernel Input layer: | ||
134 | |||
135 | * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and | ||
136 | other such events when the user presses certain keys, buttons, or | ||
137 | toggles certain physical switches. | ||
138 | |||
139 | THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE | ||
140 | KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT. It is | ||
141 | used to issue *commands* for the system to change behaviour, and these | ||
142 | commands may or may not be carried out by some kernel driver or | ||
143 | userspace application. It follows that doing user feedback based only | ||
144 | on input events is broken, as there is no guarantee that an input event | ||
145 | will be acted upon. | ||
146 | |||
147 | Most wireless communication device drivers implementing rfkill | ||
148 | functionality MUST NOT generate these events, and have no reason to | ||
149 | register themselves with the input layer. Doing otherwise is a common | ||
150 | misconception. There is an API to propagate rfkill status change | ||
151 | information, and it is NOT the input layer. | ||
152 | |||
153 | rfkill class: | ||
154 | |||
155 | * Calls a hook in a driver to effectively change the wireless | ||
156 | transmitter state; | ||
157 | * Keeps track of the wireless transmitter state (with help from | ||
158 | the driver); | ||
159 | * Generates userspace notifications (uevents) and a call to a | ||
160 | notification chain (kernel) when there is a wireless transmitter | ||
161 | state change; | ||
162 | * Connects a wireless communications driver with the common rfkill | ||
163 | control system, which, for example, allows actions such as | ||
164 | "switch all bluetooth devices offline" to be carried out by | ||
165 | userspace or by rfkill-input. | ||
166 | |||
167 | THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES | ||
168 | NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL | ||
169 | EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS. Doing otherwise is | ||
170 | a layering violation. | ||
171 | |||
172 | Most wireless data communication drivers in the kernel have just to | ||
173 | implement the rfkill class API to work properly. Interfacing to the | ||
174 | input layer is not often required (and is very often a *bug*) on | ||
175 | wireless drivers. | ||
176 | |||
177 | Platform drivers often have to attach to the input layer to *issue* | ||
178 | (but never to listen to) rfkill events for rfkill switches, and also to | ||
179 | the rfkill class to export a control interface for the platform rfkill | ||
180 | controllers to the rfkill subsystem. This does NOT mean the rfkill | ||
181 | switch is attached to a rfkill class (doing so is almost always wrong). | ||
182 | It just means the same kernel module is the driver for different | ||
183 | devices (rfkill switches and rfkill controllers). | ||
184 | |||
185 | |||
186 | Userspace input handlers (uevents) or kernel input handlers (rfkill-input): | ||
187 | |||
188 | * Implements the policy of what should happen when one of the input | ||
189 | layer events related to rfkill operation is received. | ||
190 | * Uses the sysfs interface (userspace) or private rfkill API calls | ||
191 | to tell the devices registered with the rfkill class to change | ||
192 | their state (i.e. translates the input layer event into real | ||
193 | action). | ||
194 | |||
195 | * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0 | ||
196 | (power off all transmitters) in a special way: it ignores any | ||
197 | overrides and local state cache and forces all transmitters to the | ||
198 | RFKILL_STATE_SOFT_BLOCKED state (including those which are already | ||
199 | supposed to be BLOCKED). | ||
200 | * rfkill EPO will remain active until rfkill-input receives an | ||
201 | EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters | ||
202 | are locked in the blocked state (rfkill will refuse to unblock them). | ||
203 | * rfkill-input implements different policies that the user can | ||
204 | select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill, | ||
205 | and either do nothing (leave transmitters blocked, but now unlocked), | ||
206 | restore the transmitters to their state before the EPO, or unblock | ||
207 | them all. | ||
208 | |||
209 | Userspace uevent handler or kernel platform-specific drivers hooked to the | ||
210 | rfkill notifier chain: | ||
211 | |||
212 | * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents, | ||
213 | in order to know when a device that is registered with the rfkill | ||
214 | class changes state; | ||
215 | * Issues feedback notifications to the user; | ||
216 | * In the rare platforms where this is required, synthesizes an input | ||
217 | event to command all *OTHER* rfkill devices to also change their | ||
218 | statues when a specific rfkill device changes state. | ||
219 | |||
220 | |||
221 | =============================================================================== | ||
222 | 3: Kernel driver guidelines | ||
223 | |||
224 | Remember: point-of-view is everything for a driver that connects to the rfkill | ||
225 | subsystem. All the details below must be measured/perceived from the point of | ||
226 | view of the specific driver being modified. | ||
227 | |||
228 | The first thing one needs to know is whether his driver should be talking to | ||
229 | the rfkill class or to the input layer. In rare cases (platform drivers), it | ||
230 | could happen that you need to do both, as platform drivers often handle a | ||
231 | variety of devices in the same driver. | ||
232 | |||
233 | Do not mistake input devices for rfkill controllers. The only type of "rfkill | ||
234 | switch" device that is to be registered with the rfkill class are those | ||
235 | directly controlling the circuits that cause a wireless transmitter to stop | ||
236 | working (or the software equivalent of them), i.e. what we call a rfkill | ||
237 | controller. Every other kind of "rfkill switch" is just an input device and | ||
238 | MUST NOT be registered with the rfkill class. | ||
239 | |||
240 | A driver should register a device with the rfkill class when ALL of the | ||
241 | following conditions are met (they define a rfkill controller): | ||
242 | |||
243 | 1. The device is/controls a data communications wireless transmitter; | ||
244 | |||
245 | 2. The kernel can interact with the hardware/firmware to CHANGE the wireless | ||
246 | transmitter state (block/unblock TX operation); | ||
247 | |||
248 | 3. The transmitter can be made to not emit any energy when "blocked": | ||
249 | rfkill is not about blocking data transmissions, it is about blocking | ||
250 | energy emission; | ||
251 | |||
252 | A driver should register a device with the input subsystem to issue | ||
253 | rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX, | ||
254 | SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met: | ||
255 | |||
256 | 1. It is directly related to some physical device the user interacts with, to | ||
257 | command the O.S./firmware/hardware to enable/disable a data communications | ||
258 | wireless transmitter. | ||
259 | |||
260 | Examples of the physical device are: buttons, keys and switches the user | ||
261 | will press/touch/slide/switch to enable or disable the wireless | ||
262 | communication device. | ||
263 | |||
264 | 2. It is NOT slaved to another device, i.e. there is no other device that | ||
265 | issues rfkill-related input events in preference to this one. | ||
266 | |||
267 | Please refer to the corner cases and examples section for more details. | ||
268 | |||
269 | When in doubt, do not issue input events. For drivers that should generate | ||
270 | input events in some platforms, but not in others (e.g. b43), the best solution | ||
271 | is to NEVER generate input events in the first place. That work should be | ||
272 | deferred to a platform-specific kernel module (which will know when to generate | ||
273 | events through the rfkill notifier chain) or to userspace. This avoids the | ||
274 | usual maintenance problems with DMI whitelisting. | ||
275 | |||
276 | |||
277 | Corner cases and examples: | ||
278 | ==================================== | ||
279 | |||
280 | 1. If the device is an input device that, because of hardware or firmware, | ||
281 | causes wireless transmitters to be blocked regardless of the kernel's will, it | ||
282 | is still just an input device, and NOT to be registered with the rfkill class. | ||
283 | |||
284 | 2. If the wireless transmitter switch control is read-only, it is an input | ||
285 | device and not to be registered with the rfkill class (and maybe not to be made | ||
286 | an input layer event source either, see below). | ||
287 | |||
288 | 3. If there is some other device driver *closer* to the actual hardware the | ||
289 | user interacted with (the button/switch/key) to issue an input event, THAT is | ||
290 | the device driver that should be issuing input events. | ||
291 | |||
292 | E.g: | ||
293 | [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input] | ||
294 | (platform driver) (wireless card driver) | ||
295 | |||
296 | The user is closer to the RFKILL slide switch plaform driver, so the driver | ||
297 | which must issue input events is the platform driver looking at the GPIO | ||
298 | hardware, and NEVER the wireless card driver (which is just a slave). It is | ||
299 | very likely that there are other leaves than just the WLAN card rf-kill input | ||
300 | (e.g. a bluetooth card, etc)... | ||
301 | |||
302 | On the other hand, some embedded devices do this: | ||
303 | |||
304 | [RFKILL slider switch] -- [WLAN card rf-kill input] | ||
305 | (wireless card driver) | ||
306 | |||
307 | In this situation, the wireless card driver *could* register itself as an input | ||
308 | device and issue rf-kill related input events... but in order to AVOID the need | ||
309 | for DMI whitelisting, the wireless card driver does NOT do it. Userspace (HAL) | ||
310 | or a platform driver (that exists only on these embedded devices) will do the | ||
311 | dirty job of issuing the input events. | ||
312 | |||
313 | |||
314 | COMMON MISTAKES in kernel drivers, related to rfkill: | ||
315 | ==================================== | ||
316 | |||
317 | 1. NEVER confuse input device keys and buttons with input device switches. | ||
318 | |||
319 | 1a. Switches are always set or reset. They report the current state | ||
320 | (on position or off position). | ||
321 | |||
322 | 1b. Keys and buttons are either in the pressed or not-pressed state, and | ||
323 | that's it. A "button" that latches down when you press it, and | ||
324 | unlatches when you press it again is in fact a switch as far as input | ||
325 | devices go. | ||
326 | |||
327 | Add the SW_* events you need for switches, do NOT try to emulate a button using | ||
328 | KEY_* events just because there is no such SW_* event yet. Do NOT try to use, | ||
329 | for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead. | ||
330 | |||
331 | 2. Input device switches (sources of EV_SW events) DO store their current state | ||
332 | (so you *must* initialize it by issuing a gratuitous input layer event on | ||
333 | driver start-up and also when resuming from sleep), and that state CAN be | ||
334 | queried from userspace through IOCTLs. There is no sysfs interface for this, | ||
335 | but that doesn't mean you should break things trying to hook it to the rfkill | ||
336 | class to get a sysfs interface :-) | ||
337 | |||
338 | 3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the | ||
339 | correct event for your switch/button. These events are emergency power-off | ||
340 | events when they are trying to turn the transmitters off. An example of an | ||
341 | input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill | ||
342 | switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch. | ||
343 | An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by | ||
344 | default, is any sort of hot key that is type-specific (e.g. the one for WLAN). | ||
345 | |||
346 | |||
347 | 3.1 Guidelines for wireless device drivers | ||
348 | ------------------------------------------ | ||
349 | |||
350 | (in this text, rfkill->foo means the foo field of struct rfkill). | ||
351 | |||
352 | 1. Each independent transmitter in a wireless device (usually there is only one | ||
353 | transmitter per device) should have a SINGLE rfkill class attached to it. | ||
354 | |||
355 | 2. If the device does not have any sort of hardware assistance to allow the | ||
356 | driver to rfkill the device, the driver should emulate it by taking all actions | ||
357 | required to silence the transmitter. | ||
358 | |||
359 | 3. If it is impossible to silence the transmitter (i.e. it still emits energy, | ||
360 | even if it is just in brief pulses, when there is no data to transmit and there | ||
361 | is no hardware support to turn it off) do NOT lie to the users. Do not attach | ||
362 | it to a rfkill class. The rfkill subsystem does not deal with data | ||
363 | transmission, it deals with energy emission. If the transmitter is emitting | ||
364 | energy, it is not blocked in rfkill terms. | ||
365 | |||
366 | 4. It doesn't matter if the device has multiple rfkill input lines affecting | ||
367 | the same transmitter, their combined state is to be exported as a single state | ||
368 | per transmitter (see rule 1). | ||
369 | |||
370 | This rule exists because users of the rfkill subsystem expect to get (and set, | ||
371 | when possible) the overall transmitter rfkill state, not of a particular rfkill | ||
372 | line. | ||
373 | |||
374 | 5. The wireless device driver MUST NOT leave the transmitter enabled during | ||
375 | suspend and hibernation unless: | ||
376 | 35 | ||
377 | 5.1. The transmitter has to be enabled for some sort of functionality | 36 | The rfkill class code also notifies userspace of state changes, this is |
378 | like wake-on-wireless-packet or autonomous packed forwarding in a mesh | 37 | achieved via uevents. It also provides some sysfs files for userspace to |
379 | network, and that functionality is enabled for this suspend/hibernation | 38 | check the status of radio transmitters. See the "Userspace support" section |
380 | cycle. | 39 | below. |
381 | 40 | ||
382 | AND | ||
383 | 41 | ||
384 | 5.2. The device was not on a user-requested BLOCKED state before | 42 | The rfkill-input code implements a basic response to rfkill buttons -- it |
385 | the suspend (i.e. the driver must NOT unblock a device, not even | 43 | implements turning on/off all devices of a certain class (or all). |
386 | to support wake-on-wireless-packet or remain in the mesh). | ||
387 | 44 | ||
388 | In other words, there is absolutely no allowed scenario where a driver can | 45 | When the device is hard-blocked (either by a call to rfkill_set_hw_state() |
389 | automatically take action to unblock a rfkill controller (obviously, this deals | 46 | or from query_hw_block) set_block() will be invoked but drivers can well |
390 | with scenarios where soft-blocking or both soft and hard blocking is happening. | 47 | ignore the method call since they can use the return value of the function |
391 | Scenarios where hardware rfkill lines are the only ones blocking the | 48 | rfkill_set_hw_state() to sync the software state instead of keeping track |
392 | transmitter are outside of this rule, since the wireless device driver does not | 49 | of calls to set_block(). |
393 | control its input hardware rfkill lines in the first place). | ||
394 | 50 | ||
395 | 6. During resume, rfkill will try to restore its previous state. | ||
396 | 51 | ||
397 | 7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio | 52 | The entire functionality is spread over more than one subsystem: |
398 | until it is resumed. | ||
399 | 53 | ||
54 | * The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and | ||
55 | SW_RFKILL_ALL -- when the user presses a button. Drivers for radio | ||
56 | transmitters generally do not register to the input layer, unless the | ||
57 | device really provides an input device (i.e. a button that has no | ||
58 | effect other than generating a button press event) | ||
400 | 59 | ||
401 | Example of a WLAN wireless driver connected to the rfkill subsystem: | 60 | * The rfkill-input code hooks up to these events and switches the soft-block |
402 | -------------------------------------------------------------------- | 61 | of the various radio transmitters, depending on the button type. |
403 | 62 | ||
404 | A certain WLAN card has one input pin that causes it to block the transmitter | 63 | * The rfkill drivers turn off/on their transmitters as requested. |
405 | and makes the status of that input pin available (only for reading!) to the | ||
406 | kernel driver. This is a hard rfkill input line (it cannot be overridden by | ||
407 | the kernel driver). | ||
408 | 64 | ||
409 | The card also has one PCI register that, if manipulated by the driver, causes | 65 | * The rfkill class will generate userspace notifications (uevents) to tell |
410 | it to block the transmitter. This is a soft rfkill input line. | 66 | userspace what the current state is. |
411 | 67 | ||
412 | It has also a thermal protection circuitry that shuts down its transmitter if | ||
413 | the card overheats, and makes the status of that protection available (only for | ||
414 | reading!) to the kernel driver. This is also a hard rfkill input line. | ||
415 | 68 | ||
416 | If either one of these rfkill lines are active, the transmitter is blocked by | ||
417 | the hardware and forced offline. | ||
418 | 69 | ||
419 | The driver should allocate and attach to its struct device *ONE* instance of | 70 | 3. Kernel driver guidelines |
420 | the rfkill class (there is only one transmitter). | ||
421 | 71 | ||
422 | It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if | ||
423 | either one of its two hard rfkill input lines are active. If the two hard | ||
424 | rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft | ||
425 | rfkill input line is active. Only if none of the rfkill input lines are | ||
426 | active, will it return RFKILL_STATE_UNBLOCKED. | ||
427 | 72 | ||
428 | Since the device has a hardware rfkill line, it IS subject to state changes | 73 | Drivers for radio transmitters normally implement only the rfkill class. |
429 | external to rfkill. Therefore, the driver must make sure that it calls | 74 | These drivers may not unblock the transmitter based on own decisions, they |
430 | rfkill_force_state() to keep the status always up-to-date, and it must do a | 75 | should act on information provided by the rfkill class only. |
431 | rfkill_force_state() on resume from sleep. | ||
432 | 76 | ||
433 | Every time the driver gets a notification from the card that one of its rfkill | 77 | Platform drivers might implement input devices if the rfkill button is just |
434 | lines changed state (polling might be needed on badly designed cards that don't | 78 | that, a button. If that button influences the hardware then you need to |
435 | generate interrupts for such events), it recomputes the rfkill state as per | 79 | implement an rfkill class instead. This also applies if the platform provides |
436 | above, and calls rfkill_force_state() to update it. | 80 | a way to turn on/off the transmitter(s). |
437 | 81 | ||
438 | The driver should implement the toggle_radio() hook, that: | 82 | During suspend/hibernation, transmitters should only be left enabled when |
83 | wake-on wlan or similar functionality requires it and the device wasn't | ||
84 | blocked before suspend/hibernate. Note that it may be necessary to update | ||
85 | the rfkill subsystem's idea of what the current state is at resume time if | ||
86 | the state may have changed over suspend. | ||
439 | 87 | ||
440 | 1. Returns an error if one of the hardware rfkill lines are active, and the | ||
441 | caller asked for RFKILL_STATE_UNBLOCKED. | ||
442 | 88 | ||
443 | 2. Activates the soft rfkill line if the caller asked for state | ||
444 | RFKILL_STATE_SOFT_BLOCKED. It should do this even if one of the hard rfkill | ||
445 | lines are active, effectively double-blocking the transmitter. | ||
446 | 89 | ||
447 | 3. Deactivates the soft rfkill line if none of the hardware rfkill lines are | 90 | 4. Kernel API |
448 | active and the caller asked for RFKILL_STATE_UNBLOCKED. | ||
449 | |||
450 | =============================================================================== | ||
451 | 4: Kernel API | ||
452 | 91 | ||
453 | To build a driver with rfkill subsystem support, the driver should depend on | 92 | To build a driver with rfkill subsystem support, the driver should depend on |
454 | (or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT. | 93 | (or select) the Kconfig symbol RFKILL. |
455 | 94 | ||
456 | The hardware the driver talks to may be write-only (where the current state | 95 | The hardware the driver talks to may be write-only (where the current state |
457 | of the hardware is unknown), or read-write (where the hardware can be queried | 96 | of the hardware is unknown), or read-write (where the hardware can be queried |
458 | about its current state). | 97 | about its current state). |
459 | 98 | ||
460 | The rfkill class will call the get_state hook of a device every time it needs | 99 | Calling rfkill_set_hw_state() when a state change happens is required from |
461 | to know the *real* current state of the hardware. This can happen often, but | 100 | rfkill drivers that control devices that can be hard-blocked unless they also |
462 | it does not do any polling, so it is not enough on hardware that is subject | 101 | assign the poll_hw_block() callback (then the rfkill core will poll the |
463 | to state changes outside of the rfkill subsystem. | 102 | device). Don't do this unless you cannot get the event in any other way. |
464 | |||
465 | Therefore, calling rfkill_force_state() when a state change happens is | ||
466 | mandatory when the device has a hardware rfkill line, or when something else | ||
467 | like the firmware could cause its state to be changed without going through the | ||
468 | rfkill class. | ||
469 | |||
470 | Some hardware provides events when its status changes. In these cases, it is | ||
471 | best for the driver to not provide a get_state hook, and instead register the | ||
472 | rfkill class *already* with the correct status, and keep it updated using | ||
473 | rfkill_force_state() when it gets an event from the hardware. | ||
474 | |||
475 | rfkill_force_state() must be used on the device resume handlers to update the | ||
476 | rfkill status, should there be any chance of the device status changing during | ||
477 | the sleep. | ||
478 | |||
479 | There is no provision for a statically-allocated rfkill struct. You must | ||
480 | use rfkill_allocate() to allocate one. | ||
481 | |||
482 | You should: | ||
483 | - rfkill_allocate() | ||
484 | - modify rfkill fields (flags, name) | ||
485 | - modify state to the current hardware state (THIS IS THE ONLY TIME | ||
486 | YOU CAN ACCESS state DIRECTLY) | ||
487 | - rfkill_register() | ||
488 | |||
489 | The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through | ||
490 | a suitable return of get_state() or through rfkill_force_state(). | ||
491 | 103 | ||
492 | When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch | ||
493 | it to a different state is through a suitable return of get_state() or through | ||
494 | rfkill_force_state(). | ||
495 | 104 | ||
496 | If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED | ||
497 | when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should | ||
498 | not return an error. Instead, it should try to double-block the transmitter, | ||
499 | so that its state will change from RFKILL_STATE_HARD_BLOCKED to | ||
500 | RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease. | ||
501 | |||
502 | Please refer to the source for more documentation. | ||
503 | |||
504 | =============================================================================== | ||
505 | 5: Userspace support | ||
506 | |||
507 | rfkill devices issue uevents (with an action of "change"), with the following | ||
508 | environment variables set: | ||
509 | |||
510 | RFKILL_NAME | ||
511 | RFKILL_STATE | ||
512 | RFKILL_TYPE | ||
513 | 105 | ||
514 | The ABI for these variables is defined by the sysfs attributes. It is best | 106 | 5. Userspace support |
515 | to take a quick look at the source to make sure of the possible values. | ||
516 | 107 | ||
517 | It is expected that HAL will trap those, and bridge them to DBUS, etc. These | 108 | The following sysfs entries exist for every rfkill device: |
518 | events CAN and SHOULD be used to give feedback to the user about the rfkill | ||
519 | status of the system. | ||
520 | |||
521 | Input devices may issue events that are related to rfkill. These are the | ||
522 | various KEY_* events and SW_* events supported by rfkill-input.c. | ||
523 | |||
524 | Userspace may not change the state of an rfkill switch in response to an | ||
525 | input event, it should refrain from changing states entirely. | ||
526 | |||
527 | Userspace cannot assume it is the only source of control for rfkill switches. | ||
528 | Their state can change due to firmware actions, direct user actions, and the | ||
529 | rfkill-input EPO override for *_RFKILL_ALL. | ||
530 | |||
531 | When rfkill-input is not active, userspace must initiate a rfkill status | ||
532 | change by writing to the "state" attribute in order for anything to happen. | ||
533 | |||
534 | Take particular care to implement EV_SW SW_RFKILL_ALL properly. When that | ||
535 | switch is set to OFF, *every* rfkill device *MUST* be immediately put into the | ||
536 | RFKILL_STATE_SOFT_BLOCKED state, no questions asked. | ||
537 | |||
538 | The following sysfs entries will be created: | ||
539 | 109 | ||
540 | name: Name assigned by driver to this key (interface or driver name). | 110 | name: Name assigned by driver to this key (interface or driver name). |
541 | type: Name of the key type ("wlan", "bluetooth", etc). | 111 | type: Name of the key type ("wlan", "bluetooth", etc). |
542 | state: Current state of the transmitter | 112 | state: Current state of the transmitter |
543 | 0: RFKILL_STATE_SOFT_BLOCKED | 113 | 0: RFKILL_STATE_SOFT_BLOCKED |
544 | transmitter is forced off, but one can override it | 114 | transmitter is turned off by software |
545 | by a write to the state attribute; | ||
546 | 1: RFKILL_STATE_UNBLOCKED | 115 | 1: RFKILL_STATE_UNBLOCKED |
547 | transmiter is NOT forced off, and may operate if | 116 | transmitter is (potentially) active |
548 | all other conditions for such operation are met | ||
549 | (such as interface is up and configured, etc); | ||
550 | 2: RFKILL_STATE_HARD_BLOCKED | 117 | 2: RFKILL_STATE_HARD_BLOCKED |
551 | transmitter is forced off by something outside of | 118 | transmitter is forced off by something outside of |
552 | the driver's control. One cannot set a device to | 119 | the driver's control. |
553 | this state through writes to the state attribute; | 120 | claim: 0: Kernel handles events (currently always reads that value) |
554 | claim: 1: Userspace handles events, 0: Kernel handles events | 121 | |
555 | 122 | rfkill devices also issue uevents (with an action of "change"), with the | |
556 | Both the "state" and "claim" entries are also writable. For the "state" entry | 123 | following environment variables set: |
557 | this means that when 1 or 0 is written, the device rfkill state (if not yet in | 124 | |
558 | the requested state), will be will be toggled accordingly. | 125 | RFKILL_NAME |
559 | 126 | RFKILL_STATE | |
560 | For the "claim" entry writing 1 to it means that the kernel no longer handles | 127 | RFKILL_TYPE |
561 | key events even though RFKILL_INPUT input was enabled. When "claim" has been | 128 | |
562 | set to 0, userspace should make sure that it listens for the input events or | 129 | The contents of these variables corresponds to the "name", "state" and |
563 | check the sysfs "state" entry regularly to correctly perform the required tasks | 130 | "type" sysfs files explained above. |
564 | when the rkfill key is pressed. | 131 | |
565 | 132 | An alternative userspace interface exists as a misc device /dev/rfkill, | |
566 | A note about input devices and EV_SW events: | 133 | which allows userspace to obtain and set the state of rfkill devices and |
567 | 134 | sets of devices. It also notifies userspace about device addition and | |
568 | In order to know the current state of an input device switch (like | 135 | removal. The API is a simple read/write API that is defined in |
569 | SW_RFKILL_ALL), you will need to use an IOCTL. That information is not | 136 | linux/rfkill.h. |
570 | available through sysfs in a generic way at this time, and it is not available | ||
571 | through the rfkill class AT ALL. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index e18baa410b50..2f6a8fcfb1f2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4753,9 +4753,9 @@ S: Supported | |||
4753 | F: fs/reiserfs/ | 4753 | F: fs/reiserfs/ |
4754 | 4754 | ||
4755 | RFKILL | 4755 | RFKILL |
4756 | P: Ivo van Doorn | 4756 | P: Johannes Berg |
4757 | M: IvDoorn@gmail.com | 4757 | M: johannes@sipsolutions.net |
4758 | L: netdev@vger.kernel.org | 4758 | L: linux-wireless@vger.kernel.org |
4759 | S: Maintained | 4759 | S: Maintained |
4760 | F Documentation/rfkill.txt | 4760 | F Documentation/rfkill.txt |
4761 | F: net/rfkill/ | 4761 | F: net/rfkill/ |
diff --git a/arch/arm/mach-pxa/tosa-bt.c b/arch/arm/mach-pxa/tosa-bt.c index bde42aa29374..c31e601eb49c 100644 --- a/arch/arm/mach-pxa/tosa-bt.c +++ b/arch/arm/mach-pxa/tosa-bt.c | |||
@@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data) | |||
35 | gpio_set_value(data->gpio_reset, 0); | 35 | gpio_set_value(data->gpio_reset, 0); |
36 | } | 36 | } |
37 | 37 | ||
38 | static int tosa_bt_toggle_radio(void *data, enum rfkill_state state) | 38 | static int tosa_bt_set_block(void *data, bool blocked) |
39 | { | 39 | { |
40 | pr_info("BT_RADIO going: %s\n", | 40 | pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on"); |
41 | state == RFKILL_STATE_UNBLOCKED ? "on" : "off"); | ||
42 | 41 | ||
43 | if (state == RFKILL_STATE_UNBLOCKED) { | 42 | if (!blocked) { |
44 | pr_info("TOSA_BT: going ON\n"); | 43 | pr_info("TOSA_BT: going ON\n"); |
45 | tosa_bt_on(data); | 44 | tosa_bt_on(data); |
46 | } else { | 45 | } else { |
47 | pr_info("TOSA_BT: going OFF\n"); | 46 | pr_info("TOSA_BT: going OFF\n"); |
48 | tosa_bt_off(data); | 47 | tosa_bt_off(data); |
49 | } | 48 | } |
49 | |||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | static const struct rfkill_ops tosa_bt_rfkill_ops = { | ||
54 | .set_block = tosa_bt_set_block, | ||
55 | }; | ||
56 | |||
53 | static int tosa_bt_probe(struct platform_device *dev) | 57 | static int tosa_bt_probe(struct platform_device *dev) |
54 | { | 58 | { |
55 | int rc; | 59 | int rc; |
@@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev) | |||
70 | if (rc) | 74 | if (rc) |
71 | goto err_pwr_dir; | 75 | goto err_pwr_dir; |
72 | 76 | ||
73 | rfk = rfkill_allocate(&dev->dev, RFKILL_TYPE_BLUETOOTH); | 77 | rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, |
78 | &tosa_bt_rfkill_ops, data); | ||
74 | if (!rfk) { | 79 | if (!rfk) { |
75 | rc = -ENOMEM; | 80 | rc = -ENOMEM; |
76 | goto err_rfk_alloc; | 81 | goto err_rfk_alloc; |
77 | } | 82 | } |
78 | 83 | ||
79 | rfk->name = "tosa-bt"; | 84 | rfkill_set_led_trigger_name(rfk, "tosa-bt"); |
80 | rfk->toggle_radio = tosa_bt_toggle_radio; | ||
81 | rfk->data = data; | ||
82 | #ifdef CONFIG_RFKILL_LEDS | ||
83 | rfk->led_trigger.name = "tosa-bt"; | ||
84 | #endif | ||
85 | 85 | ||
86 | rc = rfkill_register(rfk); | 86 | rc = rfkill_register(rfk); |
87 | if (rc) | 87 | if (rc) |
@@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev) | |||
92 | return 0; | 92 | return 0; |
93 | 93 | ||
94 | err_rfkill: | 94 | err_rfkill: |
95 | if (rfk) | 95 | rfkill_destroy(rfk); |
96 | rfkill_free(rfk); | ||
97 | rfk = NULL; | ||
98 | err_rfk_alloc: | 96 | err_rfk_alloc: |
99 | tosa_bt_off(data); | 97 | tosa_bt_off(data); |
100 | err_pwr_dir: | 98 | err_pwr_dir: |
@@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev) | |||
113 | 111 | ||
114 | platform_set_drvdata(dev, NULL); | 112 | platform_set_drvdata(dev, NULL); |
115 | 113 | ||
116 | if (rfk) | 114 | if (rfk) { |
117 | rfkill_unregister(rfk); | 115 | rfkill_unregister(rfk); |
116 | rfkill_destroy(rfk); | ||
117 | } | ||
118 | rfk = NULL; | 118 | rfk = NULL; |
119 | 119 | ||
120 | tosa_bt_off(data); | 120 | tosa_bt_off(data); |
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index afac5b6d3d78..58ce807fe440 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <linux/input.h> | 31 | #include <linux/input.h> |
32 | #include <linux/gpio.h> | 32 | #include <linux/gpio.h> |
33 | #include <linux/pda_power.h> | 33 | #include <linux/pda_power.h> |
34 | #include <linux/rfkill.h> | ||
35 | #include <linux/spi/spi.h> | 34 | #include <linux/spi/spi.h> |
36 | 35 | ||
37 | #include <asm/setup.h> | 36 | #include <asm/setup.h> |
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 837135f0390a..5ddd8c4f9019 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c | |||
@@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev) | |||
2481 | return 0; | 2481 | return 0; |
2482 | } | 2482 | } |
2483 | 2483 | ||
2484 | static int hso_radio_toggle(void *data, enum rfkill_state state) | 2484 | static int hso_rfkill_set_block(void *data, bool blocked) |
2485 | { | 2485 | { |
2486 | struct hso_device *hso_dev = data; | 2486 | struct hso_device *hso_dev = data; |
2487 | int enabled = (state == RFKILL_STATE_UNBLOCKED); | 2487 | int enabled = !blocked; |
2488 | int rv; | 2488 | int rv; |
2489 | 2489 | ||
2490 | mutex_lock(&hso_dev->mutex); | 2490 | mutex_lock(&hso_dev->mutex); |
@@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state) | |||
2498 | return rv; | 2498 | return rv; |
2499 | } | 2499 | } |
2500 | 2500 | ||
2501 | static const struct rfkill_ops hso_rfkill_ops = { | ||
2502 | .set_block = hso_rfkill_set_block, | ||
2503 | }; | ||
2504 | |||
2501 | /* Creates and sets up everything for rfkill */ | 2505 | /* Creates and sets up everything for rfkill */ |
2502 | static void hso_create_rfkill(struct hso_device *hso_dev, | 2506 | static void hso_create_rfkill(struct hso_device *hso_dev, |
2503 | struct usb_interface *interface) | 2507 | struct usb_interface *interface) |
@@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev, | |||
2506 | struct device *dev = &hso_net->net->dev; | 2510 | struct device *dev = &hso_net->net->dev; |
2507 | char *rfkn; | 2511 | char *rfkn; |
2508 | 2512 | ||
2509 | hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, | ||
2510 | RFKILL_TYPE_WWAN); | ||
2511 | if (!hso_net->rfkill) { | ||
2512 | dev_err(dev, "%s - Out of memory\n", __func__); | ||
2513 | return; | ||
2514 | } | ||
2515 | rfkn = kzalloc(20, GFP_KERNEL); | 2513 | rfkn = kzalloc(20, GFP_KERNEL); |
2516 | if (!rfkn) { | 2514 | if (!rfkn) |
2517 | rfkill_free(hso_net->rfkill); | ||
2518 | hso_net->rfkill = NULL; | ||
2519 | dev_err(dev, "%s - Out of memory\n", __func__); | 2515 | dev_err(dev, "%s - Out of memory\n", __func__); |
2520 | return; | 2516 | |
2521 | } | ||
2522 | snprintf(rfkn, 20, "hso-%d", | 2517 | snprintf(rfkn, 20, "hso-%d", |
2523 | interface->altsetting->desc.bInterfaceNumber); | 2518 | interface->altsetting->desc.bInterfaceNumber); |
2524 | hso_net->rfkill->name = rfkn; | 2519 | |
2525 | hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED; | 2520 | hso_net->rfkill = rfkill_alloc(rfkn, |
2526 | hso_net->rfkill->data = hso_dev; | 2521 | &interface_to_usbdev(interface)->dev, |
2527 | hso_net->rfkill->toggle_radio = hso_radio_toggle; | 2522 | RFKILL_TYPE_WWAN, |
2523 | &hso_rfkill_ops, hso_dev); | ||
2524 | if (!hso_net->rfkill) { | ||
2525 | dev_err(dev, "%s - Out of memory\n", __func__); | ||
2526 | kfree(rfkn); | ||
2527 | return; | ||
2528 | } | ||
2528 | if (rfkill_register(hso_net->rfkill) < 0) { | 2529 | if (rfkill_register(hso_net->rfkill) < 0) { |
2530 | rfkill_destroy(hso_net->rfkill); | ||
2529 | kfree(rfkn); | 2531 | kfree(rfkn); |
2530 | hso_net->rfkill->name = NULL; | ||
2531 | rfkill_free(hso_net->rfkill); | ||
2532 | hso_net->rfkill = NULL; | 2532 | hso_net->rfkill = NULL; |
2533 | dev_err(dev, "%s - Failed to register rfkill\n", __func__); | 2533 | dev_err(dev, "%s - Failed to register rfkill\n", __func__); |
2534 | return; | 2534 | return; |
@@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface) | |||
3165 | hso_stop_net_device(network_table[i]); | 3165 | hso_stop_net_device(network_table[i]); |
3166 | cancel_work_sync(&network_table[i]->async_put_intf); | 3166 | cancel_work_sync(&network_table[i]->async_put_intf); |
3167 | cancel_work_sync(&network_table[i]->async_get_intf); | 3167 | cancel_work_sync(&network_table[i]->async_get_intf); |
3168 | if (rfk) | 3168 | if (rfk) { |
3169 | rfkill_unregister(rfk); | 3169 | rfkill_unregister(rfk); |
3170 | rfkill_destroy(rfk); | ||
3171 | } | ||
3170 | hso_free_net_device(network_table[i]); | 3172 | hso_free_net_device(network_table[i]); |
3171 | } | 3173 | } |
3172 | } | 3174 | } |
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 867324163ca2..daf4c805be58 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -333,11 +333,11 @@ config USB_ZD1201 | |||
333 | config USB_NET_RNDIS_WLAN | 333 | config USB_NET_RNDIS_WLAN |
334 | tristate "Wireless RNDIS USB support" | 334 | tristate "Wireless RNDIS USB support" |
335 | depends on USB && WLAN_80211 && EXPERIMENTAL | 335 | depends on USB && WLAN_80211 && EXPERIMENTAL |
336 | depends on CFG80211 | ||
336 | select USB_USBNET | 337 | select USB_USBNET |
337 | select USB_NET_CDCETHER | 338 | select USB_NET_CDCETHER |
338 | select USB_NET_RNDIS_HOST | 339 | select USB_NET_RNDIS_HOST |
339 | select WIRELESS_EXT | 340 | select WIRELESS_EXT |
340 | select CFG80211 | ||
341 | ---help--- | 341 | ---help--- |
342 | This is a driver for wireless RNDIS devices. | 342 | This is a driver for wireless RNDIS devices. |
343 | These are USB based adapters found in devices such as: | 343 | These are USB based adapters found in devices such as: |
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 17bd3eaf3e03..c7cba66b63cb 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h | |||
@@ -91,6 +91,7 @@ struct ar9170_led { | |||
91 | struct led_classdev l; | 91 | struct led_classdev l; |
92 | char name[32]; | 92 | char name[32]; |
93 | unsigned int toggled; | 93 | unsigned int toggled; |
94 | bool last_state; | ||
94 | bool registered; | 95 | bool registered; |
95 | }; | 96 | }; |
96 | 97 | ||
@@ -101,7 +102,6 @@ enum ar9170_device_state { | |||
101 | AR9170_STOPPED, | 102 | AR9170_STOPPED, |
102 | AR9170_IDLE, | 103 | AR9170_IDLE, |
103 | AR9170_STARTED, | 104 | AR9170_STARTED, |
104 | AR9170_ASSOCIATED, | ||
105 | }; | 105 | }; |
106 | 106 | ||
107 | struct ar9170_rxstream_mpdu_merge { | 107 | struct ar9170_rxstream_mpdu_merge { |
@@ -140,7 +140,7 @@ struct ar9170 { | |||
140 | struct work_struct filter_config_work; | 140 | struct work_struct filter_config_work; |
141 | u64 cur_mc_hash, want_mc_hash; | 141 | u64 cur_mc_hash, want_mc_hash; |
142 | u32 cur_filter, want_filter; | 142 | u32 cur_filter, want_filter; |
143 | unsigned int filter_changed; | 143 | unsigned long filter_changed; |
144 | unsigned int filter_state; | 144 | unsigned int filter_state; |
145 | bool sniffer_enabled; | 145 | bool sniffer_enabled; |
146 | 146 | ||
@@ -195,7 +195,7 @@ struct ar9170_sta_info { | |||
195 | #define IS_STARTED(a) (a->state >= AR9170_STARTED) | 195 | #define IS_STARTED(a) (a->state >= AR9170_STARTED) |
196 | #define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) | 196 | #define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) |
197 | 197 | ||
198 | #define AR9170_FILTER_CHANGED_PROMISC BIT(0) | 198 | #define AR9170_FILTER_CHANGED_MODE BIT(0) |
199 | #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) | 199 | #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) |
200 | #define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) | 200 | #define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) |
201 | 201 | ||
@@ -206,6 +206,7 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); | |||
206 | void ar9170_unregister(struct ar9170 *ar); | 206 | void ar9170_unregister(struct ar9170 *ar); |
207 | void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, | 207 | void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, |
208 | bool update_statistics, u16 tx_status); | 208 | bool update_statistics, u16 tx_status); |
209 | void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); | ||
209 | 210 | ||
210 | /* MAC */ | 211 | /* MAC */ |
211 | int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | 212 | int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); |
@@ -215,6 +216,9 @@ int ar9170_update_multicast(struct ar9170 *ar); | |||
215 | int ar9170_update_frame_filter(struct ar9170 *ar); | 216 | int ar9170_update_frame_filter(struct ar9170 *ar); |
216 | int ar9170_set_operating_mode(struct ar9170 *ar); | 217 | int ar9170_set_operating_mode(struct ar9170 *ar); |
217 | int ar9170_set_beacon_timers(struct ar9170 *ar); | 218 | int ar9170_set_beacon_timers(struct ar9170 *ar); |
219 | int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); | ||
220 | int ar9170_set_slot_time(struct ar9170 *ar); | ||
221 | int ar9170_set_basic_rates(struct ar9170 *ar); | ||
218 | int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); | 222 | int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); |
219 | int ar9170_update_beacon(struct ar9170 *ar); | 223 | int ar9170_update_beacon(struct ar9170 *ar); |
220 | void ar9170_new_beacon(struct work_struct *work); | 224 | void ar9170_new_beacon(struct work_struct *work); |
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 3293e0fb24fb..3c8004fb7307 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h | |||
@@ -207,7 +207,8 @@ enum ar9170_cmd { | |||
207 | #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) | 207 | #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) |
208 | #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) | 208 | #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) |
209 | 209 | ||
210 | #define AR9170_MAC_REG_AMPDU_SET (AR9170_MAC_REG_BASE + 0xba0) | 210 | #define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) |
211 | #define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) | ||
211 | 212 | ||
212 | #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) | 213 | #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) |
213 | #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) | 214 | #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) |
@@ -376,7 +377,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) | |||
376 | #define AR9170_RX_ERROR_FATAL 0x80 | 377 | #define AR9170_RX_ERROR_FATAL 0x80 |
377 | 378 | ||
378 | struct ar9170_cmd_tx_status { | 379 | struct ar9170_cmd_tx_status { |
379 | __le16 unkn; | ||
380 | u8 dst[ETH_ALEN]; | 380 | u8 dst[ETH_ALEN]; |
381 | __le32 rate; | 381 | __le32 rate; |
382 | __le16 status; | 382 | __le16 status; |
@@ -394,6 +394,7 @@ struct ar9170_cmd_ba_failed_count { | |||
394 | struct ar9170_cmd_response { | 394 | struct ar9170_cmd_response { |
395 | u8 flag; | 395 | u8 flag; |
396 | u8 type; | 396 | u8 type; |
397 | __le16 padding; | ||
397 | 398 | ||
398 | union { | 399 | union { |
399 | struct ar9170_cmd_tx_status tx_status; | 400 | struct ar9170_cmd_tx_status tx_status; |
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c index 341cead7f606..63fda6cd2101 100644 --- a/drivers/net/wireless/ath/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c | |||
@@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work) | |||
74 | 74 | ||
75 | mutex_lock(&ar->mutex); | 75 | mutex_lock(&ar->mutex); |
76 | for (i = 0; i < AR9170_NUM_LEDS; i++) | 76 | for (i = 0; i < AR9170_NUM_LEDS; i++) |
77 | if (ar->leds[i].toggled) { | 77 | if (ar->leds[i].registered && ar->leds[i].toggled) { |
78 | led_val |= 1 << i; | 78 | led_val |= 1 << i; |
79 | 79 | ||
80 | tmp = 70 + 200 / (ar->leds[i].toggled); | 80 | tmp = 70 + 200 / (ar->leds[i].toggled); |
@@ -101,9 +101,15 @@ static void ar9170_led_brightness_set(struct led_classdev *led, | |||
101 | struct ar9170_led *arl = container_of(led, struct ar9170_led, l); | 101 | struct ar9170_led *arl = container_of(led, struct ar9170_led, l); |
102 | struct ar9170 *ar = arl->ar; | 102 | struct ar9170 *ar = arl->ar; |
103 | 103 | ||
104 | arl->toggled++; | 104 | if (unlikely(!arl->registered)) |
105 | return ; | ||
106 | |||
107 | if (arl->last_state != !!brightness) { | ||
108 | arl->toggled++; | ||
109 | arl->last_state = !!brightness; | ||
110 | } | ||
105 | 111 | ||
106 | if (likely(IS_ACCEPTING_CMD(ar) && brightness)) | 112 | if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) |
107 | queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); | 113 | queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); |
108 | } | 114 | } |
109 | 115 | ||
@@ -136,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar) | |||
136 | { | 142 | { |
137 | int i; | 143 | int i; |
138 | 144 | ||
139 | cancel_delayed_work_sync(&ar->led_work); | ||
140 | |||
141 | for (i = 0; i < AR9170_NUM_LEDS; i++) | 145 | for (i = 0; i < AR9170_NUM_LEDS; i++) |
142 | if (ar->leds[i].registered) { | 146 | if (ar->leds[i].registered) { |
143 | led_classdev_unregister(&ar->leds[i].l); | 147 | led_classdev_unregister(&ar->leds[i].l); |
144 | ar->leds[i].registered = false; | 148 | ar->leds[i].registered = false; |
149 | ar->leds[i].toggled = 0; | ||
145 | } | 150 | } |
151 | |||
152 | cancel_delayed_work_sync(&ar->led_work); | ||
146 | } | 153 | } |
147 | 154 | ||
148 | int ar9170_register_leds(struct ar9170 *ar) | 155 | int ar9170_register_leds(struct ar9170 *ar) |
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 43aeb69685d3..d9f1f46de183 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c | |||
@@ -38,6 +38,55 @@ | |||
38 | #include "ar9170.h" | 38 | #include "ar9170.h" |
39 | #include "cmd.h" | 39 | #include "cmd.h" |
40 | 40 | ||
41 | int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) | ||
42 | { | ||
43 | u32 val; | ||
44 | |||
45 | if (conf_is_ht40(&ar->hw->conf)) | ||
46 | val = 0x010a; | ||
47 | else { | ||
48 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
49 | val = 0x105; | ||
50 | else | ||
51 | val = 0x104; | ||
52 | } | ||
53 | |||
54 | return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); | ||
55 | } | ||
56 | |||
57 | int ar9170_set_slot_time(struct ar9170 *ar) | ||
58 | { | ||
59 | u32 slottime = 20; | ||
60 | |||
61 | if (!ar->vif) | ||
62 | return 0; | ||
63 | |||
64 | if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || | ||
65 | ar->vif->bss_conf.use_short_slot) | ||
66 | slottime = 9; | ||
67 | |||
68 | return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); | ||
69 | } | ||
70 | |||
71 | int ar9170_set_basic_rates(struct ar9170 *ar) | ||
72 | { | ||
73 | u8 cck, ofdm; | ||
74 | |||
75 | if (!ar->vif) | ||
76 | return 0; | ||
77 | |||
78 | ofdm = ar->vif->bss_conf.basic_rates >> 4; | ||
79 | |||
80 | /* FIXME: is still necessary? */ | ||
81 | if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) | ||
82 | cck = 0; | ||
83 | else | ||
84 | cck = ar->vif->bss_conf.basic_rates & 0xf; | ||
85 | |||
86 | return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, | ||
87 | ofdm << 8 | cck); | ||
88 | } | ||
89 | |||
41 | int ar9170_set_qos(struct ar9170 *ar) | 90 | int ar9170_set_qos(struct ar9170 *ar) |
42 | { | 91 | { |
43 | ar9170_regwrite_begin(ar); | 92 | ar9170_regwrite_begin(ar); |
@@ -84,7 +133,7 @@ static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) | |||
84 | val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); | 133 | val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); |
85 | 134 | ||
86 | ar9170_regwrite_begin(ar); | 135 | ar9170_regwrite_begin(ar); |
87 | ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val); | 136 | ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); |
88 | ar9170_regwrite_finish(); | 137 | ar9170_regwrite_finish(); |
89 | 138 | ||
90 | return ar9170_regwrite_result(); | 139 | return ar9170_regwrite_result(); |
@@ -398,10 +447,10 @@ int ar9170_update_beacon(struct ar9170 *ar) | |||
398 | /* XXX: use skb->cb info */ | 447 | /* XXX: use skb->cb info */ |
399 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) | 448 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) |
400 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, | 449 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, |
401 | ((skb->len + 4) << (3+16)) + 0x0400); | 450 | ((skb->len + 4) << (3 + 16)) + 0x0400); |
402 | else | 451 | else |
403 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, | 452 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, |
404 | ((skb->len + 4) << (3+16)) + 0x0400); | 453 | ((skb->len + 4) << 16) + 0x001b); |
405 | 454 | ||
406 | ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); | 455 | ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); |
407 | ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); | 456 | ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); |
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 99df9ddae9cb..b104d7efd676 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c | |||
@@ -146,7 +146,6 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { | |||
146 | { \ | 146 | { \ |
147 | .ht_supported = true, \ | 147 | .ht_supported = true, \ |
148 | .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ | 148 | .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ |
149 | IEEE80211_HT_CAP_SM_PS | \ | ||
150 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ | 149 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ |
151 | IEEE80211_HT_CAP_SGI_40 | \ | 150 | IEEE80211_HT_CAP_SGI_40 | \ |
152 | IEEE80211_HT_CAP_DSSSCCK40 | \ | 151 | IEEE80211_HT_CAP_DSSSCCK40 | \ |
@@ -344,7 +343,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work) | |||
344 | if (unlikely(!IS_STARTED(ar))) | 343 | if (unlikely(!IS_STARTED(ar))) |
345 | return ; | 344 | return ; |
346 | 345 | ||
347 | mutex_lock(&ar->mutex); | ||
348 | /* recycle the garbage back to mac80211... one by one. */ | 346 | /* recycle the garbage back to mac80211... one by one. */ |
349 | while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { | 347 | while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { |
350 | #ifdef AR9170_QUEUE_DEBUG | 348 | #ifdef AR9170_QUEUE_DEBUG |
@@ -370,12 +368,9 @@ static void ar9170_tx_status_janitor(struct work_struct *work) | |||
370 | if (skb_queue_len(&ar->global_tx_status_waste) > 0) | 368 | if (skb_queue_len(&ar->global_tx_status_waste) > 0) |
371 | queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, | 369 | queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, |
372 | msecs_to_jiffies(100)); | 370 | msecs_to_jiffies(100)); |
373 | |||
374 | mutex_unlock(&ar->mutex); | ||
375 | } | 371 | } |
376 | 372 | ||
377 | static void ar9170_handle_command_response(struct ar9170 *ar, | 373 | void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) |
378 | void *buf, u32 len) | ||
379 | { | 374 | { |
380 | struct ar9170_cmd_response *cmd = (void *) buf; | 375 | struct ar9170_cmd_response *cmd = (void *) buf; |
381 | 376 | ||
@@ -957,6 +952,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) | |||
957 | 952 | ||
958 | mutex_lock(&ar->mutex); | 953 | mutex_lock(&ar->mutex); |
959 | 954 | ||
955 | ar->filter_changed = 0; | ||
956 | |||
960 | /* reinitialize queues statistics */ | 957 | /* reinitialize queues statistics */ |
961 | memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); | 958 | memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); |
962 | for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) | 959 | for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) |
@@ -1012,10 +1009,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) | |||
1012 | 1009 | ||
1013 | flush_workqueue(ar->hw->workqueue); | 1010 | flush_workqueue(ar->hw->workqueue); |
1014 | 1011 | ||
1015 | mutex_lock(&ar->mutex); | ||
1016 | cancel_delayed_work_sync(&ar->tx_status_janitor); | 1012 | cancel_delayed_work_sync(&ar->tx_status_janitor); |
1017 | cancel_work_sync(&ar->filter_config_work); | 1013 | cancel_work_sync(&ar->filter_config_work); |
1018 | cancel_work_sync(&ar->beacon_work); | 1014 | cancel_work_sync(&ar->beacon_work); |
1015 | mutex_lock(&ar->mutex); | ||
1019 | skb_queue_purge(&ar->global_tx_status_waste); | 1016 | skb_queue_purge(&ar->global_tx_status_waste); |
1020 | skb_queue_purge(&ar->global_tx_status); | 1017 | skb_queue_purge(&ar->global_tx_status); |
1021 | 1018 | ||
@@ -1306,11 +1303,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1306 | 1303 | ||
1307 | mutex_lock(&ar->mutex); | 1304 | mutex_lock(&ar->mutex); |
1308 | 1305 | ||
1309 | if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { | ||
1310 | /* TODO */ | ||
1311 | err = 0; | ||
1312 | } | ||
1313 | |||
1314 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { | 1306 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { |
1315 | /* TODO */ | 1307 | /* TODO */ |
1316 | err = 0; | 1308 | err = 0; |
@@ -1344,15 +1336,21 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1344 | } | 1336 | } |
1345 | 1337 | ||
1346 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 1338 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
1339 | |||
1340 | /* adjust slot time for 5 GHz */ | ||
1341 | err = ar9170_set_slot_time(ar); | ||
1342 | if (err) | ||
1343 | goto out; | ||
1344 | |||
1345 | err = ar9170_set_dyn_sifs_ack(ar); | ||
1346 | if (err) | ||
1347 | goto out; | ||
1348 | |||
1347 | err = ar9170_set_channel(ar, hw->conf.channel, | 1349 | err = ar9170_set_channel(ar, hw->conf.channel, |
1348 | AR9170_RFI_NONE, | 1350 | AR9170_RFI_NONE, |
1349 | nl80211_to_ar9170(hw->conf.channel_type)); | 1351 | nl80211_to_ar9170(hw->conf.channel_type)); |
1350 | if (err) | 1352 | if (err) |
1351 | goto out; | 1353 | goto out; |
1352 | /* adjust slot time for 5 GHz */ | ||
1353 | if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) | ||
1354 | err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, | ||
1355 | 9 << 10); | ||
1356 | } | 1354 | } |
1357 | 1355 | ||
1358 | out: | 1356 | out: |
@@ -1370,20 +1368,26 @@ static void ar9170_set_filters(struct work_struct *work) | |||
1370 | return ; | 1368 | return ; |
1371 | 1369 | ||
1372 | mutex_lock(&ar->mutex); | 1370 | mutex_lock(&ar->mutex); |
1373 | if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { | 1371 | if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, |
1372 | &ar->filter_changed)) { | ||
1374 | err = ar9170_set_operating_mode(ar); | 1373 | err = ar9170_set_operating_mode(ar); |
1375 | if (err) | 1374 | if (err) |
1376 | goto unlock; | 1375 | goto unlock; |
1377 | } | 1376 | } |
1378 | 1377 | ||
1379 | if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { | 1378 | if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, |
1379 | &ar->filter_changed)) { | ||
1380 | err = ar9170_update_multicast(ar); | 1380 | err = ar9170_update_multicast(ar); |
1381 | if (err) | 1381 | if (err) |
1382 | goto unlock; | 1382 | goto unlock; |
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) | 1385 | if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, |
1386 | &ar->filter_changed)) { | ||
1386 | err = ar9170_update_frame_filter(ar); | 1387 | err = ar9170_update_frame_filter(ar); |
1388 | if (err) | ||
1389 | goto unlock; | ||
1390 | } | ||
1387 | 1391 | ||
1388 | unlock: | 1392 | unlock: |
1389 | mutex_unlock(&ar->mutex); | 1393 | mutex_unlock(&ar->mutex); |
@@ -1413,7 +1417,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | |||
1413 | int i; | 1417 | int i; |
1414 | 1418 | ||
1415 | /* always get broadcast frames */ | 1419 | /* always get broadcast frames */ |
1416 | mchash = 1ULL << (0xff>>2); | 1420 | mchash = 1ULL << (0xff >> 2); |
1417 | 1421 | ||
1418 | for (i = 0; i < mc_count; i++) { | 1422 | for (i = 0; i < mc_count; i++) { |
1419 | if (WARN_ON(!mclist)) | 1423 | if (WARN_ON(!mclist)) |
@@ -1423,7 +1427,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | |||
1423 | } | 1427 | } |
1424 | ar->want_mc_hash = mchash; | 1428 | ar->want_mc_hash = mchash; |
1425 | } | 1429 | } |
1426 | ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; | 1430 | set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); |
1427 | } | 1431 | } |
1428 | 1432 | ||
1429 | if (changed_flags & FIF_CONTROL) { | 1433 | if (changed_flags & FIF_CONTROL) { |
@@ -1439,12 +1443,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | |||
1439 | else | 1443 | else |
1440 | ar->want_filter = ar->cur_filter & ~filter; | 1444 | ar->want_filter = ar->cur_filter & ~filter; |
1441 | 1445 | ||
1442 | ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; | 1446 | set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, |
1447 | &ar->filter_changed); | ||
1443 | } | 1448 | } |
1444 | 1449 | ||
1445 | if (changed_flags & FIF_PROMISC_IN_BSS) { | 1450 | if (changed_flags & FIF_PROMISC_IN_BSS) { |
1446 | ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; | 1451 | ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; |
1447 | ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; | 1452 | set_bit(AR9170_FILTER_CHANGED_MODE, |
1453 | &ar->filter_changed); | ||
1448 | } | 1454 | } |
1449 | 1455 | ||
1450 | if (likely(IS_STARTED(ar))) | 1456 | if (likely(IS_STARTED(ar))) |
@@ -1464,27 +1470,32 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1464 | if (changed & BSS_CHANGED_BSSID) { | 1470 | if (changed & BSS_CHANGED_BSSID) { |
1465 | memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); | 1471 | memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); |
1466 | err = ar9170_set_operating_mode(ar); | 1472 | err = ar9170_set_operating_mode(ar); |
1473 | if (err) | ||
1474 | goto out; | ||
1467 | } | 1475 | } |
1468 | 1476 | ||
1469 | if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { | 1477 | if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { |
1470 | err = ar9170_update_beacon(ar); | 1478 | err = ar9170_update_beacon(ar); |
1471 | if (!err) | 1479 | if (err) |
1472 | ar9170_set_beacon_timers(ar); | 1480 | goto out; |
1473 | } | ||
1474 | 1481 | ||
1475 | ar9170_regwrite_begin(ar); | 1482 | err = ar9170_set_beacon_timers(ar); |
1483 | if (err) | ||
1484 | goto out; | ||
1485 | } | ||
1476 | 1486 | ||
1477 | if (changed & BSS_CHANGED_ASSOC) { | 1487 | if (changed & BSS_CHANGED_ASSOC) { |
1478 | ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; | ||
1479 | |||
1480 | #ifndef CONFIG_AR9170_LEDS | 1488 | #ifndef CONFIG_AR9170_LEDS |
1481 | /* enable assoc LED. */ | 1489 | /* enable assoc LED. */ |
1482 | err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); | 1490 | err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); |
1483 | #endif /* CONFIG_AR9170_LEDS */ | 1491 | #endif /* CONFIG_AR9170_LEDS */ |
1484 | } | 1492 | } |
1485 | 1493 | ||
1486 | if (changed & BSS_CHANGED_BEACON_INT) | 1494 | if (changed & BSS_CHANGED_BEACON_INT) { |
1487 | err = ar9170_set_beacon_timers(ar); | 1495 | err = ar9170_set_beacon_timers(ar); |
1496 | if (err) | ||
1497 | goto out; | ||
1498 | } | ||
1488 | 1499 | ||
1489 | if (changed & BSS_CHANGED_HT) { | 1500 | if (changed & BSS_CHANGED_HT) { |
1490 | /* TODO */ | 1501 | /* TODO */ |
@@ -1492,31 +1503,18 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1492 | } | 1503 | } |
1493 | 1504 | ||
1494 | if (changed & BSS_CHANGED_ERP_SLOT) { | 1505 | if (changed & BSS_CHANGED_ERP_SLOT) { |
1495 | u32 slottime = 20; | 1506 | err = ar9170_set_slot_time(ar); |
1496 | 1507 | if (err) | |
1497 | if (bss_conf->use_short_slot) | 1508 | goto out; |
1498 | slottime = 9; | ||
1499 | |||
1500 | ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); | ||
1501 | } | 1509 | } |
1502 | 1510 | ||
1503 | if (changed & BSS_CHANGED_BASIC_RATES) { | 1511 | if (changed & BSS_CHANGED_BASIC_RATES) { |
1504 | u32 cck, ofdm; | 1512 | err = ar9170_set_basic_rates(ar); |
1505 | 1513 | if (err) | |
1506 | if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { | 1514 | goto out; |
1507 | ofdm = bss_conf->basic_rates; | ||
1508 | cck = 0; | ||
1509 | } else { | ||
1510 | /* four cck rates */ | ||
1511 | cck = bss_conf->basic_rates & 0xf; | ||
1512 | ofdm = bss_conf->basic_rates >> 4; | ||
1513 | } | ||
1514 | ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, | ||
1515 | ofdm << 8 | cck); | ||
1516 | } | 1515 | } |
1517 | 1516 | ||
1518 | ar9170_regwrite_finish(); | 1517 | out: |
1519 | err = ar9170_regwrite_result(); | ||
1520 | mutex_unlock(&ar->mutex); | 1518 | mutex_unlock(&ar->mutex); |
1521 | } | 1519 | } |
1522 | 1520 | ||
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 6ce20754b8e7..df86f70cd817 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c | |||
@@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) | |||
401 | int i, err; | 401 | int i, err; |
402 | u32 val; | 402 | u32 val; |
403 | bool is_2ghz = band == IEEE80211_BAND_2GHZ; | 403 | bool is_2ghz = band == IEEE80211_BAND_2GHZ; |
404 | bool is_40mhz = false; /* XXX: for now */ | 404 | bool is_40mhz = conf_is_ht40(&ar->hw->conf); |
405 | 405 | ||
406 | ar9170_regwrite_begin(ar); | 406 | ar9170_regwrite_begin(ar); |
407 | 407 | ||
@@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | |||
1200 | return -ENOSYS; | 1200 | return -ENOSYS; |
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | if (0 /* 2 streams capable */) | 1203 | if (ar->eeprom.tx_mask != 1) |
1204 | tmp |= 0x100; | 1204 | tmp |= 0x100; |
1205 | 1205 | ||
1206 | err = ar9170_write_reg(ar, 0x1c5804, tmp); | 1206 | err = ar9170_write_reg(ar, 0x1c5804, tmp); |
@@ -1214,7 +1214,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | |||
1214 | freqpar = ar9170_get_hw_dyn_params(channel, bw); | 1214 | freqpar = ar9170_get_hw_dyn_params(channel, bw); |
1215 | 1215 | ||
1216 | vals[0] = cpu_to_le32(channel->center_freq * 1000); | 1216 | vals[0] = cpu_to_le32(channel->center_freq * 1000); |
1217 | vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); | 1217 | vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); |
1218 | vals[2] = cpu_to_le32(offs << 2 | 1); | 1218 | vals[2] = cpu_to_le32(offs << 2 | 1); |
1219 | vals[3] = cpu_to_le32(freqpar->coeff_exp); | 1219 | vals[3] = cpu_to_le32(freqpar->coeff_exp); |
1220 | vals[4] = cpu_to_le32(freqpar->coeff_man); | 1220 | vals[4] = cpu_to_le32(freqpar->coeff_man); |
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index d7c13c0177ca..f752698669d2 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c | |||
@@ -51,9 +51,14 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | |||
51 | MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); | 51 | MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); |
52 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
53 | MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); | 53 | MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); |
54 | MODULE_FIRMWARE("ar9170.fw"); | ||
54 | MODULE_FIRMWARE("ar9170-1.fw"); | 55 | MODULE_FIRMWARE("ar9170-1.fw"); |
55 | MODULE_FIRMWARE("ar9170-2.fw"); | 56 | MODULE_FIRMWARE("ar9170-2.fw"); |
56 | 57 | ||
58 | enum ar9170_requirements { | ||
59 | AR9170_REQ_FW1_ONLY = 1, | ||
60 | }; | ||
61 | |||
57 | static struct usb_device_id ar9170_usb_ids[] = { | 62 | static struct usb_device_id ar9170_usb_ids[] = { |
58 | /* Atheros 9170 */ | 63 | /* Atheros 9170 */ |
59 | { USB_DEVICE(0x0cf3, 0x9170) }, | 64 | { USB_DEVICE(0x0cf3, 0x9170) }, |
@@ -81,6 +86,10 @@ static struct usb_device_id ar9170_usb_ids[] = { | |||
81 | { USB_DEVICE(0x2019, 0x5304) }, | 86 | { USB_DEVICE(0x2019, 0x5304) }, |
82 | /* IO-Data WNGDNUS2 */ | 87 | /* IO-Data WNGDNUS2 */ |
83 | { USB_DEVICE(0x04bb, 0x093f) }, | 88 | { USB_DEVICE(0x04bb, 0x093f) }, |
89 | /* AVM FRITZ!WLAN USB Stick N */ | ||
90 | { USB_DEVICE(0x057C, 0x8401) }, | ||
91 | /* AVM FRITZ!WLAN USB Stick N 2.4 */ | ||
92 | { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, | ||
84 | 93 | ||
85 | /* terminate */ | 94 | /* terminate */ |
86 | {} | 95 | {} |
@@ -93,7 +102,7 @@ static void ar9170_usb_tx_urb_complete_free(struct urb *urb) | |||
93 | struct ar9170_usb *aru = (struct ar9170_usb *) | 102 | struct ar9170_usb *aru = (struct ar9170_usb *) |
94 | usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | 103 | usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); |
95 | 104 | ||
96 | if (!aru) { | 105 | if (unlikely(!aru)) { |
97 | dev_kfree_skb_irq(skb); | 106 | dev_kfree_skb_irq(skb); |
98 | return ; | 107 | return ; |
99 | } | 108 | } |
@@ -126,8 +135,8 @@ static void ar9170_usb_irq_completed(struct urb *urb) | |||
126 | goto resubmit; | 135 | goto resubmit; |
127 | } | 136 | } |
128 | 137 | ||
129 | print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, | 138 | ar9170_handle_command_response(&aru->common, urb->transfer_buffer, |
130 | urb->transfer_buffer, urb->actual_length); | 139 | urb->actual_length); |
131 | 140 | ||
132 | resubmit: | 141 | resubmit: |
133 | usb_anchor_urb(urb, &aru->rx_submitted); | 142 | usb_anchor_urb(urb, &aru->rx_submitted); |
@@ -177,16 +186,15 @@ resubmit: | |||
177 | 186 | ||
178 | usb_anchor_urb(urb, &aru->rx_submitted); | 187 | usb_anchor_urb(urb, &aru->rx_submitted); |
179 | err = usb_submit_urb(urb, GFP_ATOMIC); | 188 | err = usb_submit_urb(urb, GFP_ATOMIC); |
180 | if (err) { | 189 | if (unlikely(err)) { |
181 | usb_unanchor_urb(urb); | 190 | usb_unanchor_urb(urb); |
182 | dev_kfree_skb_irq(skb); | 191 | goto free; |
183 | } | 192 | } |
184 | 193 | ||
185 | return ; | 194 | return ; |
186 | 195 | ||
187 | free: | 196 | free: |
188 | dev_kfree_skb_irq(skb); | 197 | dev_kfree_skb_irq(skb); |
189 | return; | ||
190 | } | 198 | } |
191 | 199 | ||
192 | static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, | 200 | static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, |
@@ -337,7 +345,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, | |||
337 | 345 | ||
338 | usb_anchor_urb(urb, &aru->tx_submitted); | 346 | usb_anchor_urb(urb, &aru->tx_submitted); |
339 | err = usb_submit_urb(urb, GFP_ATOMIC); | 347 | err = usb_submit_urb(urb, GFP_ATOMIC); |
340 | if (err) { | 348 | if (unlikely(err)) { |
341 | usb_unanchor_urb(urb); | 349 | usb_unanchor_urb(urb); |
342 | usb_free_urb(urb); | 350 | usb_free_urb(urb); |
343 | goto err_unbuf; | 351 | goto err_unbuf; |
@@ -418,7 +426,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) | |||
418 | unsigned long flags; | 426 | unsigned long flags; |
419 | u32 in, out; | 427 | u32 in, out; |
420 | 428 | ||
421 | if (!buffer) | 429 | if (unlikely(!buffer)) |
422 | return ; | 430 | return ; |
423 | 431 | ||
424 | in = le32_to_cpup((__le32 *)buffer); | 432 | in = le32_to_cpup((__le32 *)buffer); |
@@ -504,17 +512,29 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru) | |||
504 | { | 512 | { |
505 | int err = 0; | 513 | int err = 0; |
506 | 514 | ||
507 | err = request_firmware(&aru->init_values, "ar9170-1.fw", | 515 | err = request_firmware(&aru->firmware, "ar9170.fw", |
508 | &aru->udev->dev); | 516 | &aru->udev->dev); |
509 | if (err) { | 517 | if (!err) { |
510 | dev_err(&aru->udev->dev, "file with init values not found.\n"); | 518 | aru->init_values = NULL; |
511 | return err; | 519 | return 0; |
512 | } | 520 | } |
513 | 521 | ||
522 | if (aru->req_one_stage_fw) { | ||
523 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
524 | "not found and is required for this device\n"); | ||
525 | return -EINVAL; | ||
526 | } | ||
527 | |||
528 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
529 | "not found, trying old firmware...\n"); | ||
530 | |||
531 | err = request_firmware(&aru->init_values, "ar9170-1.fw", | ||
532 | &aru->udev->dev); | ||
533 | |||
514 | err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); | 534 | err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); |
515 | if (err) { | 535 | if (err) { |
516 | release_firmware(aru->init_values); | 536 | release_firmware(aru->init_values); |
517 | dev_err(&aru->udev->dev, "firmware file not found.\n"); | 537 | dev_err(&aru->udev->dev, "file with init values not found.\n"); |
518 | return err; | 538 | return err; |
519 | } | 539 | } |
520 | 540 | ||
@@ -548,6 +568,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) | |||
548 | { | 568 | { |
549 | int err; | 569 | int err; |
550 | 570 | ||
571 | if (!aru->init_values) | ||
572 | goto upload_fw_start; | ||
573 | |||
551 | /* First, upload initial values to device RAM */ | 574 | /* First, upload initial values to device RAM */ |
552 | err = ar9170_usb_upload(aru, aru->init_values->data, | 575 | err = ar9170_usb_upload(aru, aru->init_values->data, |
553 | aru->init_values->size, 0x102800, false); | 576 | aru->init_values->size, 0x102800, false); |
@@ -557,6 +580,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) | |||
557 | return err; | 580 | return err; |
558 | } | 581 | } |
559 | 582 | ||
583 | upload_fw_start: | ||
584 | |||
560 | /* Then, upload the firmware itself and start it */ | 585 | /* Then, upload the firmware itself and start it */ |
561 | return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, | 586 | return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, |
562 | 0x200000, true); | 587 | 0x200000, true); |
@@ -656,6 +681,15 @@ err_out: | |||
656 | return err; | 681 | return err; |
657 | } | 682 | } |
658 | 683 | ||
684 | static bool ar9170_requires_one_stage(const struct usb_device_id *id) | ||
685 | { | ||
686 | if (!id->driver_info) | ||
687 | return false; | ||
688 | if (id->driver_info == AR9170_REQ_FW1_ONLY) | ||
689 | return true; | ||
690 | return false; | ||
691 | } | ||
692 | |||
659 | static int ar9170_usb_probe(struct usb_interface *intf, | 693 | static int ar9170_usb_probe(struct usb_interface *intf, |
660 | const struct usb_device_id *id) | 694 | const struct usb_device_id *id) |
661 | { | 695 | { |
@@ -676,6 +710,8 @@ static int ar9170_usb_probe(struct usb_interface *intf, | |||
676 | aru->intf = intf; | 710 | aru->intf = intf; |
677 | ar = &aru->common; | 711 | ar = &aru->common; |
678 | 712 | ||
713 | aru->req_one_stage_fw = ar9170_requires_one_stage(id); | ||
714 | |||
679 | usb_set_intfdata(intf, aru); | 715 | usb_set_intfdata(intf, aru); |
680 | SET_IEEE80211_DEV(ar->hw, &udev->dev); | 716 | SET_IEEE80211_DEV(ar->hw, &udev->dev); |
681 | 717 | ||
@@ -691,7 +727,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, | |||
691 | 727 | ||
692 | #ifdef CONFIG_PM | 728 | #ifdef CONFIG_PM |
693 | udev->reset_resume = 1; | 729 | udev->reset_resume = 1; |
694 | #endif | 730 | #endif /* CONFIG_PM */ |
695 | err = ar9170_usb_reset(aru); | 731 | err = ar9170_usb_reset(aru); |
696 | if (err) | 732 | if (err) |
697 | goto err_freehw; | 733 | goto err_freehw; |
@@ -776,11 +812,6 @@ static int ar9170_resume(struct usb_interface *intf) | |||
776 | usb_unpoison_anchored_urbs(&aru->rx_submitted); | 812 | usb_unpoison_anchored_urbs(&aru->rx_submitted); |
777 | usb_unpoison_anchored_urbs(&aru->tx_submitted); | 813 | usb_unpoison_anchored_urbs(&aru->tx_submitted); |
778 | 814 | ||
779 | /* | ||
780 | * FIXME: firmware upload will fail on resume. | ||
781 | * but this is better than a hang! | ||
782 | */ | ||
783 | |||
784 | err = ar9170_usb_init_device(aru); | 815 | err = ar9170_usb_init_device(aru); |
785 | if (err) | 816 | if (err) |
786 | goto err_unrx; | 817 | goto err_unrx; |
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index ac42586495d8..69f4bceb0af3 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h | |||
@@ -62,6 +62,8 @@ struct ar9170_usb { | |||
62 | struct usb_anchor rx_submitted; | 62 | struct usb_anchor rx_submitted; |
63 | struct usb_anchor tx_submitted; | 63 | struct usb_anchor tx_submitted; |
64 | 64 | ||
65 | bool req_one_stage_fw; | ||
66 | |||
65 | spinlock_t cmdlock; | 67 | spinlock_t cmdlock; |
66 | struct completion cmd_wait; | 68 | struct completion cmd_wait; |
67 | int readlen; | 69 | int readlen; |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index fb5193764afa..85a00db4867d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -2070,6 +2070,13 @@ err_unmap: | |||
2070 | return ret; | 2070 | return ret; |
2071 | } | 2071 | } |
2072 | 2072 | ||
2073 | static void ath5k_beacon_disable(struct ath5k_softc *sc) | ||
2074 | { | ||
2075 | sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); | ||
2076 | ath5k_hw_set_imr(sc->ah, sc->imask); | ||
2077 | ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); | ||
2078 | } | ||
2079 | |||
2073 | /* | 2080 | /* |
2074 | * Transmit a beacon frame at SWBA. Dynamic updates to the | 2081 | * Transmit a beacon frame at SWBA. Dynamic updates to the |
2075 | * frame contents are done as needed and the slot time is | 2082 | * frame contents are done as needed and the slot time is |
@@ -2757,6 +2764,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, | |||
2757 | goto end; | 2764 | goto end; |
2758 | 2765 | ||
2759 | ath5k_hw_set_lladdr(sc->ah, mac); | 2766 | ath5k_hw_set_lladdr(sc->ah, mac); |
2767 | ath5k_beacon_disable(sc); | ||
2760 | sc->vif = NULL; | 2768 | sc->vif = NULL; |
2761 | end: | 2769 | end: |
2762 | mutex_unlock(&sc->lock); | 2770 | mutex_unlock(&sc->lock); |
@@ -2775,11 +2783,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) | |||
2775 | 2783 | ||
2776 | mutex_lock(&sc->lock); | 2784 | mutex_lock(&sc->lock); |
2777 | 2785 | ||
2778 | sc->bintval = conf->beacon_int; | ||
2779 | |||
2780 | ret = ath5k_chan_set(sc, conf->channel); | 2786 | ret = ath5k_chan_set(sc, conf->channel); |
2781 | if (ret < 0) | 2787 | if (ret < 0) |
2782 | return ret; | 2788 | goto unlock; |
2783 | 2789 | ||
2784 | if ((changed & IEEE80211_CONF_CHANGE_POWER) && | 2790 | if ((changed & IEEE80211_CONF_CHANGE_POWER) && |
2785 | (sc->power_level != conf->power_level)) { | 2791 | (sc->power_level != conf->power_level)) { |
@@ -2808,8 +2814,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) | |||
2808 | */ | 2814 | */ |
2809 | ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); | 2815 | ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); |
2810 | 2816 | ||
2817 | unlock: | ||
2811 | mutex_unlock(&sc->lock); | 2818 | mutex_unlock(&sc->lock); |
2812 | return 0; | 2819 | return ret; |
2813 | } | 2820 | } |
2814 | 2821 | ||
2815 | #define SUPPORTED_FIF_FLAGS \ | 2822 | #define SUPPORTED_FIF_FLAGS \ |
@@ -3061,7 +3068,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
3061 | { | 3068 | { |
3062 | int ret; | 3069 | int ret; |
3063 | struct ath5k_softc *sc = hw->priv; | 3070 | struct ath5k_softc *sc = hw->priv; |
3064 | struct sk_buff *skb = ieee80211_beacon_get(hw, vif); | 3071 | struct sk_buff *skb; |
3072 | |||
3073 | if (WARN_ON(!vif)) { | ||
3074 | ret = -EINVAL; | ||
3075 | goto out; | ||
3076 | } | ||
3077 | |||
3078 | skb = ieee80211_beacon_get(hw, vif); | ||
3065 | 3079 | ||
3066 | if (!skb) { | 3080 | if (!skb) { |
3067 | ret = -ENOMEM; | 3081 | ret = -ENOMEM; |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 796a3adffea0..515880aa2116 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -460,12 +460,9 @@ struct ath_led { | |||
460 | bool registered; | 460 | bool registered; |
461 | }; | 461 | }; |
462 | 462 | ||
463 | /* Rfkill */ | ||
464 | #define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ | ||
465 | |||
466 | struct ath_rfkill { | 463 | struct ath_rfkill { |
467 | struct rfkill *rfkill; | 464 | struct rfkill *rfkill; |
468 | struct delayed_work rfkill_poll; | 465 | struct rfkill_ops ops; |
469 | char rfkill_name[32]; | 466 | char rfkill_name[32]; |
470 | }; | 467 | }; |
471 | 468 | ||
@@ -509,8 +506,6 @@ struct ath_rfkill { | |||
509 | #define SC_OP_RXFLUSH BIT(7) | 506 | #define SC_OP_RXFLUSH BIT(7) |
510 | #define SC_OP_LED_ASSOCIATED BIT(8) | 507 | #define SC_OP_LED_ASSOCIATED BIT(8) |
511 | #define SC_OP_RFKILL_REGISTERED BIT(9) | 508 | #define SC_OP_RFKILL_REGISTERED BIT(9) |
512 | #define SC_OP_RFKILL_SW_BLOCKED BIT(10) | ||
513 | #define SC_OP_RFKILL_HW_BLOCKED BIT(11) | ||
514 | #define SC_OP_WAIT_FOR_BEACON BIT(12) | 509 | #define SC_OP_WAIT_FOR_BEACON BIT(12) |
515 | #define SC_OP_LED_ON BIT(13) | 510 | #define SC_OP_LED_ON BIT(13) |
516 | #define SC_OP_SCANNING BIT(14) | 511 | #define SC_OP_SCANNING BIT(14) |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a21b21339fbc..3639a2e6987d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -411,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
411 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { | 411 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { |
412 | DPRINTF(sc, ATH_DBG_BEACON, | 412 | DPRINTF(sc, ATH_DBG_BEACON, |
413 | "beacon is officially stuck\n"); | 413 | "beacon is officially stuck\n"); |
414 | sc->sc_flags |= SC_OP_TSF_RESET; | ||
414 | ath_reset(sc, false); | 415 | ath_reset(sc, false); |
415 | } | 416 | } |
416 | 417 | ||
@@ -673,6 +674,14 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
673 | 674 | ||
674 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 675 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; |
675 | 676 | ||
677 | /* | ||
678 | * It looks like mac80211 may end up using beacon interval of zero in | ||
679 | * some cases (at least for mesh point). Avoid getting into an | ||
680 | * infinite loop by using a bit safer value instead.. | ||
681 | */ | ||
682 | if (intval == 0) | ||
683 | intval = 100; | ||
684 | |||
676 | /* Pull nexttbtt forward to reflect the current TSF */ | 685 | /* Pull nexttbtt forward to reflect the current TSF */ |
677 | 686 | ||
678 | nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); | 687 | nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 97df20cbf528..6d20725d6451 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -44,6 +44,44 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) | |||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | static ssize_t read_file_debug(struct file *file, char __user *user_buf, | ||
48 | size_t count, loff_t *ppos) | ||
49 | { | ||
50 | struct ath_softc *sc = file->private_data; | ||
51 | char buf[32]; | ||
52 | unsigned int len; | ||
53 | |||
54 | len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); | ||
55 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
56 | } | ||
57 | |||
58 | static ssize_t write_file_debug(struct file *file, const char __user *user_buf, | ||
59 | size_t count, loff_t *ppos) | ||
60 | { | ||
61 | struct ath_softc *sc = file->private_data; | ||
62 | unsigned long mask; | ||
63 | char buf[32]; | ||
64 | ssize_t len; | ||
65 | |||
66 | len = min(count, sizeof(buf) - 1); | ||
67 | if (copy_from_user(buf, user_buf, len)) | ||
68 | return -EINVAL; | ||
69 | |||
70 | buf[len] = '\0'; | ||
71 | if (strict_strtoul(buf, 0, &mask)) | ||
72 | return -EINVAL; | ||
73 | |||
74 | sc->debug.debug_mask = mask; | ||
75 | return count; | ||
76 | } | ||
77 | |||
78 | static const struct file_operations fops_debug = { | ||
79 | .read = read_file_debug, | ||
80 | .write = write_file_debug, | ||
81 | .open = ath9k_debugfs_open, | ||
82 | .owner = THIS_MODULE | ||
83 | }; | ||
84 | |||
47 | static ssize_t read_file_dma(struct file *file, char __user *user_buf, | 85 | static ssize_t read_file_dma(struct file *file, char __user *user_buf, |
48 | size_t count, loff_t *ppos) | 86 | size_t count, loff_t *ppos) |
49 | { | 87 | { |
@@ -224,111 +262,66 @@ static const struct file_operations fops_interrupt = { | |||
224 | .owner = THIS_MODULE | 262 | .owner = THIS_MODULE |
225 | }; | 263 | }; |
226 | 264 | ||
227 | static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) | 265 | void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) |
228 | { | ||
229 | struct ath_tx_info_priv *tx_info_priv = NULL; | ||
230 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
231 | struct ieee80211_tx_rate *rates = tx_info->status.rates; | ||
232 | int final_ts_idx, idx; | ||
233 | |||
234 | tx_info_priv = ATH_TX_INFO_PRIV(tx_info); | ||
235 | final_ts_idx = tx_info_priv->tx.ts_rateindex; | ||
236 | idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; | ||
237 | |||
238 | sc->debug.stats.n_rcstats[idx].success++; | ||
239 | } | ||
240 | |||
241 | static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) | ||
242 | { | 266 | { |
243 | struct ath_tx_info_priv *tx_info_priv = NULL; | 267 | struct ath_tx_info_priv *tx_info_priv = NULL; |
244 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 268 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
245 | struct ieee80211_tx_rate *rates = tx_info->status.rates; | 269 | struct ieee80211_tx_rate *rates = tx_info->status.rates; |
246 | int final_ts_idx, idx; | 270 | int final_ts_idx, idx; |
271 | struct ath_rc_stats *stats; | ||
247 | 272 | ||
248 | tx_info_priv = ATH_TX_INFO_PRIV(tx_info); | 273 | tx_info_priv = ATH_TX_INFO_PRIV(tx_info); |
249 | final_ts_idx = tx_info_priv->tx.ts_rateindex; | 274 | final_ts_idx = tx_info_priv->tx.ts_rateindex; |
250 | idx = rates[final_ts_idx].idx; | 275 | idx = rates[final_ts_idx].idx; |
251 | 276 | stats = &sc->debug.stats.rcstats[idx]; | |
252 | sc->debug.stats.legacy_rcstats[idx].success++; | 277 | stats->success++; |
253 | } | ||
254 | |||
255 | void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) | ||
256 | { | ||
257 | if (conf_is_ht(&sc->hw->conf)) | ||
258 | ath_debug_stat_11n_rc(sc, skb); | ||
259 | else | ||
260 | ath_debug_stat_legacy_rc(sc, skb); | ||
261 | } | 278 | } |
262 | 279 | ||
263 | /* FIXME: legacy rates, later on .. */ | ||
264 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, | 280 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, |
265 | int xretries, int retries, u8 per) | 281 | int xretries, int retries, u8 per) |
266 | { | 282 | { |
267 | if (conf_is_ht(&sc->hw->conf)) { | 283 | struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; |
268 | int idx = sc->cur_rate_table->info[rix].dot11rate; | ||
269 | 284 | ||
270 | sc->debug.stats.n_rcstats[idx].xretries += xretries; | 285 | stats->xretries += xretries; |
271 | sc->debug.stats.n_rcstats[idx].retries += retries; | 286 | stats->retries += retries; |
272 | sc->debug.stats.n_rcstats[idx].per = per; | 287 | stats->per = per; |
273 | } | ||
274 | } | 288 | } |
275 | 289 | ||
276 | static ssize_t ath_read_file_stat_11n_rc(struct file *file, | 290 | static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, |
277 | char __user *user_buf, | 291 | size_t count, loff_t *ppos) |
278 | size_t count, loff_t *ppos) | ||
279 | { | 292 | { |
280 | struct ath_softc *sc = file->private_data; | 293 | struct ath_softc *sc = file->private_data; |
281 | char buf[1024]; | 294 | char *buf; |
282 | unsigned int len = 0; | 295 | unsigned int len = 0, max; |
283 | int i = 0; | 296 | int i = 0; |
297 | ssize_t retval; | ||
284 | 298 | ||
285 | len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", | 299 | if (sc->cur_rate_table == NULL) |
286 | "Retries", "XRetries", "PER"); | 300 | return 0; |
287 | |||
288 | for (i = 0; i <= 15; i++) { | ||
289 | len += snprintf(buf + len, sizeof(buf) - len, | ||
290 | "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, | ||
291 | sc->debug.stats.n_rcstats[i].success, | ||
292 | sc->debug.stats.n_rcstats[i].retries, | ||
293 | sc->debug.stats.n_rcstats[i].xretries, | ||
294 | sc->debug.stats.n_rcstats[i].per); | ||
295 | } | ||
296 | |||
297 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
298 | } | ||
299 | 301 | ||
300 | static ssize_t ath_read_file_stat_legacy_rc(struct file *file, | 302 | max = 80 + sc->cur_rate_table->rate_cnt * 64; |
301 | char __user *user_buf, | 303 | buf = kmalloc(max + 1, GFP_KERNEL); |
302 | size_t count, loff_t *ppos) | 304 | if (buf == NULL) |
303 | { | 305 | return 0; |
304 | struct ath_softc *sc = file->private_data; | 306 | buf[max] = 0; |
305 | char buf[512]; | ||
306 | unsigned int len = 0; | ||
307 | int i = 0; | ||
308 | 307 | ||
309 | len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); | 308 | len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", |
309 | "Retries", "XRetries", "PER"); | ||
310 | 310 | ||
311 | for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { | 311 | for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { |
312 | len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", | 312 | u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; |
313 | sc->cur_rate_table->info[i].ratekbps / 1000, | 313 | struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; |
314 | sc->debug.stats.legacy_rcstats[i].success); | 314 | |
315 | len += snprintf(buf + len, max - len, | ||
316 | "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, | ||
317 | (ratekbps % 1000) / 100, stats->success, | ||
318 | stats->retries, stats->xretries, | ||
319 | stats->per); | ||
315 | } | 320 | } |
316 | 321 | ||
317 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 322 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); |
318 | } | 323 | kfree(buf); |
319 | 324 | return retval; | |
320 | static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, | ||
321 | size_t count, loff_t *ppos) | ||
322 | { | ||
323 | struct ath_softc *sc = file->private_data; | ||
324 | |||
325 | if (sc->cur_rate_table == NULL) | ||
326 | return 0; | ||
327 | |||
328 | if (conf_is_ht(&sc->hw->conf)) | ||
329 | return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); | ||
330 | else | ||
331 | return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); | ||
332 | } | 325 | } |
333 | 326 | ||
334 | static const struct file_operations fops_rcstat = { | 327 | static const struct file_operations fops_rcstat = { |
@@ -506,6 +499,11 @@ int ath9k_init_debug(struct ath_softc *sc) | |||
506 | if (!sc->debug.debugfs_phy) | 499 | if (!sc->debug.debugfs_phy) |
507 | goto err; | 500 | goto err; |
508 | 501 | ||
502 | sc->debug.debugfs_debug = debugfs_create_file("debug", | ||
503 | S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); | ||
504 | if (!sc->debug.debugfs_debug) | ||
505 | goto err; | ||
506 | |||
509 | sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, | 507 | sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, |
510 | sc->debug.debugfs_phy, sc, &fops_dma); | 508 | sc->debug.debugfs_phy, sc, &fops_dma); |
511 | if (!sc->debug.debugfs_dma) | 509 | if (!sc->debug.debugfs_dma) |
@@ -543,6 +541,7 @@ void ath9k_exit_debug(struct ath_softc *sc) | |||
543 | debugfs_remove(sc->debug.debugfs_rcstat); | 541 | debugfs_remove(sc->debug.debugfs_rcstat); |
544 | debugfs_remove(sc->debug.debugfs_interrupt); | 542 | debugfs_remove(sc->debug.debugfs_interrupt); |
545 | debugfs_remove(sc->debug.debugfs_dma); | 543 | debugfs_remove(sc->debug.debugfs_dma); |
544 | debugfs_remove(sc->debug.debugfs_debug); | ||
546 | debugfs_remove(sc->debug.debugfs_phy); | 545 | debugfs_remove(sc->debug.debugfs_phy); |
547 | } | 546 | } |
548 | 547 | ||
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index db845cf960c9..edda15bf2c15 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h | |||
@@ -80,11 +80,7 @@ struct ath_interrupt_stats { | |||
80 | u32 dtim; | 80 | u32 dtim; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct ath_legacy_rc_stats { | 83 | struct ath_rc_stats { |
84 | u32 success; | ||
85 | }; | ||
86 | |||
87 | struct ath_11n_rc_stats { | ||
88 | u32 success; | 84 | u32 success; |
89 | u32 retries; | 85 | u32 retries; |
90 | u32 xretries; | 86 | u32 xretries; |
@@ -93,13 +89,13 @@ struct ath_11n_rc_stats { | |||
93 | 89 | ||
94 | struct ath_stats { | 90 | struct ath_stats { |
95 | struct ath_interrupt_stats istats; | 91 | struct ath_interrupt_stats istats; |
96 | struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ | 92 | struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; |
97 | struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ | ||
98 | }; | 93 | }; |
99 | 94 | ||
100 | struct ath9k_debug { | 95 | struct ath9k_debug { |
101 | int debug_mask; | 96 | int debug_mask; |
102 | struct dentry *debugfs_phy; | 97 | struct dentry *debugfs_phy; |
98 | struct dentry *debugfs_debug; | ||
103 | struct dentry *debugfs_dma; | 99 | struct dentry *debugfs_dma; |
104 | struct dentry *debugfs_interrupt; | 100 | struct dentry *debugfs_interrupt; |
105 | struct dentry *debugfs_rcstat; | 101 | struct dentry *debugfs_rcstat; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 61da08a1648c..f7baa406918b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) | |||
1192 | ah->rfkill_polarity; | 1192 | ah->rfkill_polarity; |
1193 | } | 1193 | } |
1194 | 1194 | ||
1195 | /* h/w rfkill poll function */ | 1195 | /* s/w rfkill handlers */ |
1196 | static void ath_rfkill_poll(struct work_struct *work) | 1196 | static int ath_rfkill_set_block(void *data, bool blocked) |
1197 | { | 1197 | { |
1198 | struct ath_softc *sc = container_of(work, struct ath_softc, | 1198 | struct ath_softc *sc = data; |
1199 | rf_kill.rfkill_poll.work); | ||
1200 | bool radio_on; | ||
1201 | |||
1202 | if (sc->sc_flags & SC_OP_INVALID) | ||
1203 | return; | ||
1204 | |||
1205 | radio_on = !ath_is_rfkill_set(sc); | ||
1206 | |||
1207 | /* | ||
1208 | * enable/disable radio only when there is a | ||
1209 | * state change in RF switch | ||
1210 | */ | ||
1211 | if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { | ||
1212 | enum rfkill_state state; | ||
1213 | |||
1214 | if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { | ||
1215 | state = radio_on ? RFKILL_STATE_SOFT_BLOCKED | ||
1216 | : RFKILL_STATE_HARD_BLOCKED; | ||
1217 | } else if (radio_on) { | ||
1218 | ath_radio_enable(sc); | ||
1219 | state = RFKILL_STATE_UNBLOCKED; | ||
1220 | } else { | ||
1221 | ath_radio_disable(sc); | ||
1222 | state = RFKILL_STATE_HARD_BLOCKED; | ||
1223 | } | ||
1224 | |||
1225 | if (state == RFKILL_STATE_HARD_BLOCKED) | ||
1226 | sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; | ||
1227 | else | ||
1228 | sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; | ||
1229 | 1199 | ||
1230 | rfkill_force_state(sc->rf_kill.rfkill, state); | 1200 | if (blocked) |
1231 | } | 1201 | ath_radio_disable(sc); |
1202 | else | ||
1203 | ath_radio_enable(sc); | ||
1232 | 1204 | ||
1233 | queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, | 1205 | return 0; |
1234 | msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); | ||
1235 | } | 1206 | } |
1236 | 1207 | ||
1237 | /* s/w rfkill handler */ | 1208 | static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data) |
1238 | static int ath_sw_toggle_radio(void *data, enum rfkill_state state) | ||
1239 | { | 1209 | { |
1240 | struct ath_softc *sc = data; | 1210 | struct ath_softc *sc = data; |
1211 | bool blocked = !!ath_is_rfkill_set(sc); | ||
1241 | 1212 | ||
1242 | switch (state) { | 1213 | if (rfkill_set_hw_state(rfkill, blocked)) |
1243 | case RFKILL_STATE_SOFT_BLOCKED: | 1214 | ath_radio_disable(sc); |
1244 | if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | | 1215 | else |
1245 | SC_OP_RFKILL_SW_BLOCKED))) | 1216 | ath_radio_enable(sc); |
1246 | ath_radio_disable(sc); | ||
1247 | sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; | ||
1248 | return 0; | ||
1249 | case RFKILL_STATE_UNBLOCKED: | ||
1250 | if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { | ||
1251 | sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; | ||
1252 | if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { | ||
1253 | DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" | ||
1254 | "radio as it is disabled by h/w\n"); | ||
1255 | return -EPERM; | ||
1256 | } | ||
1257 | ath_radio_enable(sc); | ||
1258 | } | ||
1259 | return 0; | ||
1260 | default: | ||
1261 | return -EINVAL; | ||
1262 | } | ||
1263 | } | 1217 | } |
1264 | 1218 | ||
1265 | /* Init s/w rfkill */ | 1219 | /* Init s/w rfkill */ |
1266 | static int ath_init_sw_rfkill(struct ath_softc *sc) | 1220 | static int ath_init_sw_rfkill(struct ath_softc *sc) |
1267 | { | 1221 | { |
1268 | sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), | 1222 | sc->rf_kill.ops.set_block = ath_rfkill_set_block; |
1269 | RFKILL_TYPE_WLAN); | 1223 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
1224 | sc->rf_kill.ops.poll = ath_rfkill_poll_state; | ||
1225 | |||
1226 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), | ||
1227 | "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); | ||
1228 | |||
1229 | sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name, | ||
1230 | wiphy_dev(sc->hw->wiphy), | ||
1231 | RFKILL_TYPE_WLAN, | ||
1232 | &sc->rf_kill.ops, sc); | ||
1270 | if (!sc->rf_kill.rfkill) { | 1233 | if (!sc->rf_kill.rfkill) { |
1271 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); | 1234 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); |
1272 | return -ENOMEM; | 1235 | return -ENOMEM; |
1273 | } | 1236 | } |
1274 | 1237 | ||
1275 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), | ||
1276 | "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); | ||
1277 | sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; | ||
1278 | sc->rf_kill.rfkill->data = sc; | ||
1279 | sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; | ||
1280 | sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
1281 | |||
1282 | return 0; | 1238 | return 0; |
1283 | } | 1239 | } |
1284 | 1240 | ||
1285 | /* Deinitialize rfkill */ | 1241 | /* Deinitialize rfkill */ |
1286 | static void ath_deinit_rfkill(struct ath_softc *sc) | 1242 | static void ath_deinit_rfkill(struct ath_softc *sc) |
1287 | { | 1243 | { |
1288 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1289 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
1290 | |||
1291 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { | 1244 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { |
1292 | rfkill_unregister(sc->rf_kill.rfkill); | 1245 | rfkill_unregister(sc->rf_kill.rfkill); |
1246 | rfkill_destroy(sc->rf_kill.rfkill); | ||
1293 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; | 1247 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; |
1294 | sc->rf_kill.rfkill = NULL; | ||
1295 | } | 1248 | } |
1296 | } | 1249 | } |
1297 | 1250 | ||
1298 | static int ath_start_rfkill_poll(struct ath_softc *sc) | 1251 | static int ath_start_rfkill_poll(struct ath_softc *sc) |
1299 | { | 1252 | { |
1300 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1301 | queue_delayed_work(sc->hw->workqueue, | ||
1302 | &sc->rf_kill.rfkill_poll, 0); | ||
1303 | |||
1304 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { | 1253 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { |
1305 | if (rfkill_register(sc->rf_kill.rfkill)) { | 1254 | if (rfkill_register(sc->rf_kill.rfkill)) { |
1306 | DPRINTF(sc, ATH_DBG_FATAL, | 1255 | DPRINTF(sc, ATH_DBG_FATAL, |
1307 | "Unable to register rfkill\n"); | 1256 | "Unable to register rfkill\n"); |
1308 | rfkill_free(sc->rf_kill.rfkill); | 1257 | rfkill_destroy(sc->rf_kill.rfkill); |
1309 | 1258 | ||
1310 | /* Deinitialize the device */ | 1259 | /* Deinitialize the device */ |
1311 | ath_cleanup(sc); | 1260 | ath_cleanup(sc); |
@@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1678 | goto error_attach; | 1627 | goto error_attach; |
1679 | 1628 | ||
1680 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1629 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
1681 | /* Initialze h/w Rfkill */ | ||
1682 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1683 | INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); | ||
1684 | |||
1685 | /* Initialize s/w rfkill */ | 1630 | /* Initialize s/w rfkill */ |
1686 | error = ath_init_sw_rfkill(sc); | 1631 | error = ath_init_sw_rfkill(sc); |
1687 | if (error) | 1632 | if (error) |
@@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
2214 | } else | 2159 | } else |
2215 | sc->rx.rxlink = NULL; | 2160 | sc->rx.rxlink = NULL; |
2216 | 2161 | ||
2217 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 2162 | rfkill_pause_polling(sc->rf_kill.rfkill); |
2218 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 2163 | |
2219 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
2220 | #endif | ||
2221 | /* disable HAL and put h/w to sleep */ | 2164 | /* disable HAL and put h/w to sleep */ |
2222 | ath9k_hw_disable(sc->sc_ah); | 2165 | ath9k_hw_disable(sc->sc_ah); |
2223 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); | 2166 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 168411d322a2..ccdf20a2e9be 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
227 | 227 | ||
228 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 228 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
229 | 229 | ||
230 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
231 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
232 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
233 | #endif | ||
234 | |||
235 | pci_save_state(pdev); | 230 | pci_save_state(pdev); |
236 | pci_disable_device(pdev); | 231 | pci_disable_device(pdev); |
237 | pci_set_power_state(pdev, PCI_D3hot); | 232 | pci_set_power_state(pdev, PCI_D3hot); |
@@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
256 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 251 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
257 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 252 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
258 | 253 | ||
259 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
260 | /* | ||
261 | * check the h/w rfkill state on resume | ||
262 | * and start the rfkill poll timer | ||
263 | */ | ||
264 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
265 | queue_delayed_work(sc->hw->workqueue, | ||
266 | &sc->rf_kill.rfkill_poll, 0); | ||
267 | #endif | ||
268 | |||
269 | return 0; | 254 | return 0; |
270 | } | 255 | } |
271 | 256 | ||
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 7a89f9fac7d4..eef370bd1211 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c | |||
@@ -366,11 +366,17 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) | |||
366 | if (rd & COUNTRY_ERD_FLAG) { | 366 | if (rd & COUNTRY_ERD_FLAG) { |
367 | /* EEPROM value is a country code */ | 367 | /* EEPROM value is a country code */ |
368 | u16 cc = rd & ~COUNTRY_ERD_FLAG; | 368 | u16 cc = rd & ~COUNTRY_ERD_FLAG; |
369 | printk(KERN_DEBUG | ||
370 | "ath: EEPROM indicates we should expect " | ||
371 | "a country code\n"); | ||
369 | for (i = 0; i < ARRAY_SIZE(allCountries); i++) | 372 | for (i = 0; i < ARRAY_SIZE(allCountries); i++) |
370 | if (allCountries[i].countryCode == cc) | 373 | if (allCountries[i].countryCode == cc) |
371 | return true; | 374 | return true; |
372 | } else { | 375 | } else { |
373 | /* EEPROM value is a regpair value */ | 376 | /* EEPROM value is a regpair value */ |
377 | if (rd != CTRY_DEFAULT) | ||
378 | printk(KERN_DEBUG "ath: EEPROM indicates we " | ||
379 | "should expect a direct regpair map\n"); | ||
374 | for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) | 380 | for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) |
375 | if (regDomainPairs[i].regDmnEnum == rd) | 381 | if (regDomainPairs[i].regDmnEnum == rd) |
376 | return true; | 382 | return true; |
@@ -477,6 +483,11 @@ ath_regd_init(struct ath_regulatory *reg, | |||
477 | struct country_code_to_enum_rd *country = NULL; | 483 | struct country_code_to_enum_rd *country = NULL; |
478 | u16 regdmn; | 484 | u16 regdmn; |
479 | 485 | ||
486 | if (!reg) | ||
487 | return -EINVAL; | ||
488 | |||
489 | printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); | ||
490 | |||
480 | if (!ath_regd_is_eeprom_valid(reg)) { | 491 | if (!ath_regd_is_eeprom_valid(reg)) { |
481 | printk(KERN_ERR "ath: Invalid EEPROM contents\n"); | 492 | printk(KERN_ERR "ath: Invalid EEPROM contents\n"); |
482 | return -EINVAL; | 493 | return -EINVAL; |
@@ -486,20 +497,30 @@ ath_regd_init(struct ath_regulatory *reg, | |||
486 | reg->country_code = ath_regd_get_default_country(regdmn); | 497 | reg->country_code = ath_regd_get_default_country(regdmn); |
487 | 498 | ||
488 | if (reg->country_code == CTRY_DEFAULT && | 499 | if (reg->country_code == CTRY_DEFAULT && |
489 | regdmn == CTRY_DEFAULT) | 500 | regdmn == CTRY_DEFAULT) { |
501 | printk(KERN_DEBUG "ath: EEPROM indicates default " | ||
502 | "country code should be used\n"); | ||
490 | reg->country_code = CTRY_UNITED_STATES; | 503 | reg->country_code = CTRY_UNITED_STATES; |
504 | } | ||
491 | 505 | ||
492 | if (reg->country_code == CTRY_DEFAULT) { | 506 | if (reg->country_code == CTRY_DEFAULT) { |
493 | country = NULL; | 507 | country = NULL; |
494 | } else { | 508 | } else { |
509 | printk(KERN_DEBUG "ath: doing EEPROM country->regdmn " | ||
510 | "map search\n"); | ||
495 | country = ath_regd_find_country(reg->country_code); | 511 | country = ath_regd_find_country(reg->country_code); |
496 | if (country == NULL) { | 512 | if (country == NULL) { |
497 | printk(KERN_DEBUG | 513 | printk(KERN_DEBUG |
498 | "ath: Country is NULL!!!!, cc= %d\n", | 514 | "ath: no valid country maps found for " |
515 | "country code: 0x%0x\n", | ||
499 | reg->country_code); | 516 | reg->country_code); |
500 | return -EINVAL; | 517 | return -EINVAL; |
501 | } else | 518 | } else { |
502 | regdmn = country->regDmnEnum; | 519 | regdmn = country->regDmnEnum; |
520 | printk(KERN_DEBUG "ath: country maps to " | ||
521 | "regdmn code: 0x%0x\n", | ||
522 | regdmn); | ||
523 | } | ||
503 | } | 524 | } |
504 | 525 | ||
505 | reg->regpair = ath_get_regpair(regdmn); | 526 | reg->regpair = ath_get_regpair(regdmn); |
@@ -523,7 +544,7 @@ ath_regd_init(struct ath_regulatory *reg, | |||
523 | 544 | ||
524 | printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", | 545 | printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", |
525 | reg->alpha2[0], reg->alpha2[1]); | 546 | reg->alpha2[0], reg->alpha2[1]); |
526 | printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n", | 547 | printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", |
527 | reg->regpair->regDmnEnum); | 548 | reg->regpair->regDmnEnum); |
528 | 549 | ||
529 | ath_regd_init_wiphy(reg, wiphy, reg_notifier); | 550 | ath_regd_init_wiphy(reg, wiphy, reg_notifier); |
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 21572e40b79d..07a99e3faf94 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
@@ -102,7 +102,7 @@ config B43_LEDS | |||
102 | # if it's possible. | 102 | # if it's possible. |
103 | config B43_RFKILL | 103 | config B43_RFKILL |
104 | bool | 104 | bool |
105 | depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) | 105 | depends on B43 && (RFKILL = y || RFKILL = B43) |
106 | default y | 106 | default y |
107 | 107 | ||
108 | # This config option automatically enables b43 HW-RNG support, | 108 | # This config option automatically enables b43 HW-RNG support, |
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 76f4c7bad8b8..9a498d3fc653 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c | |||
@@ -87,7 +87,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, | |||
87 | } | 87 | } |
88 | 88 | ||
89 | static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, | 89 | static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, |
90 | const char *name, char *default_trigger, | 90 | const char *name, const char *default_trigger, |
91 | u8 led_index, bool activelow) | 91 | u8 led_index, bool activelow) |
92 | { | 92 | { |
93 | int err; | 93 | int err; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cb4a8712946a..1d3e40095ada 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -3470,7 +3470,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3470 | 3470 | ||
3471 | if (!!conf->radio_enabled != phy->radio_on) { | 3471 | if (!!conf->radio_enabled != phy->radio_on) { |
3472 | if (conf->radio_enabled) { | 3472 | if (conf->radio_enabled) { |
3473 | b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); | 3473 | b43_software_rfkill(dev, false); |
3474 | b43info(dev->wl, "Radio turned on by software\n"); | 3474 | b43info(dev->wl, "Radio turned on by software\n"); |
3475 | if (!dev->radio_hw_enable) { | 3475 | if (!dev->radio_hw_enable) { |
3476 | b43info(dev->wl, "The hardware RF-kill button " | 3476 | b43info(dev->wl, "The hardware RF-kill button " |
@@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3478 | "Press the button to turn it on.\n"); | 3478 | "Press the button to turn it on.\n"); |
3479 | } | 3479 | } |
3480 | } else { | 3480 | } else { |
3481 | b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | 3481 | b43_software_rfkill(dev, true); |
3482 | b43info(dev->wl, "Radio turned off by software\n"); | 3482 | b43info(dev->wl, "Radio turned off by software\n"); |
3483 | } | 3483 | } |
3484 | } | 3484 | } |
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index c836c077d51d..816e028a2620 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c | |||
@@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) | |||
480 | } | 480 | } |
481 | 481 | ||
482 | static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, | 482 | static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, |
483 | enum rfkill_state state) | 483 | bool blocked) |
484 | { | 484 | { |
485 | struct b43_phy *phy = &dev->phy; | 485 | struct b43_phy *phy = &dev->phy; |
486 | 486 | ||
487 | if (state == RFKILL_STATE_UNBLOCKED) { | 487 | if (!blocked) { |
488 | if (phy->radio_on) | 488 | if (phy->radio_on) |
489 | return; | 489 | return; |
490 | b43_radio_write16(dev, 0x0004, 0x00C0); | 490 | b43_radio_write16(dev, 0x0004, 0x00C0); |
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e176b6e0d9cf..6d241622210e 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c | |||
@@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev) | |||
84 | 84 | ||
85 | phy->channel = ops->get_default_chan(dev); | 85 | phy->channel = ops->get_default_chan(dev); |
86 | 86 | ||
87 | ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); | 87 | ops->software_rfkill(dev, false); |
88 | err = ops->init(dev); | 88 | err = ops->init(dev); |
89 | if (err) { | 89 | if (err) { |
90 | b43err(dev->wl, "PHY init failed\n"); | 90 | b43err(dev->wl, "PHY init failed\n"); |
@@ -104,7 +104,7 @@ err_phy_exit: | |||
104 | if (ops->exit) | 104 | if (ops->exit) |
105 | ops->exit(dev); | 105 | ops->exit(dev); |
106 | err_block_rf: | 106 | err_block_rf: |
107 | ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | 107 | ops->software_rfkill(dev, true); |
108 | 108 | ||
109 | return err; | 109 | return err; |
110 | } | 110 | } |
@@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev) | |||
113 | { | 113 | { |
114 | const struct b43_phy_operations *ops = dev->phy.ops; | 114 | const struct b43_phy_operations *ops = dev->phy.ops; |
115 | 115 | ||
116 | ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | 116 | ops->software_rfkill(dev, true); |
117 | if (ops->exit) | 117 | if (ops->exit) |
118 | ops->exit(dev); | 118 | ops->exit(dev); |
119 | } | 119 | } |
@@ -295,18 +295,13 @@ err_restore_cookie: | |||
295 | return err; | 295 | return err; |
296 | } | 296 | } |
297 | 297 | ||
298 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) | 298 | void b43_software_rfkill(struct b43_wldev *dev, bool blocked) |
299 | { | 299 | { |
300 | struct b43_phy *phy = &dev->phy; | 300 | struct b43_phy *phy = &dev->phy; |
301 | 301 | ||
302 | if (state == RFKILL_STATE_HARD_BLOCKED) { | ||
303 | /* We cannot hardware-block the device */ | ||
304 | state = RFKILL_STATE_SOFT_BLOCKED; | ||
305 | } | ||
306 | |||
307 | b43_mac_suspend(dev); | 302 | b43_mac_suspend(dev); |
308 | phy->ops->software_rfkill(dev, state); | 303 | phy->ops->software_rfkill(dev, blocked); |
309 | phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); | 304 | phy->radio_on = !blocked; |
310 | b43_mac_enable(dev); | 305 | b43_mac_enable(dev); |
311 | } | 306 | } |
312 | 307 | ||
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b2d99101947b..f4c2d79cbc89 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h | |||
@@ -159,7 +159,7 @@ struct b43_phy_operations { | |||
159 | 159 | ||
160 | /* Radio */ | 160 | /* Radio */ |
161 | bool (*supports_hwpctl)(struct b43_wldev *dev); | 161 | bool (*supports_hwpctl)(struct b43_wldev *dev); |
162 | void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); | 162 | void (*software_rfkill)(struct b43_wldev *dev, bool blocked); |
163 | void (*switch_analog)(struct b43_wldev *dev, bool on); | 163 | void (*switch_analog)(struct b43_wldev *dev, bool on); |
164 | int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); | 164 | int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); |
165 | unsigned int (*get_default_chan)(struct b43_wldev *dev); | 165 | unsigned int (*get_default_chan)(struct b43_wldev *dev); |
@@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); | |||
364 | /** | 364 | /** |
365 | * b43_software_rfkill - Turn the radio ON or OFF in software. | 365 | * b43_software_rfkill - Turn the radio ON or OFF in software. |
366 | */ | 366 | */ |
367 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); | 367 | void b43_software_rfkill(struct b43_wldev *dev, bool blocked); |
368 | 368 | ||
369 | /** | 369 | /** |
370 | * b43_phy_txpower_check - Check TX power output. | 370 | * b43_phy_txpower_check - Check TX power output. |
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e7b98f013b0f..5300232449f6 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c | |||
@@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) | |||
2592 | } | 2592 | } |
2593 | 2593 | ||
2594 | static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, | 2594 | static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, |
2595 | enum rfkill_state state) | 2595 | bool blocked) |
2596 | { | 2596 | { |
2597 | struct b43_phy *phy = &dev->phy; | 2597 | struct b43_phy *phy = &dev->phy; |
2598 | struct b43_phy_g *gphy = phy->g; | 2598 | struct b43_phy_g *gphy = phy->g; |
@@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, | |||
2600 | 2600 | ||
2601 | might_sleep(); | 2601 | might_sleep(); |
2602 | 2602 | ||
2603 | if (state == RFKILL_STATE_UNBLOCKED) { | 2603 | if (!blocked) { |
2604 | /* Turn radio ON */ | 2604 | /* Turn radio ON */ |
2605 | if (phy->radio_on) | 2605 | if (phy->radio_on) |
2606 | return; | 2606 | return; |
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 58e319d6b1ed..ea0d3a3a6a64 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c | |||
@@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) | |||
488 | } | 488 | } |
489 | 489 | ||
490 | static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, | 490 | static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, |
491 | enum rfkill_state state) | 491 | bool blocked) |
492 | { | 492 | { |
493 | //TODO | 493 | //TODO |
494 | } | 494 | } |
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8bcfda5f3f07..be7b5604947b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c | |||
@@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) | |||
579 | } | 579 | } |
580 | 580 | ||
581 | static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, | 581 | static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, |
582 | enum rfkill_state state) | 582 | bool blocked) |
583 | {//TODO | 583 | {//TODO |
584 | } | 584 | } |
585 | 585 | ||
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 9e1d00bc24d3..96047843cd56 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c | |||
@@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) | |||
45 | } | 45 | } |
46 | 46 | ||
47 | /* The poll callback for the hardware button. */ | 47 | /* The poll callback for the hardware button. */ |
48 | static void b43_rfkill_poll(struct input_polled_dev *poll_dev) | 48 | static void b43_rfkill_poll(struct rfkill *rfkill, void *data) |
49 | { | 49 | { |
50 | struct b43_wldev *dev = poll_dev->private; | 50 | struct b43_wldev *dev = data; |
51 | struct b43_wl *wl = dev->wl; | 51 | struct b43_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(b43_status(dev) < B43_STAT_INITIALIZED)) { | 55 | if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { |
@@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) | |||
60 | enabled = b43_is_hw_radio_enabled(dev); | 59 | enabled = b43_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 | b43info(wl, "Radio hardware status changed to %s\n", | 62 | b43info(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 | b43_software_rfkill(dev, !enabled); | ||
66 | } | 67 | } |
67 | mutex_unlock(&wl->mutex); | 68 | 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 | } | 69 | } |
76 | 70 | ||
77 | /* Called when the RFKILL toggled in software. */ | 71 | /* Called when the RFKILL toggled in software. */ |
78 | static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) | 72 | static int b43_rfkill_soft_set(void *data, bool blocked) |
79 | { | 73 | { |
80 | struct b43_wldev *dev = data; | 74 | struct b43_wldev *dev = data; |
81 | struct b43_wl *wl = dev->wl; | 75 | struct b43_wl *wl = dev->wl; |
82 | int err = -EBUSY; | 76 | int err = -EINVAL; |
83 | 77 | ||
84 | if (!wl->rfkill.registered) | 78 | if (WARN_ON(!wl->rfkill.registered)) |
85 | return 0; | 79 | return -EINVAL; |
86 | 80 | ||
87 | mutex_lock(&wl->mutex); | 81 | mutex_lock(&wl->mutex); |
82 | |||
88 | if (b43_status(dev) < B43_STAT_INITIALIZED) | 83 | if (b43_status(dev) < B43_STAT_INITIALIZED) |
89 | goto out_unlock; | 84 | goto out_unlock; |
85 | |||
86 | if (!dev->radio_hw_enable) | ||
87 | goto out_unlock; | ||
88 | |||
89 | if (!blocked != dev->phy.radio_on) | ||
90 | b43_software_rfkill(dev, blocked); | ||
90 | err = 0; | 91 | err = 0; |
91 | switch (state) { | ||
92 | case RFKILL_STATE_UNBLOCKED: | ||
93 | if (!dev->radio_hw_enable) { | ||
94 | /* No luck. We can't toggle the hardware RF-kill | ||
95 | * button from software. */ | ||
96 | err = -EBUSY; | ||
97 | goto out_unlock; | ||
98 | } | ||
99 | if (!dev->phy.radio_on) | ||
100 | b43_software_rfkill(dev, state); | ||
101 | break; | ||
102 | case RFKILL_STATE_SOFT_BLOCKED: | ||
103 | if (dev->phy.radio_on) | ||
104 | b43_software_rfkill(dev, state); | ||
105 | break; | ||
106 | default: | ||
107 | b43warn(wl, "Received unexpected rfkill state %d.\n", state); | ||
108 | break; | ||
109 | } | ||
110 | out_unlock: | 92 | out_unlock: |
111 | mutex_unlock(&wl->mutex); | 93 | mutex_unlock(&wl->mutex); |
112 | |||
113 | return err; | 94 | return err; |
114 | } | 95 | } |
115 | 96 | ||
116 | char *b43_rfkill_led_name(struct b43_wldev *dev) | 97 | const char *b43_rfkill_led_name(struct b43_wldev *dev) |
117 | { | 98 | { |
118 | struct b43_rfkill *rfk = &(dev->wl->rfkill); | 99 | struct b43_rfkill *rfk = &(dev->wl->rfkill); |
119 | 100 | ||
120 | if (!rfk->registered) | 101 | if (!rfk->registered) |
121 | return NULL; | 102 | return NULL; |
122 | return rfkill_get_led_name(rfk->rfkill); | 103 | return rfkill_get_led_trigger_name(rfk->rfkill); |
123 | } | 104 | } |
124 | 105 | ||
106 | static const struct rfkill_ops b43_rfkill_ops = { | ||
107 | .set_block = b43_rfkill_soft_set, | ||
108 | .poll = b43_rfkill_poll, | ||
109 | }; | ||
110 | |||
125 | void b43_rfkill_init(struct b43_wldev *dev) | 111 | void b43_rfkill_init(struct b43_wldev *dev) |
126 | { | 112 | { |
127 | struct b43_wl *wl = dev->wl; | 113 | struct b43_wl *wl = dev->wl; |
@@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev) | |||
130 | 116 | ||
131 | rfk->registered = 0; | 117 | rfk->registered = 0; |
132 | 118 | ||
133 | rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); | ||
134 | if (!rfk->rfkill) | ||
135 | goto out_error; | ||
136 | snprintf(rfk->name, sizeof(rfk->name), | 119 | snprintf(rfk->name, sizeof(rfk->name), |
137 | "b43-%s", wiphy_name(wl->hw->wiphy)); | 120 | "b43-%s", wiphy_name(wl->hw->wiphy)); |
138 | rfk->rfkill->name = rfk->name; | ||
139 | rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
140 | rfk->rfkill->data = dev; | ||
141 | rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; | ||
142 | |||
143 | rfk->poll_dev = input_allocate_polled_device(); | ||
144 | if (!rfk->poll_dev) { | ||
145 | rfkill_free(rfk->rfkill); | ||
146 | goto err_freed_rfk; | ||
147 | } | ||
148 | |||
149 | rfk->poll_dev->private = dev; | ||
150 | rfk->poll_dev->poll = b43_rfkill_poll; | ||
151 | rfk->poll_dev->poll_interval = 1000; /* msecs */ | ||
152 | 121 | ||
153 | rfk->poll_dev->input->name = rfk->name; | 122 | rfk->rfkill = rfkill_alloc(rfk->name, |
154 | rfk->poll_dev->input->id.bustype = BUS_HOST; | 123 | dev->dev->dev, |
155 | rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; | 124 | RFKILL_TYPE_WLAN, |
156 | rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); | 125 | &b43_rfkill_ops, dev); |
157 | set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); | 126 | if (!rfk->rfkill) |
127 | goto out_error; | ||
158 | 128 | ||
159 | err = rfkill_register(rfk->rfkill); | 129 | err = rfkill_register(rfk->rfkill); |
160 | if (err) | 130 | if (err) |
161 | goto err_free_polldev; | 131 | goto err_free; |
162 | |||
163 | #ifdef CONFIG_RFKILL_INPUT_MODULE | ||
164 | /* B43 RF-kill isn't useful without the rfkill-input subsystem. | ||
165 | * Try to load the module. */ | ||
166 | err = request_module("rfkill-input"); | ||
167 | if (err) | ||
168 | b43warn(wl, "Failed to load the rfkill-input module. " | ||
169 | "The built-in radio LED will not work.\n"); | ||
170 | #endif /* CONFIG_RFKILL_INPUT */ | ||
171 | |||
172 | #if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE) | ||
173 | b43warn(wl, "The rfkill-input subsystem is not available. " | ||
174 | "The built-in radio LED will not work.\n"); | ||
175 | #endif | ||
176 | |||
177 | err = input_register_polled_device(rfk->poll_dev); | ||
178 | if (err) | ||
179 | goto err_unreg_rfk; | ||
180 | 132 | ||
181 | rfk->registered = 1; | 133 | rfk->registered = 1; |
182 | 134 | ||
183 | return; | 135 | return; |
184 | err_unreg_rfk: | 136 | err_free: |
185 | rfkill_unregister(rfk->rfkill); | 137 | rfkill_destroy(rfk->rfkill); |
186 | err_free_polldev: | 138 | out_error: |
187 | input_free_polled_device(rfk->poll_dev); | ||
188 | rfk->poll_dev = NULL; | ||
189 | err_freed_rfk: | ||
190 | rfk->rfkill = NULL; | ||
191 | out_error: | ||
192 | rfk->registered = 0; | 139 | rfk->registered = 0; |
193 | b43warn(wl, "RF-kill button init failed\n"); | 140 | b43warn(wl, "RF-kill button init failed\n"); |
194 | } | 141 | } |
@@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev) | |||
201 | return; | 148 | return; |
202 | rfk->registered = 0; | 149 | rfk->registered = 0; |
203 | 150 | ||
204 | input_unregister_polled_device(rfk->poll_dev); | ||
205 | rfkill_unregister(rfk->rfkill); | 151 | rfkill_unregister(rfk->rfkill); |
206 | input_free_polled_device(rfk->poll_dev); | 152 | rfkill_destroy(rfk->rfkill); |
207 | rfk->poll_dev = NULL; | ||
208 | rfk->rfkill = NULL; | 153 | rfk->rfkill = NULL; |
209 | } | 154 | } |
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index adacf936d815..da497e01bbb1 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h | |||
@@ -7,14 +7,11 @@ struct b43_wldev; | |||
7 | #ifdef CONFIG_B43_RFKILL | 7 | #ifdef CONFIG_B43_RFKILL |
8 | 8 | ||
9 | #include <linux/rfkill.h> | 9 | #include <linux/rfkill.h> |
10 | #include <linux/input-polldev.h> | ||
11 | 10 | ||
12 | 11 | ||
13 | struct b43_rfkill { | 12 | struct b43_rfkill { |
14 | /* The RFKILL subsystem data structure */ | 13 | /* The RFKILL subsystem data structure */ |
15 | struct rfkill *rfkill; | 14 | struct rfkill *rfkill; |
16 | /* The poll device for the RFKILL input button */ | ||
17 | struct input_polled_dev *poll_dev; | ||
18 | /* Did initialization succeed? Used for freeing. */ | 15 | /* Did initialization succeed? Used for freeing. */ |
19 | bool registered; | 16 | bool registered; |
20 | /* The unique name of this rfkill switch */ | 17 | /* The unique name of this rfkill switch */ |
@@ -26,7 +23,7 @@ struct b43_rfkill { | |||
26 | void b43_rfkill_init(struct b43_wldev *dev); | 23 | void b43_rfkill_init(struct b43_wldev *dev); |
27 | void b43_rfkill_exit(struct b43_wldev *dev); | 24 | void b43_rfkill_exit(struct b43_wldev *dev); |
28 | 25 | ||
29 | char * b43_rfkill_led_name(struct b43_wldev *dev); | 26 | const char *b43_rfkill_led_name(struct b43_wldev *dev); |
30 | 27 | ||
31 | 28 | ||
32 | #else /* CONFIG_B43_RFKILL */ | 29 | #else /* CONFIG_B43_RFKILL */ |
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. |
48 | config B43LEGACY_RFKILL | 48 | config 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 | ||
87 | static int b43legacy_register_led(struct b43legacy_wldev *dev, | 87 | static 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. */ |
48 | static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) | 48 | static 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. */ |
79 | static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) | 77 | static 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 | ||
113 | out_unlock: | 101 | out_unlock: |
114 | mutex_unlock(&wl->mutex); | 102 | mutex_unlock(&wl->mutex); |
115 | 103 | return ret; | |
116 | return err; | ||
117 | } | 104 | } |
118 | 105 | ||
119 | char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) | 106 | const 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 | ||
115 | static const struct rfkill_ops b43legacy_rfkill_ops = { | ||
116 | .set_block = b43legacy_rfkill_soft_set, | ||
117 | .poll = b43legacy_rfkill_poll, | ||
118 | }; | ||
119 | |||
128 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev) | 120 | void 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; |
182 | err_unreg_rfk: | 144 | err_free: |
183 | rfkill_unregister(rfk->rfkill); | 145 | rfkill_destroy(rfk->rfkill); |
184 | err_free_polldev: | 146 | out_error: |
185 | input_free_polled_device(rfk->poll_dev); | ||
186 | rfk->poll_dev = NULL; | ||
187 | err_freed_rfk: | ||
188 | rfk->rfkill = NULL; | ||
189 | out_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 | ||
14 | struct b43legacy_rfkill { | 12 | struct 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 { | |||
27 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev); | 23 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev); |
28 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); | 24 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); |
29 | 25 | ||
30 | char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); | 26 | const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); |
31 | 27 | ||
32 | 28 | ||
33 | #else /* CONFIG_B43LEGACY_RFKILL */ | 29 | #else /* CONFIG_B43LEGACY_RFKILL */ |
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 8304f6406a17..6fe259fcfb8f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -5,15 +5,14 @@ config IWLWIFI | |||
5 | select FW_LOADER | 5 | select FW_LOADER |
6 | select MAC80211_LEDS if IWLWIFI_LEDS | 6 | select MAC80211_LEDS if IWLWIFI_LEDS |
7 | select LEDS_CLASS if IWLWIFI_LEDS | 7 | select LEDS_CLASS if IWLWIFI_LEDS |
8 | select RFKILL if IWLWIFI_RFKILL | ||
9 | 8 | ||
10 | config IWLWIFI_LEDS | 9 | config IWLWIFI_LEDS |
11 | bool "Enable LED support in iwlagn and iwl3945 drivers" | 10 | bool "Enable LED support in iwlagn and iwl3945 drivers" |
12 | depends on IWLWIFI | 11 | depends on IWLWIFI |
13 | 12 | ||
14 | config IWLWIFI_RFKILL | 13 | config IWLWIFI_RFKILL |
15 | bool "Enable RF kill support in iwlagn and iwl3945 drivers" | 14 | def_bool y |
16 | depends on IWLWIFI | 15 | depends on IWLWIFI && RFKILL |
17 | 16 | ||
18 | config IWLWIFI_SPECTRUM_MEASUREMENT | 17 | config IWLWIFI_SPECTRUM_MEASUREMENT |
19 | bool "Enable Spectrum Measurement in iwlagn driver" | 18 | bool "Enable Spectrum Measurement in iwlagn driver" |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index bd7e520d98c2..225e5f889346 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c | |||
@@ -167,10 +167,6 @@ static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) | |||
167 | IWL_DEBUG_LED(priv, "Disassociated\n"); | 167 | IWL_DEBUG_LED(priv, "Disassociated\n"); |
168 | 168 | ||
169 | priv->allow_blinking = 0; | 169 | priv->allow_blinking = 0; |
170 | if (iwl_is_rfkill(priv)) | ||
171 | iwl3945_led_off(priv, led_id); | ||
172 | else | ||
173 | iwl3945_led_on(priv, led_id); | ||
174 | 170 | ||
175 | return 0; | 171 | return 0; |
176 | } | 172 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 814afaf6d10b..5eb538d18a80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | #include "iwl-commands.h" | 39 | #include "iwl-commands.h" |
40 | #include "iwl-3945.h" | 40 | #include "iwl-3945.h" |
41 | #include "iwl-sta.h" | ||
41 | 42 | ||
42 | #define RS_NAME "iwl-3945-rs" | 43 | #define RS_NAME "iwl-3945-rs" |
43 | 44 | ||
@@ -714,13 +715,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, | |||
714 | 715 | ||
715 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && | 716 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && |
716 | !rs_sta->ibss_sta_added) { | 717 | !rs_sta->ibss_sta_added) { |
717 | u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); | 718 | u8 sta_id = iwl_find_station(priv, hdr->addr1); |
718 | 719 | ||
719 | if (sta_id == IWL_INVALID_STATION) { | 720 | if (sta_id == IWL_INVALID_STATION) { |
720 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n", | 721 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n", |
721 | hdr->addr1); | 722 | hdr->addr1); |
722 | sta_id = iwl3945_add_station(priv, | 723 | sta_id = iwl_add_station(priv, hdr->addr1, false, |
723 | hdr->addr1, 0, CMD_ASYNC, NULL); | 724 | CMD_ASYNC, NULL); |
724 | } | 725 | } |
725 | if (sta_id != IWL_INVALID_STATION) | 726 | if (sta_id != IWL_INVALID_STATION) |
726 | rs_sta->ibss_sta_added = 1; | 727 | rs_sta->ibss_sta_added = 1; |
@@ -975,7 +976,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) | |||
975 | 976 | ||
976 | rcu_read_lock(); | 977 | rcu_read_lock(); |
977 | 978 | ||
978 | sta = ieee80211_find_sta(hw, priv->stations_39[sta_id].sta.sta.addr); | 979 | sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); |
979 | if (!sta) { | 980 | if (!sta) { |
980 | rcu_read_unlock(); | 981 | rcu_read_unlock(); |
981 | return; | 982 | return; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index fd65e1c3e055..46288e724889 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -769,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
769 | return ; | 769 | return ; |
770 | } | 770 | } |
771 | 771 | ||
772 | u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr) | ||
773 | { | ||
774 | int i, start = IWL_AP_ID; | ||
775 | int ret = IWL_INVALID_STATION; | ||
776 | unsigned long flags; | ||
777 | |||
778 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || | ||
779 | (priv->iw_mode == NL80211_IFTYPE_AP)) | ||
780 | start = IWL_STA_ID; | ||
781 | |||
782 | if (is_broadcast_ether_addr(addr)) | ||
783 | return priv->hw_params.bcast_sta_id; | ||
784 | |||
785 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
786 | for (i = start; i < priv->hw_params.max_stations; i++) | ||
787 | if ((priv->stations_39[i].used) && | ||
788 | (!compare_ether_addr | ||
789 | (priv->stations_39[i].sta.sta.addr, addr))) { | ||
790 | ret = i; | ||
791 | goto out; | ||
792 | } | ||
793 | |||
794 | IWL_DEBUG_INFO(priv, "can not find STA %pM (total %d)\n", | ||
795 | addr, priv->num_stations); | ||
796 | out: | ||
797 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
798 | return ret; | ||
799 | } | ||
800 | |||
801 | /** | 772 | /** |
802 | * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: | 773 | * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: |
803 | * | 774 | * |
@@ -875,13 +846,13 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, | |||
875 | u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) | 846 | u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) |
876 | { | 847 | { |
877 | unsigned long flags_spin; | 848 | unsigned long flags_spin; |
878 | struct iwl3945_station_entry *station; | 849 | struct iwl_station_entry *station; |
879 | 850 | ||
880 | if (sta_id == IWL_INVALID_STATION) | 851 | if (sta_id == IWL_INVALID_STATION) |
881 | return IWL_INVALID_STATION; | 852 | return IWL_INVALID_STATION; |
882 | 853 | ||
883 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | 854 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
884 | station = &priv->stations_39[sta_id]; | 855 | station = &priv->stations[sta_id]; |
885 | 856 | ||
886 | station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; | 857 | station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; |
887 | station->sta.rate_n_flags = cpu_to_le16(tx_rate); | 858 | station->sta.rate_n_flags = cpu_to_le16(tx_rate); |
@@ -889,8 +860,7 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) | |||
889 | 860 | ||
890 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 861 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
891 | 862 | ||
892 | iwl_send_add_sta(priv, | 863 | iwl_send_add_sta(priv, &station->sta, flags); |
893 | (struct iwl_addsta_cmd *)&station->sta, flags); | ||
894 | IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n", | 864 | IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n", |
895 | sta_id, tx_rate); | 865 | sta_id, tx_rate); |
896 | return sta_id; | 866 | return sta_id; |
@@ -2029,7 +1999,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) | |||
2029 | 1999 | ||
2030 | memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); | 2000 | memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); |
2031 | 2001 | ||
2032 | priv->cfg->ops->smgmt->clear_station_table(priv); | 2002 | iwl_clear_stations_table(priv); |
2033 | 2003 | ||
2034 | /* If we issue a new RXON command which required a tune then we must | 2004 | /* If we issue a new RXON command which required a tune then we must |
2035 | * send a new TXPOWER command or we won't be able to Tx any frames */ | 2005 | * send a new TXPOWER command or we won't be able to Tx any frames */ |
@@ -2040,7 +2010,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) | |||
2040 | } | 2010 | } |
2041 | 2011 | ||
2042 | /* Add the broadcast address so we can send broadcast frames */ | 2012 | /* Add the broadcast address so we can send broadcast frames */ |
2043 | if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) == | 2013 | if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) == |
2044 | IWL_INVALID_STATION) { | 2014 | IWL_INVALID_STATION) { |
2045 | IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); | 2015 | IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); |
2046 | return -EIO; | 2016 | return -EIO; |
@@ -2050,9 +2020,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) | |||
2050 | * add the IWL_AP_ID to the station rate table */ | 2020 | * add the IWL_AP_ID to the station rate table */ |
2051 | if (iwl_is_associated(priv) && | 2021 | if (iwl_is_associated(priv) && |
2052 | (priv->iw_mode == NL80211_IFTYPE_STATION)) | 2022 | (priv->iw_mode == NL80211_IFTYPE_STATION)) |
2053 | if (priv->cfg->ops->smgmt->add_station(priv, | 2023 | if (iwl_add_station(priv, priv->active_rxon.bssid_addr, |
2054 | priv->active_rxon.bssid_addr, 1, 0, NULL) | 2024 | true, CMD_SYNC, NULL) == IWL_INVALID_STATION) { |
2055 | == IWL_INVALID_STATION) { | ||
2056 | IWL_ERR(priv, "Error adding AP address for transmit\n"); | 2025 | IWL_ERR(priv, "Error adding AP address for transmit\n"); |
2057 | return -EIO; | 2026 | return -EIO; |
2058 | } | 2027 | } |
@@ -2466,13 +2435,25 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len) | |||
2466 | } | 2435 | } |
2467 | } | 2436 | } |
2468 | 2437 | ||
2438 | |||
2469 | static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) | 2439 | static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) |
2470 | { | 2440 | { |
2471 | u16 size = (u16)sizeof(struct iwl3945_addsta_cmd); | 2441 | struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data; |
2472 | memcpy(data, cmd, size); | 2442 | addsta->mode = cmd->mode; |
2473 | return size; | 2443 | memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); |
2444 | memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); | ||
2445 | addsta->station_flags = cmd->station_flags; | ||
2446 | addsta->station_flags_msk = cmd->station_flags_msk; | ||
2447 | addsta->tid_disable_tx = cpu_to_le16(0); | ||
2448 | addsta->rate_n_flags = cmd->rate_n_flags; | ||
2449 | addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; | ||
2450 | addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; | ||
2451 | addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; | ||
2452 | |||
2453 | return (u16)sizeof(struct iwl3945_addsta_cmd); | ||
2474 | } | 2454 | } |
2475 | 2455 | ||
2456 | |||
2476 | /** | 2457 | /** |
2477 | * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table | 2458 | * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table |
2478 | */ | 2459 | */ |
@@ -2842,15 +2823,6 @@ static struct iwl_lib_ops iwl3945_lib = { | |||
2842 | .config_ap = iwl3945_config_ap, | 2823 | .config_ap = iwl3945_config_ap, |
2843 | }; | 2824 | }; |
2844 | 2825 | ||
2845 | static struct iwl_station_mgmt_ops iwl3945_station_mgmt = { | ||
2846 | .add_station = iwl3945_add_station, | ||
2847 | #if 0 | ||
2848 | .remove_station = iwl3945_remove_station, | ||
2849 | #endif | ||
2850 | .find_station = iwl3945_hw_find_station, | ||
2851 | .clear_station_table = iwl3945_clear_stations_table, | ||
2852 | }; | ||
2853 | |||
2854 | static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { | 2826 | static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { |
2855 | .get_hcmd_size = iwl3945_get_hcmd_size, | 2827 | .get_hcmd_size = iwl3945_get_hcmd_size, |
2856 | .build_addsta_hcmd = iwl3945_build_addsta_hcmd, | 2828 | .build_addsta_hcmd = iwl3945_build_addsta_hcmd, |
@@ -2860,7 +2832,6 @@ static struct iwl_ops iwl3945_ops = { | |||
2860 | .lib = &iwl3945_lib, | 2832 | .lib = &iwl3945_lib, |
2861 | .hcmd = &iwl3945_hcmd, | 2833 | .hcmd = &iwl3945_hcmd, |
2862 | .utils = &iwl3945_hcmd_utils, | 2834 | .utils = &iwl3945_hcmd_utils, |
2863 | .smgmt = &iwl3945_station_mgmt, | ||
2864 | }; | 2835 | }; |
2865 | 2836 | ||
2866 | static struct iwl_cfg iwl3945_bg_cfg = { | 2837 | static struct iwl_cfg iwl3945_bg_cfg = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index da87528f355f..4d8a325ea9d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h | |||
@@ -202,12 +202,6 @@ struct iwl3945_ibss_seq { | |||
202 | * for use by iwl-*.c | 202 | * for use by iwl-*.c |
203 | * | 203 | * |
204 | *****************************************************************************/ | 204 | *****************************************************************************/ |
205 | struct iwl3945_addsta_cmd; | ||
206 | extern int iwl3945_send_add_station(struct iwl_priv *priv, | ||
207 | struct iwl3945_addsta_cmd *sta, u8 flags); | ||
208 | extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid, | ||
209 | int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); | ||
210 | extern void iwl3945_clear_stations_table(struct iwl_priv *priv); | ||
211 | extern int iwl3945_power_init_handle(struct iwl_priv *priv); | 205 | extern int iwl3945_power_init_handle(struct iwl_priv *priv); |
212 | extern int iwl3945_eeprom_init(struct iwl_priv *priv); | 206 | extern int iwl3945_eeprom_init(struct iwl_priv *priv); |
213 | extern int iwl3945_calc_db_from_ratio(int sig_ratio); | 207 | extern int iwl3945_calc_db_from_ratio(int sig_ratio); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a0b29411a4b3..8f3d4bc6a03f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -2221,13 +2221,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) | |||
2221 | cancel_work_sync(&priv->txpower_work); | 2221 | cancel_work_sync(&priv->txpower_work); |
2222 | } | 2222 | } |
2223 | 2223 | ||
2224 | static struct iwl_station_mgmt_ops iwl4965_station_mgmt = { | ||
2225 | .add_station = iwl_add_station_flags, | ||
2226 | .remove_station = iwl_remove_station, | ||
2227 | .find_station = iwl_find_station, | ||
2228 | .clear_station_table = iwl_clear_stations_table, | ||
2229 | }; | ||
2230 | |||
2231 | static struct iwl_hcmd_ops iwl4965_hcmd = { | 2224 | static struct iwl_hcmd_ops iwl4965_hcmd = { |
2232 | .rxon_assoc = iwl4965_send_rxon_assoc, | 2225 | .rxon_assoc = iwl4965_send_rxon_assoc, |
2233 | .commit_rxon = iwl_commit_rxon, | 2226 | .commit_rxon = iwl_commit_rxon, |
@@ -2297,7 +2290,6 @@ static struct iwl_ops iwl4965_ops = { | |||
2297 | .lib = &iwl4965_lib, | 2290 | .lib = &iwl4965_lib, |
2298 | .hcmd = &iwl4965_hcmd, | 2291 | .hcmd = &iwl4965_hcmd, |
2299 | .utils = &iwl4965_hcmd_utils, | 2292 | .utils = &iwl4965_hcmd_utils, |
2300 | .smgmt = &iwl4965_station_mgmt, | ||
2301 | }; | 2293 | }; |
2302 | 2294 | ||
2303 | struct iwl_cfg iwl4965_agn_cfg = { | 2295 | struct iwl_cfg iwl4965_agn_cfg = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ab29aab6b2d5..b3c648ce8c7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -651,7 +651,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) | |||
651 | goto restart; | 651 | goto restart; |
652 | } | 652 | } |
653 | 653 | ||
654 | priv->cfg->ops->smgmt->clear_station_table(priv); | 654 | iwl_clear_stations_table(priv); |
655 | ret = priv->cfg->ops->lib->alive_notify(priv); | 655 | ret = priv->cfg->ops->lib->alive_notify(priv); |
656 | if (ret) { | 656 | if (ret) { |
657 | IWL_WARN(priv, | 657 | IWL_WARN(priv, |
@@ -1049,7 +1049,10 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | |||
1049 | u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) | 1049 | u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) |
1050 | { | 1050 | { |
1051 | u16 size = (u16)sizeof(struct iwl_addsta_cmd); | 1051 | u16 size = (u16)sizeof(struct iwl_addsta_cmd); |
1052 | memcpy(data, cmd, size); | 1052 | struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; |
1053 | memcpy(addsta, cmd, size); | ||
1054 | /* resrved in 5000 */ | ||
1055 | addsta->rate_n_flags = cpu_to_le16(0); | ||
1053 | return size; | 1056 | return size; |
1054 | } | 1057 | } |
1055 | 1058 | ||
@@ -1423,13 +1426,6 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, | |||
1423 | return max_rssi - agc - IWL49_RSSI_OFFSET; | 1426 | return max_rssi - agc - IWL49_RSSI_OFFSET; |
1424 | } | 1427 | } |
1425 | 1428 | ||
1426 | struct iwl_station_mgmt_ops iwl5000_station_mgmt = { | ||
1427 | .add_station = iwl_add_station_flags, | ||
1428 | .remove_station = iwl_remove_station, | ||
1429 | .find_station = iwl_find_station, | ||
1430 | .clear_station_table = iwl_clear_stations_table, | ||
1431 | }; | ||
1432 | |||
1433 | struct iwl_hcmd_ops iwl5000_hcmd = { | 1429 | struct iwl_hcmd_ops iwl5000_hcmd = { |
1434 | .rxon_assoc = iwl5000_send_rxon_assoc, | 1430 | .rxon_assoc = iwl5000_send_rxon_assoc, |
1435 | .commit_rxon = iwl_commit_rxon, | 1431 | .commit_rxon = iwl_commit_rxon, |
@@ -1549,14 +1545,12 @@ struct iwl_ops iwl5000_ops = { | |||
1549 | .lib = &iwl5000_lib, | 1545 | .lib = &iwl5000_lib, |
1550 | .hcmd = &iwl5000_hcmd, | 1546 | .hcmd = &iwl5000_hcmd, |
1551 | .utils = &iwl5000_hcmd_utils, | 1547 | .utils = &iwl5000_hcmd_utils, |
1552 | .smgmt = &iwl5000_station_mgmt, | ||
1553 | }; | 1548 | }; |
1554 | 1549 | ||
1555 | static struct iwl_ops iwl5150_ops = { | 1550 | static struct iwl_ops iwl5150_ops = { |
1556 | .lib = &iwl5150_lib, | 1551 | .lib = &iwl5150_lib, |
1557 | .hcmd = &iwl5000_hcmd, | 1552 | .hcmd = &iwl5000_hcmd, |
1558 | .utils = &iwl5000_hcmd_utils, | 1553 | .utils = &iwl5000_hcmd_utils, |
1559 | .smgmt = &iwl5000_station_mgmt, | ||
1560 | }; | 1554 | }; |
1561 | 1555 | ||
1562 | struct iwl_mod_params iwl50_mod_params = { | 1556 | struct iwl_mod_params iwl50_mod_params = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 7236382aeaa6..bd438d8acf55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -72,7 +72,6 @@ static struct iwl_ops iwl6000_ops = { | |||
72 | .lib = &iwl5000_lib, | 72 | .lib = &iwl5000_lib, |
73 | .hcmd = &iwl5000_hcmd, | 73 | .hcmd = &iwl5000_hcmd, |
74 | .utils = &iwl6000_hcmd_utils, | 74 | .utils = &iwl6000_hcmd_utils, |
75 | .smgmt = &iwl5000_station_mgmt, | ||
76 | }; | 75 | }; |
77 | 76 | ||
78 | struct iwl_cfg iwl6000_2ag_cfg = { | 77 | struct iwl_cfg iwl6000_2ag_cfg = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 23a58b00f180..ff20e5048a55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -2502,15 +2502,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, | |||
2502 | 2502 | ||
2503 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && | 2503 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && |
2504 | !lq_sta->ibss_sta_added) { | 2504 | !lq_sta->ibss_sta_added) { |
2505 | u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, | 2505 | u8 sta_id = iwl_find_station(priv, hdr->addr1); |
2506 | hdr->addr1); | ||
2507 | 2506 | ||
2508 | if (sta_id == IWL_INVALID_STATION) { | 2507 | if (sta_id == IWL_INVALID_STATION) { |
2509 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", | 2508 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", |
2510 | hdr->addr1); | 2509 | hdr->addr1); |
2511 | sta_id = priv->cfg->ops->smgmt->add_station(priv, | 2510 | sta_id = iwl_add_station(priv, hdr->addr1, |
2512 | hdr->addr1, 0, | 2511 | false, CMD_ASYNC, NULL); |
2513 | CMD_ASYNC, NULL); | ||
2514 | } | 2512 | } |
2515 | if ((sta_id != IWL_INVALID_STATION)) { | 2513 | if ((sta_id != IWL_INVALID_STATION)) { |
2516 | lq_sta->lq.sta_id = sta_id; | 2514 | lq_sta->lq.sta_id = sta_id; |
@@ -2598,7 +2596,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | |||
2598 | 2596 | ||
2599 | lq_sta->ibss_sta_added = 0; | 2597 | lq_sta->ibss_sta_added = 0; |
2600 | if (priv->iw_mode == NL80211_IFTYPE_AP) { | 2598 | if (priv->iw_mode == NL80211_IFTYPE_AP) { |
2601 | u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, | 2599 | u8 sta_id = iwl_find_station(priv, |
2602 | sta->addr); | 2600 | sta->addr); |
2603 | 2601 | ||
2604 | /* for IBSS the call are from tasklet */ | 2602 | /* for IBSS the call are from tasklet */ |
@@ -2606,9 +2604,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | |||
2606 | 2604 | ||
2607 | if (sta_id == IWL_INVALID_STATION) { | 2605 | if (sta_id == IWL_INVALID_STATION) { |
2608 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); | 2606 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); |
2609 | sta_id = priv->cfg->ops->smgmt->add_station(priv, | 2607 | sta_id = iwl_add_station(priv, sta->addr, false, |
2610 | sta->addr, 0, | 2608 | CMD_ASYNC, NULL); |
2611 | CMD_ASYNC, NULL); | ||
2612 | } | 2609 | } |
2613 | if ((sta_id != IWL_INVALID_STATION)) { | 2610 | if ((sta_id != IWL_INVALID_STATION)) { |
2614 | lq_sta->lq.sta_id = sta_id; | 2611 | lq_sta->lq.sta_id = sta_id; |
@@ -2790,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, | |||
2790 | repeat_rate--; | 2787 | repeat_rate--; |
2791 | } | 2788 | } |
2792 | 2789 | ||
2793 | lq_cmd->agg_params.agg_frame_cnt_limit = 64; | 2790 | lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; |
2794 | lq_cmd->agg_params.agg_dis_start_th = 3; | 2791 | lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; |
2795 | lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); | 2792 | lq_cmd->agg_params.agg_time_limit = |
2793 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
2796 | } | 2794 | } |
2797 | 2795 | ||
2798 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 2796 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0a5507cbeb3f..b77208de92ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
188 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 188 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
189 | } | 189 | } |
190 | 190 | ||
191 | priv->cfg->ops->smgmt->clear_station_table(priv); | 191 | iwl_clear_stations_table(priv); |
192 | 192 | ||
193 | priv->start_calib = 0; | 193 | priv->start_calib = 0; |
194 | 194 | ||
@@ -1617,7 +1617,7 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
1617 | goto restart; | 1617 | goto restart; |
1618 | } | 1618 | } |
1619 | 1619 | ||
1620 | priv->cfg->ops->smgmt->clear_station_table(priv); | 1620 | iwl_clear_stations_table(priv); |
1621 | ret = priv->cfg->ops->lib->alive_notify(priv); | 1621 | ret = priv->cfg->ops->lib->alive_notify(priv); |
1622 | if (ret) { | 1622 | if (ret) { |
1623 | IWL_WARN(priv, | 1623 | IWL_WARN(priv, |
@@ -1703,7 +1703,7 @@ static void __iwl_down(struct iwl_priv *priv) | |||
1703 | 1703 | ||
1704 | iwl_leds_unregister(priv); | 1704 | iwl_leds_unregister(priv); |
1705 | 1705 | ||
1706 | priv->cfg->ops->smgmt->clear_station_table(priv); | 1706 | iwl_clear_stations_table(priv); |
1707 | 1707 | ||
1708 | /* Unblock any waiting calls */ | 1708 | /* Unblock any waiting calls */ |
1709 | wake_up_interruptible_all(&priv->wait_command_queue); | 1709 | wake_up_interruptible_all(&priv->wait_command_queue); |
@@ -1887,8 +1887,6 @@ static int __iwl_up(struct iwl_priv *priv) | |||
1887 | 1887 | ||
1888 | /* clear (again), then enable host interrupts */ | 1888 | /* clear (again), then enable host interrupts */ |
1889 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | 1889 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
1890 | /* enable dram interrupt */ | ||
1891 | iwl_reset_ict(priv); | ||
1892 | iwl_enable_interrupts(priv); | 1890 | iwl_enable_interrupts(priv); |
1893 | 1891 | ||
1894 | /* really make sure rfkill handshake bits are cleared */ | 1892 | /* really make sure rfkill handshake bits are cleared */ |
@@ -1903,7 +1901,7 @@ static int __iwl_up(struct iwl_priv *priv) | |||
1903 | 1901 | ||
1904 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 1902 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
1905 | 1903 | ||
1906 | priv->cfg->ops->smgmt->clear_station_table(priv); | 1904 | iwl_clear_stations_table(priv); |
1907 | 1905 | ||
1908 | /* load bootstrap state machine, | 1906 | /* load bootstrap state machine, |
1909 | * load bootstrap program into processor's memory, | 1907 | * load bootstrap program into processor's memory, |
@@ -1962,6 +1960,9 @@ static void iwl_bg_alive_start(struct work_struct *data) | |||
1962 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 1960 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
1963 | return; | 1961 | return; |
1964 | 1962 | ||
1963 | /* enable dram interrupt */ | ||
1964 | iwl_reset_ict(priv); | ||
1965 | |||
1965 | mutex_lock(&priv->mutex); | 1966 | mutex_lock(&priv->mutex); |
1966 | iwl_alive_start(priv); | 1967 | iwl_alive_start(priv); |
1967 | mutex_unlock(&priv->mutex); | 1968 | mutex_unlock(&priv->mutex); |
@@ -2348,7 +2349,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
2348 | return -EOPNOTSUPP; | 2349 | return -EOPNOTSUPP; |
2349 | } | 2350 | } |
2350 | addr = sta ? sta->addr : iwl_bcast_addr; | 2351 | addr = sta ? sta->addr : iwl_bcast_addr; |
2351 | sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 2352 | sta_id = iwl_find_station(priv, addr); |
2352 | if (sta_id == IWL_INVALID_STATION) { | 2353 | if (sta_id == IWL_INVALID_STATION) { |
2353 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", | 2354 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", |
2354 | addr); | 2355 | addr); |
@@ -3121,7 +3122,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3121 | iwl_rx_queue_free(priv, &priv->rxq); | 3122 | iwl_rx_queue_free(priv, &priv->rxq); |
3122 | iwl_hw_txq_ctx_free(priv); | 3123 | iwl_hw_txq_ctx_free(priv); |
3123 | 3124 | ||
3124 | priv->cfg->ops->smgmt->clear_station_table(priv); | 3125 | iwl_clear_stations_table(priv); |
3125 | iwl_eeprom_free(priv); | 3126 | iwl_eeprom_free(priv); |
3126 | 3127 | ||
3127 | 3128 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e581dc323f0a..c87033bf3ad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -1067,7 +1067,7 @@ struct iwl_addsta_cmd { | |||
1067 | * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ | 1067 | * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ |
1068 | __le16 tid_disable_tx; | 1068 | __le16 tid_disable_tx; |
1069 | 1069 | ||
1070 | __le16 reserved1; | 1070 | __le16 rate_n_flags; /* 3945 only */ |
1071 | 1071 | ||
1072 | /* TID for which to add block-ack support. | 1072 | /* TID for which to add block-ack support. |
1073 | * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ | 1073 | * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ |
@@ -1913,6 +1913,18 @@ struct iwl_link_qual_general_params { | |||
1913 | u8 start_rate_index[LINK_QUAL_AC_NUM]; | 1913 | u8 start_rate_index[LINK_QUAL_AC_NUM]; |
1914 | } __attribute__ ((packed)); | 1914 | } __attribute__ ((packed)); |
1915 | 1915 | ||
1916 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ | ||
1917 | #define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535) | ||
1918 | #define LINK_QUAL_AGG_TIME_LIMIT_MIN (0) | ||
1919 | |||
1920 | #define LINK_QUAL_AGG_DISABLE_START_DEF (3) | ||
1921 | #define LINK_QUAL_AGG_DISABLE_START_MAX (255) | ||
1922 | #define LINK_QUAL_AGG_DISABLE_START_MIN (0) | ||
1923 | |||
1924 | #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) | ||
1925 | #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64) | ||
1926 | #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) | ||
1927 | |||
1916 | /** | 1928 | /** |
1917 | * struct iwl_link_qual_agg_params | 1929 | * struct iwl_link_qual_agg_params |
1918 | * | 1930 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e93ddb74457e..51cae4ec26a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1389,7 +1389,7 @@ int iwl_init_drv(struct iwl_priv *priv) | |||
1389 | mutex_init(&priv->mutex); | 1389 | mutex_init(&priv->mutex); |
1390 | 1390 | ||
1391 | /* Clear the driver's (not device's) station table */ | 1391 | /* Clear the driver's (not device's) station table */ |
1392 | priv->cfg->ops->smgmt->clear_station_table(priv); | 1392 | iwl_clear_stations_table(priv); |
1393 | 1393 | ||
1394 | priv->data_retry_limit = -1; | 1394 | priv->data_retry_limit = -1; |
1395 | priv->ieee_channels = NULL; | 1395 | priv->ieee_channels = NULL; |
@@ -1704,8 +1704,9 @@ static irqreturn_t iwl_isr(int irq, void *data) | |||
1704 | { | 1704 | { |
1705 | struct iwl_priv *priv = data; | 1705 | struct iwl_priv *priv = data; |
1706 | u32 inta, inta_mask; | 1706 | u32 inta, inta_mask; |
1707 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1707 | u32 inta_fh; | 1708 | u32 inta_fh; |
1708 | 1709 | #endif | |
1709 | if (!priv) | 1710 | if (!priv) |
1710 | return IRQ_NONE; | 1711 | return IRQ_NONE; |
1711 | 1712 | ||
@@ -2679,19 +2680,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) | |||
2679 | 2680 | ||
2680 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 2681 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
2681 | 2682 | ||
2682 | priv->cfg->ops->smgmt->clear_station_table(priv); | 2683 | iwl_clear_stations_table(priv); |
2683 | 2684 | ||
2684 | /* dont commit rxon if rf-kill is on*/ | 2685 | /* dont commit rxon if rf-kill is on*/ |
2685 | if (!iwl_is_ready_rf(priv)) | 2686 | if (!iwl_is_ready_rf(priv)) |
2686 | return -EAGAIN; | 2687 | return -EAGAIN; |
2687 | 2688 | ||
2688 | cancel_delayed_work(&priv->scan_check); | ||
2689 | if (iwl_scan_cancel_timeout(priv, 100)) { | ||
2690 | IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); | ||
2691 | IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); | ||
2692 | return -EAGAIN; | ||
2693 | } | ||
2694 | |||
2695 | iwlcore_commit_rxon(priv); | 2689 | iwlcore_commit_rxon(priv); |
2696 | 2690 | ||
2697 | return 0; | 2691 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 87df1b767941..b52d0fb16060 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -83,15 +83,6 @@ struct iwl_cmd; | |||
83 | #define IWL_SKU_A 0x2 | 83 | #define IWL_SKU_A 0x2 |
84 | #define IWL_SKU_N 0x8 | 84 | #define IWL_SKU_N 0x8 |
85 | 85 | ||
86 | struct iwl_station_mgmt_ops { | ||
87 | u8 (*add_station)(struct iwl_priv *priv, const u8 *addr, | ||
88 | int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); | ||
89 | int (*remove_station)(struct iwl_priv *priv, const u8 *addr, | ||
90 | int is_ap); | ||
91 | u8 (*find_station)(struct iwl_priv *priv, const u8 *addr); | ||
92 | void (*clear_station_table)(struct iwl_priv *priv); | ||
93 | }; | ||
94 | |||
95 | struct iwl_hcmd_ops { | 86 | struct iwl_hcmd_ops { |
96 | int (*rxon_assoc)(struct iwl_priv *priv); | 87 | int (*rxon_assoc)(struct iwl_priv *priv); |
97 | int (*commit_rxon)(struct iwl_priv *priv); | 88 | int (*commit_rxon)(struct iwl_priv *priv); |
@@ -183,7 +174,6 @@ struct iwl_ops { | |||
183 | const struct iwl_lib_ops *lib; | 174 | const struct iwl_lib_ops *lib; |
184 | const struct iwl_hcmd_ops *hcmd; | 175 | const struct iwl_hcmd_ops *hcmd; |
185 | const struct iwl_hcmd_utils_ops *utils; | 176 | const struct iwl_hcmd_utils_ops *utils; |
186 | const struct iwl_station_mgmt_ops *smgmt; | ||
187 | }; | 177 | }; |
188 | 178 | ||
189 | struct iwl_mod_params { | 179 | struct iwl_mod_params { |
@@ -192,7 +182,7 @@ struct iwl_mod_params { | |||
192 | int disable_hw_scan; /* def: 0 = use h/w scan */ | 182 | int disable_hw_scan; /* def: 0 = use h/w scan */ |
193 | int num_of_queues; /* def: HW dependent */ | 183 | int num_of_queues; /* def: HW dependent */ |
194 | int num_of_ampdu_queues;/* def: HW dependent */ | 184 | int num_of_ampdu_queues;/* def: HW dependent */ |
195 | int disable_11n; /* def: 0 = disable 11n capabilities */ | 185 | int disable_11n; /* def: 0 = 11n capabilities enabled */ |
196 | int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ | 186 | int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ |
197 | int antenna; /* def: 0 = both antennas (use diversity) */ | 187 | int antenna; /* def: 0 = both antennas (use diversity) */ |
198 | int restart_fw; /* def: 1 = restart firmware */ | 188 | int restart_fw; /* def: 1 = restart firmware */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2dafc26fb6a8..28c39cf8b126 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -70,7 +70,6 @@ extern struct iwl_ops iwl5000_ops; | |||
70 | extern struct iwl_lib_ops iwl5000_lib; | 70 | extern struct iwl_lib_ops iwl5000_lib; |
71 | extern struct iwl_hcmd_ops iwl5000_hcmd; | 71 | extern struct iwl_hcmd_ops iwl5000_hcmd; |
72 | extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; | 72 | extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; |
73 | extern struct iwl_station_mgmt_ops iwl5000_station_mgmt; | ||
74 | 73 | ||
75 | /* shared functions from iwl-5000.c */ | 74 | /* shared functions from iwl-5000.c */ |
76 | extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len); | 75 | extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len); |
@@ -290,11 +289,11 @@ struct iwl_frame { | |||
290 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) | 289 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) |
291 | 290 | ||
292 | enum { | 291 | enum { |
293 | /* CMD_SIZE_NORMAL = 0, */ | 292 | CMD_SYNC = 0, |
293 | CMD_SIZE_NORMAL = 0, | ||
294 | CMD_NO_SKB = 0, | ||
294 | CMD_SIZE_HUGE = (1 << 0), | 295 | CMD_SIZE_HUGE = (1 << 0), |
295 | /* CMD_SYNC = 0, */ | ||
296 | CMD_ASYNC = (1 << 1), | 296 | CMD_ASYNC = (1 << 1), |
297 | /* CMD_NO_SKB = 0, */ | ||
298 | CMD_WANT_SKB = (1 << 2), | 297 | CMD_WANT_SKB = (1 << 2), |
299 | }; | 298 | }; |
300 | 299 | ||
@@ -1119,8 +1118,6 @@ struct iwl_priv { | |||
1119 | 1118 | ||
1120 | struct iwl3945_notif_statistics statistics_39; | 1119 | struct iwl3945_notif_statistics statistics_39; |
1121 | 1120 | ||
1122 | struct iwl3945_station_entry stations_39[IWL_STATION_COUNT]; | ||
1123 | |||
1124 | u32 sta_supp_rates; | 1121 | u32 sta_supp_rates; |
1125 | }; /*iwl_priv */ | 1122 | }; /*iwl_priv */ |
1126 | 1123 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index cefa501e5971..7d7554a2f341 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -240,13 +240,11 @@ static int iwl_init_otp_access(struct iwl_priv *priv) | |||
240 | if (ret < 0) | 240 | if (ret < 0) |
241 | IWL_ERR(priv, "Time out access OTP\n"); | 241 | IWL_ERR(priv, "Time out access OTP\n"); |
242 | else { | 242 | else { |
243 | if (!ret) { | 243 | iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, |
244 | iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, | 244 | APMG_PS_CTRL_VAL_RESET_REQ); |
245 | APMG_PS_CTRL_VAL_RESET_REQ); | 245 | udelay(5); |
246 | udelay(5); | 246 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, |
247 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, | 247 | APMG_PS_CTRL_VAL_RESET_REQ); |
248 | APMG_PS_CTRL_VAL_RESET_REQ); | ||
249 | } | ||
250 | } | 248 | } |
251 | return ret; | 249 | return ret; |
252 | } | 250 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 19680f72087f..5e64252f80f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c | |||
@@ -176,10 +176,6 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id) | |||
176 | static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) | 176 | static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) |
177 | { | 177 | { |
178 | priv->allow_blinking = 0; | 178 | priv->allow_blinking = 0; |
179 | if (iwl_is_rfkill(priv)) | ||
180 | iwl4965_led_off_reg(priv, led_id); | ||
181 | else | ||
182 | iwl4965_led_on_reg(priv, led_id); | ||
183 | 179 | ||
184 | return 0; | 180 | return 0; |
185 | } | 181 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 65605ad44e4b..13149936fd26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c | |||
@@ -36,42 +36,37 @@ | |||
36 | #include "iwl-core.h" | 36 | #include "iwl-core.h" |
37 | 37 | ||
38 | /* software rf-kill from user */ | 38 | /* software rf-kill from user */ |
39 | static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) | 39 | static int iwl_rfkill_soft_rf_kill(void *data, bool blocked) |
40 | { | 40 | { |
41 | struct iwl_priv *priv = data; | 41 | struct iwl_priv *priv = data; |
42 | int err = 0; | ||
43 | 42 | ||
44 | if (!priv->rfkill) | 43 | if (!priv->rfkill) |
45 | return 0; | 44 | return -EINVAL; |
46 | 45 | ||
47 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 46 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
48 | return 0; | 47 | return 0; |
49 | 48 | ||
50 | IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state); | 49 | IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked); |
50 | |||
51 | mutex_lock(&priv->mutex); | 51 | mutex_lock(&priv->mutex); |
52 | 52 | ||
53 | switch (state) { | 53 | if (iwl_is_rfkill_hw(priv)) |
54 | case RFKILL_STATE_UNBLOCKED: | 54 | goto out_unlock; |
55 | if (iwl_is_rfkill_hw(priv)) { | 55 | |
56 | err = -EBUSY; | 56 | if (!blocked) |
57 | goto out_unlock; | ||
58 | } | ||
59 | iwl_radio_kill_sw_enable_radio(priv); | 57 | iwl_radio_kill_sw_enable_radio(priv); |
60 | break; | 58 | else |
61 | case RFKILL_STATE_SOFT_BLOCKED: | ||
62 | iwl_radio_kill_sw_disable_radio(priv); | 59 | iwl_radio_kill_sw_disable_radio(priv); |
63 | break; | 60 | |
64 | default: | ||
65 | IWL_WARN(priv, "we received unexpected RFKILL state %d\n", | ||
66 | state); | ||
67 | break; | ||
68 | } | ||
69 | out_unlock: | 61 | out_unlock: |
70 | mutex_unlock(&priv->mutex); | 62 | mutex_unlock(&priv->mutex); |
71 | 63 | return 0; | |
72 | return err; | ||
73 | } | 64 | } |
74 | 65 | ||
66 | static const struct rfkill_ops iwl_rfkill_ops = { | ||
67 | .set_block = iwl_rfkill_soft_rf_kill, | ||
68 | }; | ||
69 | |||
75 | int iwl_rfkill_init(struct iwl_priv *priv) | 70 | int iwl_rfkill_init(struct iwl_priv *priv) |
76 | { | 71 | { |
77 | struct device *device = wiphy_dev(priv->hw->wiphy); | 72 | struct device *device = wiphy_dev(priv->hw->wiphy); |
@@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv) | |||
80 | BUG_ON(device == NULL); | 75 | BUG_ON(device == NULL); |
81 | 76 | ||
82 | IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); | 77 | IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); |
83 | priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); | 78 | priv->rfkill = rfkill_alloc(priv->cfg->name, |
79 | device, | ||
80 | RFKILL_TYPE_WLAN, | ||
81 | &iwl_rfkill_ops, priv); | ||
84 | if (!priv->rfkill) { | 82 | if (!priv->rfkill) { |
85 | IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); | 83 | IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); |
86 | ret = -ENOMEM; | 84 | ret = -ENOMEM; |
87 | goto error; | 85 | goto error; |
88 | } | 86 | } |
89 | 87 | ||
90 | priv->rfkill->name = priv->cfg->name; | ||
91 | priv->rfkill->data = priv; | ||
92 | priv->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
93 | priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; | ||
94 | |||
95 | priv->rfkill->dev.class->suspend = NULL; | ||
96 | priv->rfkill->dev.class->resume = NULL; | ||
97 | |||
98 | ret = rfkill_register(priv->rfkill); | 88 | ret = rfkill_register(priv->rfkill); |
99 | if (ret) { | 89 | if (ret) { |
100 | IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); | 90 | IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); |
@@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv) | |||
102 | } | 92 | } |
103 | 93 | ||
104 | IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); | 94 | IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); |
105 | return ret; | 95 | return 0; |
106 | 96 | ||
107 | free_rfkill: | 97 | free_rfkill: |
108 | if (priv->rfkill != NULL) | 98 | rfkill_destroy(priv->rfkill); |
109 | rfkill_free(priv->rfkill); | ||
110 | priv->rfkill = NULL; | 99 | priv->rfkill = NULL; |
111 | 100 | ||
112 | error: | 101 | error: |
@@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init); | |||
118 | void iwl_rfkill_unregister(struct iwl_priv *priv) | 107 | void iwl_rfkill_unregister(struct iwl_priv *priv) |
119 | { | 108 | { |
120 | 109 | ||
121 | if (priv->rfkill) | 110 | if (priv->rfkill) { |
122 | rfkill_unregister(priv->rfkill); | 111 | rfkill_unregister(priv->rfkill); |
112 | rfkill_destroy(priv->rfkill); | ||
113 | } | ||
123 | 114 | ||
124 | priv->rfkill = NULL; | 115 | priv->rfkill = NULL; |
125 | } | 116 | } |
@@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) | |||
131 | if (!priv->rfkill) | 122 | if (!priv->rfkill) |
132 | return; | 123 | return; |
133 | 124 | ||
134 | if (iwl_is_rfkill_hw(priv)) { | 125 | if (rfkill_set_hw_state(priv->rfkill, |
135 | rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); | 126 | !!iwl_is_rfkill_hw(priv))) |
136 | return; | 127 | iwl_radio_kill_sw_disable_radio(priv); |
137 | } | ||
138 | |||
139 | if (!iwl_is_rfkill_sw(priv)) | ||
140 | rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); | ||
141 | else | 128 | else |
142 | rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); | 129 | iwl_radio_kill_sw_enable_radio(priv); |
143 | } | 130 | } |
144 | EXPORT_SYMBOL(iwl_rfkill_set_hw_state); | 131 | EXPORT_SYMBOL(iwl_rfkill_set_hw_state); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 0eb939c40ac1..2addf735b193 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | |||
75 | return IWL_AP_ID; | 75 | return IWL_AP_ID; |
76 | } else { | 76 | } else { |
77 | u8 *da = ieee80211_get_DA(hdr); | 77 | u8 *da = ieee80211_get_DA(hdr); |
78 | return priv->cfg->ops->smgmt->find_station(priv, da); | 78 | return iwl_find_station(priv, da); |
79 | } | 79 | } |
80 | } | 80 | } |
81 | EXPORT_SYMBOL(iwl_get_ra_sta_id); | 81 | EXPORT_SYMBOL(iwl_get_ra_sta_id); |
@@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) | |||
86 | 86 | ||
87 | spin_lock_irqsave(&priv->sta_lock, flags); | 87 | spin_lock_irqsave(&priv->sta_lock, flags); |
88 | 88 | ||
89 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && | 89 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) |
90 | !(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE)) | ||
91 | IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", | 90 | IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", |
92 | sta_id); | 91 | sta_id); |
93 | 92 | ||
@@ -228,15 +227,16 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | |||
228 | } | 227 | } |
229 | 228 | ||
230 | /** | 229 | /** |
231 | * iwl_add_station_flags - Add station to tables in driver and device | 230 | * iwl_add_station - Add station to tables in driver and device |
232 | */ | 231 | */ |
233 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | 232 | u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, |
234 | u8 flags, struct ieee80211_sta_ht_cap *ht_info) | 233 | struct ieee80211_sta_ht_cap *ht_info) |
235 | { | 234 | { |
236 | int i; | ||
237 | int sta_id = IWL_INVALID_STATION; | ||
238 | struct iwl_station_entry *station; | 235 | struct iwl_station_entry *station; |
239 | unsigned long flags_spin; | 236 | unsigned long flags_spin; |
237 | int i; | ||
238 | int sta_id = IWL_INVALID_STATION; | ||
239 | u16 rate; | ||
240 | 240 | ||
241 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | 241 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
242 | if (is_ap) | 242 | if (is_ap) |
@@ -288,6 +288,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | |||
288 | priv->iw_mode != NL80211_IFTYPE_ADHOC) | 288 | priv->iw_mode != NL80211_IFTYPE_ADHOC) |
289 | iwl_set_ht_add_station(priv, sta_id, ht_info); | 289 | iwl_set_ht_add_station(priv, sta_id, ht_info); |
290 | 290 | ||
291 | /* 3945 only */ | ||
292 | rate = (priv->band == IEEE80211_BAND_5GHZ) ? | ||
293 | IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; | ||
294 | /* Turn on both antennas for the station... */ | ||
295 | station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); | ||
296 | |||
291 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 297 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
292 | 298 | ||
293 | /* Add station to device's station table */ | 299 | /* Add station to device's station table */ |
@@ -295,12 +301,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | |||
295 | return sta_id; | 301 | return sta_id; |
296 | 302 | ||
297 | } | 303 | } |
298 | EXPORT_SYMBOL(iwl_add_station_flags); | 304 | EXPORT_SYMBOL(iwl_add_station); |
299 | 305 | ||
300 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) | 306 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) |
301 | { | 307 | { |
302 | unsigned long flags; | 308 | unsigned long flags; |
303 | u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 309 | u8 sta_id = iwl_find_station(priv, addr); |
304 | 310 | ||
305 | BUG_ON(sta_id == IWL_INVALID_STATION); | 311 | BUG_ON(sta_id == IWL_INVALID_STATION); |
306 | 312 | ||
@@ -408,7 +414,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | |||
408 | /** | 414 | /** |
409 | * iwl_remove_station - Remove driver's knowledge of station. | 415 | * iwl_remove_station - Remove driver's knowledge of station. |
410 | */ | 416 | */ |
411 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | 417 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) |
412 | { | 418 | { |
413 | int sta_id = IWL_INVALID_STATION; | 419 | int sta_id = IWL_INVALID_STATION; |
414 | int i, ret = -EINVAL; | 420 | int i, ret = -EINVAL; |
@@ -767,7 +773,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, | |||
767 | unsigned long flags; | 773 | unsigned long flags; |
768 | int i; | 774 | int i; |
769 | 775 | ||
770 | sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 776 | sta_id = iwl_find_station(priv, addr); |
771 | if (sta_id == IWL_INVALID_STATION) { | 777 | if (sta_id == IWL_INVALID_STATION) { |
772 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", | 778 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", |
773 | addr); | 779 | addr); |
@@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd); | |||
946 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | 952 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, |
947 | * which requires station table entry to exist). | 953 | * which requires station table entry to exist). |
948 | */ | 954 | */ |
949 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) | 955 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) |
950 | { | 956 | { |
951 | int i, r; | 957 | int i, r; |
952 | struct iwl_link_quality_cmd link_cmd = { | 958 | struct iwl_link_quality_cmd link_cmd = { |
@@ -979,8 +985,9 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) | |||
979 | link_cmd.general_params.single_stream_ant_msk = | 985 | link_cmd.general_params.single_stream_ant_msk = |
980 | first_antenna(priv->hw_params.valid_tx_ant); | 986 | first_antenna(priv->hw_params.valid_tx_ant); |
981 | link_cmd.general_params.dual_stream_ant_msk = 3; | 987 | link_cmd.general_params.dual_stream_ant_msk = 3; |
982 | link_cmd.agg_params.agg_dis_start_th = 3; | 988 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; |
983 | link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); | 989 | link_cmd.agg_params.agg_time_limit = |
990 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
984 | 991 | ||
985 | /* Update the rate scaling for control frame Tx to AP */ | 992 | /* Update the rate scaling for control frame Tx to AP */ |
986 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | 993 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; |
@@ -995,7 +1002,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) | |||
995 | * there is only one AP station with id= IWL_AP_ID | 1002 | * there is only one AP station with id= IWL_AP_ID |
996 | * NOTE: mutex must be held before calling this function | 1003 | * NOTE: mutex must be held before calling this function |
997 | */ | 1004 | */ |
998 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | 1005 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) |
999 | { | 1006 | { |
1000 | struct ieee80211_sta *sta; | 1007 | struct ieee80211_sta *sta; |
1001 | struct ieee80211_sta_ht_cap ht_config; | 1008 | struct ieee80211_sta_ht_cap ht_config; |
@@ -1020,8 +1027,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | |||
1020 | rcu_read_unlock(); | 1027 | rcu_read_unlock(); |
1021 | } | 1028 | } |
1022 | 1029 | ||
1023 | sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap, | 1030 | sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); |
1024 | 0, cur_ht_config); | ||
1025 | 1031 | ||
1026 | /* Set up default rate scaling table in device's station table */ | 1032 | /* Set up default rate scaling table in device's station table */ |
1027 | iwl_sta_init_lq(priv, addr, is_ap); | 1033 | iwl_sta_init_lq(priv, addr, is_ap); |
@@ -1054,7 +1060,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | |||
1054 | 1060 | ||
1055 | /* If we are an AP, then find the station, or use BCAST */ | 1061 | /* If we are an AP, then find the station, or use BCAST */ |
1056 | case NL80211_IFTYPE_AP: | 1062 | case NL80211_IFTYPE_AP: |
1057 | sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); | 1063 | sta_id = iwl_find_station(priv, hdr->addr1); |
1058 | if (sta_id != IWL_INVALID_STATION) | 1064 | if (sta_id != IWL_INVALID_STATION) |
1059 | return sta_id; | 1065 | return sta_id; |
1060 | return priv->hw_params.bcast_sta_id; | 1066 | return priv->hw_params.bcast_sta_id; |
@@ -1062,13 +1068,13 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | |||
1062 | /* If this frame is going out to an IBSS network, find the station, | 1068 | /* If this frame is going out to an IBSS network, find the station, |
1063 | * or create a new station table entry */ | 1069 | * or create a new station table entry */ |
1064 | case NL80211_IFTYPE_ADHOC: | 1070 | case NL80211_IFTYPE_ADHOC: |
1065 | sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); | 1071 | sta_id = iwl_find_station(priv, hdr->addr1); |
1066 | if (sta_id != IWL_INVALID_STATION) | 1072 | if (sta_id != IWL_INVALID_STATION) |
1067 | return sta_id; | 1073 | return sta_id; |
1068 | 1074 | ||
1069 | /* Create new station table entry */ | 1075 | /* Create new station table entry */ |
1070 | sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1, | 1076 | sta_id = iwl_add_station(priv, hdr->addr1, false, |
1071 | 0, CMD_ASYNC, NULL); | 1077 | CMD_ASYNC, NULL); |
1072 | 1078 | ||
1073 | if (sta_id != IWL_INVALID_STATION) | 1079 | if (sta_id != IWL_INVALID_STATION) |
1074 | return sta_id; | 1080 | return sta_id; |
@@ -1111,7 +1117,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, | |||
1111 | unsigned long flags; | 1117 | unsigned long flags; |
1112 | int sta_id; | 1118 | int sta_id; |
1113 | 1119 | ||
1114 | sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 1120 | sta_id = iwl_find_station(priv, addr); |
1115 | if (sta_id == IWL_INVALID_STATION) | 1121 | if (sta_id == IWL_INVALID_STATION) |
1116 | return -ENXIO; | 1122 | return -ENXIO; |
1117 | 1123 | ||
@@ -1133,7 +1139,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) | |||
1133 | unsigned long flags; | 1139 | unsigned long flags; |
1134 | int sta_id; | 1140 | int sta_id; |
1135 | 1141 | ||
1136 | sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 1142 | sta_id = iwl_find_station(priv, addr); |
1137 | if (sta_id == IWL_INVALID_STATION) { | 1143 | if (sta_id == IWL_INVALID_STATION) { |
1138 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | 1144 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); |
1139 | return -ENXIO; | 1145 | return -ENXIO; |
@@ -1168,7 +1174,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) | |||
1168 | void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) | 1174 | void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) |
1169 | { | 1175 | { |
1170 | /* FIXME: need locking over ps_status ??? */ | 1176 | /* FIXME: need locking over ps_status ??? */ |
1171 | u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 1177 | u8 sta_id = iwl_find_station(priv, addr); |
1172 | 1178 | ||
1173 | if (sta_id != IWL_INVALID_STATION) { | 1179 | if (sta_id != IWL_INVALID_STATION) { |
1174 | u8 sta_awake = priv->stations[sta_id]. | 1180 | u8 sta_awake = priv->stations[sta_id]. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 59a586b6b56c..6deebade6361 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h | |||
@@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv, | |||
51 | struct ieee80211_key_conf *keyconf, | 51 | struct ieee80211_key_conf *keyconf, |
52 | const u8 *addr, u32 iv32, u16 *phase1key); | 52 | const u8 *addr, u32 iv32, u16 *phase1key); |
53 | 53 | ||
54 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); | 54 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); |
55 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); | 55 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); |
56 | void iwl_clear_stations_table(struct iwl_priv *priv); | 56 | void iwl_clear_stations_table(struct iwl_priv *priv); |
57 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); | 57 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); |
58 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); | 58 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); |
59 | int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); | 59 | int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); |
60 | int iwl_send_add_sta(struct iwl_priv *priv, | 60 | int iwl_send_add_sta(struct iwl_priv *priv, |
61 | struct iwl_addsta_cmd *sta, u8 flags); | 61 | struct iwl_addsta_cmd *sta, u8 flags); |
62 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, | 62 | u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, |
63 | int is_ap, u8 flags, | ||
64 | struct ieee80211_sta_ht_cap *ht_info); | 63 | struct ieee80211_sta_ht_cap *ht_info); |
65 | void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); | 64 | void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); |
66 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, | 65 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5c10b87d0336..92fa1a39c446 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = { | |||
95 | /* the rest are 0 by default */ | 95 | /* the rest are 0 by default */ |
96 | }; | 96 | }; |
97 | 97 | ||
98 | /*************** STATION TABLE MANAGEMENT **** | ||
99 | * mac80211 should be examined to determine if sta_info is duplicating | ||
100 | * the functionality provided here | ||
101 | */ | ||
102 | |||
103 | /**************************************************************/ | ||
104 | #if 0 /* temporary disable till we add real remove station */ | ||
105 | /** | ||
106 | * iwl3945_remove_station - Remove driver's knowledge of station. | ||
107 | * | ||
108 | * NOTE: This does not remove station from device's station table. | ||
109 | */ | ||
110 | static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||
111 | { | ||
112 | int index = IWL_INVALID_STATION; | ||
113 | int i; | ||
114 | unsigned long flags; | ||
115 | |||
116 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
117 | |||
118 | if (is_ap) | ||
119 | index = IWL_AP_ID; | ||
120 | else if (is_broadcast_ether_addr(addr)) | ||
121 | index = priv->hw_params.bcast_sta_id; | ||
122 | else | ||
123 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) | ||
124 | if (priv->stations_39[i].used && | ||
125 | !compare_ether_addr(priv->stations_39[i].sta.sta.addr, | ||
126 | addr)) { | ||
127 | index = i; | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | if (unlikely(index == IWL_INVALID_STATION)) | ||
132 | goto out; | ||
133 | |||
134 | if (priv->stations_39[index].used) { | ||
135 | priv->stations_39[index].used = 0; | ||
136 | priv->num_stations--; | ||
137 | } | ||
138 | |||
139 | BUG_ON(priv->num_stations < 0); | ||
140 | |||
141 | out: | ||
142 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
143 | return 0; | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | /** | ||
148 | * iwl3945_clear_stations_table - Clear the driver's station table | ||
149 | * | ||
150 | * NOTE: This does not clear or otherwise alter the device's station table. | ||
151 | */ | ||
152 | void iwl3945_clear_stations_table(struct iwl_priv *priv) | ||
153 | { | ||
154 | unsigned long flags; | ||
155 | |||
156 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
157 | |||
158 | priv->num_stations = 0; | ||
159 | memset(priv->stations_39, 0, sizeof(priv->stations_39)); | ||
160 | |||
161 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * iwl3945_add_station - Add station to station tables in driver and device | ||
166 | */ | ||
167 | u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info) | ||
168 | { | ||
169 | int i; | ||
170 | int index = IWL_INVALID_STATION; | ||
171 | struct iwl3945_station_entry *station; | ||
172 | unsigned long flags_spin; | ||
173 | u8 rate; | ||
174 | |||
175 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
176 | if (is_ap) | ||
177 | index = IWL_AP_ID; | ||
178 | else if (is_broadcast_ether_addr(addr)) | ||
179 | index = priv->hw_params.bcast_sta_id; | ||
180 | else | ||
181 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { | ||
182 | if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr, | ||
183 | addr)) { | ||
184 | index = i; | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | if (!priv->stations_39[i].used && | ||
189 | index == IWL_INVALID_STATION) | ||
190 | index = i; | ||
191 | } | ||
192 | |||
193 | /* These two conditions has the same outcome but keep them separate | ||
194 | since they have different meaning */ | ||
195 | if (unlikely(index == IWL_INVALID_STATION)) { | ||
196 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
197 | return index; | ||
198 | } | ||
199 | |||
200 | if (priv->stations_39[index].used && | ||
201 | !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) { | ||
202 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
203 | return index; | ||
204 | } | ||
205 | |||
206 | IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr); | ||
207 | station = &priv->stations_39[index]; | ||
208 | station->used = 1; | ||
209 | priv->num_stations++; | ||
210 | |||
211 | /* Set up the REPLY_ADD_STA command to send to device */ | ||
212 | memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); | ||
213 | memcpy(station->sta.sta.addr, addr, ETH_ALEN); | ||
214 | station->sta.mode = 0; | ||
215 | station->sta.sta.sta_id = index; | ||
216 | station->sta.station_flags = 0; | ||
217 | |||
218 | if (priv->band == IEEE80211_BAND_5GHZ) | ||
219 | rate = IWL_RATE_6M_PLCP; | ||
220 | else | ||
221 | rate = IWL_RATE_1M_PLCP; | ||
222 | |||
223 | /* Turn on both antennas for the station... */ | ||
224 | station->sta.rate_n_flags = | ||
225 | iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); | ||
226 | |||
227 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
228 | |||
229 | /* Add station to device's station table */ | ||
230 | iwl_send_add_sta(priv, | ||
231 | (struct iwl_addsta_cmd *)&station->sta, flags); | ||
232 | return index; | ||
233 | |||
234 | } | ||
235 | |||
236 | /** | 98 | /** |
237 | * iwl3945_get_antenna_flags - Get antenna flags for RXON command | 99 | * iwl3945_get_antenna_flags - Get antenna flags for RXON command |
238 | * @priv: eeprom and antenna fields are used to determine antenna flags | 100 | * @priv: eeprom and antenna fields are used to determine antenna flags |
@@ -289,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
289 | key_flags &= ~STA_KEY_FLG_INVALID; | 151 | key_flags &= ~STA_KEY_FLG_INVALID; |
290 | 152 | ||
291 | spin_lock_irqsave(&priv->sta_lock, flags); | 153 | spin_lock_irqsave(&priv->sta_lock, flags); |
292 | priv->stations_39[sta_id].keyinfo.alg = keyconf->alg; | 154 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; |
293 | priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen; | 155 | priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; |
294 | memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key, | 156 | memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, |
295 | keyconf->keylen); | 157 | keyconf->keylen); |
296 | 158 | ||
297 | memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, | 159 | memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, |
298 | keyconf->keylen); | 160 | keyconf->keylen); |
299 | 161 | ||
300 | if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | 162 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) |
301 | == STA_KEY_FLG_NO_ENC) | 163 | == STA_KEY_FLG_NO_ENC) |
302 | priv->stations_39[sta_id].sta.key.key_offset = | 164 | priv->stations[sta_id].sta.key.key_offset = |
303 | iwl_get_free_ucode_key_index(priv); | 165 | iwl_get_free_ucode_key_index(priv); |
304 | /* else, we are overriding an existing key => no need to allocated room | 166 | /* else, we are overriding an existing key => no need to allocated room |
305 | * in uCode. */ | 167 | * in uCode. */ |
306 | 168 | ||
307 | WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, | 169 | WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, |
308 | "no space for a new key"); | 170 | "no space for a new key"); |
309 | 171 | ||
310 | priv->stations_39[sta_id].sta.key.key_flags = key_flags; | 172 | priv->stations[sta_id].sta.key.key_flags = key_flags; |
311 | priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 173 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
312 | priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 174 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
313 | 175 | ||
314 | IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); | 176 | IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); |
315 | 177 | ||
316 | ret = iwl_send_add_sta(priv, | 178 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); |
317 | (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC); | ||
318 | 179 | ||
319 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 180 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
320 | 181 | ||
@@ -340,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) | |||
340 | unsigned long flags; | 201 | unsigned long flags; |
341 | 202 | ||
342 | spin_lock_irqsave(&priv->sta_lock, flags); | 203 | spin_lock_irqsave(&priv->sta_lock, flags); |
343 | memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); | 204 | memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); |
344 | memset(&priv->stations_39[sta_id].sta.key, 0, | 205 | memset(&priv->stations[sta_id].sta.key, 0, |
345 | sizeof(struct iwl4965_keyinfo)); | 206 | sizeof(struct iwl4965_keyinfo)); |
346 | priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; | 207 | priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; |
347 | priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 208 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
348 | priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 209 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
349 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 210 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
350 | 211 | ||
351 | IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); | 212 | IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); |
352 | iwl_send_add_sta(priv, | 213 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); |
353 | (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0); | ||
354 | return 0; | 214 | return 0; |
355 | } | 215 | } |
356 | 216 | ||
@@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, | |||
578 | int sta_id) | 438 | int sta_id) |
579 | { | 439 | { |
580 | struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; | 440 | struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; |
581 | struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo; | 441 | struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; |
582 | 442 | ||
583 | switch (keyinfo->alg) { | 443 | switch (keyinfo->alg) { |
584 | case ALG_CCMP: | 444 | case ALG_CCMP: |
@@ -753,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
753 | if (ieee80211_is_data_qos(fc)) { | 613 | if (ieee80211_is_data_qos(fc)) { |
754 | qc = ieee80211_get_qos_ctl(hdr); | 614 | qc = ieee80211_get_qos_ctl(hdr); |
755 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | 615 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
756 | seq_number = priv->stations_39[sta_id].tid[tid].seq_number & | 616 | seq_number = priv->stations[sta_id].tid[tid].seq_number & |
757 | IEEE80211_SCTL_SEQ; | 617 | IEEE80211_SCTL_SEQ; |
758 | hdr->seq_ctrl = cpu_to_le16(seq_number) | | 618 | hdr->seq_ctrl = cpu_to_le16(seq_number) | |
759 | (hdr->seq_ctrl & | 619 | (hdr->seq_ctrl & |
@@ -813,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
813 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | 673 | if (!ieee80211_has_morefrags(hdr->frame_control)) { |
814 | txq->need_update = 1; | 674 | txq->need_update = 1; |
815 | if (qc) | 675 | if (qc) |
816 | priv->stations_39[sta_id].tid[tid].seq_number = seq_number; | 676 | priv->stations[sta_id].tid[tid].seq_number = seq_number; |
817 | } else { | 677 | } else { |
818 | wait_write_ptr = 1; | 678 | wait_write_ptr = 1; |
819 | txq->need_update = 0; | 679 | txq->need_update = 0; |
@@ -1316,7 +1176,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) | |||
1316 | 1176 | ||
1317 | /* If we've added more space for the firmware to place data, tell it. | 1177 | /* If we've added more space for the firmware to place data, tell it. |
1318 | * Increment device's write pointer in multiples of 8. */ | 1178 | * Increment device's write pointer in multiples of 8. */ |
1319 | if ((write != (rxq->write & ~0x7)) | 1179 | if ((rxq->write_actual != (rxq->write & ~0x7)) |
1320 | || (abs(rxq->write - rxq->read) > 7)) { | 1180 | || (abs(rxq->write - rxq->read) > 7)) { |
1321 | spin_lock_irqsave(&rxq->lock, flags); | 1181 | spin_lock_irqsave(&rxq->lock, flags); |
1322 | rxq->need_update = 1; | 1182 | rxq->need_update = 1; |
@@ -1337,7 +1197,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) | |||
1337 | * Also restock the Rx queue via iwl3945_rx_queue_restock. | 1197 | * Also restock the Rx queue via iwl3945_rx_queue_restock. |
1338 | * This is called as a scheduled work item (except for during initialization) | 1198 | * This is called as a scheduled work item (except for during initialization) |
1339 | */ | 1199 | */ |
1340 | static void iwl3945_rx_allocate(struct iwl_priv *priv) | 1200 | static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) |
1341 | { | 1201 | { |
1342 | struct iwl_rx_queue *rxq = &priv->rxq; | 1202 | struct iwl_rx_queue *rxq = &priv->rxq; |
1343 | struct list_head *element; | 1203 | struct list_head *element; |
@@ -1360,7 +1220,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) | |||
1360 | /* Alloc a new receive buffer */ | 1220 | /* Alloc a new receive buffer */ |
1361 | rxb->skb = | 1221 | rxb->skb = |
1362 | alloc_skb(priv->hw_params.rx_buf_size, | 1222 | alloc_skb(priv->hw_params.rx_buf_size, |
1363 | GFP_KERNEL); | 1223 | priority); |
1364 | if (!rxb->skb) { | 1224 | if (!rxb->skb) { |
1365 | if (net_ratelimit()) | 1225 | if (net_ratelimit()) |
1366 | IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); | 1226 | IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); |
@@ -1419,6 +1279,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
1419 | * not restocked the Rx queue with fresh buffers */ | 1279 | * not restocked the Rx queue with fresh buffers */ |
1420 | rxq->read = rxq->write = 0; | 1280 | rxq->read = rxq->write = 0; |
1421 | rxq->free_count = 0; | 1281 | rxq->free_count = 0; |
1282 | rxq->write_actual = 0; | ||
1422 | spin_unlock_irqrestore(&rxq->lock, flags); | 1283 | spin_unlock_irqrestore(&rxq->lock, flags); |
1423 | } | 1284 | } |
1424 | 1285 | ||
@@ -1427,13 +1288,21 @@ void iwl3945_rx_replenish(void *data) | |||
1427 | struct iwl_priv *priv = data; | 1288 | struct iwl_priv *priv = data; |
1428 | unsigned long flags; | 1289 | unsigned long flags; |
1429 | 1290 | ||
1430 | iwl3945_rx_allocate(priv); | 1291 | iwl3945_rx_allocate(priv, GFP_KERNEL); |
1431 | 1292 | ||
1432 | spin_lock_irqsave(&priv->lock, flags); | 1293 | spin_lock_irqsave(&priv->lock, flags); |
1433 | iwl3945_rx_queue_restock(priv); | 1294 | iwl3945_rx_queue_restock(priv); |
1434 | spin_unlock_irqrestore(&priv->lock, flags); | 1295 | spin_unlock_irqrestore(&priv->lock, flags); |
1435 | } | 1296 | } |
1436 | 1297 | ||
1298 | static void iwl3945_rx_replenish_now(struct iwl_priv *priv) | ||
1299 | { | ||
1300 | iwl3945_rx_allocate(priv, GFP_ATOMIC); | ||
1301 | |||
1302 | iwl3945_rx_queue_restock(priv); | ||
1303 | } | ||
1304 | |||
1305 | |||
1437 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. | 1306 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. |
1438 | * If an SKB has been detached, the POOL needs to have its SKB set to NULL | 1307 | * If an SKB has been detached, the POOL needs to have its SKB set to NULL |
1439 | * This free routine walks the list of POOL entries and if SKB is set to | 1308 | * This free routine walks the list of POOL entries and if SKB is set to |
@@ -1556,13 +1425,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) | |||
1556 | unsigned long flags; | 1425 | unsigned long flags; |
1557 | u8 fill_rx = 0; | 1426 | u8 fill_rx = 0; |
1558 | u32 count = 8; | 1427 | u32 count = 8; |
1428 | int total_empty = 0; | ||
1559 | 1429 | ||
1560 | /* uCode's read index (stored in shared DRAM) indicates the last Rx | 1430 | /* uCode's read index (stored in shared DRAM) indicates the last Rx |
1561 | * buffer that the driver may process (last buffer filled by ucode). */ | 1431 | * buffer that the driver may process (last buffer filled by ucode). */ |
1562 | r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; | 1432 | r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; |
1563 | i = rxq->read; | 1433 | i = rxq->read; |
1564 | 1434 | ||
1565 | if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) | 1435 | /* calculate total frames need to be restock after handling RX */ |
1436 | total_empty = r - priv->rxq.write_actual; | ||
1437 | if (total_empty < 0) | ||
1438 | total_empty += RX_QUEUE_SIZE; | ||
1439 | |||
1440 | if (total_empty > (RX_QUEUE_SIZE / 2)) | ||
1566 | fill_rx = 1; | 1441 | fill_rx = 1; |
1567 | /* Rx interrupt, but nothing sent from uCode */ | 1442 | /* Rx interrupt, but nothing sent from uCode */ |
1568 | if (i == r) | 1443 | if (i == r) |
@@ -1639,7 +1514,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) | |||
1639 | count++; | 1514 | count++; |
1640 | if (count >= 8) { | 1515 | if (count >= 8) { |
1641 | priv->rxq.read = i; | 1516 | priv->rxq.read = i; |
1642 | iwl3945_rx_queue_restock(priv); | 1517 | iwl3945_rx_replenish_now(priv); |
1643 | count = 0; | 1518 | count = 0; |
1644 | } | 1519 | } |
1645 | } | 1520 | } |
@@ -1647,7 +1522,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) | |||
1647 | 1522 | ||
1648 | /* Backtrack one entry */ | 1523 | /* Backtrack one entry */ |
1649 | priv->rxq.read = i; | 1524 | priv->rxq.read = i; |
1650 | iwl3945_rx_queue_restock(priv); | 1525 | if (fill_rx) |
1526 | iwl3945_rx_replenish_now(priv); | ||
1527 | else | ||
1528 | iwl3945_rx_queue_restock(priv); | ||
1651 | } | 1529 | } |
1652 | 1530 | ||
1653 | /* call this function to flush any scheduled tasklet */ | 1531 | /* call this function to flush any scheduled tasklet */ |
@@ -2589,7 +2467,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) | |||
2589 | goto restart; | 2467 | goto restart; |
2590 | } | 2468 | } |
2591 | 2469 | ||
2592 | priv->cfg->ops->smgmt->clear_station_table(priv); | 2470 | iwl_clear_stations_table(priv); |
2593 | 2471 | ||
2594 | rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); | 2472 | rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); |
2595 | IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); | 2473 | IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); |
@@ -2681,7 +2559,7 @@ static void __iwl3945_down(struct iwl_priv *priv) | |||
2681 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 2559 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
2682 | 2560 | ||
2683 | iwl3945_led_unregister(priv); | 2561 | iwl3945_led_unregister(priv); |
2684 | priv->cfg->ops->smgmt->clear_station_table(priv); | 2562 | iwl_clear_stations_table(priv); |
2685 | 2563 | ||
2686 | /* Unblock any waiting calls */ | 2564 | /* Unblock any waiting calls */ |
2687 | wake_up_interruptible_all(&priv->wait_command_queue); | 2565 | wake_up_interruptible_all(&priv->wait_command_queue); |
@@ -2833,7 +2711,7 @@ static int __iwl3945_up(struct iwl_priv *priv) | |||
2833 | 2711 | ||
2834 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 2712 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
2835 | 2713 | ||
2836 | priv->cfg->ops->smgmt->clear_station_table(priv); | 2714 | iwl_clear_stations_table(priv); |
2837 | 2715 | ||
2838 | /* load bootstrap state machine, | 2716 | /* load bootstrap state machine, |
2839 | * load bootstrap program into processor's memory, | 2717 | * load bootstrap program into processor's memory, |
@@ -3247,7 +3125,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) | |||
3247 | case NL80211_IFTYPE_ADHOC: | 3125 | case NL80211_IFTYPE_ADHOC: |
3248 | 3126 | ||
3249 | priv->assoc_id = 1; | 3127 | priv->assoc_id = 1; |
3250 | priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL); | 3128 | iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL); |
3251 | iwl3945_sync_sta(priv, IWL_STA_ID, | 3129 | iwl3945_sync_sta(priv, IWL_STA_ID, |
3252 | (priv->band == IEEE80211_BAND_5GHZ) ? | 3130 | (priv->band == IEEE80211_BAND_5GHZ) ? |
3253 | IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, | 3131 | IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, |
@@ -3438,7 +3316,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) | |||
3438 | /* restore RXON assoc */ | 3316 | /* restore RXON assoc */ |
3439 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; | 3317 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; |
3440 | iwlcore_commit_rxon(priv); | 3318 | iwlcore_commit_rxon(priv); |
3441 | priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL); | 3319 | iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL); |
3442 | } | 3320 | } |
3443 | iwl3945_send_beacon_cmd(priv); | 3321 | iwl3945_send_beacon_cmd(priv); |
3444 | 3322 | ||
@@ -3469,7 +3347,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3469 | static_key = !iwl_is_associated(priv); | 3347 | static_key = !iwl_is_associated(priv); |
3470 | 3348 | ||
3471 | if (!static_key) { | 3349 | if (!static_key) { |
3472 | sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); | 3350 | sta_id = iwl_find_station(priv, addr); |
3473 | if (sta_id == IWL_INVALID_STATION) { | 3351 | if (sta_id == IWL_INVALID_STATION) { |
3474 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", | 3352 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", |
3475 | addr); | 3353 | addr); |
@@ -4044,7 +3922,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) | |||
4044 | mutex_init(&priv->mutex); | 3922 | mutex_init(&priv->mutex); |
4045 | 3923 | ||
4046 | /* Clear the driver's (not device's) station table */ | 3924 | /* Clear the driver's (not device's) station table */ |
4047 | priv->cfg->ops->smgmt->clear_station_table(priv); | 3925 | iwl_clear_stations_table(priv); |
4048 | 3926 | ||
4049 | priv->data_retry_limit = -1; | 3927 | priv->data_retry_limit = -1; |
4050 | priv->ieee_channels = NULL; | 3928 | priv->ieee_channels = NULL; |
@@ -4407,7 +4285,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) | |||
4407 | iwl3945_hw_txq_ctx_free(priv); | 4285 | iwl3945_hw_txq_ctx_free(priv); |
4408 | 4286 | ||
4409 | iwl3945_unset_hw_params(priv); | 4287 | iwl3945_unset_hw_params(priv); |
4410 | priv->cfg->ops->smgmt->clear_station_table(priv); | 4288 | iwl_clear_stations_table(priv); |
4411 | 4289 | ||
4412 | /*netif_stop_queue(dev); */ | 4290 | /*netif_stop_queue(dev); */ |
4413 | flush_workqueue(priv->workqueue); | 4291 | flush_workqueue(priv->workqueue); |
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 41bd4b2b5411..1eccb6df46dd 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig | |||
@@ -1,10 +1,9 @@ | |||
1 | config IWM | 1 | config IWM |
2 | tristate "Intel Wireless Multicomm 3200 WiFi driver" | 2 | tristate "Intel Wireless Multicomm 3200 WiFi driver" |
3 | depends on MMC && WLAN_80211 && EXPERIMENTAL | 3 | depends on MMC && WLAN_80211 && EXPERIMENTAL |
4 | depends on CFG80211 | ||
4 | select WIRELESS_EXT | 5 | select WIRELESS_EXT |
5 | select CFG80211 | ||
6 | select FW_LOADER | 6 | select FW_LOADER |
7 | select RFKILL | ||
8 | 7 | ||
9 | config IWM_DEBUG | 8 | config IWM_DEBUG |
10 | bool "Enable full debugging output in iwmc3200wifi" | 9 | bool "Enable full debugging output in iwmc3200wifi" |
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile index 7cb415e5c11b..927f022545c1 100644 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ b/drivers/net/wireless/iwmc3200wifi/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_IWM) := iwmc3200wifi.o | 1 | obj-$(CONFIG_IWM) := iwmc3200wifi.o |
2 | iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o | 2 | iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o |
3 | iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o | 3 | iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o |
4 | 4 | ||
5 | iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o | 5 | iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o |
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 3256ad2c96ce..96f714e6e12b 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c | |||
@@ -268,7 +268,7 @@ static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
268 | 268 | ||
269 | iwm->conf.frag_threshold = wiphy->frag_threshold; | 269 | iwm->conf.frag_threshold = wiphy->frag_threshold; |
270 | 270 | ||
271 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | 271 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, |
272 | CFG_FRAG_THRESHOLD, | 272 | CFG_FRAG_THRESHOLD, |
273 | iwm->conf.frag_threshold); | 273 | iwm->conf.frag_threshold); |
274 | if (ret < 0) | 274 | if (ret < 0) |
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index db4ba0864730..ec1a15a5a0e4 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c | |||
@@ -72,7 +72,7 @@ static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, | |||
72 | } | 72 | } |
73 | 73 | ||
74 | if (fw->size < IWM_HDR_LEN) { | 74 | if (fw->size < IWM_HDR_LEN) { |
75 | IWM_ERR(iwm, "FW is too small (%d)\n", fw->size); | 75 | IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size); |
76 | return -EINVAL; | 76 | return -EINVAL; |
77 | } | 77 | } |
78 | 78 | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 3b29681792bb..635c16ee6186 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h | |||
@@ -343,8 +343,4 @@ int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, | |||
343 | struct iwm_wifi_cmd *cmd); | 343 | struct iwm_wifi_cmd *cmd); |
344 | void iwm_rx_free(struct iwm_priv *iwm); | 344 | void iwm_rx_free(struct iwm_priv *iwm); |
345 | 345 | ||
346 | /* RF Kill API */ | ||
347 | int iwm_rfkill_init(struct iwm_priv *iwm); | ||
348 | void iwm_rfkill_exit(struct iwm_priv *iwm); | ||
349 | |||
350 | #endif | 346 | #endif |
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index eec7201e91a8..68e2c3b6c7a1 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c | |||
@@ -136,17 +136,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, | |||
136 | 136 | ||
137 | wdev->netdev = ndev; | 137 | wdev->netdev = ndev; |
138 | 138 | ||
139 | ret = iwm_rfkill_init(iwm); | ||
140 | if (ret) { | ||
141 | dev_err(dev, "Failed to init rfkill\n"); | ||
142 | goto out_rfkill; | ||
143 | } | ||
144 | |||
145 | return iwm; | 139 | return iwm; |
146 | 140 | ||
147 | out_rfkill: | ||
148 | unregister_netdev(ndev); | ||
149 | |||
150 | out_ndev: | 141 | out_ndev: |
151 | free_netdev(ndev); | 142 | free_netdev(ndev); |
152 | 143 | ||
@@ -162,7 +153,6 @@ void iwm_if_free(struct iwm_priv *iwm) | |||
162 | if (!iwm_to_ndev(iwm)) | 153 | if (!iwm_to_ndev(iwm)) |
163 | return; | 154 | return; |
164 | 155 | ||
165 | iwm_rfkill_exit(iwm); | ||
166 | unregister_netdev(iwm_to_ndev(iwm)); | 156 | unregister_netdev(iwm_to_ndev(iwm)); |
167 | free_netdev(iwm_to_ndev(iwm)); | 157 | free_netdev(iwm_to_ndev(iwm)); |
168 | iwm_wdev_free(iwm); | 158 | iwm_wdev_free(iwm); |
diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c deleted file mode 100644 index 4ca8b495f82d..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/rfkill.c +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/rfkill.h> | ||
25 | |||
26 | #include "iwm.h" | ||
27 | |||
28 | static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) | ||
29 | { | ||
30 | struct iwm_priv *iwm = data; | ||
31 | |||
32 | switch (state) { | ||
33 | case RFKILL_STATE_UNBLOCKED: | ||
34 | if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) | ||
35 | return -EBUSY; | ||
36 | |||
37 | if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && | ||
38 | (iwm_to_ndev(iwm)->flags & IFF_UP)) | ||
39 | iwm_up(iwm); | ||
40 | |||
41 | break; | ||
42 | case RFKILL_STATE_SOFT_BLOCKED: | ||
43 | if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) | ||
44 | iwm_down(iwm); | ||
45 | |||
46 | break; | ||
47 | default: | ||
48 | break; | ||
49 | } | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | int iwm_rfkill_init(struct iwm_priv *iwm) | ||
55 | { | ||
56 | int ret; | ||
57 | |||
58 | iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); | ||
59 | if (!iwm->rfkill) { | ||
60 | IWM_ERR(iwm, "Unable to allocate rfkill device\n"); | ||
61 | return -ENOMEM; | ||
62 | } | ||
63 | |||
64 | iwm->rfkill->name = KBUILD_MODNAME; | ||
65 | iwm->rfkill->data = iwm; | ||
66 | iwm->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
67 | iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle; | ||
68 | |||
69 | ret = rfkill_register(iwm->rfkill); | ||
70 | if (ret) { | ||
71 | IWM_ERR(iwm, "Failed to register rfkill device\n"); | ||
72 | goto fail; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | fail: | ||
77 | rfkill_free(iwm->rfkill); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | void iwm_rfkill_exit(struct iwm_priv *iwm) | ||
82 | { | ||
83 | if (iwm->rfkill) | ||
84 | rfkill_unregister(iwm->rfkill); | ||
85 | |||
86 | rfkill_free(iwm->rfkill); | ||
87 | iwm->rfkill = NULL; | ||
88 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index edc0a0091058..b54da677b371 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c | |||
@@ -395,7 +395,7 @@ static struct iwm_if_ops if_sdio_ops = { | |||
395 | .debugfs_init = if_sdio_debugfs_init, | 395 | .debugfs_init = if_sdio_debugfs_init, |
396 | .debugfs_exit = if_sdio_debugfs_exit, | 396 | .debugfs_exit = if_sdio_debugfs_exit, |
397 | .umac_name = "iwmc3200wifi-umac-sdio.bin", | 397 | .umac_name = "iwmc3200wifi-umac-sdio.bin", |
398 | .calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin", | 398 | .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", |
399 | .lmac_name = "iwmc3200wifi-lmac-sdio.bin", | 399 | .lmac_name = "iwmc3200wifi-lmac-sdio.bin", |
400 | }; | 400 | }; |
401 | 401 | ||
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 4bc46a60ae2f..9a5408e7d94a 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c | |||
@@ -207,7 +207,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d | |||
207 | lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); | 207 | lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); |
208 | lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, | 208 | lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, |
209 | COUNTRY_CODE_LEN + 1 + | 209 | COUNTRY_CODE_LEN + 1 + |
210 | sizeof(struct ieeetypes_subbandset) * nr_subband); | 210 | sizeof(struct ieee_subbandset) * nr_subband); |
211 | return 0; | 211 | return 0; |
212 | } | 212 | } |
213 | 213 | ||
@@ -302,11 +302,9 @@ done: | |||
302 | * @param parsed_region_chan pointer to parsed_region_chan_11d | 302 | * @param parsed_region_chan pointer to parsed_region_chan_11d |
303 | * @return 0 | 303 | * @return 0 |
304 | */ | 304 | */ |
305 | static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* | 305 | static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo, |
306 | countryinfo, | ||
307 | u8 band, | 306 | u8 band, |
308 | struct parsed_region_chan_11d * | 307 | struct parsed_region_chan_11d *parsed_region_chan) |
309 | parsed_region_chan) | ||
310 | { | 308 | { |
311 | u8 nr_subband, nrchan; | 309 | u8 nr_subband, nrchan; |
312 | u8 lastchan, firstchan; | 310 | u8 lastchan, firstchan; |
@@ -331,7 +329,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* | |||
331 | lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); | 329 | lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); |
332 | 330 | ||
333 | if ((*(countryinfo->countrycode)) == 0 | 331 | if ((*(countryinfo->countrycode)) == 0 |
334 | || (countryinfo->len <= COUNTRY_CODE_LEN)) { | 332 | || (countryinfo->header.len <= COUNTRY_CODE_LEN)) { |
335 | /* No region Info or Wrong region info: treat as No 11D info */ | 333 | /* No region Info or Wrong region info: treat as No 11D info */ |
336 | goto done; | 334 | goto done; |
337 | } | 335 | } |
@@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* | |||
349 | memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, | 347 | memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, |
350 | COUNTRY_CODE_LEN); | 348 | COUNTRY_CODE_LEN); |
351 | 349 | ||
352 | nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / | 350 | nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) / |
353 | sizeof(struct ieeetypes_subbandset); | 351 | sizeof(struct ieee_subbandset); |
354 | 352 | ||
355 | for (j = 0, lastchan = 0; j < nr_subband; j++) { | 353 | for (j = 0, lastchan = 0; j < nr_subband; j++) { |
356 | 354 | ||
@@ -502,7 +500,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, | |||
502 | { | 500 | { |
503 | struct cmd_ds_802_11d_domain_info *pdomaininfo = | 501 | struct cmd_ds_802_11d_domain_info *pdomaininfo = |
504 | &cmd->params.domaininfo; | 502 | &cmd->params.domaininfo; |
505 | struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; | 503 | struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain; |
506 | u8 nr_subband = priv->domainreg.nr_subband; | 504 | u8 nr_subband = priv->domainreg.nr_subband; |
507 | 505 | ||
508 | lbs_deb_enter(LBS_DEB_11D); | 506 | lbs_deb_enter(LBS_DEB_11D); |
@@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, | |||
524 | sizeof(domain->countrycode)); | 522 | sizeof(domain->countrycode)); |
525 | 523 | ||
526 | domain->header.len = | 524 | domain->header.len = |
527 | cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + | 525 | cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) + |
528 | sizeof(domain->countrycode)); | 526 | sizeof(domain->countrycode)); |
529 | 527 | ||
530 | if (nr_subband) { | 528 | if (nr_subband) { |
531 | memcpy(domain->subband, priv->domainreg.subband, | 529 | memcpy(domain->subband, priv->domainreg.subband, |
532 | nr_subband * sizeof(struct ieeetypes_subbandset)); | 530 | nr_subband * sizeof(struct ieee_subbandset)); |
533 | 531 | ||
534 | cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + | 532 | cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + |
535 | le16_to_cpu(domain->header.len) + | 533 | le16_to_cpu(domain->header.len) + |
536 | sizeof(struct mrvlietypesheader) + | 534 | sizeof(struct mrvl_ie_header) + |
537 | S_DS_GEN); | 535 | S_DS_GEN); |
538 | } else { | 536 | } else { |
539 | cmd->size = | 537 | cmd->size = |
@@ -556,7 +554,7 @@ done: | |||
556 | int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) | 554 | int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) |
557 | { | 555 | { |
558 | struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; | 556 | struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; |
559 | struct mrvlietypes_domainparamset *domain = &domaininfo->domain; | 557 | struct mrvl_ie_domain_param_set *domain = &domaininfo->domain; |
560 | u16 action = le16_to_cpu(domaininfo->action); | 558 | u16 action = le16_to_cpu(domaininfo->action); |
561 | s16 ret = 0; | 559 | s16 ret = 0; |
562 | u8 nr_subband = 0; | 560 | u8 nr_subband = 0; |
@@ -567,7 +565,7 @@ int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) | |||
567 | (int)le16_to_cpu(resp->size)); | 565 | (int)le16_to_cpu(resp->size)); |
568 | 566 | ||
569 | nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / | 567 | nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / |
570 | sizeof(struct ieeetypes_subbandset); | 568 | sizeof(struct ieee_subbandset); |
571 | 569 | ||
572 | lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); | 570 | lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); |
573 | 571 | ||
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 4f4f47f0f878..fb75d3e321a0 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h | |||
@@ -20,35 +20,36 @@ | |||
20 | struct cmd_ds_command; | 20 | struct cmd_ds_command; |
21 | 21 | ||
22 | /** Data structure for Country IE*/ | 22 | /** Data structure for Country IE*/ |
23 | struct ieeetypes_subbandset { | 23 | struct ieee_subbandset { |
24 | u8 firstchan; | 24 | u8 firstchan; |
25 | u8 nrchan; | 25 | u8 nrchan; |
26 | u8 maxtxpwr; | 26 | u8 maxtxpwr; |
27 | } __attribute__ ((packed)); | 27 | } __attribute__ ((packed)); |
28 | 28 | ||
29 | struct ieeetypes_countryinfoset { | 29 | struct ieee_ie_country_info_set { |
30 | u8 element_id; | 30 | struct ieee_ie_header header; |
31 | u8 len; | 31 | |
32 | u8 countrycode[COUNTRY_CODE_LEN]; | 32 | u8 countrycode[COUNTRY_CODE_LEN]; |
33 | struct ieeetypes_subbandset subband[1]; | 33 | struct ieee_subbandset subband[1]; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | struct ieeetypes_countryinfofullset { | 36 | struct ieee_ie_country_info_full_set { |
37 | u8 element_id; | 37 | struct ieee_ie_header header; |
38 | u8 len; | 38 | |
39 | u8 countrycode[COUNTRY_CODE_LEN]; | 39 | u8 countrycode[COUNTRY_CODE_LEN]; |
40 | struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; | 40 | struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; |
41 | } __attribute__ ((packed)); | 41 | } __attribute__ ((packed)); |
42 | 42 | ||
43 | struct mrvlietypes_domainparamset { | 43 | struct mrvl_ie_domain_param_set { |
44 | struct mrvlietypesheader header; | 44 | struct mrvl_ie_header header; |
45 | |||
45 | u8 countrycode[COUNTRY_CODE_LEN]; | 46 | u8 countrycode[COUNTRY_CODE_LEN]; |
46 | struct ieeetypes_subbandset subband[1]; | 47 | struct ieee_subbandset subband[1]; |
47 | } __attribute__ ((packed)); | 48 | } __attribute__ ((packed)); |
48 | 49 | ||
49 | struct cmd_ds_802_11d_domain_info { | 50 | struct cmd_ds_802_11d_domain_info { |
50 | __le16 action; | 51 | __le16 action; |
51 | struct mrvlietypes_domainparamset domain; | 52 | struct mrvl_ie_domain_param_set domain; |
52 | } __attribute__ ((packed)); | 53 | } __attribute__ ((packed)); |
53 | 54 | ||
54 | /** domain regulatory information */ | 55 | /** domain regulatory information */ |
@@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg { | |||
57 | u8 countrycode[COUNTRY_CODE_LEN]; | 58 | u8 countrycode[COUNTRY_CODE_LEN]; |
58 | /** No. of subband*/ | 59 | /** No. of subband*/ |
59 | u8 nr_subband; | 60 | u8 nr_subband; |
60 | struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; | 61 | struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; |
61 | }; | 62 | }; |
62 | 63 | ||
63 | struct chan_power_11d { | 64 | struct chan_power_11d { |
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a0e440cd8967..b9b374119033 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c | |||
@@ -12,15 +12,14 @@ | |||
12 | #include "scan.h" | 12 | #include "scan.h" |
13 | #include "cmd.h" | 13 | #include "cmd.h" |
14 | 14 | ||
15 | static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); | ||
16 | |||
17 | static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = | 15 | static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = |
18 | { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 16 | { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
19 | static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = | 17 | static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = |
20 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 18 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
21 | 19 | ||
22 | /* The firmware needs certain bits masked out of the beacon-derviced capability | 20 | /* The firmware needs the following bits masked out of the beacon-derived |
23 | * field when associating/joining to BSSs. | 21 | * capability field when associating/joining to a BSS: |
22 | * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) | ||
24 | */ | 23 | */ |
25 | #define CAPINFO_MASK (~(0xda00)) | 24 | #define CAPINFO_MASK (~(0xda00)) |
26 | 25 | ||
@@ -102,6 +101,295 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) | |||
102 | } | 101 | } |
103 | 102 | ||
104 | 103 | ||
104 | static u8 iw_auth_to_ieee_auth(u8 auth) | ||
105 | { | ||
106 | if (auth == IW_AUTH_ALG_OPEN_SYSTEM) | ||
107 | return 0x00; | ||
108 | else if (auth == IW_AUTH_ALG_SHARED_KEY) | ||
109 | return 0x01; | ||
110 | else if (auth == IW_AUTH_ALG_LEAP) | ||
111 | return 0x80; | ||
112 | |||
113 | lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * @brief This function prepares the authenticate command. AUTHENTICATE only | ||
119 | * sets the authentication suite for future associations, as the firmware | ||
120 | * handles authentication internally during the ASSOCIATE command. | ||
121 | * | ||
122 | * @param priv A pointer to struct lbs_private structure | ||
123 | * @param bssid The peer BSSID with which to authenticate | ||
124 | * @param auth The authentication mode to use (from wireless.h) | ||
125 | * | ||
126 | * @return 0 or -1 | ||
127 | */ | ||
128 | static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth) | ||
129 | { | ||
130 | struct cmd_ds_802_11_authenticate cmd; | ||
131 | int ret = -1; | ||
132 | DECLARE_MAC_BUF(mac); | ||
133 | |||
134 | lbs_deb_enter(LBS_DEB_JOIN); | ||
135 | |||
136 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
137 | memcpy(cmd.bssid, bssid, ETH_ALEN); | ||
138 | |||
139 | cmd.authtype = iw_auth_to_ieee_auth(auth); | ||
140 | |||
141 | lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", | ||
142 | print_mac(mac, bssid), cmd.authtype); | ||
143 | |||
144 | ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); | ||
145 | |||
146 | lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | |||
151 | static int lbs_assoc_post(struct lbs_private *priv, | ||
152 | struct cmd_ds_802_11_associate_response *resp) | ||
153 | { | ||
154 | int ret = 0; | ||
155 | union iwreq_data wrqu; | ||
156 | struct bss_descriptor *bss; | ||
157 | u16 status_code; | ||
158 | |||
159 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
160 | |||
161 | if (!priv->in_progress_assoc_req) { | ||
162 | lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); | ||
163 | ret = -1; | ||
164 | goto done; | ||
165 | } | ||
166 | bss = &priv->in_progress_assoc_req->bss; | ||
167 | |||
168 | /* | ||
169 | * Older FW versions map the IEEE 802.11 Status Code in the association | ||
170 | * response to the following values returned in resp->statuscode: | ||
171 | * | ||
172 | * IEEE Status Code Marvell Status Code | ||
173 | * 0 -> 0x0000 ASSOC_RESULT_SUCCESS | ||
174 | * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
175 | * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
176 | * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
177 | * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
178 | * others -> 0x0003 ASSOC_RESULT_REFUSED | ||
179 | * | ||
180 | * Other response codes: | ||
181 | * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) | ||
182 | * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for | ||
183 | * association response from the AP) | ||
184 | */ | ||
185 | |||
186 | status_code = le16_to_cpu(resp->statuscode); | ||
187 | if (priv->fwrelease < 0x09000000) { | ||
188 | switch (status_code) { | ||
189 | case 0x00: | ||
190 | break; | ||
191 | case 0x01: | ||
192 | lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); | ||
193 | break; | ||
194 | case 0x02: | ||
195 | lbs_deb_assoc("ASSOC_RESP: internal timer " | ||
196 | "expired while waiting for the AP\n"); | ||
197 | break; | ||
198 | case 0x03: | ||
199 | lbs_deb_assoc("ASSOC_RESP: association " | ||
200 | "refused by AP\n"); | ||
201 | break; | ||
202 | case 0x04: | ||
203 | lbs_deb_assoc("ASSOC_RESP: authentication " | ||
204 | "refused by AP\n"); | ||
205 | break; | ||
206 | default: | ||
207 | lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " | ||
208 | " unknown\n", status_code); | ||
209 | break; | ||
210 | } | ||
211 | } else { | ||
212 | /* v9+ returns the AP's association response */ | ||
213 | lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code); | ||
214 | } | ||
215 | |||
216 | if (status_code) { | ||
217 | lbs_mac_event_disconnected(priv); | ||
218 | ret = -1; | ||
219 | goto done; | ||
220 | } | ||
221 | |||
222 | lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", | ||
223 | (void *) (resp + sizeof (resp->hdr)), | ||
224 | le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr)); | ||
225 | |||
226 | /* Send a Media Connected event, according to the Spec */ | ||
227 | priv->connect_status = LBS_CONNECTED; | ||
228 | |||
229 | /* Update current SSID and BSSID */ | ||
230 | memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); | ||
231 | priv->curbssparams.ssid_len = bss->ssid_len; | ||
232 | memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); | ||
233 | |||
234 | priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; | ||
235 | priv->NF[TYPE_RXPD][TYPE_AVG] = 0; | ||
236 | |||
237 | memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); | ||
238 | memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); | ||
239 | priv->nextSNRNF = 0; | ||
240 | priv->numSNRNF = 0; | ||
241 | |||
242 | netif_carrier_on(priv->dev); | ||
243 | if (!priv->tx_pending_len) | ||
244 | netif_wake_queue(priv->dev); | ||
245 | |||
246 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
247 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
248 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
249 | |||
250 | done: | ||
251 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * @brief This function prepares an association-class command. | ||
257 | * | ||
258 | * @param priv A pointer to struct lbs_private structure | ||
259 | * @param assoc_req The association request describing the BSS to associate | ||
260 | * or reassociate with | ||
261 | * @param command The actual command, either CMD_802_11_ASSOCIATE or | ||
262 | * CMD_802_11_REASSOCIATE | ||
263 | * | ||
264 | * @return 0 or -1 | ||
265 | */ | ||
266 | static int lbs_associate(struct lbs_private *priv, | ||
267 | struct assoc_request *assoc_req, | ||
268 | u16 command) | ||
269 | { | ||
270 | struct cmd_ds_802_11_associate cmd; | ||
271 | int ret = 0; | ||
272 | struct bss_descriptor *bss = &assoc_req->bss; | ||
273 | u8 *pos = &(cmd.iebuf[0]); | ||
274 | u16 tmpcap, tmplen, tmpauth; | ||
275 | struct mrvl_ie_ssid_param_set *ssid; | ||
276 | struct mrvl_ie_ds_param_set *ds; | ||
277 | struct mrvl_ie_cf_param_set *cf; | ||
278 | struct mrvl_ie_rates_param_set *rates; | ||
279 | struct mrvl_ie_rsn_param_set *rsn; | ||
280 | struct mrvl_ie_auth_type *auth; | ||
281 | |||
282 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
283 | |||
284 | BUG_ON((command != CMD_802_11_ASSOCIATE) && | ||
285 | (command != CMD_802_11_REASSOCIATE)); | ||
286 | |||
287 | memset(&cmd, 0, sizeof(cmd)); | ||
288 | cmd.hdr.command = cpu_to_le16(command); | ||
289 | |||
290 | /* Fill in static fields */ | ||
291 | memcpy(cmd.bssid, bss->bssid, ETH_ALEN); | ||
292 | cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); | ||
293 | |||
294 | /* Capability info */ | ||
295 | tmpcap = (bss->capability & CAPINFO_MASK); | ||
296 | if (bss->mode == IW_MODE_INFRA) | ||
297 | tmpcap |= WLAN_CAPABILITY_ESS; | ||
298 | cmd.capability = cpu_to_le16(tmpcap); | ||
299 | lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); | ||
300 | |||
301 | /* SSID */ | ||
302 | ssid = (struct mrvl_ie_ssid_param_set *) pos; | ||
303 | ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
304 | tmplen = bss->ssid_len; | ||
305 | ssid->header.len = cpu_to_le16(tmplen); | ||
306 | memcpy(ssid->ssid, bss->ssid, tmplen); | ||
307 | pos += sizeof(ssid->header) + tmplen; | ||
308 | |||
309 | ds = (struct mrvl_ie_ds_param_set *) pos; | ||
310 | ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); | ||
311 | ds->header.len = cpu_to_le16(1); | ||
312 | ds->channel = bss->phy.ds.channel; | ||
313 | pos += sizeof(ds->header) + 1; | ||
314 | |||
315 | cf = (struct mrvl_ie_cf_param_set *) pos; | ||
316 | cf->header.type = cpu_to_le16(TLV_TYPE_CF); | ||
317 | tmplen = sizeof(*cf) - sizeof (cf->header); | ||
318 | cf->header.len = cpu_to_le16(tmplen); | ||
319 | /* IE payload should be zeroed, firmware fills it in for us */ | ||
320 | pos += sizeof(*cf); | ||
321 | |||
322 | rates = (struct mrvl_ie_rates_param_set *) pos; | ||
323 | rates->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
324 | memcpy(&rates->rates, &bss->rates, MAX_RATES); | ||
325 | tmplen = MAX_RATES; | ||
326 | if (get_common_rates(priv, rates->rates, &tmplen)) { | ||
327 | ret = -1; | ||
328 | goto done; | ||
329 | } | ||
330 | pos += sizeof(rates->header) + tmplen; | ||
331 | rates->header.len = cpu_to_le16(tmplen); | ||
332 | lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); | ||
333 | |||
334 | /* Copy the infra. association rates into Current BSS state structure */ | ||
335 | memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); | ||
336 | memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); | ||
337 | |||
338 | /* Set MSB on basic rates as the firmware requires, but _after_ | ||
339 | * copying to current bss rates. | ||
340 | */ | ||
341 | lbs_set_basic_rate_flags(rates->rates, tmplen); | ||
342 | |||
343 | /* Firmware v9+ indicate authentication suites as a TLV */ | ||
344 | if (priv->fwrelease >= 0x09000000) { | ||
345 | DECLARE_MAC_BUF(mac); | ||
346 | |||
347 | auth = (struct mrvl_ie_auth_type *) pos; | ||
348 | auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); | ||
349 | auth->header.len = cpu_to_le16(2); | ||
350 | tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); | ||
351 | auth->auth = cpu_to_le16(tmpauth); | ||
352 | pos += sizeof(auth->header) + 2; | ||
353 | |||
354 | lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", | ||
355 | print_mac(mac, bss->bssid), priv->secinfo.auth_mode); | ||
356 | } | ||
357 | |||
358 | /* WPA/WPA2 IEs */ | ||
359 | if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { | ||
360 | rsn = (struct mrvl_ie_rsn_param_set *) pos; | ||
361 | /* WPA_IE or WPA2_IE */ | ||
362 | rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); | ||
363 | tmplen = (u16) assoc_req->wpa_ie[1]; | ||
364 | rsn->header.len = cpu_to_le16(tmplen); | ||
365 | memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); | ||
366 | lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn, | ||
367 | sizeof(rsn->header) + tmplen); | ||
368 | pos += sizeof(rsn->header) + tmplen; | ||
369 | } | ||
370 | |||
371 | cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) + | ||
372 | (u16)(pos - (u8 *) &cmd.iebuf)); | ||
373 | |||
374 | /* update curbssparams */ | ||
375 | priv->curbssparams.channel = bss->phy.ds.channel; | ||
376 | |||
377 | if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { | ||
378 | ret = -1; | ||
379 | goto done; | ||
380 | } | ||
381 | |||
382 | ret = lbs_cmd_with_response(priv, command, &cmd); | ||
383 | if (ret == 0) { | ||
384 | ret = lbs_assoc_post(priv, | ||
385 | (struct cmd_ds_802_11_associate_response *) &cmd); | ||
386 | } | ||
387 | |||
388 | done: | ||
389 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
390 | return ret; | ||
391 | } | ||
392 | |||
105 | /** | 393 | /** |
106 | * @brief Associate to a specific BSS discovered in a scan | 394 | * @brief Associate to a specific BSS discovered in a scan |
107 | * | 395 | * |
@@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) | |||
110 | * | 398 | * |
111 | * @return 0-success, otherwise fail | 399 | * @return 0-success, otherwise fail |
112 | */ | 400 | */ |
113 | static int lbs_associate(struct lbs_private *priv, | 401 | static int lbs_try_associate(struct lbs_private *priv, |
114 | struct assoc_request *assoc_req) | 402 | struct assoc_request *assoc_req) |
115 | { | 403 | { |
116 | int ret; | 404 | int ret; |
@@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv, | |||
118 | 406 | ||
119 | lbs_deb_enter(LBS_DEB_ASSOC); | 407 | lbs_deb_enter(LBS_DEB_ASSOC); |
120 | 408 | ||
121 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, | 409 | /* FW v9 and higher indicate authentication suites as a TLV in the |
122 | 0, CMD_OPTION_WAITFORRSP, | 410 | * association command, not as a separate authentication command. |
123 | 0, assoc_req->bss.bssid); | 411 | */ |
124 | if (ret) | 412 | if (priv->fwrelease < 0x09000000) { |
125 | goto out; | 413 | ret = lbs_set_authentication(priv, assoc_req->bss.bssid, |
414 | priv->secinfo.auth_mode); | ||
415 | if (ret) | ||
416 | goto out; | ||
417 | } | ||
126 | 418 | ||
127 | /* Use short preamble only when both the BSS and firmware support it */ | 419 | /* Use short preamble only when both the BSS and firmware support it */ |
128 | if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && | 420 | if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && |
@@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv, | |||
133 | if (ret) | 425 | if (ret) |
134 | goto out; | 426 | goto out; |
135 | 427 | ||
136 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, | 428 | ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); |
137 | 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); | ||
138 | 429 | ||
139 | out: | 430 | out: |
140 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | 431 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); |
141 | return ret; | 432 | return ret; |
142 | } | 433 | } |
143 | 434 | ||
435 | static int lbs_adhoc_post(struct lbs_private *priv, | ||
436 | struct cmd_ds_802_11_ad_hoc_result *resp) | ||
437 | { | ||
438 | int ret = 0; | ||
439 | u16 command = le16_to_cpu(resp->hdr.command); | ||
440 | u16 result = le16_to_cpu(resp->hdr.result); | ||
441 | union iwreq_data wrqu; | ||
442 | struct bss_descriptor *bss; | ||
443 | DECLARE_SSID_BUF(ssid); | ||
444 | |||
445 | lbs_deb_enter(LBS_DEB_JOIN); | ||
446 | |||
447 | if (!priv->in_progress_assoc_req) { | ||
448 | lbs_deb_join("ADHOC_RESP: no in-progress association " | ||
449 | "request\n"); | ||
450 | ret = -1; | ||
451 | goto done; | ||
452 | } | ||
453 | bss = &priv->in_progress_assoc_req->bss; | ||
454 | |||
455 | /* | ||
456 | * Join result code 0 --> SUCCESS | ||
457 | */ | ||
458 | if (result) { | ||
459 | lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); | ||
460 | if (priv->connect_status == LBS_CONNECTED) | ||
461 | lbs_mac_event_disconnected(priv); | ||
462 | ret = -1; | ||
463 | goto done; | ||
464 | } | ||
465 | |||
466 | /* Send a Media Connected event, according to the Spec */ | ||
467 | priv->connect_status = LBS_CONNECTED; | ||
468 | |||
469 | if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { | ||
470 | /* Update the created network descriptor with the new BSSID */ | ||
471 | memcpy(bss->bssid, resp->bssid, ETH_ALEN); | ||
472 | } | ||
473 | |||
474 | /* Set the BSSID from the joined/started descriptor */ | ||
475 | memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); | ||
476 | |||
477 | /* Set the new SSID to current SSID */ | ||
478 | memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); | ||
479 | priv->curbssparams.ssid_len = bss->ssid_len; | ||
480 | |||
481 | netif_carrier_on(priv->dev); | ||
482 | if (!priv->tx_pending_len) | ||
483 | netif_wake_queue(priv->dev); | ||
484 | |||
485 | memset(&wrqu, 0, sizeof(wrqu)); | ||
486 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
487 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
488 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
489 | |||
490 | lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", | ||
491 | print_ssid(ssid, bss->ssid, bss->ssid_len), | ||
492 | priv->curbssparams.bssid, | ||
493 | priv->curbssparams.channel); | ||
494 | |||
495 | done: | ||
496 | lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); | ||
497 | return ret; | ||
498 | } | ||
499 | |||
144 | /** | 500 | /** |
145 | * @brief Join an adhoc network found in a previous scan | 501 | * @brief Join an adhoc network found in a previous scan |
146 | * | 502 | * |
@@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, | |||
219 | memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); | 575 | memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); |
220 | memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); | 576 | memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); |
221 | 577 | ||
222 | memcpy(&cmd.bss.phyparamset, &bss->phyparamset, | 578 | memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set)); |
223 | sizeof(union ieeetypes_phyparamset)); | ||
224 | 579 | ||
225 | memcpy(&cmd.bss.ssparamset, &bss->ssparamset, | 580 | memcpy(&cmd.bss.ibss, &bss->ss.ibss, |
226 | sizeof(union IEEEtypes_ssparamset)); | 581 | sizeof(struct ieee_ie_ibss_param_set)); |
227 | 582 | ||
228 | cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); | 583 | cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); |
229 | lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", | 584 | lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", |
@@ -260,7 +615,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, | |||
260 | */ | 615 | */ |
261 | lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); | 616 | lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); |
262 | 617 | ||
263 | cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); | 618 | cmd.bss.ibss.atimwindow = bss->atimwindow; |
264 | 619 | ||
265 | if (assoc_req->secinfo.wep_enabled) { | 620 | if (assoc_req->secinfo.wep_enabled) { |
266 | u16 tmp = le16_to_cpu(cmd.bss.capability); | 621 | u16 tmp = le16_to_cpu(cmd.bss.capability); |
@@ -287,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, | |||
287 | } | 642 | } |
288 | 643 | ||
289 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); | 644 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); |
290 | if (ret == 0) | 645 | if (ret == 0) { |
291 | ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); | 646 | ret = lbs_adhoc_post(priv, |
647 | (struct cmd_ds_802_11_ad_hoc_result *)&cmd); | ||
648 | } | ||
292 | 649 | ||
293 | out: | 650 | out: |
294 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | 651 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); |
@@ -343,22 +700,24 @@ static int lbs_adhoc_start(struct lbs_private *priv, | |||
343 | WARN_ON(!assoc_req->channel); | 700 | WARN_ON(!assoc_req->channel); |
344 | 701 | ||
345 | /* set Physical parameter set */ | 702 | /* set Physical parameter set */ |
346 | cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; | 703 | cmd.ds.header.id = WLAN_EID_DS_PARAMS; |
347 | cmd.phyparamset.dsparamset.len = 1; | 704 | cmd.ds.header.len = 1; |
348 | cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; | 705 | cmd.ds.channel = assoc_req->channel; |
349 | 706 | ||
350 | /* set IBSS parameter set */ | 707 | /* set IBSS parameter set */ |
351 | cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; | 708 | cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; |
352 | cmd.ssparamset.ibssparamset.len = 2; | 709 | cmd.ibss.header.len = 2; |
353 | cmd.ssparamset.ibssparamset.atimwindow = 0; | 710 | cmd.ibss.atimwindow = cpu_to_le16(0); |
354 | 711 | ||
355 | /* set capability info */ | 712 | /* set capability info */ |
356 | tmpcap = WLAN_CAPABILITY_IBSS; | 713 | tmpcap = WLAN_CAPABILITY_IBSS; |
357 | if (assoc_req->secinfo.wep_enabled) { | 714 | if (assoc_req->secinfo.wep_enabled || |
358 | lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); | 715 | assoc_req->secinfo.WPAenabled || |
716 | assoc_req->secinfo.WPA2enabled) { | ||
717 | lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n"); | ||
359 | tmpcap |= WLAN_CAPABILITY_PRIVACY; | 718 | tmpcap |= WLAN_CAPABILITY_PRIVACY; |
360 | } else | 719 | } else |
361 | lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); | 720 | lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n"); |
362 | 721 | ||
363 | cmd.capability = cpu_to_le16(tmpcap); | 722 | cmd.capability = cpu_to_le16(tmpcap); |
364 | 723 | ||
@@ -395,7 +754,8 @@ static int lbs_adhoc_start(struct lbs_private *priv, | |||
395 | 754 | ||
396 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); | 755 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); |
397 | if (ret == 0) | 756 | if (ret == 0) |
398 | ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); | 757 | ret = lbs_adhoc_post(priv, |
758 | (struct cmd_ds_802_11_ad_hoc_result *)&cmd); | ||
399 | 759 | ||
400 | out: | 760 | out: |
401 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | 761 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); |
@@ -720,7 +1080,7 @@ static int assoc_helper_essid(struct lbs_private *priv, | |||
720 | assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); | 1080 | assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); |
721 | if (bss != NULL) { | 1081 | if (bss != NULL) { |
722 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); | 1082 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); |
723 | ret = lbs_associate(priv, assoc_req); | 1083 | ret = lbs_try_associate(priv, assoc_req); |
724 | } else { | 1084 | } else { |
725 | lbs_deb_assoc("SSID not found; cannot associate\n"); | 1085 | lbs_deb_assoc("SSID not found; cannot associate\n"); |
726 | } | 1086 | } |
@@ -772,8 +1132,9 @@ static int assoc_helper_bssid(struct lbs_private *priv, | |||
772 | 1132 | ||
773 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); | 1133 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); |
774 | if (assoc_req->mode == IW_MODE_INFRA) { | 1134 | if (assoc_req->mode == IW_MODE_INFRA) { |
775 | ret = lbs_associate(priv, assoc_req); | 1135 | ret = lbs_try_associate(priv, assoc_req); |
776 | lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); | 1136 | lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n", |
1137 | ret); | ||
777 | } else if (assoc_req->mode == IW_MODE_ADHOC) { | 1138 | } else if (assoc_req->mode == IW_MODE_ADHOC) { |
778 | lbs_adhoc_join(priv, assoc_req); | 1139 | lbs_adhoc_join(priv, assoc_req); |
779 | } | 1140 | } |
@@ -1467,57 +1828,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) | |||
1467 | 1828 | ||
1468 | 1829 | ||
1469 | /** | 1830 | /** |
1470 | * @brief This function prepares command of authenticate. | ||
1471 | * | ||
1472 | * @param priv A pointer to struct lbs_private structure | ||
1473 | * @param cmd A pointer to cmd_ds_command structure | ||
1474 | * @param pdata_buf Void cast of pointer to a BSSID to authenticate with | ||
1475 | * | ||
1476 | * @return 0 or -1 | ||
1477 | */ | ||
1478 | int lbs_cmd_80211_authenticate(struct lbs_private *priv, | ||
1479 | struct cmd_ds_command *cmd, | ||
1480 | void *pdata_buf) | ||
1481 | { | ||
1482 | struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; | ||
1483 | int ret = -1; | ||
1484 | u8 *bssid = pdata_buf; | ||
1485 | |||
1486 | lbs_deb_enter(LBS_DEB_JOIN); | ||
1487 | |||
1488 | cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); | ||
1489 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) | ||
1490 | + S_DS_GEN); | ||
1491 | |||
1492 | /* translate auth mode to 802.11 defined wire value */ | ||
1493 | switch (priv->secinfo.auth_mode) { | ||
1494 | case IW_AUTH_ALG_OPEN_SYSTEM: | ||
1495 | pauthenticate->authtype = 0x00; | ||
1496 | break; | ||
1497 | case IW_AUTH_ALG_SHARED_KEY: | ||
1498 | pauthenticate->authtype = 0x01; | ||
1499 | break; | ||
1500 | case IW_AUTH_ALG_LEAP: | ||
1501 | pauthenticate->authtype = 0x80; | ||
1502 | break; | ||
1503 | default: | ||
1504 | lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", | ||
1505 | priv->secinfo.auth_mode); | ||
1506 | goto out; | ||
1507 | } | ||
1508 | |||
1509 | memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); | ||
1510 | |||
1511 | lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", | ||
1512 | bssid, pauthenticate->authtype); | ||
1513 | ret = 0; | ||
1514 | |||
1515 | out: | ||
1516 | lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); | ||
1517 | return ret; | ||
1518 | } | ||
1519 | |||
1520 | /** | ||
1521 | * @brief Deauthenticate from a specific BSS | 1831 | * @brief Deauthenticate from a specific BSS |
1522 | * | 1832 | * |
1523 | * @param priv A pointer to struct lbs_private structure | 1833 | * @param priv A pointer to struct lbs_private structure |
@@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], | |||
1550 | return ret; | 1860 | return ret; |
1551 | } | 1861 | } |
1552 | 1862 | ||
1553 | int lbs_cmd_80211_associate(struct lbs_private *priv, | ||
1554 | struct cmd_ds_command *cmd, void *pdata_buf) | ||
1555 | { | ||
1556 | struct cmd_ds_802_11_associate *passo = &cmd->params.associate; | ||
1557 | int ret = 0; | ||
1558 | struct assoc_request *assoc_req = pdata_buf; | ||
1559 | struct bss_descriptor *bss = &assoc_req->bss; | ||
1560 | u8 *pos; | ||
1561 | u16 tmpcap, tmplen; | ||
1562 | struct mrvlietypes_ssidparamset *ssid; | ||
1563 | struct mrvlietypes_phyparamset *phy; | ||
1564 | struct mrvlietypes_ssparamset *ss; | ||
1565 | struct mrvlietypes_ratesparamset *rates; | ||
1566 | struct mrvlietypes_rsnparamset *rsn; | ||
1567 | |||
1568 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1569 | |||
1570 | pos = (u8 *) passo; | ||
1571 | |||
1572 | if (!priv) { | ||
1573 | ret = -1; | ||
1574 | goto done; | ||
1575 | } | ||
1576 | |||
1577 | cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); | ||
1578 | |||
1579 | memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); | ||
1580 | pos += sizeof(passo->peerstaaddr); | ||
1581 | |||
1582 | /* set the listen interval */ | ||
1583 | passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); | ||
1584 | |||
1585 | pos += sizeof(passo->capability); | ||
1586 | pos += sizeof(passo->listeninterval); | ||
1587 | pos += sizeof(passo->bcnperiod); | ||
1588 | pos += sizeof(passo->dtimperiod); | ||
1589 | |||
1590 | ssid = (struct mrvlietypes_ssidparamset *) pos; | ||
1591 | ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
1592 | tmplen = bss->ssid_len; | ||
1593 | ssid->header.len = cpu_to_le16(tmplen); | ||
1594 | memcpy(ssid->ssid, bss->ssid, tmplen); | ||
1595 | pos += sizeof(ssid->header) + tmplen; | ||
1596 | |||
1597 | phy = (struct mrvlietypes_phyparamset *) pos; | ||
1598 | phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); | ||
1599 | tmplen = sizeof(phy->fh_ds.dsparamset); | ||
1600 | phy->header.len = cpu_to_le16(tmplen); | ||
1601 | memcpy(&phy->fh_ds.dsparamset, | ||
1602 | &bss->phyparamset.dsparamset.currentchan, | ||
1603 | tmplen); | ||
1604 | pos += sizeof(phy->header) + tmplen; | ||
1605 | |||
1606 | ss = (struct mrvlietypes_ssparamset *) pos; | ||
1607 | ss->header.type = cpu_to_le16(TLV_TYPE_CF); | ||
1608 | tmplen = sizeof(ss->cf_ibss.cfparamset); | ||
1609 | ss->header.len = cpu_to_le16(tmplen); | ||
1610 | pos += sizeof(ss->header) + tmplen; | ||
1611 | |||
1612 | rates = (struct mrvlietypes_ratesparamset *) pos; | ||
1613 | rates->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
1614 | memcpy(&rates->rates, &bss->rates, MAX_RATES); | ||
1615 | tmplen = MAX_RATES; | ||
1616 | if (get_common_rates(priv, rates->rates, &tmplen)) { | ||
1617 | ret = -1; | ||
1618 | goto done; | ||
1619 | } | ||
1620 | pos += sizeof(rates->header) + tmplen; | ||
1621 | rates->header.len = cpu_to_le16(tmplen); | ||
1622 | lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); | ||
1623 | |||
1624 | /* Copy the infra. association rates into Current BSS state structure */ | ||
1625 | memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); | ||
1626 | memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); | ||
1627 | |||
1628 | /* Set MSB on basic rates as the firmware requires, but _after_ | ||
1629 | * copying to current bss rates. | ||
1630 | */ | ||
1631 | lbs_set_basic_rate_flags(rates->rates, tmplen); | ||
1632 | |||
1633 | if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { | ||
1634 | rsn = (struct mrvlietypes_rsnparamset *) pos; | ||
1635 | /* WPA_IE or WPA2_IE */ | ||
1636 | rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); | ||
1637 | tmplen = (u16) assoc_req->wpa_ie[1]; | ||
1638 | rsn->header.len = cpu_to_le16(tmplen); | ||
1639 | memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); | ||
1640 | lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, | ||
1641 | sizeof(rsn->header) + tmplen); | ||
1642 | pos += sizeof(rsn->header) + tmplen; | ||
1643 | } | ||
1644 | |||
1645 | /* update curbssparams */ | ||
1646 | priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; | ||
1647 | |||
1648 | if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { | ||
1649 | ret = -1; | ||
1650 | goto done; | ||
1651 | } | ||
1652 | |||
1653 | cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); | ||
1654 | |||
1655 | /* set the capability info */ | ||
1656 | tmpcap = (bss->capability & CAPINFO_MASK); | ||
1657 | if (bss->mode == IW_MODE_INFRA) | ||
1658 | tmpcap |= WLAN_CAPABILITY_ESS; | ||
1659 | passo->capability = cpu_to_le16(tmpcap); | ||
1660 | lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); | ||
1661 | |||
1662 | done: | ||
1663 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1664 | return ret; | ||
1665 | } | ||
1666 | |||
1667 | int lbs_ret_80211_associate(struct lbs_private *priv, | ||
1668 | struct cmd_ds_command *resp) | ||
1669 | { | ||
1670 | int ret = 0; | ||
1671 | union iwreq_data wrqu; | ||
1672 | struct ieeetypes_assocrsp *passocrsp; | ||
1673 | struct bss_descriptor *bss; | ||
1674 | u16 status_code; | ||
1675 | |||
1676 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1677 | |||
1678 | if (!priv->in_progress_assoc_req) { | ||
1679 | lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); | ||
1680 | ret = -1; | ||
1681 | goto done; | ||
1682 | } | ||
1683 | bss = &priv->in_progress_assoc_req->bss; | ||
1684 | |||
1685 | passocrsp = (struct ieeetypes_assocrsp *) &resp->params; | ||
1686 | |||
1687 | /* | ||
1688 | * Older FW versions map the IEEE 802.11 Status Code in the association | ||
1689 | * response to the following values returned in passocrsp->statuscode: | ||
1690 | * | ||
1691 | * IEEE Status Code Marvell Status Code | ||
1692 | * 0 -> 0x0000 ASSOC_RESULT_SUCCESS | ||
1693 | * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
1694 | * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
1695 | * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
1696 | * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
1697 | * others -> 0x0003 ASSOC_RESULT_REFUSED | ||
1698 | * | ||
1699 | * Other response codes: | ||
1700 | * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) | ||
1701 | * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for | ||
1702 | * association response from the AP) | ||
1703 | */ | ||
1704 | |||
1705 | status_code = le16_to_cpu(passocrsp->statuscode); | ||
1706 | switch (status_code) { | ||
1707 | case 0x00: | ||
1708 | break; | ||
1709 | case 0x01: | ||
1710 | lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); | ||
1711 | break; | ||
1712 | case 0x02: | ||
1713 | lbs_deb_assoc("ASSOC_RESP: internal timer " | ||
1714 | "expired while waiting for the AP\n"); | ||
1715 | break; | ||
1716 | case 0x03: | ||
1717 | lbs_deb_assoc("ASSOC_RESP: association " | ||
1718 | "refused by AP\n"); | ||
1719 | break; | ||
1720 | case 0x04: | ||
1721 | lbs_deb_assoc("ASSOC_RESP: authentication " | ||
1722 | "refused by AP\n"); | ||
1723 | break; | ||
1724 | default: | ||
1725 | lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " | ||
1726 | " unknown\n", status_code); | ||
1727 | break; | ||
1728 | } | ||
1729 | |||
1730 | if (status_code) { | ||
1731 | lbs_mac_event_disconnected(priv); | ||
1732 | ret = -1; | ||
1733 | goto done; | ||
1734 | } | ||
1735 | |||
1736 | lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, | ||
1737 | le16_to_cpu(resp->size) - S_DS_GEN); | ||
1738 | |||
1739 | /* Send a Media Connected event, according to the Spec */ | ||
1740 | priv->connect_status = LBS_CONNECTED; | ||
1741 | |||
1742 | /* Update current SSID and BSSID */ | ||
1743 | memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); | ||
1744 | priv->curbssparams.ssid_len = bss->ssid_len; | ||
1745 | memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); | ||
1746 | |||
1747 | priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; | ||
1748 | priv->NF[TYPE_RXPD][TYPE_AVG] = 0; | ||
1749 | |||
1750 | memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); | ||
1751 | memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); | ||
1752 | priv->nextSNRNF = 0; | ||
1753 | priv->numSNRNF = 0; | ||
1754 | |||
1755 | netif_carrier_on(priv->dev); | ||
1756 | if (!priv->tx_pending_len) | ||
1757 | netif_wake_queue(priv->dev); | ||
1758 | |||
1759 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
1760 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
1761 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
1762 | |||
1763 | done: | ||
1764 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1765 | return ret; | ||
1766 | } | ||
1767 | |||
1768 | static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) | ||
1769 | { | ||
1770 | int ret = 0; | ||
1771 | u16 command = le16_to_cpu(resp->command); | ||
1772 | u16 result = le16_to_cpu(resp->result); | ||
1773 | struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; | ||
1774 | union iwreq_data wrqu; | ||
1775 | struct bss_descriptor *bss; | ||
1776 | DECLARE_SSID_BUF(ssid); | ||
1777 | |||
1778 | lbs_deb_enter(LBS_DEB_JOIN); | ||
1779 | |||
1780 | adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; | ||
1781 | |||
1782 | if (!priv->in_progress_assoc_req) { | ||
1783 | lbs_deb_join("ADHOC_RESP: no in-progress association " | ||
1784 | "request\n"); | ||
1785 | ret = -1; | ||
1786 | goto done; | ||
1787 | } | ||
1788 | bss = &priv->in_progress_assoc_req->bss; | ||
1789 | |||
1790 | /* | ||
1791 | * Join result code 0 --> SUCCESS | ||
1792 | */ | ||
1793 | if (result) { | ||
1794 | lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); | ||
1795 | if (priv->connect_status == LBS_CONNECTED) | ||
1796 | lbs_mac_event_disconnected(priv); | ||
1797 | ret = -1; | ||
1798 | goto done; | ||
1799 | } | ||
1800 | |||
1801 | /* Send a Media Connected event, according to the Spec */ | ||
1802 | priv->connect_status = LBS_CONNECTED; | ||
1803 | |||
1804 | if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { | ||
1805 | /* Update the created network descriptor with the new BSSID */ | ||
1806 | memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); | ||
1807 | } | ||
1808 | |||
1809 | /* Set the BSSID from the joined/started descriptor */ | ||
1810 | memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); | ||
1811 | |||
1812 | /* Set the new SSID to current SSID */ | ||
1813 | memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); | ||
1814 | priv->curbssparams.ssid_len = bss->ssid_len; | ||
1815 | |||
1816 | netif_carrier_on(priv->dev); | ||
1817 | if (!priv->tx_pending_len) | ||
1818 | netif_wake_queue(priv->dev); | ||
1819 | |||
1820 | memset(&wrqu, 0, sizeof(wrqu)); | ||
1821 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
1822 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
1823 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
1824 | |||
1825 | lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", | ||
1826 | print_ssid(ssid, bss->ssid, bss->ssid_len), | ||
1827 | priv->curbssparams.bssid, | ||
1828 | priv->curbssparams.channel); | ||
1829 | |||
1830 | done: | ||
1831 | lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); | ||
1832 | return ret; | ||
1833 | } | ||
1834 | |||
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 8b7336dd02a3..6e765e9f91a3 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h | |||
@@ -8,22 +8,9 @@ | |||
8 | void lbs_association_worker(struct work_struct *work); | 8 | void lbs_association_worker(struct work_struct *work); |
9 | struct assoc_request *lbs_get_association_request(struct lbs_private *priv); | 9 | struct assoc_request *lbs_get_association_request(struct lbs_private *priv); |
10 | 10 | ||
11 | struct cmd_ds_command; | ||
12 | int lbs_cmd_80211_authenticate(struct lbs_private *priv, | ||
13 | struct cmd_ds_command *cmd, | ||
14 | void *pdata_buf); | ||
15 | |||
16 | int lbs_adhoc_stop(struct lbs_private *priv); | 11 | int lbs_adhoc_stop(struct lbs_private *priv); |
17 | 12 | ||
18 | int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, | 13 | int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, |
19 | u8 bssid[ETH_ALEN], u16 reason); | 14 | u8 bssid[ETH_ALEN], u16 reason); |
20 | int lbs_cmd_80211_associate(struct lbs_private *priv, | ||
21 | struct cmd_ds_command *cmd, | ||
22 | void *pdata_buf); | ||
23 | |||
24 | int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, | ||
25 | struct cmd_ds_command *resp); | ||
26 | int lbs_ret_80211_associate(struct lbs_private *priv, | ||
27 | struct cmd_ds_command *resp); | ||
28 | 15 | ||
29 | #endif /* _LBS_ASSOC_H */ | 16 | #endif /* _LBS_ASSOC_H */ |
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c455b9abbfc0..01db705a38ec 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -1220,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv, | |||
1220 | command = le16_to_cpu(cmd->command); | 1220 | command = le16_to_cpu(cmd->command); |
1221 | 1221 | ||
1222 | /* These commands take longer */ | 1222 | /* These commands take longer */ |
1223 | if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || | 1223 | if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE) |
1224 | command == CMD_802_11_AUTHENTICATE) | ||
1225 | timeo = 5 * HZ; | 1224 | timeo = 5 * HZ; |
1226 | 1225 | ||
1227 | lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", | 1226 | lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", |
@@ -1415,15 +1414,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1415 | ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action); | 1414 | ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action); |
1416 | break; | 1415 | break; |
1417 | 1416 | ||
1418 | case CMD_802_11_ASSOCIATE: | ||
1419 | case CMD_802_11_REASSOCIATE: | ||
1420 | ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); | ||
1421 | break; | ||
1422 | |||
1423 | case CMD_802_11_AUTHENTICATE: | ||
1424 | ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); | ||
1425 | break; | ||
1426 | |||
1427 | case CMD_MAC_REG_ACCESS: | 1417 | case CMD_MAC_REG_ACCESS: |
1428 | case CMD_BBP_REG_ACCESS: | 1418 | case CMD_BBP_REG_ACCESS: |
1429 | case CMD_RF_REG_ACCESS: | 1419 | case CMD_RF_REG_ACCESS: |
@@ -1470,8 +1460,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1470 | break; | 1460 | break; |
1471 | case CMD_802_11_LED_GPIO_CTRL: | 1461 | case CMD_802_11_LED_GPIO_CTRL: |
1472 | { | 1462 | { |
1473 | struct mrvlietypes_ledgpio *gpio = | 1463 | struct mrvl_ie_ledgpio *gpio = |
1474 | (struct mrvlietypes_ledgpio*) | 1464 | (struct mrvl_ie_ledgpio*) |
1475 | cmdptr->params.ledgpio.data; | 1465 | cmdptr->params.ledgpio.data; |
1476 | 1466 | ||
1477 | memmove(&cmdptr->params.ledgpio, | 1467 | memmove(&cmdptr->params.ledgpio, |
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bcf2a9756fb6..c42d3faa2660 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <linux/delay.h> | 5 | #include <linux/delay.h> |
6 | #include <linux/if_arp.h> | 6 | #include <linux/if_arp.h> |
7 | #include <linux/netdevice.h> | 7 | #include <linux/netdevice.h> |
8 | 8 | #include <asm/unaligned.h> | |
9 | #include <net/iw_handler.h> | 9 | #include <net/iw_handler.h> |
10 | 10 | ||
11 | #include "host.h" | 11 | #include "host.h" |
@@ -154,11 +154,11 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv, | |||
154 | lbs_deb_enter(LBS_DEB_CMD); | 154 | lbs_deb_enter(LBS_DEB_CMD); |
155 | 155 | ||
156 | /* store the non average value */ | 156 | /* store the non average value */ |
157 | priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); | 157 | priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); |
158 | priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); | 158 | priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor); |
159 | 159 | ||
160 | priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); | 160 | priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); |
161 | priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); | 161 | priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor); |
162 | 162 | ||
163 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = | 163 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = |
164 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], | 164 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], |
@@ -210,12 +210,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
210 | ret = lbs_ret_reg_access(priv, respcmd, resp); | 210 | ret = lbs_ret_reg_access(priv, respcmd, resp); |
211 | break; | 211 | break; |
212 | 212 | ||
213 | case CMD_RET_802_11_ASSOCIATE: | ||
214 | case CMD_RET(CMD_802_11_ASSOCIATE): | ||
215 | case CMD_RET(CMD_802_11_REASSOCIATE): | ||
216 | ret = lbs_ret_80211_associate(priv, resp); | ||
217 | break; | ||
218 | |||
219 | case CMD_RET(CMD_802_11_SET_AFC): | 213 | case CMD_RET(CMD_802_11_SET_AFC): |
220 | case CMD_RET(CMD_802_11_GET_AFC): | 214 | case CMD_RET(CMD_802_11_GET_AFC): |
221 | spin_lock_irqsave(&priv->driver_lock, flags); | 215 | spin_lock_irqsave(&priv->driver_lock, flags); |
@@ -225,7 +219,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
225 | 219 | ||
226 | break; | 220 | break; |
227 | 221 | ||
228 | case CMD_RET(CMD_802_11_AUTHENTICATE): | ||
229 | case CMD_RET(CMD_802_11_BEACON_STOP): | 222 | case CMD_RET(CMD_802_11_BEACON_STOP): |
230 | break; | 223 | break; |
231 | 224 | ||
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 50e28a0cdfee..811ffc3ef414 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c | |||
@@ -183,12 +183,12 @@ out_unlock: | |||
183 | */ | 183 | */ |
184 | static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) | 184 | static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) |
185 | { | 185 | { |
186 | struct mrvlietypesheader *tlv_h; | 186 | struct mrvl_ie_header *tlv_h; |
187 | uint16_t length; | 187 | uint16_t length; |
188 | ssize_t pos = 0; | 188 | ssize_t pos = 0; |
189 | 189 | ||
190 | while (pos < size) { | 190 | while (pos < size) { |
191 | tlv_h = (struct mrvlietypesheader *) tlv; | 191 | tlv_h = (struct mrvl_ie_header *) tlv; |
192 | if (!tlv_h->len) | 192 | if (!tlv_h->len) |
193 | return NULL; | 193 | return NULL; |
194 | if (tlv_h->type == cpu_to_le16(tlv_type)) | 194 | if (tlv_h->type == cpu_to_le16(tlv_type)) |
@@ -206,7 +206,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, | |||
206 | size_t count, loff_t *ppos) | 206 | size_t count, loff_t *ppos) |
207 | { | 207 | { |
208 | struct cmd_ds_802_11_subscribe_event *subscribed; | 208 | struct cmd_ds_802_11_subscribe_event *subscribed; |
209 | struct mrvlietypes_thresholds *got; | 209 | struct mrvl_ie_thresholds *got; |
210 | struct lbs_private *priv = file->private_data; | 210 | struct lbs_private *priv = file->private_data; |
211 | ssize_t ret = 0; | 211 | ssize_t ret = 0; |
212 | size_t pos = 0; | 212 | size_t pos = 0; |
@@ -259,7 +259,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, | |||
259 | loff_t *ppos) | 259 | loff_t *ppos) |
260 | { | 260 | { |
261 | struct cmd_ds_802_11_subscribe_event *events; | 261 | struct cmd_ds_802_11_subscribe_event *events; |
262 | struct mrvlietypes_thresholds *tlv; | 262 | struct mrvl_ie_thresholds *tlv; |
263 | struct lbs_private *priv = file->private_data; | 263 | struct lbs_private *priv = file->private_data; |
264 | ssize_t buf_size; | 264 | ssize_t buf_size; |
265 | int value, freq, new_mask; | 265 | int value, freq, new_mask; |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a4455ec7c354..f9ec69e04734 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -321,8 +321,6 @@ struct lbs_private { | |||
321 | 321 | ||
322 | u32 monitormode; | 322 | u32 monitormode; |
323 | u8 fw_ready; | 323 | u8 fw_ready; |
324 | u8 fn_init_required; | ||
325 | u8 fn_shutdown_required; | ||
326 | }; | 324 | }; |
327 | 325 | ||
328 | extern struct cmd_confirm_sleep confirm_sleep; | 326 | extern struct cmd_confirm_sleep confirm_sleep; |
@@ -340,7 +338,7 @@ struct bss_descriptor { | |||
340 | u32 rssi; | 338 | u32 rssi; |
341 | u32 channel; | 339 | u32 channel; |
342 | u16 beaconperiod; | 340 | u16 beaconperiod; |
343 | u32 atimwindow; | 341 | __le16 atimwindow; |
344 | 342 | ||
345 | /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ | 343 | /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ |
346 | u8 mode; | 344 | u8 mode; |
@@ -350,10 +348,10 @@ struct bss_descriptor { | |||
350 | 348 | ||
351 | unsigned long last_scanned; | 349 | unsigned long last_scanned; |
352 | 350 | ||
353 | union ieeetypes_phyparamset phyparamset; | 351 | union ieee_phy_param_set phy; |
354 | union IEEEtypes_ssparamset ssparamset; | 352 | union ieee_ss_param_set ss; |
355 | 353 | ||
356 | struct ieeetypes_countryinfofullset countryinfo; | 354 | struct ieee_ie_country_info_full_set countryinfo; |
357 | 355 | ||
358 | u8 wpa_ie[MAX_WPA_IE_LEN]; | 356 | u8 wpa_ie[MAX_WPA_IE_LEN]; |
359 | size_t wpa_ie_len; | 357 | size_t wpa_ie_len; |
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 391c54ab2b09..0a2e29140add 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h | |||
@@ -250,7 +250,9 @@ struct cmd_ds_gspi_bus_config { | |||
250 | } __attribute__ ((packed)); | 250 | } __attribute__ ((packed)); |
251 | 251 | ||
252 | struct cmd_ds_802_11_authenticate { | 252 | struct cmd_ds_802_11_authenticate { |
253 | u8 macaddr[ETH_ALEN]; | 253 | struct cmd_header hdr; |
254 | |||
255 | u8 bssid[ETH_ALEN]; | ||
254 | u8 authtype; | 256 | u8 authtype; |
255 | u8 reserved[10]; | 257 | u8 reserved[10]; |
256 | } __attribute__ ((packed)); | 258 | } __attribute__ ((packed)); |
@@ -263,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate { | |||
263 | } __attribute__ ((packed)); | 265 | } __attribute__ ((packed)); |
264 | 266 | ||
265 | struct cmd_ds_802_11_associate { | 267 | struct cmd_ds_802_11_associate { |
266 | u8 peerstaaddr[6]; | 268 | struct cmd_header hdr; |
269 | |||
270 | u8 bssid[6]; | ||
267 | __le16 capability; | 271 | __le16 capability; |
268 | __le16 listeninterval; | 272 | __le16 listeninterval; |
269 | __le16 bcnperiod; | 273 | __le16 bcnperiod; |
270 | u8 dtimperiod; | 274 | u8 dtimperiod; |
271 | 275 | u8 iebuf[512]; /* Enough for required and most optional IEs */ | |
272 | #if 0 | ||
273 | mrvlietypes_ssidparamset_t ssidParamSet; | ||
274 | mrvlietypes_phyparamset_t phyparamset; | ||
275 | mrvlietypes_ssparamset_t ssparamset; | ||
276 | mrvlietypes_ratesparamset_t ratesParamSet; | ||
277 | #endif | ||
278 | } __attribute__ ((packed)); | 276 | } __attribute__ ((packed)); |
279 | 277 | ||
280 | struct cmd_ds_802_11_associate_rsp { | 278 | struct cmd_ds_802_11_associate_response { |
281 | struct ieeetypes_assocrsp assocRsp; | 279 | struct cmd_header hdr; |
280 | |||
281 | __le16 capability; | ||
282 | __le16 statuscode; | ||
283 | __le16 aid; | ||
284 | u8 iebuf[512]; | ||
282 | } __attribute__ ((packed)); | 285 | } __attribute__ ((packed)); |
283 | 286 | ||
284 | struct cmd_ds_802_11_set_wep { | 287 | struct cmd_ds_802_11_set_wep { |
@@ -535,9 +538,11 @@ struct cmd_ds_802_11_ad_hoc_start { | |||
535 | u8 bsstype; | 538 | u8 bsstype; |
536 | __le16 beaconperiod; | 539 | __le16 beaconperiod; |
537 | u8 dtimperiod; /* Reserved on v9 and later */ | 540 | u8 dtimperiod; /* Reserved on v9 and later */ |
538 | union IEEEtypes_ssparamset ssparamset; | 541 | struct ieee_ie_ibss_param_set ibss; |
539 | union ieeetypes_phyparamset phyparamset; | 542 | u8 reserved1[4]; |
540 | __le16 probedelay; | 543 | struct ieee_ie_ds_param_set ds; |
544 | u8 reserved2[4]; | ||
545 | __le16 probedelay; /* Reserved on v9 and later */ | ||
541 | __le16 capability; | 546 | __le16 capability; |
542 | u8 rates[MAX_RATES]; | 547 | u8 rates[MAX_RATES]; |
543 | u8 tlv_memory_size_pad[100]; | 548 | u8 tlv_memory_size_pad[100]; |
@@ -558,8 +563,10 @@ struct adhoc_bssdesc { | |||
558 | u8 dtimperiod; | 563 | u8 dtimperiod; |
559 | __le64 timestamp; | 564 | __le64 timestamp; |
560 | __le64 localtime; | 565 | __le64 localtime; |
561 | union ieeetypes_phyparamset phyparamset; | 566 | struct ieee_ie_ds_param_set ds; |
562 | union IEEEtypes_ssparamset ssparamset; | 567 | u8 reserved1[4]; |
568 | struct ieee_ie_ibss_param_set ibss; | ||
569 | u8 reserved2[4]; | ||
563 | __le16 capability; | 570 | __le16 capability; |
564 | u8 rates[MAX_RATES]; | 571 | u8 rates[MAX_RATES]; |
565 | 572 | ||
@@ -765,8 +772,6 @@ struct cmd_ds_command { | |||
765 | /* command Body */ | 772 | /* command Body */ |
766 | union { | 773 | union { |
767 | struct cmd_ds_802_11_ps_mode psmode; | 774 | struct cmd_ds_802_11_ps_mode psmode; |
768 | struct cmd_ds_802_11_associate associate; | ||
769 | struct cmd_ds_802_11_authenticate auth; | ||
770 | struct cmd_ds_802_11_get_stat gstat; | 775 | struct cmd_ds_802_11_get_stat gstat; |
771 | struct cmd_ds_802_3_get_stat gstat_8023; | 776 | struct cmd_ds_802_3_get_stat gstat_8023; |
772 | struct cmd_ds_802_11_rf_antenna rant; | 777 | struct cmd_ds_802_11_rf_antenna rant; |
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index a7e3fc119b70..8cdb88c6ca28 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -39,8 +39,24 @@ | |||
39 | #include "decl.h" | 39 | #include "decl.h" |
40 | #include "defs.h" | 40 | #include "defs.h" |
41 | #include "dev.h" | 41 | #include "dev.h" |
42 | #include "cmd.h" | ||
42 | #include "if_sdio.h" | 43 | #include "if_sdio.h" |
43 | 44 | ||
45 | /* The if_sdio_remove() callback function is called when | ||
46 | * user removes this module from kernel space or ejects | ||
47 | * the card from the slot. The driver handles these 2 cases | ||
48 | * differently for SD8688 combo chip. | ||
49 | * If the user is removing the module, the FUNC_SHUTDOWN | ||
50 | * command for SD8688 is sent to the firmware. | ||
51 | * If the card is removed, there is no need to send this command. | ||
52 | * | ||
53 | * The variable 'user_rmmod' is used to distinguish these two | ||
54 | * scenarios. This flag is initialized as FALSE in case the card | ||
55 | * is removed, and will be set to TRUE for module removal when | ||
56 | * module_exit function is called. | ||
57 | */ | ||
58 | static u8 user_rmmod; | ||
59 | |||
44 | static char *lbs_helper_name = NULL; | 60 | static char *lbs_helper_name = NULL; |
45 | module_param_named(helper_name, lbs_helper_name, charp, 0644); | 61 | module_param_named(helper_name, lbs_helper_name, charp, 0644); |
46 | 62 | ||
@@ -61,7 +77,6 @@ struct if_sdio_model { | |||
61 | int model; | 77 | int model; |
62 | const char *helper; | 78 | const char *helper; |
63 | const char *firmware; | 79 | const char *firmware; |
64 | struct if_sdio_card *card; | ||
65 | }; | 80 | }; |
66 | 81 | ||
67 | static struct if_sdio_model if_sdio_models[] = { | 82 | static struct if_sdio_model if_sdio_models[] = { |
@@ -70,21 +85,18 @@ static struct if_sdio_model if_sdio_models[] = { | |||
70 | .model = IF_SDIO_MODEL_8385, | 85 | .model = IF_SDIO_MODEL_8385, |
71 | .helper = "sd8385_helper.bin", | 86 | .helper = "sd8385_helper.bin", |
72 | .firmware = "sd8385.bin", | 87 | .firmware = "sd8385.bin", |
73 | .card = NULL, | ||
74 | }, | 88 | }, |
75 | { | 89 | { |
76 | /* 8686 */ | 90 | /* 8686 */ |
77 | .model = IF_SDIO_MODEL_8686, | 91 | .model = IF_SDIO_MODEL_8686, |
78 | .helper = "sd8686_helper.bin", | 92 | .helper = "sd8686_helper.bin", |
79 | .firmware = "sd8686.bin", | 93 | .firmware = "sd8686.bin", |
80 | .card = NULL, | ||
81 | }, | 94 | }, |
82 | { | 95 | { |
83 | /* 8688 */ | 96 | /* 8688 */ |
84 | .model = IF_SDIO_MODEL_8688, | 97 | .model = IF_SDIO_MODEL_8688, |
85 | .helper = "sd8688_helper.bin", | 98 | .helper = "sd8688_helper.bin", |
86 | .firmware = "sd8688.bin", | 99 | .firmware = "sd8688.bin", |
87 | .card = NULL, | ||
88 | }, | 100 | }, |
89 | }; | 101 | }; |
90 | 102 | ||
@@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func, | |||
927 | goto free; | 939 | goto free; |
928 | } | 940 | } |
929 | 941 | ||
930 | if_sdio_models[i].card = card; | ||
931 | |||
932 | card->helper = if_sdio_models[i].helper; | 942 | card->helper = if_sdio_models[i].helper; |
933 | card->firmware = if_sdio_models[i].firmware; | 943 | card->firmware = if_sdio_models[i].firmware; |
934 | 944 | ||
@@ -1014,8 +1024,16 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1014 | /* | 1024 | /* |
1015 | * FUNC_INIT is required for SD8688 WLAN/BT multiple functions | 1025 | * FUNC_INIT is required for SD8688 WLAN/BT multiple functions |
1016 | */ | 1026 | */ |
1017 | priv->fn_init_required = | 1027 | if (card->model == IF_SDIO_MODEL_8688) { |
1018 | (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; | 1028 | struct cmd_header cmd; |
1029 | |||
1030 | memset(&cmd, 0, sizeof(cmd)); | ||
1031 | |||
1032 | lbs_deb_sdio("send function INIT command\n"); | ||
1033 | if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), | ||
1034 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
1035 | lbs_pr_alert("CMD_FUNC_INIT cmd failed\n"); | ||
1036 | } | ||
1019 | 1037 | ||
1020 | ret = lbs_start_card(priv); | 1038 | ret = lbs_start_card(priv); |
1021 | if (ret) | 1039 | if (ret) |
@@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func) | |||
1057 | { | 1075 | { |
1058 | struct if_sdio_card *card; | 1076 | struct if_sdio_card *card; |
1059 | struct if_sdio_packet *packet; | 1077 | struct if_sdio_packet *packet; |
1060 | int ret; | ||
1061 | 1078 | ||
1062 | lbs_deb_enter(LBS_DEB_SDIO); | 1079 | lbs_deb_enter(LBS_DEB_SDIO); |
1063 | 1080 | ||
1064 | card = sdio_get_drvdata(func); | 1081 | card = sdio_get_drvdata(func); |
1065 | 1082 | ||
1066 | lbs_stop_card(card->priv); | 1083 | if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) { |
1084 | /* | ||
1085 | * FUNC_SHUTDOWN is required for SD8688 WLAN/BT | ||
1086 | * multiple functions | ||
1087 | */ | ||
1088 | struct cmd_header cmd; | ||
1089 | |||
1090 | memset(&cmd, 0, sizeof(cmd)); | ||
1091 | |||
1092 | lbs_deb_sdio("send function SHUTDOWN command\n"); | ||
1093 | if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN, | ||
1094 | &cmd, sizeof(cmd), lbs_cmd_copyback, | ||
1095 | (unsigned long) &cmd)) | ||
1096 | lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); | ||
1097 | } | ||
1067 | 1098 | ||
1068 | card->priv->surpriseremoved = 1; | 1099 | card->priv->surpriseremoved = 1; |
1069 | 1100 | ||
1070 | lbs_deb_sdio("call remove card\n"); | 1101 | lbs_deb_sdio("call remove card\n"); |
1102 | lbs_stop_card(card->priv); | ||
1071 | lbs_remove_card(card->priv); | 1103 | lbs_remove_card(card->priv); |
1072 | 1104 | ||
1073 | flush_workqueue(card->workqueue); | 1105 | flush_workqueue(card->workqueue); |
1074 | destroy_workqueue(card->workqueue); | 1106 | destroy_workqueue(card->workqueue); |
1075 | 1107 | ||
1076 | sdio_claim_host(func); | 1108 | sdio_claim_host(func); |
1077 | |||
1078 | /* Disable interrupts */ | ||
1079 | sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret); | ||
1080 | |||
1081 | sdio_release_irq(func); | 1109 | sdio_release_irq(func); |
1082 | sdio_disable_func(func); | 1110 | sdio_disable_func(func); |
1083 | |||
1084 | sdio_release_host(func); | 1111 | sdio_release_host(func); |
1085 | 1112 | ||
1086 | while (card->packets) { | 1113 | while (card->packets) { |
@@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void) | |||
1116 | 1143 | ||
1117 | ret = sdio_register_driver(&if_sdio_driver); | 1144 | ret = sdio_register_driver(&if_sdio_driver); |
1118 | 1145 | ||
1146 | /* Clear the flag in case user removes the card. */ | ||
1147 | user_rmmod = 0; | ||
1148 | |||
1119 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 1149 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
1120 | 1150 | ||
1121 | return ret; | 1151 | return ret; |
@@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void) | |||
1123 | 1153 | ||
1124 | static void __exit if_sdio_exit_module(void) | 1154 | static void __exit if_sdio_exit_module(void) |
1125 | { | 1155 | { |
1126 | int i; | ||
1127 | struct if_sdio_card *card; | ||
1128 | |||
1129 | lbs_deb_enter(LBS_DEB_SDIO); | 1156 | lbs_deb_enter(LBS_DEB_SDIO); |
1130 | 1157 | ||
1131 | for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) { | 1158 | /* Set the flag as user is removing this module. */ |
1132 | card = if_sdio_models[i].card; | 1159 | user_rmmod = 1; |
1133 | |||
1134 | /* | ||
1135 | * FUNC_SHUTDOWN is required for SD8688 WLAN/BT | ||
1136 | * multiple functions | ||
1137 | */ | ||
1138 | if (card && card->priv) | ||
1139 | card->priv->fn_shutdown_required = | ||
1140 | (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; | ||
1141 | } | ||
1142 | 1160 | ||
1143 | sdio_unregister_driver(&if_sdio_driver); | 1161 | sdio_unregister_driver(&if_sdio_driver); |
1144 | 1162 | ||
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 5fa55fe1f860..ea23c5de1420 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -119,9 +119,6 @@ static struct chip_ident chip_id_to_device_name[] = { | |||
119 | * First we have to put a SPU register name on the bus. Then we can | 119 | * First we have to put a SPU register name on the bus. Then we can |
120 | * either read from or write to that register. | 120 | * either read from or write to that register. |
121 | * | 121 | * |
122 | * For 16-bit transactions, byte order on the bus is big-endian. | ||
123 | * We don't have to worry about that here, though. | ||
124 | * The translation takes place in the SPI routines. | ||
125 | */ | 122 | */ |
126 | 123 | ||
127 | static void spu_transaction_init(struct if_spi_card *card) | 124 | static void spu_transaction_init(struct if_spi_card *card) |
@@ -147,7 +144,7 @@ static void spu_transaction_finish(struct if_spi_card *card) | |||
147 | static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) | 144 | static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) |
148 | { | 145 | { |
149 | int err = 0; | 146 | int err = 0; |
150 | u16 reg_out = reg | IF_SPI_WRITE_OPERATION_MASK; | 147 | u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK); |
151 | 148 | ||
152 | /* You must give an even number of bytes to the SPU, even if it | 149 | /* You must give an even number of bytes to the SPU, even if it |
153 | * doesn't care about the last one. */ | 150 | * doesn't care about the last one. */ |
@@ -169,16 +166,10 @@ out: | |||
169 | 166 | ||
170 | static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val) | 167 | static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val) |
171 | { | 168 | { |
172 | return spu_write(card, reg, (u8 *)&val, sizeof(u16)); | 169 | u16 buff; |
173 | } | ||
174 | 170 | ||
175 | static inline int spu_write_u32(struct if_spi_card *card, u16 reg, u32 val) | 171 | buff = cpu_to_le16(val); |
176 | { | 172 | return spu_write(card, reg, (u8 *)&buff, sizeof(u16)); |
177 | /* The lower 16 bits are written first. */ | ||
178 | u16 out[2]; | ||
179 | out[0] = val & 0xffff; | ||
180 | out[1] = (val & 0xffff0000) >> 16; | ||
181 | return spu_write(card, reg, (u8 *)&out, sizeof(u32)); | ||
182 | } | 173 | } |
183 | 174 | ||
184 | static inline int spu_reg_is_port_reg(u16 reg) | 175 | static inline int spu_reg_is_port_reg(u16 reg) |
@@ -198,7 +189,7 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) | |||
198 | unsigned int i, delay; | 189 | unsigned int i, delay; |
199 | int err = 0; | 190 | int err = 0; |
200 | u16 zero = 0; | 191 | u16 zero = 0; |
201 | u16 reg_out = reg | IF_SPI_READ_OPERATION_MASK; | 192 | u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK); |
202 | 193 | ||
203 | /* You must take an even number of bytes from the SPU, even if you | 194 | /* You must take an even number of bytes from the SPU, even if you |
204 | * don't care about the last one. */ | 195 | * don't care about the last one. */ |
@@ -236,18 +227,25 @@ out: | |||
236 | /* Read 16 bits from an SPI register */ | 227 | /* Read 16 bits from an SPI register */ |
237 | static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) | 228 | static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) |
238 | { | 229 | { |
239 | return spu_read(card, reg, (u8 *)val, sizeof(u16)); | 230 | u16 buf; |
231 | int ret; | ||
232 | |||
233 | ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); | ||
234 | if (ret == 0) | ||
235 | *val = le16_to_cpup(&buf); | ||
236 | return ret; | ||
240 | } | 237 | } |
241 | 238 | ||
242 | /* Read 32 bits from an SPI register. | 239 | /* Read 32 bits from an SPI register. |
243 | * The low 16 bits are read first. */ | 240 | * The low 16 bits are read first. */ |
244 | static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) | 241 | static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) |
245 | { | 242 | { |
246 | u16 buf[2]; | 243 | u32 buf; |
247 | int err; | 244 | int err; |
248 | err = spu_read(card, reg, (u8 *)buf, sizeof(u32)); | 245 | |
246 | err = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); | ||
249 | if (!err) | 247 | if (!err) |
250 | *val = buf[0] | (buf[1] << 16); | 248 | *val = le32_to_cpup(&buf); |
251 | return err; | 249 | return err; |
252 | } | 250 | } |
253 | 251 | ||
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a58a12352672..89575e448015 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -1002,17 +1002,9 @@ static int lbs_setup_firmware(struct lbs_private *priv) | |||
1002 | { | 1002 | { |
1003 | int ret = -1; | 1003 | int ret = -1; |
1004 | s16 curlevel = 0, minlevel = 0, maxlevel = 0; | 1004 | s16 curlevel = 0, minlevel = 0, maxlevel = 0; |
1005 | struct cmd_header cmd; | ||
1006 | 1005 | ||
1007 | lbs_deb_enter(LBS_DEB_FW); | 1006 | lbs_deb_enter(LBS_DEB_FW); |
1008 | 1007 | ||
1009 | if (priv->fn_init_required) { | ||
1010 | memset(&cmd, 0, sizeof(cmd)); | ||
1011 | if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), | ||
1012 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
1013 | lbs_pr_alert("CMD_FUNC_INIT command failed\n"); | ||
1014 | } | ||
1015 | |||
1016 | /* Read MAC address from firmware */ | 1008 | /* Read MAC address from firmware */ |
1017 | memset(priv->current_addr, 0xff, ETH_ALEN); | 1009 | memset(priv->current_addr, 0xff, ETH_ALEN); |
1018 | ret = lbs_update_hw_spec(priv); | 1010 | ret = lbs_update_hw_spec(priv); |
@@ -1200,9 +1192,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1200 | priv->mesh_open = 0; | 1192 | priv->mesh_open = 0; |
1201 | priv->infra_open = 0; | 1193 | priv->infra_open = 0; |
1202 | 1194 | ||
1203 | priv->fn_init_required = 0; | ||
1204 | priv->fn_shutdown_required = 0; | ||
1205 | |||
1206 | /* Setup the OS Interface to our functions */ | 1195 | /* Setup the OS Interface to our functions */ |
1207 | dev->netdev_ops = &lbs_netdev_ops; | 1196 | dev->netdev_ops = &lbs_netdev_ops; |
1208 | dev->watchdog_timeo = 5 * HZ; | 1197 | dev->watchdog_timeo = 5 * HZ; |
@@ -1384,20 +1373,11 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1384 | struct net_device *dev; | 1373 | struct net_device *dev; |
1385 | struct cmd_ctrl_node *cmdnode; | 1374 | struct cmd_ctrl_node *cmdnode; |
1386 | unsigned long flags; | 1375 | unsigned long flags; |
1387 | struct cmd_header cmd; | ||
1388 | 1376 | ||
1389 | lbs_deb_enter(LBS_DEB_MAIN); | 1377 | lbs_deb_enter(LBS_DEB_MAIN); |
1390 | 1378 | ||
1391 | if (!priv) | 1379 | if (!priv) |
1392 | goto out; | 1380 | goto out; |
1393 | |||
1394 | if (priv->fn_shutdown_required) { | ||
1395 | memset(&cmd, 0, sizeof(cmd)); | ||
1396 | if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), | ||
1397 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
1398 | lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n"); | ||
1399 | } | ||
1400 | |||
1401 | dev = priv->dev; | 1381 | dev = priv->dev; |
1402 | 1382 | ||
1403 | netif_stop_queue(dev); | 1383 | netif_stop_queue(dev); |
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8124db36aaff..601b54249677 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c | |||
@@ -27,12 +27,12 @@ | |||
27 | + 40) /* 40 for WPAIE */ | 27 | + 40) /* 40 for WPAIE */ |
28 | 28 | ||
29 | //! Memory needed to store a max sized channel List TLV for a firmware scan | 29 | //! Memory needed to store a max sized channel List TLV for a firmware scan |
30 | #define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \ | 30 | #define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \ |
31 | + (MRVDRV_MAX_CHANNELS_PER_SCAN \ | 31 | + (MRVDRV_MAX_CHANNELS_PER_SCAN \ |
32 | * sizeof(struct chanscanparamset))) | 32 | * sizeof(struct chanscanparamset))) |
33 | 33 | ||
34 | //! Memory needed to store a max number/size SSID TLV for a firmware scan | 34 | //! Memory needed to store a max number/size SSID TLV for a firmware scan |
35 | #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) | 35 | #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set)) |
36 | 36 | ||
37 | //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max | 37 | //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max |
38 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ | 38 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ |
@@ -211,7 +211,7 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
211 | */ | 211 | */ |
212 | static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) | 212 | static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) |
213 | { | 213 | { |
214 | struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; | 214 | struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; |
215 | 215 | ||
216 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); | 216 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); |
217 | ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); | 217 | ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); |
@@ -249,7 +249,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, | |||
249 | int chan_count) | 249 | int chan_count) |
250 | { | 250 | { |
251 | size_t size = sizeof(struct chanscanparamset) *chan_count; | 251 | size_t size = sizeof(struct chanscanparamset) *chan_count; |
252 | struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv; | 252 | struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv; |
253 | 253 | ||
254 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | 254 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); |
255 | memcpy(chan_tlv->chanscanparam, chan_list, size); | 255 | memcpy(chan_tlv->chanscanparam, chan_list, size); |
@@ -270,7 +270,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, | |||
270 | static int lbs_scan_add_rates_tlv(uint8_t *tlv) | 270 | static int lbs_scan_add_rates_tlv(uint8_t *tlv) |
271 | { | 271 | { |
272 | int i; | 272 | int i; |
273 | struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv; | 273 | struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; |
274 | 274 | ||
275 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); | 275 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); |
276 | tlv += sizeof(rate_tlv->header); | 276 | tlv += sizeof(rate_tlv->header); |
@@ -513,12 +513,12 @@ void lbs_scan_worker(struct work_struct *work) | |||
513 | static int lbs_process_bss(struct bss_descriptor *bss, | 513 | static int lbs_process_bss(struct bss_descriptor *bss, |
514 | uint8_t **pbeaconinfo, int *bytesleft) | 514 | uint8_t **pbeaconinfo, int *bytesleft) |
515 | { | 515 | { |
516 | struct ieeetypes_fhparamset *pFH; | 516 | struct ieee_ie_fh_param_set *fh; |
517 | struct ieeetypes_dsparamset *pDS; | 517 | struct ieee_ie_ds_param_set *ds; |
518 | struct ieeetypes_cfparamset *pCF; | 518 | struct ieee_ie_cf_param_set *cf; |
519 | struct ieeetypes_ibssparamset *pibss; | 519 | struct ieee_ie_ibss_param_set *ibss; |
520 | DECLARE_SSID_BUF(ssid); | 520 | DECLARE_SSID_BUF(ssid); |
521 | struct ieeetypes_countryinfoset *pcountryinfo; | 521 | struct ieee_ie_country_info_set *pcountryinfo; |
522 | uint8_t *pos, *end, *p; | 522 | uint8_t *pos, *end, *p; |
523 | uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; | 523 | uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; |
524 | uint16_t beaconsize = 0; | 524 | uint16_t beaconsize = 0; |
@@ -616,50 +616,49 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
616 | break; | 616 | break; |
617 | 617 | ||
618 | case WLAN_EID_FH_PARAMS: | 618 | case WLAN_EID_FH_PARAMS: |
619 | pFH = (struct ieeetypes_fhparamset *) pos; | 619 | fh = (struct ieee_ie_fh_param_set *) pos; |
620 | memmove(&bss->phyparamset.fhparamset, pFH, | 620 | memcpy(&bss->phy.fh, fh, sizeof(*fh)); |
621 | sizeof(struct ieeetypes_fhparamset)); | ||
622 | lbs_deb_scan("got FH IE\n"); | 621 | lbs_deb_scan("got FH IE\n"); |
623 | break; | 622 | break; |
624 | 623 | ||
625 | case WLAN_EID_DS_PARAMS: | 624 | case WLAN_EID_DS_PARAMS: |
626 | pDS = (struct ieeetypes_dsparamset *) pos; | 625 | ds = (struct ieee_ie_ds_param_set *) pos; |
627 | bss->channel = pDS->currentchan; | 626 | bss->channel = ds->channel; |
628 | memcpy(&bss->phyparamset.dsparamset, pDS, | 627 | memcpy(&bss->phy.ds, ds, sizeof(*ds)); |
629 | sizeof(struct ieeetypes_dsparamset)); | ||
630 | lbs_deb_scan("got DS IE, channel %d\n", bss->channel); | 628 | lbs_deb_scan("got DS IE, channel %d\n", bss->channel); |
631 | break; | 629 | break; |
632 | 630 | ||
633 | case WLAN_EID_CF_PARAMS: | 631 | case WLAN_EID_CF_PARAMS: |
634 | pCF = (struct ieeetypes_cfparamset *) pos; | 632 | cf = (struct ieee_ie_cf_param_set *) pos; |
635 | memcpy(&bss->ssparamset.cfparamset, pCF, | 633 | memcpy(&bss->ss.cf, cf, sizeof(*cf)); |
636 | sizeof(struct ieeetypes_cfparamset)); | ||
637 | lbs_deb_scan("got CF IE\n"); | 634 | lbs_deb_scan("got CF IE\n"); |
638 | break; | 635 | break; |
639 | 636 | ||
640 | case WLAN_EID_IBSS_PARAMS: | 637 | case WLAN_EID_IBSS_PARAMS: |
641 | pibss = (struct ieeetypes_ibssparamset *) pos; | 638 | ibss = (struct ieee_ie_ibss_param_set *) pos; |
642 | bss->atimwindow = le16_to_cpu(pibss->atimwindow); | 639 | bss->atimwindow = ibss->atimwindow; |
643 | memmove(&bss->ssparamset.ibssparamset, pibss, | 640 | memcpy(&bss->ss.ibss, ibss, sizeof(*ibss)); |
644 | sizeof(struct ieeetypes_ibssparamset)); | ||
645 | lbs_deb_scan("got IBSS IE\n"); | 641 | lbs_deb_scan("got IBSS IE\n"); |
646 | break; | 642 | break; |
647 | 643 | ||
648 | case WLAN_EID_COUNTRY: | 644 | case WLAN_EID_COUNTRY: |
649 | pcountryinfo = (struct ieeetypes_countryinfoset *) pos; | 645 | pcountryinfo = (struct ieee_ie_country_info_set *) pos; |
650 | lbs_deb_scan("got COUNTRY IE\n"); | 646 | lbs_deb_scan("got COUNTRY IE\n"); |
651 | if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) | 647 | if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) |
652 | || pcountryinfo->len > 254) { | 648 | || pcountryinfo->header.len > 254) { |
653 | lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n", | 649 | lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", |
654 | pcountryinfo->len, sizeof(pcountryinfo->countrycode)); | 650 | __func__, |
651 | pcountryinfo->header.len, | ||
652 | sizeof(pcountryinfo->countrycode)); | ||
655 | ret = -1; | 653 | ret = -1; |
656 | goto done; | 654 | goto done; |
657 | } | 655 | } |
658 | 656 | ||
659 | memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); | 657 | memcpy(&bss->countryinfo, pcountryinfo, |
658 | pcountryinfo->header.len + 2); | ||
660 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", | 659 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", |
661 | (uint8_t *) pcountryinfo, | 660 | (uint8_t *) pcountryinfo, |
662 | (int) (pcountryinfo->len + 2)); | 661 | (int) (pcountryinfo->header.len + 2)); |
663 | break; | 662 | break; |
664 | 663 | ||
665 | case WLAN_EID_EXT_SUPP_RATES: | 664 | case WLAN_EID_EXT_SUPP_RATES: |
@@ -1130,7 +1129,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, | |||
1130 | goto done; | 1129 | goto done; |
1131 | } | 1130 | } |
1132 | 1131 | ||
1133 | bytesleft = le16_to_cpu(scanresp->bssdescriptsize); | 1132 | bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize); |
1134 | lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); | 1133 | lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); |
1135 | 1134 | ||
1136 | scanrespsize = le16_to_cpu(resp->size); | 1135 | scanrespsize = le16_to_cpu(resp->size); |
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index de03b9c9c204..99905df65b25 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h | |||
@@ -8,9 +8,14 @@ | |||
8 | #include <asm/byteorder.h> | 8 | #include <asm/byteorder.h> |
9 | #include <linux/wireless.h> | 9 | #include <linux/wireless.h> |
10 | 10 | ||
11 | struct ieeetypes_cfparamset { | 11 | struct ieee_ie_header { |
12 | u8 elementid; | 12 | u8 id; |
13 | u8 len; | 13 | u8 len; |
14 | } __attribute__ ((packed)); | ||
15 | |||
16 | struct ieee_ie_cf_param_set { | ||
17 | struct ieee_ie_header header; | ||
18 | |||
14 | u8 cfpcnt; | 19 | u8 cfpcnt; |
15 | u8 cfpperiod; | 20 | u8 cfpperiod; |
16 | __le16 cfpmaxduration; | 21 | __le16 cfpmaxduration; |
@@ -18,42 +23,35 @@ struct ieeetypes_cfparamset { | |||
18 | } __attribute__ ((packed)); | 23 | } __attribute__ ((packed)); |
19 | 24 | ||
20 | 25 | ||
21 | struct ieeetypes_ibssparamset { | 26 | struct ieee_ie_ibss_param_set { |
22 | u8 elementid; | 27 | struct ieee_ie_header header; |
23 | u8 len; | 28 | |
24 | __le16 atimwindow; | 29 | __le16 atimwindow; |
25 | } __attribute__ ((packed)); | 30 | } __attribute__ ((packed)); |
26 | 31 | ||
27 | union IEEEtypes_ssparamset { | 32 | union ieee_ss_param_set { |
28 | struct ieeetypes_cfparamset cfparamset; | 33 | struct ieee_ie_cf_param_set cf; |
29 | struct ieeetypes_ibssparamset ibssparamset; | 34 | struct ieee_ie_ibss_param_set ibss; |
30 | } __attribute__ ((packed)); | 35 | } __attribute__ ((packed)); |
31 | 36 | ||
32 | struct ieeetypes_fhparamset { | 37 | struct ieee_ie_fh_param_set { |
33 | u8 elementid; | 38 | struct ieee_ie_header header; |
34 | u8 len; | 39 | |
35 | __le16 dwelltime; | 40 | __le16 dwelltime; |
36 | u8 hopset; | 41 | u8 hopset; |
37 | u8 hoppattern; | 42 | u8 hoppattern; |
38 | u8 hopindex; | 43 | u8 hopindex; |
39 | } __attribute__ ((packed)); | 44 | } __attribute__ ((packed)); |
40 | 45 | ||
41 | struct ieeetypes_dsparamset { | 46 | struct ieee_ie_ds_param_set { |
42 | u8 elementid; | 47 | struct ieee_ie_header header; |
43 | u8 len; | ||
44 | u8 currentchan; | ||
45 | } __attribute__ ((packed)); | ||
46 | 48 | ||
47 | union ieeetypes_phyparamset { | 49 | u8 channel; |
48 | struct ieeetypes_fhparamset fhparamset; | ||
49 | struct ieeetypes_dsparamset dsparamset; | ||
50 | } __attribute__ ((packed)); | 50 | } __attribute__ ((packed)); |
51 | 51 | ||
52 | struct ieeetypes_assocrsp { | 52 | union ieee_phy_param_set { |
53 | __le16 capability; | 53 | struct ieee_ie_fh_param_set fh; |
54 | __le16 statuscode; | 54 | struct ieee_ie_ds_param_set ds; |
55 | __le16 aid; | ||
56 | u8 iebuffer[1]; | ||
57 | } __attribute__ ((packed)); | 55 | } __attribute__ ((packed)); |
58 | 56 | ||
59 | /** TLV type ID definition */ | 57 | /** TLV type ID definition */ |
@@ -94,32 +92,33 @@ struct ieeetypes_assocrsp { | |||
94 | #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) | 92 | #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) |
95 | #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) | 93 | #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) |
96 | #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) | 94 | #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) |
95 | #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) | ||
97 | #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) | 96 | #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) |
98 | #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) | 97 | #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) |
99 | 98 | ||
100 | /** TLV related data structures*/ | 99 | /** TLV related data structures*/ |
101 | struct mrvlietypesheader { | 100 | struct mrvl_ie_header { |
102 | __le16 type; | 101 | __le16 type; |
103 | __le16 len; | 102 | __le16 len; |
104 | } __attribute__ ((packed)); | 103 | } __attribute__ ((packed)); |
105 | 104 | ||
106 | struct mrvlietypes_data { | 105 | struct mrvl_ie_data { |
107 | struct mrvlietypesheader header; | 106 | struct mrvl_ie_header header; |
108 | u8 Data[1]; | 107 | u8 Data[1]; |
109 | } __attribute__ ((packed)); | 108 | } __attribute__ ((packed)); |
110 | 109 | ||
111 | struct mrvlietypes_ratesparamset { | 110 | struct mrvl_ie_rates_param_set { |
112 | struct mrvlietypesheader header; | 111 | struct mrvl_ie_header header; |
113 | u8 rates[1]; | 112 | u8 rates[1]; |
114 | } __attribute__ ((packed)); | 113 | } __attribute__ ((packed)); |
115 | 114 | ||
116 | struct mrvlietypes_ssidparamset { | 115 | struct mrvl_ie_ssid_param_set { |
117 | struct mrvlietypesheader header; | 116 | struct mrvl_ie_header header; |
118 | u8 ssid[1]; | 117 | u8 ssid[1]; |
119 | } __attribute__ ((packed)); | 118 | } __attribute__ ((packed)); |
120 | 119 | ||
121 | struct mrvlietypes_wildcardssidparamset { | 120 | struct mrvl_ie_wildcard_ssid_param_set { |
122 | struct mrvlietypesheader header; | 121 | struct mrvl_ie_header header; |
123 | u8 MaxSsidlength; | 122 | u8 MaxSsidlength; |
124 | u8 ssid[1]; | 123 | u8 ssid[1]; |
125 | } __attribute__ ((packed)); | 124 | } __attribute__ ((packed)); |
@@ -144,91 +143,72 @@ struct chanscanparamset { | |||
144 | __le16 maxscantime; | 143 | __le16 maxscantime; |
145 | } __attribute__ ((packed)); | 144 | } __attribute__ ((packed)); |
146 | 145 | ||
147 | struct mrvlietypes_chanlistparamset { | 146 | struct mrvl_ie_chanlist_param_set { |
148 | struct mrvlietypesheader header; | 147 | struct mrvl_ie_header header; |
149 | struct chanscanparamset chanscanparam[1]; | 148 | struct chanscanparamset chanscanparam[1]; |
150 | } __attribute__ ((packed)); | 149 | } __attribute__ ((packed)); |
151 | 150 | ||
152 | struct cfparamset { | 151 | struct mrvl_ie_cf_param_set { |
152 | struct mrvl_ie_header header; | ||
153 | u8 cfpcnt; | 153 | u8 cfpcnt; |
154 | u8 cfpperiod; | 154 | u8 cfpperiod; |
155 | __le16 cfpmaxduration; | 155 | __le16 cfpmaxduration; |
156 | __le16 cfpdurationremaining; | 156 | __le16 cfpdurationremaining; |
157 | } __attribute__ ((packed)); | 157 | } __attribute__ ((packed)); |
158 | 158 | ||
159 | struct ibssparamset { | 159 | struct mrvl_ie_ds_param_set { |
160 | __le16 atimwindow; | 160 | struct mrvl_ie_header header; |
161 | } __attribute__ ((packed)); | 161 | u8 channel; |
162 | |||
163 | struct mrvlietypes_ssparamset { | ||
164 | struct mrvlietypesheader header; | ||
165 | union { | ||
166 | struct cfparamset cfparamset[1]; | ||
167 | struct ibssparamset ibssparamset[1]; | ||
168 | } cf_ibss; | ||
169 | } __attribute__ ((packed)); | 162 | } __attribute__ ((packed)); |
170 | 163 | ||
171 | struct fhparamset { | 164 | struct mrvl_ie_rsn_param_set { |
172 | __le16 dwelltime; | 165 | struct mrvl_ie_header header; |
173 | u8 hopset; | ||
174 | u8 hoppattern; | ||
175 | u8 hopindex; | ||
176 | } __attribute__ ((packed)); | ||
177 | |||
178 | struct dsparamset { | ||
179 | u8 currentchan; | ||
180 | } __attribute__ ((packed)); | ||
181 | |||
182 | struct mrvlietypes_phyparamset { | ||
183 | struct mrvlietypesheader header; | ||
184 | union { | ||
185 | struct fhparamset fhparamset[1]; | ||
186 | struct dsparamset dsparamset[1]; | ||
187 | } fh_ds; | ||
188 | } __attribute__ ((packed)); | ||
189 | |||
190 | struct mrvlietypes_rsnparamset { | ||
191 | struct mrvlietypesheader header; | ||
192 | u8 rsnie[1]; | 166 | u8 rsnie[1]; |
193 | } __attribute__ ((packed)); | 167 | } __attribute__ ((packed)); |
194 | 168 | ||
195 | struct mrvlietypes_tsftimestamp { | 169 | struct mrvl_ie_tsf_timestamp { |
196 | struct mrvlietypesheader header; | 170 | struct mrvl_ie_header header; |
197 | __le64 tsftable[1]; | 171 | __le64 tsftable[1]; |
198 | } __attribute__ ((packed)); | 172 | } __attribute__ ((packed)); |
199 | 173 | ||
174 | /* v9 and later firmware only */ | ||
175 | struct mrvl_ie_auth_type { | ||
176 | struct mrvl_ie_header header; | ||
177 | __le16 auth; | ||
178 | } __attribute__ ((packed)); | ||
179 | |||
200 | /** Local Power capability */ | 180 | /** Local Power capability */ |
201 | struct mrvlietypes_powercapability { | 181 | struct mrvl_ie_power_capability { |
202 | struct mrvlietypesheader header; | 182 | struct mrvl_ie_header header; |
203 | s8 minpower; | 183 | s8 minpower; |
204 | s8 maxpower; | 184 | s8 maxpower; |
205 | } __attribute__ ((packed)); | 185 | } __attribute__ ((packed)); |
206 | 186 | ||
207 | /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ | 187 | /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ |
208 | struct mrvlietypes_thresholds { | 188 | struct mrvl_ie_thresholds { |
209 | struct mrvlietypesheader header; | 189 | struct mrvl_ie_header header; |
210 | u8 value; | 190 | u8 value; |
211 | u8 freq; | 191 | u8 freq; |
212 | } __attribute__ ((packed)); | 192 | } __attribute__ ((packed)); |
213 | 193 | ||
214 | struct mrvlietypes_beaconsmissed { | 194 | struct mrvl_ie_beacons_missed { |
215 | struct mrvlietypesheader header; | 195 | struct mrvl_ie_header header; |
216 | u8 beaconmissed; | 196 | u8 beaconmissed; |
217 | u8 reserved; | 197 | u8 reserved; |
218 | } __attribute__ ((packed)); | 198 | } __attribute__ ((packed)); |
219 | 199 | ||
220 | struct mrvlietypes_numprobes { | 200 | struct mrvl_ie_num_probes { |
221 | struct mrvlietypesheader header; | 201 | struct mrvl_ie_header header; |
222 | __le16 numprobes; | 202 | __le16 numprobes; |
223 | } __attribute__ ((packed)); | 203 | } __attribute__ ((packed)); |
224 | 204 | ||
225 | struct mrvlietypes_bcastprobe { | 205 | struct mrvl_ie_bcast_probe { |
226 | struct mrvlietypesheader header; | 206 | struct mrvl_ie_header header; |
227 | __le16 bcastprobe; | 207 | __le16 bcastprobe; |
228 | } __attribute__ ((packed)); | 208 | } __attribute__ ((packed)); |
229 | 209 | ||
230 | struct mrvlietypes_numssidprobe { | 210 | struct mrvl_ie_num_ssid_probe { |
231 | struct mrvlietypesheader header; | 211 | struct mrvl_ie_header header; |
232 | __le16 numssidprobe; | 212 | __le16 numssidprobe; |
233 | } __attribute__ ((packed)); | 213 | } __attribute__ ((packed)); |
234 | 214 | ||
@@ -237,8 +217,8 @@ struct led_pin { | |||
237 | u8 pin; | 217 | u8 pin; |
238 | } __attribute__ ((packed)); | 218 | } __attribute__ ((packed)); |
239 | 219 | ||
240 | struct mrvlietypes_ledgpio { | 220 | struct mrvl_ie_ledgpio { |
241 | struct mrvlietypesheader header; | 221 | struct mrvl_ie_header header; |
242 | struct led_pin ledpin[1]; | 222 | struct led_pin ledpin[1]; |
243 | } __attribute__ ((packed)); | 223 | } __attribute__ ((packed)); |
244 | 224 | ||
@@ -250,8 +230,8 @@ struct led_bhv { | |||
250 | } __attribute__ ((packed)); | 230 | } __attribute__ ((packed)); |
251 | 231 | ||
252 | 232 | ||
253 | struct mrvlietypes_ledbhv { | 233 | struct mrvl_ie_ledbhv { |
254 | struct mrvlietypesheader header; | 234 | struct mrvl_ie_header header; |
255 | struct led_bhv ledbhv[1]; | 235 | struct led_bhv ledbhv[1]; |
256 | } __attribute__ ((packed)); | 236 | } __attribute__ ((packed)); |
257 | 237 | ||
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 574b8bb121e1..e789c6e9938c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -280,7 +280,6 @@ struct mac80211_hwsim_data { | |||
280 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; | 280 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; |
281 | 281 | ||
282 | struct ieee80211_channel *channel; | 282 | struct ieee80211_channel *channel; |
283 | int radio_enabled; | ||
284 | unsigned long beacon_int; /* in jiffies unit */ | 283 | unsigned long beacon_int; /* in jiffies unit */ |
285 | unsigned int rx_filter; | 284 | unsigned int rx_filter; |
286 | int started; | 285 | int started; |
@@ -418,8 +417,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
418 | if (data == data2) | 417 | if (data == data2) |
419 | continue; | 418 | continue; |
420 | 419 | ||
421 | if (!data2->started || !data2->radio_enabled || | 420 | if (!data2->started || !hwsim_ps_rx_ok(data2, skb) || |
422 | !hwsim_ps_rx_ok(data2, skb) || | ||
423 | data->channel->center_freq != data2->channel->center_freq || | 421 | data->channel->center_freq != data2->channel->center_freq || |
424 | !(data->group & data2->group)) | 422 | !(data->group & data2->group)) |
425 | continue; | 423 | continue; |
@@ -441,7 +439,6 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
441 | 439 | ||
442 | static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 440 | static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
443 | { | 441 | { |
444 | struct mac80211_hwsim_data *data = hw->priv; | ||
445 | bool ack; | 442 | bool ack; |
446 | struct ieee80211_tx_info *txi; | 443 | struct ieee80211_tx_info *txi; |
447 | 444 | ||
@@ -453,13 +450,6 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
453 | return NETDEV_TX_OK; | 450 | return NETDEV_TX_OK; |
454 | } | 451 | } |
455 | 452 | ||
456 | if (!data->radio_enabled) { | ||
457 | printk(KERN_DEBUG "%s: dropped TX frame since radio " | ||
458 | "disabled\n", wiphy_name(hw->wiphy)); | ||
459 | dev_kfree_skb(skb); | ||
460 | return NETDEV_TX_OK; | ||
461 | } | ||
462 | |||
463 | ack = mac80211_hwsim_tx_frame(hw, skb); | 453 | ack = mac80211_hwsim_tx_frame(hw, skb); |
464 | 454 | ||
465 | txi = IEEE80211_SKB_CB(skb); | 455 | txi = IEEE80211_SKB_CB(skb); |
@@ -546,7 +536,7 @@ static void mac80211_hwsim_beacon(unsigned long arg) | |||
546 | struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; | 536 | struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; |
547 | struct mac80211_hwsim_data *data = hw->priv; | 537 | struct mac80211_hwsim_data *data = hw->priv; |
548 | 538 | ||
549 | if (!data->started || !data->radio_enabled) | 539 | if (!data->started) |
550 | return; | 540 | return; |
551 | 541 | ||
552 | ieee80211_iterate_active_interfaces_atomic( | 542 | ieee80211_iterate_active_interfaces_atomic( |
@@ -562,15 +552,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | |||
562 | struct mac80211_hwsim_data *data = hw->priv; | 552 | struct mac80211_hwsim_data *data = hw->priv; |
563 | struct ieee80211_conf *conf = &hw->conf; | 553 | struct ieee80211_conf *conf = &hw->conf; |
564 | 554 | ||
565 | printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d idle=%d ps=%d)\n", | 555 | printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", |
566 | wiphy_name(hw->wiphy), __func__, | 556 | wiphy_name(hw->wiphy), __func__, |
567 | conf->channel->center_freq, conf->radio_enabled, | 557 | conf->channel->center_freq, |
568 | !!(conf->flags & IEEE80211_CONF_IDLE), | 558 | !!(conf->flags & IEEE80211_CONF_IDLE), |
569 | !!(conf->flags & IEEE80211_CONF_PS)); | 559 | !!(conf->flags & IEEE80211_CONF_PS)); |
570 | 560 | ||
571 | data->channel = conf->channel; | 561 | data->channel = conf->channel; |
572 | data->radio_enabled = conf->radio_enabled; | 562 | if (!data->started || !data->beacon_int) |
573 | if (!data->started || !data->radio_enabled || !data->beacon_int) | ||
574 | del_timer(&data->beacon_timer); | 563 | del_timer(&data->beacon_timer); |
575 | else | 564 | else |
576 | mod_timer(&data->beacon_timer, jiffies + data->beacon_int); | 565 | mod_timer(&data->beacon_timer, jiffies + data->beacon_int); |
@@ -787,8 +776,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
787 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | 776 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); |
788 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | 777 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); |
789 | memcpy(pspoll->ta, mac, ETH_ALEN); | 778 | memcpy(pspoll->ta, mac, ETH_ALEN); |
790 | if (data->radio_enabled && | 779 | if (!mac80211_hwsim_tx_frame(data->hw, skb)) |
791 | !mac80211_hwsim_tx_frame(data->hw, skb)) | ||
792 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); | 780 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); |
793 | dev_kfree_skb(skb); | 781 | dev_kfree_skb(skb); |
794 | } | 782 | } |
@@ -819,8 +807,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | |||
819 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | 807 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); |
820 | memcpy(hdr->addr2, mac, ETH_ALEN); | 808 | memcpy(hdr->addr2, mac, ETH_ALEN); |
821 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | 809 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); |
822 | if (data->radio_enabled && | 810 | if (!mac80211_hwsim_tx_frame(data->hw, skb)) |
823 | !mac80211_hwsim_tx_frame(data->hw, skb)) | ||
824 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | 811 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); |
825 | dev_kfree_skb(skb); | 812 | dev_kfree_skb(skb); |
826 | } | 813 | } |
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index f40c0f468b27..0e877a104a89 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c | |||
@@ -84,8 +84,8 @@ MODULE_DEVICE_TABLE(usb, p54u_table); | |||
84 | static const struct { | 84 | static const struct { |
85 | u32 intf; | 85 | u32 intf; |
86 | enum p54u_hw_type type; | 86 | enum p54u_hw_type type; |
87 | char fw[FIRMWARE_NAME_MAX]; | 87 | const char *fw; |
88 | char fw_legacy[FIRMWARE_NAME_MAX]; | 88 | const char *fw_legacy; |
89 | char hw[20]; | 89 | char hw[20]; |
90 | } p54u_fwlist[__NUM_P54U_HWTYPES] = { | 90 | } p54u_fwlist[__NUM_P54U_HWTYPES] = { |
91 | { | 91 | { |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0197531bd88c..435f945fe64d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -520,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, | |||
520 | if (state == STATE_SLEEP) { | 520 | if (state == STATE_SLEEP) { |
521 | rt2x00pci_register_read(rt2x00dev, CSR20, ®); | 521 | rt2x00pci_register_read(rt2x00dev, CSR20, ®); |
522 | rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, | 522 | rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, |
523 | (libconf->conf->beacon_int - 20) * 16); | 523 | (rt2x00dev->beacon_int - 20) * 16); |
524 | rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, | 524 | rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, |
525 | libconf->conf->listen_interval - 1); | 525 | libconf->conf->listen_interval - 1); |
526 | 526 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index f95cb646f85a..08b30d01e67d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -569,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, | |||
569 | if (state == STATE_SLEEP) { | 569 | if (state == STATE_SLEEP) { |
570 | rt2x00pci_register_read(rt2x00dev, CSR20, ®); | 570 | rt2x00pci_register_read(rt2x00dev, CSR20, ®); |
571 | rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, | 571 | rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, |
572 | (libconf->conf->beacon_int - 20) * 16); | 572 | (rt2x00dev->beacon_int - 20) * 16); |
573 | rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, | 573 | rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, |
574 | libconf->conf->listen_interval - 1); | 574 | libconf->conf->listen_interval - 1); |
575 | 575 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 69f966f1ce54..66daf68ff0ee 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -647,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, | |||
647 | if (state == STATE_SLEEP) { | 647 | if (state == STATE_SLEEP) { |
648 | rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); | 648 | rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); |
649 | rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, | 649 | rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, |
650 | libconf->conf->beacon_int - 20); | 650 | rt2x00dev->beacon_int - 20); |
651 | rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, | 651 | rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, |
652 | libconf->conf->listen_interval - 1); | 652 | libconf->conf->listen_interval - 1); |
653 | 653 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 142ad34fdc49..37561667925b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -2927,12 +2927,17 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
2927 | { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2927 | { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2928 | { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2928 | { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2929 | { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2929 | { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2930 | { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2931 | { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2932 | { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2930 | { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2933 | { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2931 | { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2934 | { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2932 | /* Edimax */ | 2935 | /* Edimax */ |
2933 | { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2936 | { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2934 | { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2937 | { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2935 | { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2938 | { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2939 | /* Encore */ | ||
2940 | { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2936 | /* EnGenius */ | 2941 | /* EnGenius */ |
2937 | { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2942 | { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2938 | { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2943 | { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -2951,6 +2956,8 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
2951 | { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2956 | { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2952 | { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2957 | { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2953 | { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2958 | { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2959 | /* I-O DATA */ | ||
2960 | { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2954 | /* LevelOne */ | 2961 | /* LevelOne */ |
2955 | { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2962 | { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2956 | { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2963 | { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -2970,6 +2977,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
2970 | /* Pegatron */ | 2977 | /* Pegatron */ |
2971 | { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2978 | { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2972 | { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2979 | { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2980 | { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2973 | /* Philips */ | 2981 | /* Philips */ |
2974 | { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2982 | { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2975 | /* Planex */ | 2983 | /* Planex */ |
@@ -2981,6 +2989,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
2981 | /* Quanta */ | 2989 | /* Quanta */ |
2982 | { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2990 | { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2983 | /* Ralink */ | 2991 | /* Ralink */ |
2992 | { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2984 | { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2993 | { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2985 | { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2994 | { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2986 | { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2995 | { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -3005,6 +3014,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
3005 | { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3014 | { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3006 | { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3015 | { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3007 | { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3016 | { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3017 | { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
3008 | /* SMC */ | 3018 | /* SMC */ |
3009 | { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3019 | { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3010 | { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3020 | { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -3029,6 +3039,8 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
3029 | /* Zinwell */ | 3039 | /* Zinwell */ |
3030 | { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3040 | { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3031 | { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3041 | { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3042 | { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
3043 | { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
3032 | /* Zyxel */ | 3044 | /* Zyxel */ |
3033 | { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3045 | { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3034 | { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3046 | { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2b64a6198698..a498dde024e1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -802,6 +802,11 @@ struct rt2x00_dev { | |||
802 | u8 calibration[2]; | 802 | u8 calibration[2]; |
803 | 803 | ||
804 | /* | 804 | /* |
805 | * Beacon interval. | ||
806 | */ | ||
807 | u16 beacon_int; | ||
808 | |||
809 | /* | ||
805 | * Low level statistics which will have | 810 | * Low level statistics which will have |
806 | * to be kept up to date while device is running. | 811 | * to be kept up to date while device is running. |
807 | */ | 812 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index c5bbf0b6e207..3e019a12df2e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -108,6 +108,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, | |||
108 | erp.basic_rates = bss_conf->basic_rates; | 108 | erp.basic_rates = bss_conf->basic_rates; |
109 | erp.beacon_int = bss_conf->beacon_int; | 109 | erp.beacon_int = bss_conf->beacon_int; |
110 | 110 | ||
111 | /* Update global beacon interval time, this is needed for PS support */ | ||
112 | rt2x00dev->beacon_int = bss_conf->beacon_int; | ||
113 | |||
111 | rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); | 114 | rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); |
112 | } | 115 | } |
113 | 116 | ||
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a8bf5c432858..49b29ff90c47 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -956,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, | |||
956 | if (state == STATE_SLEEP) { | 956 | if (state == STATE_SLEEP) { |
957 | rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®); | 957 | rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®); |
958 | rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, | 958 | rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, |
959 | libconf->conf->beacon_int - 10); | 959 | rt2x00dev->beacon_int - 10); |
960 | rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, | 960 | rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, |
961 | libconf->conf->listen_interval - 1); | 961 | libconf->conf->listen_interval - 1); |
962 | rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); | 962 | rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 211a3d6bc054..c18848836f2d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -852,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, | |||
852 | if (state == STATE_SLEEP) { | 852 | if (state == STATE_SLEEP) { |
853 | rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); | 853 | rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); |
854 | rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, | 854 | rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, |
855 | libconf->conf->beacon_int - 10); | 855 | rt2x00dev->beacon_int - 10); |
856 | rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, | 856 | rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, |
857 | libconf->conf->listen_interval - 1); | 857 | libconf->conf->listen_interval - 1); |
858 | rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); | 858 | rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 284ebaca6e45..c682ac536415 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -21,7 +21,7 @@ config ACER_WMI | |||
21 | depends on NEW_LEDS | 21 | depends on NEW_LEDS |
22 | depends on BACKLIGHT_CLASS_DEVICE | 22 | depends on BACKLIGHT_CLASS_DEVICE |
23 | depends on SERIO_I8042 | 23 | depends on SERIO_I8042 |
24 | depends on RFKILL | 24 | depends on RFKILL || RFKILL = n |
25 | select ACPI_WMI | 25 | select ACPI_WMI |
26 | ---help--- | 26 | ---help--- |
27 | This is a driver for newer Acer (and Wistron) laptops. It adds | 27 | This is a driver for newer Acer (and Wistron) laptops. It adds |
@@ -60,7 +60,7 @@ config DELL_LAPTOP | |||
60 | depends on DCDBAS | 60 | depends on DCDBAS |
61 | depends on EXPERIMENTAL | 61 | depends on EXPERIMENTAL |
62 | depends on BACKLIGHT_CLASS_DEVICE | 62 | depends on BACKLIGHT_CLASS_DEVICE |
63 | depends on RFKILL | 63 | depends on RFKILL || RFKILL = n |
64 | depends on POWER_SUPPLY | 64 | depends on POWER_SUPPLY |
65 | default n | 65 | default n |
66 | ---help--- | 66 | ---help--- |
@@ -117,7 +117,7 @@ config HP_WMI | |||
117 | tristate "HP WMI extras" | 117 | tristate "HP WMI extras" |
118 | depends on ACPI_WMI | 118 | depends on ACPI_WMI |
119 | depends on INPUT | 119 | depends on INPUT |
120 | depends on RFKILL | 120 | depends on RFKILL || RFKILL = n |
121 | help | 121 | help |
122 | Say Y here if you want to support WMI-based hotkeys on HP laptops and | 122 | Say Y here if you want to support WMI-based hotkeys on HP laptops and |
123 | to read data from WMI such as docking or ambient light sensor state. | 123 | to read data from WMI such as docking or ambient light sensor state. |
@@ -196,14 +196,13 @@ config THINKPAD_ACPI | |||
196 | tristate "ThinkPad ACPI Laptop Extras" | 196 | tristate "ThinkPad ACPI Laptop Extras" |
197 | depends on ACPI | 197 | depends on ACPI |
198 | depends on INPUT | 198 | depends on INPUT |
199 | depends on RFKILL || RFKILL = n | ||
199 | select BACKLIGHT_LCD_SUPPORT | 200 | select BACKLIGHT_LCD_SUPPORT |
200 | select BACKLIGHT_CLASS_DEVICE | 201 | select BACKLIGHT_CLASS_DEVICE |
201 | select HWMON | 202 | select HWMON |
202 | select NVRAM | 203 | select NVRAM |
203 | select NEW_LEDS | 204 | select NEW_LEDS |
204 | select LEDS_CLASS | 205 | select LEDS_CLASS |
205 | select NET | ||
206 | select RFKILL | ||
207 | ---help--- | 206 | ---help--- |
208 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 207 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
209 | support for Fn-Fx key combinations, Bluetooth control, video | 208 | support for Fn-Fx key combinations, Bluetooth control, video |
@@ -338,9 +337,9 @@ config EEEPC_LAPTOP | |||
338 | depends on ACPI | 337 | depends on ACPI |
339 | depends on INPUT | 338 | depends on INPUT |
340 | depends on EXPERIMENTAL | 339 | depends on EXPERIMENTAL |
340 | depends on RFKILL || RFKILL = n | ||
341 | select BACKLIGHT_CLASS_DEVICE | 341 | select BACKLIGHT_CLASS_DEVICE |
342 | select HWMON | 342 | select HWMON |
343 | select RFKILL | ||
344 | ---help--- | 343 | ---help--- |
345 | This driver supports the Fn-Fx keys on Eee PC laptops. | 344 | This driver supports the Fn-Fx keys on Eee PC laptops. |
346 | It also adds the ability to switch camera/wlan on/off. | 345 | It also adds the ability to switch camera/wlan on/off. |
@@ -405,9 +404,8 @@ config ACPI_TOSHIBA | |||
405 | tristate "Toshiba Laptop Extras" | 404 | tristate "Toshiba Laptop Extras" |
406 | depends on ACPI | 405 | depends on ACPI |
407 | depends on INPUT | 406 | depends on INPUT |
407 | depends on RFKILL || RFKILL = n | ||
408 | select INPUT_POLLDEV | 408 | select INPUT_POLLDEV |
409 | select NET | ||
410 | select RFKILL | ||
411 | select BACKLIGHT_CLASS_DEVICE | 409 | select BACKLIGHT_CLASS_DEVICE |
412 | ---help--- | 410 | ---help--- |
413 | This driver adds support for access to certain system settings | 411 | This driver adds support for access to certain system settings |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 62d02b3c998e..b618fa51db2d 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored) | |||
958 | 958 | ||
959 | status = get_u32(&state, ACER_CAP_WIRELESS); | 959 | status = get_u32(&state, ACER_CAP_WIRELESS); |
960 | if (ACPI_SUCCESS(status)) | 960 | if (ACPI_SUCCESS(status)) |
961 | rfkill_force_state(wireless_rfkill, state ? | 961 | rfkill_set_sw_state(wireless_rfkill, !!state); |
962 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); | ||
963 | 962 | ||
964 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 963 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
965 | status = get_u32(&state, ACER_CAP_BLUETOOTH); | 964 | status = get_u32(&state, ACER_CAP_BLUETOOTH); |
966 | if (ACPI_SUCCESS(status)) | 965 | if (ACPI_SUCCESS(status)) |
967 | rfkill_force_state(bluetooth_rfkill, state ? | 966 | rfkill_set_sw_state(bluetooth_rfkill, !!state); |
968 | RFKILL_STATE_UNBLOCKED : | ||
969 | RFKILL_STATE_SOFT_BLOCKED); | ||
970 | } | 967 | } |
971 | 968 | ||
972 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 969 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
973 | } | 970 | } |
974 | 971 | ||
975 | static int acer_rfkill_set(void *data, enum rfkill_state state) | 972 | static int acer_rfkill_set(void *data, bool blocked) |
976 | { | 973 | { |
977 | acpi_status status; | 974 | acpi_status status; |
978 | u32 *cap = data; | 975 | u32 cap = (unsigned long)data; |
979 | status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); | 976 | status = set_u32(!!blocked, cap); |
980 | if (ACPI_FAILURE(status)) | 977 | if (ACPI_FAILURE(status)) |
981 | return -ENODEV; | 978 | return -ENODEV; |
982 | return 0; | 979 | return 0; |
983 | } | 980 | } |
984 | 981 | ||
985 | static struct rfkill * acer_rfkill_register(struct device *dev, | 982 | static const struct rfkill_ops acer_rfkill_ops = { |
986 | enum rfkill_type type, char *name, u32 cap) | 983 | .set_block = acer_rfkill_set, |
984 | }; | ||
985 | |||
986 | static struct rfkill *acer_rfkill_register(struct device *dev, | ||
987 | enum rfkill_type type, | ||
988 | char *name, u32 cap) | ||
987 | { | 989 | { |
988 | int err; | 990 | int err; |
989 | u32 state; | 991 | u32 state; |
990 | u32 *data; | ||
991 | struct rfkill *rfkill_dev; | 992 | struct rfkill *rfkill_dev; |
992 | 993 | ||
993 | rfkill_dev = rfkill_allocate(dev, type); | 994 | rfkill_dev = rfkill_alloc(name, dev, type, |
995 | &acer_rfkill_ops, | ||
996 | (void *)(unsigned long)cap); | ||
994 | if (!rfkill_dev) | 997 | if (!rfkill_dev) |
995 | return ERR_PTR(-ENOMEM); | 998 | return ERR_PTR(-ENOMEM); |
996 | rfkill_dev->name = name; | ||
997 | get_u32(&state, cap); | 999 | get_u32(&state, cap); |
998 | rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : | 1000 | rfkill_set_sw_state(rfkill_dev, !state); |
999 | RFKILL_STATE_SOFT_BLOCKED; | ||
1000 | data = kzalloc(sizeof(u32), GFP_KERNEL); | ||
1001 | if (!data) { | ||
1002 | rfkill_free(rfkill_dev); | ||
1003 | return ERR_PTR(-ENOMEM); | ||
1004 | } | ||
1005 | *data = cap; | ||
1006 | rfkill_dev->data = data; | ||
1007 | rfkill_dev->toggle_radio = acer_rfkill_set; | ||
1008 | 1001 | ||
1009 | err = rfkill_register(rfkill_dev); | 1002 | err = rfkill_register(rfkill_dev); |
1010 | if (err) { | 1003 | if (err) { |
1011 | kfree(rfkill_dev->data); | 1004 | rfkill_destroy(rfkill_dev); |
1012 | rfkill_free(rfkill_dev); | ||
1013 | return ERR_PTR(err); | 1005 | return ERR_PTR(err); |
1014 | } | 1006 | } |
1015 | return rfkill_dev; | 1007 | return rfkill_dev; |
@@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev) | |||
1027 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", | 1019 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", |
1028 | ACER_CAP_BLUETOOTH); | 1020 | ACER_CAP_BLUETOOTH); |
1029 | if (IS_ERR(bluetooth_rfkill)) { | 1021 | if (IS_ERR(bluetooth_rfkill)) { |
1030 | kfree(wireless_rfkill->data); | ||
1031 | rfkill_unregister(wireless_rfkill); | 1022 | rfkill_unregister(wireless_rfkill); |
1023 | rfkill_destroy(wireless_rfkill); | ||
1032 | return PTR_ERR(bluetooth_rfkill); | 1024 | return PTR_ERR(bluetooth_rfkill); |
1033 | } | 1025 | } |
1034 | } | 1026 | } |
@@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev) | |||
1041 | static void acer_rfkill_exit(void) | 1033 | static void acer_rfkill_exit(void) |
1042 | { | 1034 | { |
1043 | cancel_delayed_work_sync(&acer_rfkill_work); | 1035 | cancel_delayed_work_sync(&acer_rfkill_work); |
1044 | kfree(wireless_rfkill->data); | 1036 | |
1045 | rfkill_unregister(wireless_rfkill); | 1037 | rfkill_unregister(wireless_rfkill); |
1038 | rfkill_destroy(wireless_rfkill); | ||
1039 | |||
1046 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 1040 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
1047 | kfree(bluetooth_rfkill->data); | ||
1048 | rfkill_unregister(bluetooth_rfkill); | 1041 | rfkill_unregister(bluetooth_rfkill); |
1042 | rfkill_destroy(bluetooth_rfkill); | ||
1049 | } | 1043 | } |
1050 | return; | 1044 | return; |
1051 | } | 1045 | } |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index af9f43021172..2faf0e14f05a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
174 | result[3]: NVRAM format version number | 174 | result[3]: NVRAM format version number |
175 | */ | 175 | */ |
176 | 176 | ||
177 | static int dell_rfkill_set(int radio, enum rfkill_state state) | 177 | static int dell_rfkill_set(void *data, bool blocked) |
178 | { | 178 | { |
179 | struct calling_interface_buffer buffer; | 179 | struct calling_interface_buffer buffer; |
180 | int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; | 180 | int disable = blocked ? 0 : 1; |
181 | unsigned long radio = (unsigned long)data; | ||
181 | 182 | ||
182 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 183 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); |
183 | buffer.input[0] = (1 | (radio<<8) | (disable << 16)); | 184 | buffer.input[0] = (1 | (radio<<8) | (disable << 16)); |
@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state) | |||
186 | return 0; | 187 | return 0; |
187 | } | 188 | } |
188 | 189 | ||
189 | static int dell_wifi_set(void *data, enum rfkill_state state) | 190 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) |
190 | { | ||
191 | return dell_rfkill_set(1, state); | ||
192 | } | ||
193 | |||
194 | static int dell_bluetooth_set(void *data, enum rfkill_state state) | ||
195 | { | ||
196 | return dell_rfkill_set(2, state); | ||
197 | } | ||
198 | |||
199 | static int dell_wwan_set(void *data, enum rfkill_state state) | ||
200 | { | ||
201 | return dell_rfkill_set(3, state); | ||
202 | } | ||
203 | |||
204 | static int dell_rfkill_get(int bit, enum rfkill_state *state) | ||
205 | { | 191 | { |
206 | struct calling_interface_buffer buffer; | 192 | struct calling_interface_buffer buffer; |
207 | int status; | 193 | int status; |
208 | int new_state = RFKILL_STATE_HARD_BLOCKED; | 194 | int bit = (unsigned long)data + 16; |
209 | 195 | ||
210 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 196 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); |
211 | dell_send_request(&buffer, 17, 11); | 197 | dell_send_request(&buffer, 17, 11); |
212 | status = buffer.output[1]; | 198 | status = buffer.output[1]; |
213 | 199 | ||
214 | if (status & (1<<16)) | 200 | if (status & BIT(bit)) |
215 | new_state = RFKILL_STATE_SOFT_BLOCKED; | 201 | rfkill_set_hw_state(rfkill, !!(status & BIT(16))); |
216 | |||
217 | if (status & (1<<bit)) | ||
218 | *state = new_state; | ||
219 | else | ||
220 | *state = RFKILL_STATE_UNBLOCKED; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int dell_wifi_get(void *data, enum rfkill_state *state) | ||
226 | { | ||
227 | return dell_rfkill_get(17, state); | ||
228 | } | ||
229 | |||
230 | static int dell_bluetooth_get(void *data, enum rfkill_state *state) | ||
231 | { | ||
232 | return dell_rfkill_get(18, state); | ||
233 | } | 202 | } |
234 | 203 | ||
235 | static int dell_wwan_get(void *data, enum rfkill_state *state) | 204 | static const struct rfkill_ops dell_rfkill_ops = { |
236 | { | 205 | .set_block = dell_rfkill_set, |
237 | return dell_rfkill_get(19, state); | 206 | .query = dell_rfkill_query, |
238 | } | 207 | }; |
239 | 208 | ||
240 | static int dell_setup_rfkill(void) | 209 | static int dell_setup_rfkill(void) |
241 | { | 210 | { |
@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void) | |||
248 | status = buffer.output[1]; | 217 | status = buffer.output[1]; |
249 | 218 | ||
250 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 219 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |
251 | wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN); | 220 | wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, |
252 | if (!wifi_rfkill) | 221 | &dell_rfkill_ops, (void *) 1); |
222 | if (!wifi_rfkill) { | ||
223 | ret = -ENOMEM; | ||
253 | goto err_wifi; | 224 | goto err_wifi; |
254 | wifi_rfkill->name = "dell-wifi"; | 225 | } |
255 | wifi_rfkill->toggle_radio = dell_wifi_set; | ||
256 | wifi_rfkill->get_state = dell_wifi_get; | ||
257 | ret = rfkill_register(wifi_rfkill); | 226 | ret = rfkill_register(wifi_rfkill); |
258 | if (ret) | 227 | if (ret) |
259 | goto err_wifi; | 228 | goto err_wifi; |
260 | } | 229 | } |
261 | 230 | ||
262 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | 231 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { |
263 | bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); | 232 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, |
264 | if (!bluetooth_rfkill) | 233 | RFKILL_TYPE_BLUETOOTH, |
234 | &dell_rfkill_ops, (void *) 2); | ||
235 | if (!bluetooth_rfkill) { | ||
236 | ret = -ENOMEM; | ||
265 | goto err_bluetooth; | 237 | goto err_bluetooth; |
266 | bluetooth_rfkill->name = "dell-bluetooth"; | 238 | } |
267 | bluetooth_rfkill->toggle_radio = dell_bluetooth_set; | ||
268 | bluetooth_rfkill->get_state = dell_bluetooth_get; | ||
269 | ret = rfkill_register(bluetooth_rfkill); | 239 | ret = rfkill_register(bluetooth_rfkill); |
270 | if (ret) | 240 | if (ret) |
271 | goto err_bluetooth; | 241 | goto err_bluetooth; |
272 | } | 242 | } |
273 | 243 | ||
274 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | 244 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { |
275 | wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); | 245 | wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, |
276 | if (!wwan_rfkill) | 246 | &dell_rfkill_ops, (void *) 3); |
247 | if (!wwan_rfkill) { | ||
248 | ret = -ENOMEM; | ||
277 | goto err_wwan; | 249 | goto err_wwan; |
278 | wwan_rfkill->name = "dell-wwan"; | 250 | } |
279 | wwan_rfkill->toggle_radio = dell_wwan_set; | ||
280 | wwan_rfkill->get_state = dell_wwan_get; | ||
281 | ret = rfkill_register(wwan_rfkill); | 251 | ret = rfkill_register(wwan_rfkill); |
282 | if (ret) | 252 | if (ret) |
283 | goto err_wwan; | 253 | goto err_wwan; |
@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void) | |||
285 | 255 | ||
286 | return 0; | 256 | return 0; |
287 | err_wwan: | 257 | err_wwan: |
288 | if (wwan_rfkill) | 258 | rfkill_destroy(wwan_rfkill); |
289 | rfkill_free(wwan_rfkill); | 259 | if (bluetooth_rfkill) |
290 | if (bluetooth_rfkill) { | ||
291 | rfkill_unregister(bluetooth_rfkill); | 260 | rfkill_unregister(bluetooth_rfkill); |
292 | bluetooth_rfkill = NULL; | ||
293 | } | ||
294 | err_bluetooth: | 261 | err_bluetooth: |
295 | if (bluetooth_rfkill) | 262 | rfkill_destroy(bluetooth_rfkill); |
296 | rfkill_free(bluetooth_rfkill); | 263 | if (wifi_rfkill) |
297 | if (wifi_rfkill) { | ||
298 | rfkill_unregister(wifi_rfkill); | 264 | rfkill_unregister(wifi_rfkill); |
299 | wifi_rfkill = NULL; | ||
300 | } | ||
301 | err_wifi: | 265 | err_wifi: |
302 | if (wifi_rfkill) | 266 | rfkill_destroy(wifi_rfkill); |
303 | rfkill_free(wifi_rfkill); | ||
304 | 267 | ||
305 | return ret; | 268 | return ret; |
306 | } | 269 | } |
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 353a898c3693..1208d0cedd15 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd) | |||
299 | * Rfkill helpers | 299 | * Rfkill helpers |
300 | */ | 300 | */ |
301 | 301 | ||
302 | static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) | 302 | static bool eeepc_wlan_rfkill_blocked(void) |
303 | { | ||
304 | if (state == RFKILL_STATE_SOFT_BLOCKED) | ||
305 | return set_acpi(CM_ASL_WLAN, 0); | ||
306 | else | ||
307 | return set_acpi(CM_ASL_WLAN, 1); | ||
308 | } | ||
309 | |||
310 | static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) | ||
311 | { | 303 | { |
312 | if (get_acpi(CM_ASL_WLAN) == 1) | 304 | if (get_acpi(CM_ASL_WLAN) == 1) |
313 | *state = RFKILL_STATE_UNBLOCKED; | 305 | return false; |
314 | else | 306 | return true; |
315 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
316 | return 0; | ||
317 | } | 307 | } |
318 | 308 | ||
319 | static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) | 309 | static int eeepc_rfkill_set(void *data, bool blocked) |
320 | { | 310 | { |
321 | if (state == RFKILL_STATE_SOFT_BLOCKED) | 311 | unsigned long asl = (unsigned long)data; |
322 | return set_acpi(CM_ASL_BLUETOOTH, 0); | 312 | return set_acpi(asl, !blocked); |
323 | else | ||
324 | return set_acpi(CM_ASL_BLUETOOTH, 1); | ||
325 | } | 313 | } |
326 | 314 | ||
327 | static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) | 315 | static const struct rfkill_ops eeepc_rfkill_ops = { |
328 | { | 316 | .set_block = eeepc_rfkill_set, |
329 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) | 317 | }; |
330 | *state = RFKILL_STATE_UNBLOCKED; | ||
331 | else | ||
332 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
333 | return 0; | ||
334 | } | ||
335 | 318 | ||
336 | /* | 319 | /* |
337 | * Sys helpers | 320 | * Sys helpers |
@@ -531,9 +514,9 @@ static int notify_brn(void) | |||
531 | 514 | ||
532 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | 515 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) |
533 | { | 516 | { |
534 | enum rfkill_state state; | ||
535 | struct pci_dev *dev; | 517 | struct pci_dev *dev; |
536 | struct pci_bus *bus = pci_find_bus(0, 1); | 518 | struct pci_bus *bus = pci_find_bus(0, 1); |
519 | bool blocked; | ||
537 | 520 | ||
538 | if (event != ACPI_NOTIFY_BUS_CHECK) | 521 | if (event != ACPI_NOTIFY_BUS_CHECK) |
539 | return; | 522 | return; |
@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
543 | return; | 526 | return; |
544 | } | 527 | } |
545 | 528 | ||
546 | eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state); | 529 | blocked = eeepc_wlan_rfkill_blocked(); |
547 | 530 | if (!blocked) { | |
548 | if (state == RFKILL_STATE_UNBLOCKED) { | ||
549 | dev = pci_get_slot(bus, 0); | 531 | dev = pci_get_slot(bus, 0); |
550 | if (dev) { | 532 | if (dev) { |
551 | /* Device already present */ | 533 | /* Device already present */ |
@@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
566 | } | 548 | } |
567 | } | 549 | } |
568 | 550 | ||
569 | rfkill_force_state(ehotk->eeepc_wlan_rfkill, state); | 551 | rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); |
570 | } | 552 | } |
571 | 553 | ||
572 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) | 554 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) |
@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
684 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); | 666 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); |
685 | 667 | ||
686 | if (get_acpi(CM_ASL_WLAN) != -1) { | 668 | if (get_acpi(CM_ASL_WLAN) != -1) { |
687 | ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, | 669 | ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", |
688 | RFKILL_TYPE_WLAN); | 670 | &device->dev, |
671 | RFKILL_TYPE_WLAN, | ||
672 | &eeepc_rfkill_ops, | ||
673 | (void *)CM_ASL_WLAN); | ||
689 | 674 | ||
690 | if (!ehotk->eeepc_wlan_rfkill) | 675 | if (!ehotk->eeepc_wlan_rfkill) |
691 | goto wlan_fail; | 676 | goto wlan_fail; |
692 | 677 | ||
693 | ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; | 678 | rfkill_set_global_sw_state(RFKILL_TYPE_WLAN, |
694 | ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; | 679 | get_acpi(CM_ASL_WLAN) != 1); |
695 | ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; | ||
696 | if (get_acpi(CM_ASL_WLAN) == 1) { | ||
697 | ehotk->eeepc_wlan_rfkill->state = | ||
698 | RFKILL_STATE_UNBLOCKED; | ||
699 | rfkill_set_default(RFKILL_TYPE_WLAN, | ||
700 | RFKILL_STATE_UNBLOCKED); | ||
701 | } else { | ||
702 | ehotk->eeepc_wlan_rfkill->state = | ||
703 | RFKILL_STATE_SOFT_BLOCKED; | ||
704 | rfkill_set_default(RFKILL_TYPE_WLAN, | ||
705 | RFKILL_STATE_SOFT_BLOCKED); | ||
706 | } | ||
707 | result = rfkill_register(ehotk->eeepc_wlan_rfkill); | 680 | result = rfkill_register(ehotk->eeepc_wlan_rfkill); |
708 | if (result) | 681 | if (result) |
709 | goto wlan_fail; | 682 | goto wlan_fail; |
@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
711 | 684 | ||
712 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { | 685 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { |
713 | ehotk->eeepc_bluetooth_rfkill = | 686 | ehotk->eeepc_bluetooth_rfkill = |
714 | rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); | 687 | rfkill_alloc("eeepc-bluetooth", |
688 | &device->dev, | ||
689 | RFKILL_TYPE_BLUETOOTH, | ||
690 | &eeepc_rfkill_ops, | ||
691 | (void *)CM_ASL_BLUETOOTH); | ||
715 | 692 | ||
716 | if (!ehotk->eeepc_bluetooth_rfkill) | 693 | if (!ehotk->eeepc_bluetooth_rfkill) |
717 | goto bluetooth_fail; | 694 | goto bluetooth_fail; |
718 | 695 | ||
719 | ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; | 696 | rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH, |
720 | ehotk->eeepc_bluetooth_rfkill->toggle_radio = | 697 | get_acpi(CM_ASL_BLUETOOTH) != 1); |
721 | eeepc_bluetooth_rfkill_set; | ||
722 | ehotk->eeepc_bluetooth_rfkill->get_state = | ||
723 | eeepc_bluetooth_rfkill_state; | ||
724 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) { | ||
725 | ehotk->eeepc_bluetooth_rfkill->state = | ||
726 | RFKILL_STATE_UNBLOCKED; | ||
727 | rfkill_set_default(RFKILL_TYPE_BLUETOOTH, | ||
728 | RFKILL_STATE_UNBLOCKED); | ||
729 | } else { | ||
730 | ehotk->eeepc_bluetooth_rfkill->state = | ||
731 | RFKILL_STATE_SOFT_BLOCKED; | ||
732 | rfkill_set_default(RFKILL_TYPE_BLUETOOTH, | ||
733 | RFKILL_STATE_SOFT_BLOCKED); | ||
734 | } | ||
735 | |||
736 | result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); | 698 | result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); |
737 | if (result) | 699 | if (result) |
738 | goto bluetooth_fail; | 700 | goto bluetooth_fail; |
@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
741 | return 0; | 703 | return 0; |
742 | 704 | ||
743 | bluetooth_fail: | 705 | bluetooth_fail: |
744 | if (ehotk->eeepc_bluetooth_rfkill) | 706 | rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); |
745 | rfkill_free(ehotk->eeepc_bluetooth_rfkill); | ||
746 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); | 707 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); |
747 | ehotk->eeepc_wlan_rfkill = NULL; | ||
748 | wlan_fail: | 708 | wlan_fail: |
749 | if (ehotk->eeepc_wlan_rfkill) | 709 | rfkill_destroy(ehotk->eeepc_wlan_rfkill); |
750 | rfkill_free(ehotk->eeepc_wlan_rfkill); | ||
751 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); | 710 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); |
752 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); | 711 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); |
753 | ehotk_fail: | 712 | ehotk_fail: |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fe171fad12cf..8d931145cbfa 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void) | |||
154 | return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); | 154 | return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); |
155 | } | 155 | } |
156 | 156 | ||
157 | static int hp_wmi_wifi_set(void *data, enum rfkill_state state) | 157 | static int hp_wmi_set_block(void *data, bool blocked) |
158 | { | 158 | { |
159 | if (state) | 159 | unsigned long b = (unsigned long) data; |
160 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); | 160 | int query = BIT(b + 8) | ((!!blocked) << b); |
161 | else | ||
162 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100); | ||
163 | } | ||
164 | 161 | ||
165 | static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) | 162 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); |
166 | { | ||
167 | if (state) | ||
168 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202); | ||
169 | else | ||
170 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200); | ||
171 | } | 163 | } |
172 | 164 | ||
173 | static int hp_wmi_wwan_set(void *data, enum rfkill_state state) | 165 | static const struct rfkill_ops hp_wmi_rfkill_ops = { |
174 | { | 166 | .set_block = hp_wmi_set_block, |
175 | if (state) | 167 | }; |
176 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404); | ||
177 | else | ||
178 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400); | ||
179 | } | ||
180 | 168 | ||
181 | static int hp_wmi_wifi_state(void) | 169 | static bool hp_wmi_wifi_state(void) |
182 | { | 170 | { |
183 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 171 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
184 | 172 | ||
185 | if (wireless & 0x100) | 173 | if (wireless & 0x100) |
186 | return RFKILL_STATE_UNBLOCKED; | 174 | return false; |
187 | else | 175 | else |
188 | return RFKILL_STATE_SOFT_BLOCKED; | 176 | return true; |
189 | } | 177 | } |
190 | 178 | ||
191 | static int hp_wmi_bluetooth_state(void) | 179 | static bool hp_wmi_bluetooth_state(void) |
192 | { | 180 | { |
193 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 181 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
194 | 182 | ||
195 | if (wireless & 0x10000) | 183 | if (wireless & 0x10000) |
196 | return RFKILL_STATE_UNBLOCKED; | 184 | return false; |
197 | else | 185 | else |
198 | return RFKILL_STATE_SOFT_BLOCKED; | 186 | return true; |
199 | } | 187 | } |
200 | 188 | ||
201 | static int hp_wmi_wwan_state(void) | 189 | static bool hp_wmi_wwan_state(void) |
202 | { | 190 | { |
203 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 191 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
204 | 192 | ||
205 | if (wireless & 0x1000000) | 193 | if (wireless & 0x1000000) |
206 | return RFKILL_STATE_UNBLOCKED; | 194 | return false; |
207 | else | 195 | else |
208 | return RFKILL_STATE_SOFT_BLOCKED; | 196 | return true; |
209 | } | 197 | } |
210 | 198 | ||
211 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, | 199 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, |
@@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context) | |||
347 | } | 335 | } |
348 | } else if (eventcode == 0x5) { | 336 | } else if (eventcode == 0x5) { |
349 | if (wifi_rfkill) | 337 | if (wifi_rfkill) |
350 | rfkill_force_state(wifi_rfkill, | 338 | rfkill_set_sw_state(wifi_rfkill, |
351 | hp_wmi_wifi_state()); | 339 | hp_wmi_wifi_state()); |
352 | if (bluetooth_rfkill) | 340 | if (bluetooth_rfkill) |
353 | rfkill_force_state(bluetooth_rfkill, | 341 | rfkill_set_sw_state(bluetooth_rfkill, |
354 | hp_wmi_bluetooth_state()); | 342 | hp_wmi_bluetooth_state()); |
355 | if (wwan_rfkill) | 343 | if (wwan_rfkill) |
356 | rfkill_force_state(wwan_rfkill, | 344 | rfkill_set_sw_state(wwan_rfkill, |
357 | hp_wmi_wwan_state()); | 345 | hp_wmi_wwan_state()); |
358 | } else | 346 | } else |
359 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", | 347 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", |
360 | eventcode); | 348 | eventcode); |
@@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
430 | goto add_sysfs_error; | 418 | goto add_sysfs_error; |
431 | 419 | ||
432 | if (wireless & 0x1) { | 420 | if (wireless & 0x1) { |
433 | wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | 421 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
434 | wifi_rfkill->name = "hp-wifi"; | 422 | RFKILL_TYPE_WLAN, |
435 | wifi_rfkill->state = hp_wmi_wifi_state(); | 423 | &hp_wmi_rfkill_ops, |
436 | wifi_rfkill->toggle_radio = hp_wmi_wifi_set; | 424 | (void *) 0); |
425 | rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state()); | ||
437 | err = rfkill_register(wifi_rfkill); | 426 | err = rfkill_register(wifi_rfkill); |
438 | if (err) | 427 | if (err) |
439 | goto add_sysfs_error; | 428 | goto register_wifi_error; |
440 | } | 429 | } |
441 | 430 | ||
442 | if (wireless & 0x2) { | 431 | if (wireless & 0x2) { |
443 | bluetooth_rfkill = rfkill_allocate(&device->dev, | 432 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, |
444 | RFKILL_TYPE_BLUETOOTH); | 433 | RFKILL_TYPE_BLUETOOTH, |
445 | bluetooth_rfkill->name = "hp-bluetooth"; | 434 | &hp_wmi_rfkill_ops, |
446 | bluetooth_rfkill->state = hp_wmi_bluetooth_state(); | 435 | (void *) 1); |
447 | bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; | 436 | rfkill_set_sw_state(bluetooth_rfkill, |
437 | hp_wmi_bluetooth_state()); | ||
448 | err = rfkill_register(bluetooth_rfkill); | 438 | err = rfkill_register(bluetooth_rfkill); |
449 | if (err) | 439 | if (err) |
450 | goto register_bluetooth_error; | 440 | goto register_bluetooth_error; |
451 | } | 441 | } |
452 | 442 | ||
453 | if (wireless & 0x4) { | 443 | if (wireless & 0x4) { |
454 | wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); | 444 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, |
455 | wwan_rfkill->name = "hp-wwan"; | 445 | RFKILL_TYPE_WWAN, |
456 | wwan_rfkill->state = hp_wmi_wwan_state(); | 446 | &hp_wmi_rfkill_ops, |
457 | wwan_rfkill->toggle_radio = hp_wmi_wwan_set; | 447 | (void *) 2); |
448 | rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state()); | ||
458 | err = rfkill_register(wwan_rfkill); | 449 | err = rfkill_register(wwan_rfkill); |
459 | if (err) | 450 | if (err) |
460 | goto register_wwan_err; | 451 | goto register_wwan_err; |
@@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
462 | 453 | ||
463 | return 0; | 454 | return 0; |
464 | register_wwan_err: | 455 | register_wwan_err: |
456 | rfkill_destroy(wwan_rfkill); | ||
465 | if (bluetooth_rfkill) | 457 | if (bluetooth_rfkill) |
466 | rfkill_unregister(bluetooth_rfkill); | 458 | rfkill_unregister(bluetooth_rfkill); |
467 | register_bluetooth_error: | 459 | register_bluetooth_error: |
460 | rfkill_destroy(bluetooth_rfkill); | ||
468 | if (wifi_rfkill) | 461 | if (wifi_rfkill) |
469 | rfkill_unregister(wifi_rfkill); | 462 | rfkill_unregister(wifi_rfkill); |
463 | register_wifi_error: | ||
464 | rfkill_destroy(wifi_rfkill); | ||
470 | add_sysfs_error: | 465 | add_sysfs_error: |
471 | cleanup_sysfs(device); | 466 | cleanup_sysfs(device); |
472 | return err; | 467 | return err; |
@@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) | |||
476 | { | 471 | { |
477 | cleanup_sysfs(device); | 472 | cleanup_sysfs(device); |
478 | 473 | ||
479 | if (wifi_rfkill) | 474 | if (wifi_rfkill) { |
480 | rfkill_unregister(wifi_rfkill); | 475 | rfkill_unregister(wifi_rfkill); |
481 | if (bluetooth_rfkill) | 476 | rfkill_destroy(wifi_rfkill); |
477 | } | ||
478 | if (bluetooth_rfkill) { | ||
482 | rfkill_unregister(bluetooth_rfkill); | 479 | rfkill_unregister(bluetooth_rfkill); |
483 | if (wwan_rfkill) | 480 | rfkill_destroy(wifi_rfkill); |
481 | } | ||
482 | if (wwan_rfkill) { | ||
484 | rfkill_unregister(wwan_rfkill); | 483 | rfkill_unregister(wwan_rfkill); |
484 | rfkill_destroy(wwan_rfkill); | ||
485 | } | ||
485 | 486 | ||
486 | return 0; | 487 | return 0; |
487 | } | 488 | } |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f1963b05175b..aec0b27fd774 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -128,11 +128,11 @@ enum sony_nc_rfkill { | |||
128 | SONY_BLUETOOTH, | 128 | SONY_BLUETOOTH, |
129 | SONY_WWAN, | 129 | SONY_WWAN, |
130 | SONY_WIMAX, | 130 | SONY_WIMAX, |
131 | SONY_RFKILL_MAX, | 131 | N_SONY_RFKILL, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; | 134 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
135 | static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; | 135 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
136 | static void sony_nc_rfkill_update(void); | 136 | static void sony_nc_rfkill_update(void); |
137 | 137 | ||
138 | /*********** Input Devices ***********/ | 138 | /*********** Input Devices ***********/ |
@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void) | |||
1051 | { | 1051 | { |
1052 | int i; | 1052 | int i; |
1053 | 1053 | ||
1054 | for (i = 0; i < SONY_RFKILL_MAX; i++) { | 1054 | for (i = 0; i < N_SONY_RFKILL; i++) { |
1055 | if (sony_rfkill_devices[i]) | 1055 | if (sony_rfkill_devices[i]) { |
1056 | rfkill_unregister(sony_rfkill_devices[i]); | 1056 | rfkill_unregister(sony_rfkill_devices[i]); |
1057 | rfkill_destroy(sony_rfkill_devices[i]); | ||
1058 | } | ||
1057 | } | 1059 | } |
1058 | } | 1060 | } |
1059 | 1061 | ||
1060 | static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) | 1062 | static int sony_nc_rfkill_set(void *data, bool blocked) |
1061 | { | ||
1062 | int result; | ||
1063 | int argument = sony_rfkill_address[(long) data]; | ||
1064 | |||
1065 | sony_call_snc_handle(0x124, 0x200, &result); | ||
1066 | if (result & 0x1) { | ||
1067 | sony_call_snc_handle(0x124, argument, &result); | ||
1068 | if (result & 0xf) | ||
1069 | *state = RFKILL_STATE_UNBLOCKED; | ||
1070 | else | ||
1071 | *state = RFKILL_STATE_SOFT_BLOCKED; | ||
1072 | } else { | ||
1073 | *state = RFKILL_STATE_HARD_BLOCKED; | ||
1074 | } | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int sony_nc_rfkill_set(void *data, enum rfkill_state state) | ||
1080 | { | 1063 | { |
1081 | int result; | 1064 | int result; |
1082 | int argument = sony_rfkill_address[(long) data] + 0x100; | 1065 | int argument = sony_rfkill_address[(long) data] + 0x100; |
1083 | 1066 | ||
1084 | if (state == RFKILL_STATE_UNBLOCKED) | 1067 | if (!blocked) |
1085 | argument |= 0xff0000; | 1068 | argument |= 0xff0000; |
1086 | 1069 | ||
1087 | return sony_call_snc_handle(0x124, argument, &result); | 1070 | return sony_call_snc_handle(0x124, argument, &result); |
1088 | } | 1071 | } |
1089 | 1072 | ||
1090 | static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) | 1073 | static const struct rfkill_ops sony_rfkill_ops = { |
1091 | { | 1074 | .set_block = sony_nc_rfkill_set, |
1092 | int err = 0; | 1075 | }; |
1093 | struct rfkill *sony_wifi_rfkill; | ||
1094 | |||
1095 | sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | ||
1096 | if (!sony_wifi_rfkill) | ||
1097 | return -1; | ||
1098 | sony_wifi_rfkill->name = "sony-wifi"; | ||
1099 | sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1100 | sony_wifi_rfkill->get_state = sony_nc_rfkill_get; | ||
1101 | sony_wifi_rfkill->data = (void *)SONY_WIFI; | ||
1102 | err = rfkill_register(sony_wifi_rfkill); | ||
1103 | if (err) | ||
1104 | rfkill_free(sony_wifi_rfkill); | ||
1105 | else { | ||
1106 | sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill; | ||
1107 | sony_nc_rfkill_set(sony_wifi_rfkill->data, | ||
1108 | RFKILL_STATE_UNBLOCKED); | ||
1109 | } | ||
1110 | return err; | ||
1111 | } | ||
1112 | 1076 | ||
1113 | static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) | 1077 | static int sony_nc_setup_rfkill(struct acpi_device *device, |
1078 | enum sony_nc_rfkill nc_type) | ||
1114 | { | 1079 | { |
1115 | int err = 0; | 1080 | int err = 0; |
1116 | struct rfkill *sony_bluetooth_rfkill; | 1081 | struct rfkill *rfk; |
1117 | 1082 | enum rfkill_type type; | |
1118 | sony_bluetooth_rfkill = rfkill_allocate(&device->dev, | 1083 | const char *name; |
1119 | RFKILL_TYPE_BLUETOOTH); | 1084 | |
1120 | if (!sony_bluetooth_rfkill) | 1085 | switch (nc_type) { |
1121 | return -1; | 1086 | case SONY_WIFI: |
1122 | sony_bluetooth_rfkill->name = "sony-bluetooth"; | 1087 | type = RFKILL_TYPE_WLAN; |
1123 | sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; | 1088 | name = "sony-wifi"; |
1124 | sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; | 1089 | break; |
1125 | sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; | 1090 | case SONY_BLUETOOTH: |
1126 | err = rfkill_register(sony_bluetooth_rfkill); | 1091 | type = RFKILL_TYPE_BLUETOOTH; |
1127 | if (err) | 1092 | name = "sony-bluetooth"; |
1128 | rfkill_free(sony_bluetooth_rfkill); | 1093 | break; |
1129 | else { | 1094 | case SONY_WWAN: |
1130 | sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; | 1095 | type = RFKILL_TYPE_WWAN; |
1131 | sony_nc_rfkill_set(sony_bluetooth_rfkill->data, | 1096 | name = "sony-wwan"; |
1132 | RFKILL_STATE_UNBLOCKED); | 1097 | break; |
1098 | case SONY_WIMAX: | ||
1099 | type = RFKILL_TYPE_WIMAX; | ||
1100 | name = "sony-wimax"; | ||
1101 | break; | ||
1102 | default: | ||
1103 | return -EINVAL; | ||
1133 | } | 1104 | } |
1134 | return err; | ||
1135 | } | ||
1136 | 1105 | ||
1137 | static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) | 1106 | rfk = rfkill_alloc(name, &device->dev, type, |
1138 | { | 1107 | &sony_rfkill_ops, (void *)nc_type); |
1139 | int err = 0; | 1108 | if (!rfk) |
1140 | struct rfkill *sony_wwan_rfkill; | 1109 | return -ENOMEM; |
1141 | 1110 | ||
1142 | sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); | 1111 | err = rfkill_register(rfk); |
1143 | if (!sony_wwan_rfkill) | 1112 | if (err) { |
1144 | return -1; | 1113 | rfkill_destroy(rfk); |
1145 | sony_wwan_rfkill->name = "sony-wwan"; | 1114 | return err; |
1146 | sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1147 | sony_wwan_rfkill->get_state = sony_nc_rfkill_get; | ||
1148 | sony_wwan_rfkill->data = (void *)SONY_WWAN; | ||
1149 | err = rfkill_register(sony_wwan_rfkill); | ||
1150 | if (err) | ||
1151 | rfkill_free(sony_wwan_rfkill); | ||
1152 | else { | ||
1153 | sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill; | ||
1154 | sony_nc_rfkill_set(sony_wwan_rfkill->data, | ||
1155 | RFKILL_STATE_UNBLOCKED); | ||
1156 | } | 1115 | } |
1116 | sony_rfkill_devices[nc_type] = rfk; | ||
1117 | sony_nc_rfkill_set((void *)nc_type, false); | ||
1157 | return err; | 1118 | return err; |
1158 | } | 1119 | } |
1159 | 1120 | ||
1160 | static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) | 1121 | static void sony_nc_rfkill_update() |
1161 | { | 1122 | { |
1162 | int err = 0; | 1123 | enum sony_nc_rfkill i; |
1163 | struct rfkill *sony_wimax_rfkill; | 1124 | int result; |
1125 | bool hwblock; | ||
1164 | 1126 | ||
1165 | sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); | 1127 | sony_call_snc_handle(0x124, 0x200, &result); |
1166 | if (!sony_wimax_rfkill) | 1128 | hwblock = !(result & 0x1); |
1167 | return -1; | ||
1168 | sony_wimax_rfkill->name = "sony-wimax"; | ||
1169 | sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; | ||
1170 | sony_wimax_rfkill->get_state = sony_nc_rfkill_get; | ||
1171 | sony_wimax_rfkill->data = (void *)SONY_WIMAX; | ||
1172 | err = rfkill_register(sony_wimax_rfkill); | ||
1173 | if (err) | ||
1174 | rfkill_free(sony_wimax_rfkill); | ||
1175 | else { | ||
1176 | sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill; | ||
1177 | sony_nc_rfkill_set(sony_wimax_rfkill->data, | ||
1178 | RFKILL_STATE_UNBLOCKED); | ||
1179 | } | ||
1180 | return err; | ||
1181 | } | ||
1182 | 1129 | ||
1183 | static void sony_nc_rfkill_update() | 1130 | for (i = 0; i < N_SONY_RFKILL; i++) { |
1184 | { | 1131 | int argument = sony_rfkill_address[i]; |
1185 | int i; | ||
1186 | enum rfkill_state state; | ||
1187 | 1132 | ||
1188 | for (i = 0; i < SONY_RFKILL_MAX; i++) { | 1133 | if (!sony_rfkill_devices[i]) |
1189 | if (sony_rfkill_devices[i]) { | 1134 | continue; |
1190 | sony_rfkill_devices[i]-> | 1135 | |
1191 | get_state(sony_rfkill_devices[i]->data, | 1136 | if (hwblock) { |
1192 | &state); | 1137 | if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) |
1193 | rfkill_force_state(sony_rfkill_devices[i], state); | 1138 | sony_nc_rfkill_set(sony_rfkill_devices[i], |
1139 | true); | ||
1140 | continue; | ||
1194 | } | 1141 | } |
1142 | |||
1143 | sony_call_snc_handle(0x124, argument, &result); | ||
1144 | rfkill_set_states(sony_rfkill_devices[i], | ||
1145 | !(result & 0xf), false); | ||
1195 | } | 1146 | } |
1196 | } | 1147 | } |
1197 | 1148 | ||
@@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) | |||
1210 | } | 1161 | } |
1211 | 1162 | ||
1212 | if (result & 0x1) | 1163 | if (result & 0x1) |
1213 | sony_nc_setup_wifi_rfkill(device); | 1164 | sony_nc_setup_rfkill(device, SONY_WIFI); |
1214 | if (result & 0x2) | 1165 | if (result & 0x2) |
1215 | sony_nc_setup_bluetooth_rfkill(device); | 1166 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); |
1216 | if (result & 0x1c) | 1167 | if (result & 0x1c) |
1217 | sony_nc_setup_wwan_rfkill(device); | 1168 | sony_nc_setup_rfkill(device, SONY_WWAN); |
1218 | if (result & 0x20) | 1169 | if (result & 0x20) |
1219 | sony_nc_setup_wimax_rfkill(device); | 1170 | sony_nc_setup_rfkill(device, SONY_WIMAX); |
1220 | 1171 | ||
1221 | return 0; | 1172 | return 0; |
1222 | } | 1173 | } |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 912be65b6261..cfcafa4e9473 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -166,13 +166,6 @@ enum { | |||
166 | 166 | ||
167 | #define TPACPI_MAX_ACPI_ARGS 3 | 167 | #define TPACPI_MAX_ACPI_ARGS 3 |
168 | 168 | ||
169 | /* rfkill switches */ | ||
170 | enum { | ||
171 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, | ||
172 | TPACPI_RFK_WWAN_SW_ID, | ||
173 | TPACPI_RFK_UWB_SW_ID, | ||
174 | }; | ||
175 | |||
176 | /* printk headers */ | 169 | /* printk headers */ |
177 | #define TPACPI_LOG TPACPI_FILE ": " | 170 | #define TPACPI_LOG TPACPI_FILE ": " |
178 | #define TPACPI_EMERG KERN_EMERG TPACPI_LOG | 171 | #define TPACPI_EMERG KERN_EMERG TPACPI_LOG |
@@ -1005,67 +998,237 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) | |||
1005 | return 0; | 998 | return 0; |
1006 | } | 999 | } |
1007 | 1000 | ||
1008 | static int __init tpacpi_new_rfkill(const unsigned int id, | 1001 | static void printk_deprecated_attribute(const char * const what, |
1009 | struct rfkill **rfk, | 1002 | const char * const details) |
1003 | { | ||
1004 | tpacpi_log_usertask("deprecated sysfs attribute"); | ||
1005 | printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " | ||
1006 | "will be removed. %s\n", | ||
1007 | what, details); | ||
1008 | } | ||
1009 | |||
1010 | /************************************************************************* | ||
1011 | * rfkill and radio control support helpers | ||
1012 | */ | ||
1013 | |||
1014 | /* | ||
1015 | * ThinkPad-ACPI firmware handling model: | ||
1016 | * | ||
1017 | * WLSW (master wireless switch) is event-driven, and is common to all | ||
1018 | * firmware-controlled radios. It cannot be controlled, just monitored, | ||
1019 | * as expected. It overrides all radio state in firmware | ||
1020 | * | ||
1021 | * The kernel, a masked-off hotkey, and WLSW can change the radio state | ||
1022 | * (TODO: verify how WLSW interacts with the returned radio state). | ||
1023 | * | ||
1024 | * The only time there are shadow radio state changes, is when | ||
1025 | * masked-off hotkeys are used. | ||
1026 | */ | ||
1027 | |||
1028 | /* | ||
1029 | * Internal driver API for radio state: | ||
1030 | * | ||
1031 | * int: < 0 = error, otherwise enum tpacpi_rfkill_state | ||
1032 | * bool: true means radio blocked (off) | ||
1033 | */ | ||
1034 | enum tpacpi_rfkill_state { | ||
1035 | TPACPI_RFK_RADIO_OFF = 0, | ||
1036 | TPACPI_RFK_RADIO_ON | ||
1037 | }; | ||
1038 | |||
1039 | /* rfkill switches */ | ||
1040 | enum tpacpi_rfk_id { | ||
1041 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, | ||
1042 | TPACPI_RFK_WWAN_SW_ID, | ||
1043 | TPACPI_RFK_UWB_SW_ID, | ||
1044 | TPACPI_RFK_SW_MAX | ||
1045 | }; | ||
1046 | |||
1047 | static const char *tpacpi_rfkill_names[] = { | ||
1048 | [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth", | ||
1049 | [TPACPI_RFK_WWAN_SW_ID] = "wwan", | ||
1050 | [TPACPI_RFK_UWB_SW_ID] = "uwb", | ||
1051 | [TPACPI_RFK_SW_MAX] = NULL | ||
1052 | }; | ||
1053 | |||
1054 | /* ThinkPad-ACPI rfkill subdriver */ | ||
1055 | struct tpacpi_rfk { | ||
1056 | struct rfkill *rfkill; | ||
1057 | enum tpacpi_rfk_id id; | ||
1058 | const struct tpacpi_rfk_ops *ops; | ||
1059 | }; | ||
1060 | |||
1061 | struct tpacpi_rfk_ops { | ||
1062 | /* firmware interface */ | ||
1063 | int (*get_status)(void); | ||
1064 | int (*set_status)(const enum tpacpi_rfkill_state); | ||
1065 | }; | ||
1066 | |||
1067 | static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX]; | ||
1068 | |||
1069 | /* Query FW and update rfkill sw state for a given rfkill switch */ | ||
1070 | static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk) | ||
1071 | { | ||
1072 | int status; | ||
1073 | |||
1074 | if (!tp_rfk) | ||
1075 | return -ENODEV; | ||
1076 | |||
1077 | status = (tp_rfk->ops->get_status)(); | ||
1078 | if (status < 0) | ||
1079 | return status; | ||
1080 | |||
1081 | rfkill_set_sw_state(tp_rfk->rfkill, | ||
1082 | (status == TPACPI_RFK_RADIO_OFF)); | ||
1083 | |||
1084 | return status; | ||
1085 | } | ||
1086 | |||
1087 | /* Query FW and update rfkill sw state for all rfkill switches */ | ||
1088 | static void tpacpi_rfk_update_swstate_all(void) | ||
1089 | { | ||
1090 | unsigned int i; | ||
1091 | |||
1092 | for (i = 0; i < TPACPI_RFK_SW_MAX; i++) | ||
1093 | tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]); | ||
1094 | } | ||
1095 | |||
1096 | /* | ||
1097 | * Sync the HW-blocking state of all rfkill switches, | ||
1098 | * do notice it causes the rfkill core to schedule uevents | ||
1099 | */ | ||
1100 | static void tpacpi_rfk_update_hwblock_state(bool blocked) | ||
1101 | { | ||
1102 | unsigned int i; | ||
1103 | struct tpacpi_rfk *tp_rfk; | ||
1104 | |||
1105 | for (i = 0; i < TPACPI_RFK_SW_MAX; i++) { | ||
1106 | tp_rfk = tpacpi_rfkill_switches[i]; | ||
1107 | if (tp_rfk) { | ||
1108 | if (rfkill_set_hw_state(tp_rfk->rfkill, | ||
1109 | blocked)) { | ||
1110 | /* ignore -- we track sw block */ | ||
1111 | } | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | /* Call to get the WLSW state from the firmware */ | ||
1117 | static int hotkey_get_wlsw(void); | ||
1118 | |||
1119 | /* Call to query WLSW state and update all rfkill switches */ | ||
1120 | static bool tpacpi_rfk_check_hwblock_state(void) | ||
1121 | { | ||
1122 | int res = hotkey_get_wlsw(); | ||
1123 | int hw_blocked; | ||
1124 | |||
1125 | /* When unknown or unsupported, we have to assume it is unblocked */ | ||
1126 | if (res < 0) | ||
1127 | return false; | ||
1128 | |||
1129 | hw_blocked = (res == TPACPI_RFK_RADIO_OFF); | ||
1130 | tpacpi_rfk_update_hwblock_state(hw_blocked); | ||
1131 | |||
1132 | return hw_blocked; | ||
1133 | } | ||
1134 | |||
1135 | static int tpacpi_rfk_hook_set_block(void *data, bool blocked) | ||
1136 | { | ||
1137 | struct tpacpi_rfk *tp_rfk = data; | ||
1138 | int res; | ||
1139 | |||
1140 | dbg_printk(TPACPI_DBG_RFKILL, | ||
1141 | "request to change radio state to %s\n", | ||
1142 | blocked ? "blocked" : "unblocked"); | ||
1143 | |||
1144 | /* try to set radio state */ | ||
1145 | res = (tp_rfk->ops->set_status)(blocked ? | ||
1146 | TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON); | ||
1147 | |||
1148 | /* and update the rfkill core with whatever the FW really did */ | ||
1149 | tpacpi_rfk_update_swstate(tp_rfk); | ||
1150 | |||
1151 | return (res < 0) ? res : 0; | ||
1152 | } | ||
1153 | |||
1154 | static const struct rfkill_ops tpacpi_rfk_rfkill_ops = { | ||
1155 | .set_block = tpacpi_rfk_hook_set_block, | ||
1156 | }; | ||
1157 | |||
1158 | static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | ||
1159 | const struct tpacpi_rfk_ops *tp_rfkops, | ||
1010 | const enum rfkill_type rfktype, | 1160 | const enum rfkill_type rfktype, |
1011 | const char *name, | 1161 | const char *name, |
1012 | const bool set_default, | 1162 | const bool set_default) |
1013 | int (*toggle_radio)(void *, enum rfkill_state), | ||
1014 | int (*get_state)(void *, enum rfkill_state *)) | ||
1015 | { | 1163 | { |
1164 | struct tpacpi_rfk *atp_rfk; | ||
1016 | int res; | 1165 | int res; |
1017 | enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED; | 1166 | bool initial_sw_state = false; |
1167 | int initial_sw_status; | ||
1018 | 1168 | ||
1019 | res = get_state(NULL, &initial_state); | 1169 | BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); |
1020 | if (res < 0) { | 1170 | |
1171 | initial_sw_status = (tp_rfkops->get_status)(); | ||
1172 | if (initial_sw_status < 0) { | ||
1021 | printk(TPACPI_ERR | 1173 | printk(TPACPI_ERR |
1022 | "failed to read initial state for %s, error %d; " | 1174 | "failed to read initial state for %s, error %d; " |
1023 | "will turn radio off\n", name, res); | 1175 | "will turn radio off\n", name, initial_sw_status); |
1024 | } else if (set_default) { | 1176 | } else { |
1025 | /* try to set the initial state as the default for the rfkill | 1177 | initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); |
1026 | * type, since we ask the firmware to preserve it across S5 in | 1178 | if (set_default) { |
1027 | * NVRAM */ | 1179 | /* try to set the initial state as the default for the |
1028 | if (rfkill_set_default(rfktype, | 1180 | * rfkill type, since we ask the firmware to preserve |
1029 | (initial_state == RFKILL_STATE_UNBLOCKED) ? | 1181 | * it across S5 in NVRAM */ |
1030 | RFKILL_STATE_UNBLOCKED : | 1182 | rfkill_set_global_sw_state(rfktype, initial_sw_state); |
1031 | RFKILL_STATE_SOFT_BLOCKED) == -EPERM) | 1183 | } |
1032 | vdbg_printk(TPACPI_DBG_RFKILL, | 1184 | } |
1033 | "Default state for %s cannot be changed\n", | 1185 | |
1034 | name); | 1186 | atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); |
1035 | } | 1187 | if (atp_rfk) |
1036 | 1188 | atp_rfk->rfkill = rfkill_alloc(name, | |
1037 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); | 1189 | &tpacpi_pdev->dev, |
1038 | if (!*rfk) { | 1190 | rfktype, |
1191 | &tpacpi_rfk_rfkill_ops, | ||
1192 | atp_rfk); | ||
1193 | if (!atp_rfk || !atp_rfk->rfkill) { | ||
1039 | printk(TPACPI_ERR | 1194 | printk(TPACPI_ERR |
1040 | "failed to allocate memory for rfkill class\n"); | 1195 | "failed to allocate memory for rfkill class\n"); |
1196 | kfree(atp_rfk); | ||
1041 | return -ENOMEM; | 1197 | return -ENOMEM; |
1042 | } | 1198 | } |
1043 | 1199 | ||
1044 | (*rfk)->name = name; | 1200 | atp_rfk->id = id; |
1045 | (*rfk)->get_state = get_state; | 1201 | atp_rfk->ops = tp_rfkops; |
1046 | (*rfk)->toggle_radio = toggle_radio; | 1202 | |
1047 | (*rfk)->state = initial_state; | 1203 | rfkill_set_states(atp_rfk->rfkill, initial_sw_state, |
1204 | tpacpi_rfk_check_hwblock_state()); | ||
1048 | 1205 | ||
1049 | res = rfkill_register(*rfk); | 1206 | res = rfkill_register(atp_rfk->rfkill); |
1050 | if (res < 0) { | 1207 | if (res < 0) { |
1051 | printk(TPACPI_ERR | 1208 | printk(TPACPI_ERR |
1052 | "failed to register %s rfkill switch: %d\n", | 1209 | "failed to register %s rfkill switch: %d\n", |
1053 | name, res); | 1210 | name, res); |
1054 | rfkill_free(*rfk); | 1211 | rfkill_destroy(atp_rfk->rfkill); |
1055 | *rfk = NULL; | 1212 | kfree(atp_rfk); |
1056 | return res; | 1213 | return res; |
1057 | } | 1214 | } |
1058 | 1215 | ||
1216 | tpacpi_rfkill_switches[id] = atp_rfk; | ||
1059 | return 0; | 1217 | return 0; |
1060 | } | 1218 | } |
1061 | 1219 | ||
1062 | static void printk_deprecated_attribute(const char * const what, | 1220 | static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) |
1063 | const char * const details) | ||
1064 | { | 1221 | { |
1065 | tpacpi_log_usertask("deprecated sysfs attribute"); | 1222 | struct tpacpi_rfk *tp_rfk; |
1066 | printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " | 1223 | |
1067 | "will be removed. %s\n", | 1224 | BUG_ON(id >= TPACPI_RFK_SW_MAX); |
1068 | what, details); | 1225 | |
1226 | tp_rfk = tpacpi_rfkill_switches[id]; | ||
1227 | if (tp_rfk) { | ||
1228 | rfkill_unregister(tp_rfk->rfkill); | ||
1229 | tpacpi_rfkill_switches[id] = NULL; | ||
1230 | kfree(tp_rfk); | ||
1231 | } | ||
1069 | } | 1232 | } |
1070 | 1233 | ||
1071 | static void printk_deprecated_rfkill_attribute(const char * const what) | 1234 | static void printk_deprecated_rfkill_attribute(const char * const what) |
@@ -1074,6 +1237,112 @@ static void printk_deprecated_rfkill_attribute(const char * const what) | |||
1074 | "Please switch to generic rfkill before year 2010"); | 1237 | "Please switch to generic rfkill before year 2010"); |
1075 | } | 1238 | } |
1076 | 1239 | ||
1240 | /* sysfs <radio> enable ------------------------------------------------ */ | ||
1241 | static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id, | ||
1242 | struct device_attribute *attr, | ||
1243 | char *buf) | ||
1244 | { | ||
1245 | int status; | ||
1246 | |||
1247 | printk_deprecated_rfkill_attribute(attr->attr.name); | ||
1248 | |||
1249 | /* This is in the ABI... */ | ||
1250 | if (tpacpi_rfk_check_hwblock_state()) { | ||
1251 | status = TPACPI_RFK_RADIO_OFF; | ||
1252 | } else { | ||
1253 | status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); | ||
1254 | if (status < 0) | ||
1255 | return status; | ||
1256 | } | ||
1257 | |||
1258 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
1259 | (status == TPACPI_RFK_RADIO_ON) ? 1 : 0); | ||
1260 | } | ||
1261 | |||
1262 | static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, | ||
1263 | struct device_attribute *attr, | ||
1264 | const char *buf, size_t count) | ||
1265 | { | ||
1266 | unsigned long t; | ||
1267 | int res; | ||
1268 | |||
1269 | printk_deprecated_rfkill_attribute(attr->attr.name); | ||
1270 | |||
1271 | if (parse_strtoul(buf, 1, &t)) | ||
1272 | return -EINVAL; | ||
1273 | |||
1274 | tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t); | ||
1275 | |||
1276 | /* This is in the ABI... */ | ||
1277 | if (tpacpi_rfk_check_hwblock_state() && !!t) | ||
1278 | return -EPERM; | ||
1279 | |||
1280 | res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ? | ||
1281 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF); | ||
1282 | tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); | ||
1283 | |||
1284 | return (res < 0) ? res : count; | ||
1285 | } | ||
1286 | |||
1287 | /* procfs -------------------------------------------------------------- */ | ||
1288 | static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) | ||
1289 | { | ||
1290 | int len = 0; | ||
1291 | |||
1292 | if (id >= TPACPI_RFK_SW_MAX) | ||
1293 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
1294 | else { | ||
1295 | int status; | ||
1296 | |||
1297 | /* This is in the ABI... */ | ||
1298 | if (tpacpi_rfk_check_hwblock_state()) { | ||
1299 | status = TPACPI_RFK_RADIO_OFF; | ||
1300 | } else { | ||
1301 | status = tpacpi_rfk_update_swstate( | ||
1302 | tpacpi_rfkill_switches[id]); | ||
1303 | if (status < 0) | ||
1304 | return status; | ||
1305 | } | ||
1306 | |||
1307 | len += sprintf(p + len, "status:\t\t%s\n", | ||
1308 | (status == TPACPI_RFK_RADIO_ON) ? | ||
1309 | "enabled" : "disabled"); | ||
1310 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
1311 | } | ||
1312 | |||
1313 | return len; | ||
1314 | } | ||
1315 | |||
1316 | static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) | ||
1317 | { | ||
1318 | char *cmd; | ||
1319 | int status = -1; | ||
1320 | int res = 0; | ||
1321 | |||
1322 | if (id >= TPACPI_RFK_SW_MAX) | ||
1323 | return -ENODEV; | ||
1324 | |||
1325 | while ((cmd = next_cmd(&buf))) { | ||
1326 | if (strlencmp(cmd, "enable") == 0) | ||
1327 | status = TPACPI_RFK_RADIO_ON; | ||
1328 | else if (strlencmp(cmd, "disable") == 0) | ||
1329 | status = TPACPI_RFK_RADIO_OFF; | ||
1330 | else | ||
1331 | return -EINVAL; | ||
1332 | } | ||
1333 | |||
1334 | if (status != -1) { | ||
1335 | tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", | ||
1336 | (status == TPACPI_RFK_RADIO_ON) ? | ||
1337 | "enable" : "disable", | ||
1338 | tpacpi_rfkill_names[id]); | ||
1339 | res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); | ||
1340 | tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); | ||
1341 | } | ||
1342 | |||
1343 | return res; | ||
1344 | } | ||
1345 | |||
1077 | /************************************************************************* | 1346 | /************************************************************************* |
1078 | * thinkpad-acpi driver attributes | 1347 | * thinkpad-acpi driver attributes |
1079 | */ | 1348 | */ |
@@ -1127,8 +1396,6 @@ static DRIVER_ATTR(version, S_IRUGO, | |||
1127 | 1396 | ||
1128 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 1397 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
1129 | 1398 | ||
1130 | static void tpacpi_send_radiosw_update(void); | ||
1131 | |||
1132 | /* wlsw_emulstate ------------------------------------------------------ */ | 1399 | /* wlsw_emulstate ------------------------------------------------------ */ |
1133 | static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, | 1400 | static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, |
1134 | char *buf) | 1401 | char *buf) |
@@ -1144,11 +1411,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv, | |||
1144 | if (parse_strtoul(buf, 1, &t)) | 1411 | if (parse_strtoul(buf, 1, &t)) |
1145 | return -EINVAL; | 1412 | return -EINVAL; |
1146 | 1413 | ||
1147 | if (tpacpi_wlsw_emulstate != t) { | 1414 | if (tpacpi_wlsw_emulstate != !!t) { |
1148 | tpacpi_wlsw_emulstate = !!t; | ||
1149 | tpacpi_send_radiosw_update(); | ||
1150 | } else | ||
1151 | tpacpi_wlsw_emulstate = !!t; | 1415 | tpacpi_wlsw_emulstate = !!t; |
1416 | tpacpi_rfk_update_hwblock_state(!t); /* negative logic */ | ||
1417 | } | ||
1152 | 1418 | ||
1153 | return count; | 1419 | return count; |
1154 | } | 1420 | } |
@@ -1463,17 +1729,23 @@ static struct attribute_set *hotkey_dev_attributes; | |||
1463 | /* HKEY.MHKG() return bits */ | 1729 | /* HKEY.MHKG() return bits */ |
1464 | #define TP_HOTKEY_TABLET_MASK (1 << 3) | 1730 | #define TP_HOTKEY_TABLET_MASK (1 << 3) |
1465 | 1731 | ||
1466 | static int hotkey_get_wlsw(int *status) | 1732 | static int hotkey_get_wlsw(void) |
1467 | { | 1733 | { |
1734 | int status; | ||
1735 | |||
1736 | if (!tp_features.hotkey_wlsw) | ||
1737 | return -ENODEV; | ||
1738 | |||
1468 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 1739 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
1469 | if (dbg_wlswemul) { | 1740 | if (dbg_wlswemul) |
1470 | *status = !!tpacpi_wlsw_emulstate; | 1741 | return (tpacpi_wlsw_emulstate) ? |
1471 | return 0; | 1742 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
1472 | } | ||
1473 | #endif | 1743 | #endif |
1474 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | 1744 | |
1745 | if (!acpi_evalf(hkey_handle, &status, "WLSW", "d")) | ||
1475 | return -EIO; | 1746 | return -EIO; |
1476 | return 0; | 1747 | |
1748 | return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; | ||
1477 | } | 1749 | } |
1478 | 1750 | ||
1479 | static int hotkey_get_tablet_mode(int *status) | 1751 | static int hotkey_get_tablet_mode(int *status) |
@@ -2107,12 +2379,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, | |||
2107 | struct device_attribute *attr, | 2379 | struct device_attribute *attr, |
2108 | char *buf) | 2380 | char *buf) |
2109 | { | 2381 | { |
2110 | int res, s; | 2382 | int res; |
2111 | res = hotkey_get_wlsw(&s); | 2383 | res = hotkey_get_wlsw(); |
2112 | if (res < 0) | 2384 | if (res < 0) |
2113 | return res; | 2385 | return res; |
2114 | 2386 | ||
2115 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | 2387 | /* Opportunistic update */ |
2388 | tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF)); | ||
2389 | |||
2390 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
2391 | (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); | ||
2116 | } | 2392 | } |
2117 | 2393 | ||
2118 | static struct device_attribute dev_attr_hotkey_radio_sw = | 2394 | static struct device_attribute dev_attr_hotkey_radio_sw = |
@@ -2223,30 +2499,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { | |||
2223 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | 2499 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, |
2224 | }; | 2500 | }; |
2225 | 2501 | ||
2226 | static void bluetooth_update_rfk(void); | 2502 | /* |
2227 | static void wan_update_rfk(void); | 2503 | * Sync both the hw and sw blocking state of all switches |
2228 | static void uwb_update_rfk(void); | 2504 | */ |
2229 | static void tpacpi_send_radiosw_update(void) | 2505 | static void tpacpi_send_radiosw_update(void) |
2230 | { | 2506 | { |
2231 | int wlsw; | 2507 | int wlsw; |
2232 | 2508 | ||
2233 | /* Sync these BEFORE sending any rfkill events */ | 2509 | /* |
2234 | if (tp_features.bluetooth) | 2510 | * We must sync all rfkill controllers *before* issuing any |
2235 | bluetooth_update_rfk(); | 2511 | * rfkill input events, or we will race the rfkill core input |
2236 | if (tp_features.wan) | 2512 | * handler. |
2237 | wan_update_rfk(); | 2513 | * |
2238 | if (tp_features.uwb) | 2514 | * tpacpi_inputdev_send_mutex works as a syncronization point |
2239 | uwb_update_rfk(); | 2515 | * for the above. |
2516 | * | ||
2517 | * We optimize to avoid numerous calls to hotkey_get_wlsw. | ||
2518 | */ | ||
2240 | 2519 | ||
2241 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | 2520 | wlsw = hotkey_get_wlsw(); |
2521 | |||
2522 | /* Sync hw blocking state first if it is hw-blocked */ | ||
2523 | if (wlsw == TPACPI_RFK_RADIO_OFF) | ||
2524 | tpacpi_rfk_update_hwblock_state(true); | ||
2525 | |||
2526 | /* Sync sw blocking state */ | ||
2527 | tpacpi_rfk_update_swstate_all(); | ||
2528 | |||
2529 | /* Sync hw blocking state last if it is hw-unblocked */ | ||
2530 | if (wlsw == TPACPI_RFK_RADIO_ON) | ||
2531 | tpacpi_rfk_update_hwblock_state(false); | ||
2532 | |||
2533 | /* Issue rfkill input event for WLSW switch */ | ||
2534 | if (!(wlsw < 0)) { | ||
2242 | mutex_lock(&tpacpi_inputdev_send_mutex); | 2535 | mutex_lock(&tpacpi_inputdev_send_mutex); |
2243 | 2536 | ||
2244 | input_report_switch(tpacpi_inputdev, | 2537 | input_report_switch(tpacpi_inputdev, |
2245 | SW_RFKILL_ALL, !!wlsw); | 2538 | SW_RFKILL_ALL, (wlsw > 0)); |
2246 | input_sync(tpacpi_inputdev); | 2539 | input_sync(tpacpi_inputdev); |
2247 | 2540 | ||
2248 | mutex_unlock(&tpacpi_inputdev_send_mutex); | 2541 | mutex_unlock(&tpacpi_inputdev_send_mutex); |
2249 | } | 2542 | } |
2543 | |||
2544 | /* | ||
2545 | * this can be unconditional, as we will poll state again | ||
2546 | * if userspace uses the notify to read data | ||
2547 | */ | ||
2250 | hotkey_radio_sw_notify_change(); | 2548 | hotkey_radio_sw_notify_change(); |
2251 | } | 2549 | } |
2252 | 2550 | ||
@@ -3056,8 +3354,6 @@ enum { | |||
3056 | 3354 | ||
3057 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" | 3355 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" |
3058 | 3356 | ||
3059 | static struct rfkill *tpacpi_bluetooth_rfkill; | ||
3060 | |||
3061 | static void bluetooth_suspend(pm_message_t state) | 3357 | static void bluetooth_suspend(pm_message_t state) |
3062 | { | 3358 | { |
3063 | /* Try to make sure radio will resume powered off */ | 3359 | /* Try to make sure radio will resume powered off */ |
@@ -3067,83 +3363,47 @@ static void bluetooth_suspend(pm_message_t state) | |||
3067 | "bluetooth power down on resume request failed\n"); | 3363 | "bluetooth power down on resume request failed\n"); |
3068 | } | 3364 | } |
3069 | 3365 | ||
3070 | static int bluetooth_get_radiosw(void) | 3366 | static int bluetooth_get_status(void) |
3071 | { | 3367 | { |
3072 | int status; | 3368 | int status; |
3073 | 3369 | ||
3074 | if (!tp_features.bluetooth) | ||
3075 | return -ENODEV; | ||
3076 | |||
3077 | /* WLSW overrides bluetooth in firmware/hardware, reflect that */ | ||
3078 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | ||
3079 | return RFKILL_STATE_HARD_BLOCKED; | ||
3080 | |||
3081 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3370 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3082 | if (dbg_bluetoothemul) | 3371 | if (dbg_bluetoothemul) |
3083 | return (tpacpi_bluetooth_emulstate) ? | 3372 | return (tpacpi_bluetooth_emulstate) ? |
3084 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3373 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3085 | #endif | 3374 | #endif |
3086 | 3375 | ||
3087 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 3376 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
3088 | return -EIO; | 3377 | return -EIO; |
3089 | 3378 | ||
3090 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? | 3379 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? |
3091 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3380 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3092 | } | 3381 | } |
3093 | 3382 | ||
3094 | static void bluetooth_update_rfk(void) | 3383 | static int bluetooth_set_status(enum tpacpi_rfkill_state state) |
3095 | { | 3384 | { |
3096 | int status; | 3385 | int status; |
3097 | 3386 | ||
3098 | if (!tpacpi_bluetooth_rfkill) | ||
3099 | return; | ||
3100 | |||
3101 | status = bluetooth_get_radiosw(); | ||
3102 | if (status < 0) | ||
3103 | return; | ||
3104 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); | ||
3105 | |||
3106 | vdbg_printk(TPACPI_DBG_RFKILL, | 3387 | vdbg_printk(TPACPI_DBG_RFKILL, |
3107 | "forced rfkill state to %d\n", | 3388 | "will attempt to %s bluetooth\n", |
3108 | status); | 3389 | (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); |
3109 | } | ||
3110 | |||
3111 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) | ||
3112 | { | ||
3113 | int status; | ||
3114 | |||
3115 | if (!tp_features.bluetooth) | ||
3116 | return -ENODEV; | ||
3117 | |||
3118 | /* WLSW overrides bluetooth in firmware/hardware, but there is no | ||
3119 | * reason to risk weird behaviour. */ | ||
3120 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | ||
3121 | && radio_on) | ||
3122 | return -EPERM; | ||
3123 | |||
3124 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3125 | "will %s bluetooth\n", radio_on ? "enable" : "disable"); | ||
3126 | 3390 | ||
3127 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3391 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3128 | if (dbg_bluetoothemul) { | 3392 | if (dbg_bluetoothemul) { |
3129 | tpacpi_bluetooth_emulstate = !!radio_on; | 3393 | tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON); |
3130 | if (update_rfk) | ||
3131 | bluetooth_update_rfk(); | ||
3132 | return 0; | 3394 | return 0; |
3133 | } | 3395 | } |
3134 | #endif | 3396 | #endif |
3135 | 3397 | ||
3136 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ | 3398 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ |
3137 | if (radio_on) | 3399 | if (state == TPACPI_RFK_RADIO_ON) |
3138 | status = TP_ACPI_BLUETOOTH_RADIOSSW; | 3400 | status = TP_ACPI_BLUETOOTH_RADIOSSW; |
3139 | else | 3401 | else |
3140 | status = 0; | 3402 | status = 0; |
3403 | |||
3141 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 3404 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
3142 | return -EIO; | 3405 | return -EIO; |
3143 | 3406 | ||
3144 | if (update_rfk) | ||
3145 | bluetooth_update_rfk(); | ||
3146 | |||
3147 | return 0; | 3407 | return 0; |
3148 | } | 3408 | } |
3149 | 3409 | ||
@@ -3152,35 +3412,16 @@ static ssize_t bluetooth_enable_show(struct device *dev, | |||
3152 | struct device_attribute *attr, | 3412 | struct device_attribute *attr, |
3153 | char *buf) | 3413 | char *buf) |
3154 | { | 3414 | { |
3155 | int status; | 3415 | return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID, |
3156 | 3416 | attr, buf); | |
3157 | printk_deprecated_rfkill_attribute("bluetooth_enable"); | ||
3158 | |||
3159 | status = bluetooth_get_radiosw(); | ||
3160 | if (status < 0) | ||
3161 | return status; | ||
3162 | |||
3163 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
3164 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | ||
3165 | } | 3417 | } |
3166 | 3418 | ||
3167 | static ssize_t bluetooth_enable_store(struct device *dev, | 3419 | static ssize_t bluetooth_enable_store(struct device *dev, |
3168 | struct device_attribute *attr, | 3420 | struct device_attribute *attr, |
3169 | const char *buf, size_t count) | 3421 | const char *buf, size_t count) |
3170 | { | 3422 | { |
3171 | unsigned long t; | 3423 | return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID, |
3172 | int res; | 3424 | attr, buf, count); |
3173 | |||
3174 | printk_deprecated_rfkill_attribute("bluetooth_enable"); | ||
3175 | |||
3176 | if (parse_strtoul(buf, 1, &t)) | ||
3177 | return -EINVAL; | ||
3178 | |||
3179 | tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); | ||
3180 | |||
3181 | res = bluetooth_set_radiosw(t, 1); | ||
3182 | |||
3183 | return (res) ? res : count; | ||
3184 | } | 3425 | } |
3185 | 3426 | ||
3186 | static struct device_attribute dev_attr_bluetooth_enable = | 3427 | static struct device_attribute dev_attr_bluetooth_enable = |
@@ -3198,23 +3439,10 @@ static const struct attribute_group bluetooth_attr_group = { | |||
3198 | .attrs = bluetooth_attributes, | 3439 | .attrs = bluetooth_attributes, |
3199 | }; | 3440 | }; |
3200 | 3441 | ||
3201 | static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) | 3442 | static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = { |
3202 | { | 3443 | .get_status = bluetooth_get_status, |
3203 | int bts = bluetooth_get_radiosw(); | 3444 | .set_status = bluetooth_set_status, |
3204 | 3445 | }; | |
3205 | if (bts < 0) | ||
3206 | return bts; | ||
3207 | |||
3208 | *state = bts; | ||
3209 | return 0; | ||
3210 | } | ||
3211 | |||
3212 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) | ||
3213 | { | ||
3214 | dbg_printk(TPACPI_DBG_RFKILL, | ||
3215 | "request to change radio state to %d\n", state); | ||
3216 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
3217 | } | ||
3218 | 3446 | ||
3219 | static void bluetooth_shutdown(void) | 3447 | static void bluetooth_shutdown(void) |
3220 | { | 3448 | { |
@@ -3230,13 +3458,12 @@ static void bluetooth_shutdown(void) | |||
3230 | 3458 | ||
3231 | static void bluetooth_exit(void) | 3459 | static void bluetooth_exit(void) |
3232 | { | 3460 | { |
3233 | bluetooth_shutdown(); | ||
3234 | |||
3235 | if (tpacpi_bluetooth_rfkill) | ||
3236 | rfkill_unregister(tpacpi_bluetooth_rfkill); | ||
3237 | |||
3238 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 3461 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
3239 | &bluetooth_attr_group); | 3462 | &bluetooth_attr_group); |
3463 | |||
3464 | tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); | ||
3465 | |||
3466 | bluetooth_shutdown(); | ||
3240 | } | 3467 | } |
3241 | 3468 | ||
3242 | static int __init bluetooth_init(struct ibm_init_struct *iibm) | 3469 | static int __init bluetooth_init(struct ibm_init_struct *iibm) |
@@ -3277,20 +3504,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
3277 | if (!tp_features.bluetooth) | 3504 | if (!tp_features.bluetooth) |
3278 | return 1; | 3505 | return 1; |
3279 | 3506 | ||
3280 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3281 | &bluetooth_attr_group); | ||
3282 | if (res) | ||
3283 | return res; | ||
3284 | |||
3285 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, | 3507 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, |
3286 | &tpacpi_bluetooth_rfkill, | 3508 | &bluetooth_tprfk_ops, |
3287 | RFKILL_TYPE_BLUETOOTH, | 3509 | RFKILL_TYPE_BLUETOOTH, |
3288 | TPACPI_RFK_BLUETOOTH_SW_NAME, | 3510 | TPACPI_RFK_BLUETOOTH_SW_NAME, |
3289 | true, | 3511 | true); |
3290 | tpacpi_bluetooth_rfk_set, | 3512 | if (res) |
3291 | tpacpi_bluetooth_rfk_get); | 3513 | return res; |
3514 | |||
3515 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3516 | &bluetooth_attr_group); | ||
3292 | if (res) { | 3517 | if (res) { |
3293 | bluetooth_exit(); | 3518 | tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); |
3294 | return res; | 3519 | return res; |
3295 | } | 3520 | } |
3296 | 3521 | ||
@@ -3300,46 +3525,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
3300 | /* procfs -------------------------------------------------------------- */ | 3525 | /* procfs -------------------------------------------------------------- */ |
3301 | static int bluetooth_read(char *p) | 3526 | static int bluetooth_read(char *p) |
3302 | { | 3527 | { |
3303 | int len = 0; | 3528 | return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); |
3304 | int status = bluetooth_get_radiosw(); | ||
3305 | |||
3306 | if (!tp_features.bluetooth) | ||
3307 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
3308 | else { | ||
3309 | len += sprintf(p + len, "status:\t\t%s\n", | ||
3310 | (status == RFKILL_STATE_UNBLOCKED) ? | ||
3311 | "enabled" : "disabled"); | ||
3312 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
3313 | } | ||
3314 | |||
3315 | return len; | ||
3316 | } | 3529 | } |
3317 | 3530 | ||
3318 | static int bluetooth_write(char *buf) | 3531 | static int bluetooth_write(char *buf) |
3319 | { | 3532 | { |
3320 | char *cmd; | 3533 | return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf); |
3321 | int state = -1; | ||
3322 | |||
3323 | if (!tp_features.bluetooth) | ||
3324 | return -ENODEV; | ||
3325 | |||
3326 | while ((cmd = next_cmd(&buf))) { | ||
3327 | if (strlencmp(cmd, "enable") == 0) { | ||
3328 | state = 1; | ||
3329 | } else if (strlencmp(cmd, "disable") == 0) { | ||
3330 | state = 0; | ||
3331 | } else | ||
3332 | return -EINVAL; | ||
3333 | } | ||
3334 | |||
3335 | if (state != -1) { | ||
3336 | tpacpi_disclose_usertask("procfs bluetooth", | ||
3337 | "attempt to %s\n", | ||
3338 | state ? "enable" : "disable"); | ||
3339 | bluetooth_set_radiosw(state, 1); | ||
3340 | } | ||
3341 | |||
3342 | return 0; | ||
3343 | } | 3534 | } |
3344 | 3535 | ||
3345 | static struct ibm_struct bluetooth_driver_data = { | 3536 | static struct ibm_struct bluetooth_driver_data = { |
@@ -3365,8 +3556,6 @@ enum { | |||
3365 | 3556 | ||
3366 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" | 3557 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" |
3367 | 3558 | ||
3368 | static struct rfkill *tpacpi_wan_rfkill; | ||
3369 | |||
3370 | static void wan_suspend(pm_message_t state) | 3559 | static void wan_suspend(pm_message_t state) |
3371 | { | 3560 | { |
3372 | /* Try to make sure radio will resume powered off */ | 3561 | /* Try to make sure radio will resume powered off */ |
@@ -3376,83 +3565,47 @@ static void wan_suspend(pm_message_t state) | |||
3376 | "WWAN power down on resume request failed\n"); | 3565 | "WWAN power down on resume request failed\n"); |
3377 | } | 3566 | } |
3378 | 3567 | ||
3379 | static int wan_get_radiosw(void) | 3568 | static int wan_get_status(void) |
3380 | { | 3569 | { |
3381 | int status; | 3570 | int status; |
3382 | 3571 | ||
3383 | if (!tp_features.wan) | ||
3384 | return -ENODEV; | ||
3385 | |||
3386 | /* WLSW overrides WWAN in firmware/hardware, reflect that */ | ||
3387 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | ||
3388 | return RFKILL_STATE_HARD_BLOCKED; | ||
3389 | |||
3390 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3572 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3391 | if (dbg_wwanemul) | 3573 | if (dbg_wwanemul) |
3392 | return (tpacpi_wwan_emulstate) ? | 3574 | return (tpacpi_wwan_emulstate) ? |
3393 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3575 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3394 | #endif | 3576 | #endif |
3395 | 3577 | ||
3396 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 3578 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
3397 | return -EIO; | 3579 | return -EIO; |
3398 | 3580 | ||
3399 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? | 3581 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? |
3400 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3582 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3401 | } | ||
3402 | |||
3403 | static void wan_update_rfk(void) | ||
3404 | { | ||
3405 | int status; | ||
3406 | |||
3407 | if (!tpacpi_wan_rfkill) | ||
3408 | return; | ||
3409 | |||
3410 | status = wan_get_radiosw(); | ||
3411 | if (status < 0) | ||
3412 | return; | ||
3413 | rfkill_force_state(tpacpi_wan_rfkill, status); | ||
3414 | |||
3415 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3416 | "forced rfkill state to %d\n", | ||
3417 | status); | ||
3418 | } | 3583 | } |
3419 | 3584 | ||
3420 | static int wan_set_radiosw(int radio_on, int update_rfk) | 3585 | static int wan_set_status(enum tpacpi_rfkill_state state) |
3421 | { | 3586 | { |
3422 | int status; | 3587 | int status; |
3423 | 3588 | ||
3424 | if (!tp_features.wan) | ||
3425 | return -ENODEV; | ||
3426 | |||
3427 | /* WLSW overrides bluetooth in firmware/hardware, but there is no | ||
3428 | * reason to risk weird behaviour. */ | ||
3429 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | ||
3430 | && radio_on) | ||
3431 | return -EPERM; | ||
3432 | |||
3433 | vdbg_printk(TPACPI_DBG_RFKILL, | 3589 | vdbg_printk(TPACPI_DBG_RFKILL, |
3434 | "will %s WWAN\n", radio_on ? "enable" : "disable"); | 3590 | "will attempt to %s wwan\n", |
3591 | (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); | ||
3435 | 3592 | ||
3436 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3593 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3437 | if (dbg_wwanemul) { | 3594 | if (dbg_wwanemul) { |
3438 | tpacpi_wwan_emulstate = !!radio_on; | 3595 | tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON); |
3439 | if (update_rfk) | ||
3440 | wan_update_rfk(); | ||
3441 | return 0; | 3596 | return 0; |
3442 | } | 3597 | } |
3443 | #endif | 3598 | #endif |
3444 | 3599 | ||
3445 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ | 3600 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ |
3446 | if (radio_on) | 3601 | if (state == TPACPI_RFK_RADIO_ON) |
3447 | status = TP_ACPI_WANCARD_RADIOSSW; | 3602 | status = TP_ACPI_WANCARD_RADIOSSW; |
3448 | else | 3603 | else |
3449 | status = 0; | 3604 | status = 0; |
3605 | |||
3450 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 3606 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
3451 | return -EIO; | 3607 | return -EIO; |
3452 | 3608 | ||
3453 | if (update_rfk) | ||
3454 | wan_update_rfk(); | ||
3455 | |||
3456 | return 0; | 3609 | return 0; |
3457 | } | 3610 | } |
3458 | 3611 | ||
@@ -3461,35 +3614,16 @@ static ssize_t wan_enable_show(struct device *dev, | |||
3461 | struct device_attribute *attr, | 3614 | struct device_attribute *attr, |
3462 | char *buf) | 3615 | char *buf) |
3463 | { | 3616 | { |
3464 | int status; | 3617 | return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID, |
3465 | 3618 | attr, buf); | |
3466 | printk_deprecated_rfkill_attribute("wwan_enable"); | ||
3467 | |||
3468 | status = wan_get_radiosw(); | ||
3469 | if (status < 0) | ||
3470 | return status; | ||
3471 | |||
3472 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
3473 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | ||
3474 | } | 3619 | } |
3475 | 3620 | ||
3476 | static ssize_t wan_enable_store(struct device *dev, | 3621 | static ssize_t wan_enable_store(struct device *dev, |
3477 | struct device_attribute *attr, | 3622 | struct device_attribute *attr, |
3478 | const char *buf, size_t count) | 3623 | const char *buf, size_t count) |
3479 | { | 3624 | { |
3480 | unsigned long t; | 3625 | return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID, |
3481 | int res; | 3626 | attr, buf, count); |
3482 | |||
3483 | printk_deprecated_rfkill_attribute("wwan_enable"); | ||
3484 | |||
3485 | if (parse_strtoul(buf, 1, &t)) | ||
3486 | return -EINVAL; | ||
3487 | |||
3488 | tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); | ||
3489 | |||
3490 | res = wan_set_radiosw(t, 1); | ||
3491 | |||
3492 | return (res) ? res : count; | ||
3493 | } | 3627 | } |
3494 | 3628 | ||
3495 | static struct device_attribute dev_attr_wan_enable = | 3629 | static struct device_attribute dev_attr_wan_enable = |
@@ -3507,23 +3641,10 @@ static const struct attribute_group wan_attr_group = { | |||
3507 | .attrs = wan_attributes, | 3641 | .attrs = wan_attributes, |
3508 | }; | 3642 | }; |
3509 | 3643 | ||
3510 | static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) | 3644 | static const struct tpacpi_rfk_ops wan_tprfk_ops = { |
3511 | { | 3645 | .get_status = wan_get_status, |
3512 | int wans = wan_get_radiosw(); | 3646 | .set_status = wan_set_status, |
3513 | 3647 | }; | |
3514 | if (wans < 0) | ||
3515 | return wans; | ||
3516 | |||
3517 | *state = wans; | ||
3518 | return 0; | ||
3519 | } | ||
3520 | |||
3521 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) | ||
3522 | { | ||
3523 | dbg_printk(TPACPI_DBG_RFKILL, | ||
3524 | "request to change radio state to %d\n", state); | ||
3525 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
3526 | } | ||
3527 | 3648 | ||
3528 | static void wan_shutdown(void) | 3649 | static void wan_shutdown(void) |
3529 | { | 3650 | { |
@@ -3539,13 +3660,12 @@ static void wan_shutdown(void) | |||
3539 | 3660 | ||
3540 | static void wan_exit(void) | 3661 | static void wan_exit(void) |
3541 | { | 3662 | { |
3542 | wan_shutdown(); | ||
3543 | |||
3544 | if (tpacpi_wan_rfkill) | ||
3545 | rfkill_unregister(tpacpi_wan_rfkill); | ||
3546 | |||
3547 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 3663 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
3548 | &wan_attr_group); | 3664 | &wan_attr_group); |
3665 | |||
3666 | tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); | ||
3667 | |||
3668 | wan_shutdown(); | ||
3549 | } | 3669 | } |
3550 | 3670 | ||
3551 | static int __init wan_init(struct ibm_init_struct *iibm) | 3671 | static int __init wan_init(struct ibm_init_struct *iibm) |
@@ -3584,20 +3704,19 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
3584 | if (!tp_features.wan) | 3704 | if (!tp_features.wan) |
3585 | return 1; | 3705 | return 1; |
3586 | 3706 | ||
3587 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3588 | &wan_attr_group); | ||
3589 | if (res) | ||
3590 | return res; | ||
3591 | |||
3592 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, | 3707 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, |
3593 | &tpacpi_wan_rfkill, | 3708 | &wan_tprfk_ops, |
3594 | RFKILL_TYPE_WWAN, | 3709 | RFKILL_TYPE_WWAN, |
3595 | TPACPI_RFK_WWAN_SW_NAME, | 3710 | TPACPI_RFK_WWAN_SW_NAME, |
3596 | true, | 3711 | true); |
3597 | tpacpi_wan_rfk_set, | 3712 | if (res) |
3598 | tpacpi_wan_rfk_get); | 3713 | return res; |
3714 | |||
3715 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
3716 | &wan_attr_group); | ||
3717 | |||
3599 | if (res) { | 3718 | if (res) { |
3600 | wan_exit(); | 3719 | tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); |
3601 | return res; | 3720 | return res; |
3602 | } | 3721 | } |
3603 | 3722 | ||
@@ -3607,48 +3726,12 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
3607 | /* procfs -------------------------------------------------------------- */ | 3726 | /* procfs -------------------------------------------------------------- */ |
3608 | static int wan_read(char *p) | 3727 | static int wan_read(char *p) |
3609 | { | 3728 | { |
3610 | int len = 0; | 3729 | return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); |
3611 | int status = wan_get_radiosw(); | ||
3612 | |||
3613 | tpacpi_disclose_usertask("procfs wan", "read"); | ||
3614 | |||
3615 | if (!tp_features.wan) | ||
3616 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
3617 | else { | ||
3618 | len += sprintf(p + len, "status:\t\t%s\n", | ||
3619 | (status == RFKILL_STATE_UNBLOCKED) ? | ||
3620 | "enabled" : "disabled"); | ||
3621 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
3622 | } | ||
3623 | |||
3624 | return len; | ||
3625 | } | 3730 | } |
3626 | 3731 | ||
3627 | static int wan_write(char *buf) | 3732 | static int wan_write(char *buf) |
3628 | { | 3733 | { |
3629 | char *cmd; | 3734 | return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf); |
3630 | int state = -1; | ||
3631 | |||
3632 | if (!tp_features.wan) | ||
3633 | return -ENODEV; | ||
3634 | |||
3635 | while ((cmd = next_cmd(&buf))) { | ||
3636 | if (strlencmp(cmd, "enable") == 0) { | ||
3637 | state = 1; | ||
3638 | } else if (strlencmp(cmd, "disable") == 0) { | ||
3639 | state = 0; | ||
3640 | } else | ||
3641 | return -EINVAL; | ||
3642 | } | ||
3643 | |||
3644 | if (state != -1) { | ||
3645 | tpacpi_disclose_usertask("procfs wan", | ||
3646 | "attempt to %s\n", | ||
3647 | state ? "enable" : "disable"); | ||
3648 | wan_set_radiosw(state, 1); | ||
3649 | } | ||
3650 | |||
3651 | return 0; | ||
3652 | } | 3735 | } |
3653 | 3736 | ||
3654 | static struct ibm_struct wan_driver_data = { | 3737 | static struct ibm_struct wan_driver_data = { |
@@ -3672,108 +3755,59 @@ enum { | |||
3672 | 3755 | ||
3673 | #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" | 3756 | #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" |
3674 | 3757 | ||
3675 | static struct rfkill *tpacpi_uwb_rfkill; | 3758 | static int uwb_get_status(void) |
3676 | |||
3677 | static int uwb_get_radiosw(void) | ||
3678 | { | 3759 | { |
3679 | int status; | 3760 | int status; |
3680 | 3761 | ||
3681 | if (!tp_features.uwb) | ||
3682 | return -ENODEV; | ||
3683 | |||
3684 | /* WLSW overrides UWB in firmware/hardware, reflect that */ | ||
3685 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | ||
3686 | return RFKILL_STATE_HARD_BLOCKED; | ||
3687 | |||
3688 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3762 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3689 | if (dbg_uwbemul) | 3763 | if (dbg_uwbemul) |
3690 | return (tpacpi_uwb_emulstate) ? | 3764 | return (tpacpi_uwb_emulstate) ? |
3691 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3765 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3692 | #endif | 3766 | #endif |
3693 | 3767 | ||
3694 | if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) | 3768 | if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) |
3695 | return -EIO; | 3769 | return -EIO; |
3696 | 3770 | ||
3697 | return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? | 3771 | return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? |
3698 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 3772 | TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; |
3699 | } | 3773 | } |
3700 | 3774 | ||
3701 | static void uwb_update_rfk(void) | 3775 | static int uwb_set_status(enum tpacpi_rfkill_state state) |
3702 | { | 3776 | { |
3703 | int status; | 3777 | int status; |
3704 | 3778 | ||
3705 | if (!tpacpi_uwb_rfkill) | ||
3706 | return; | ||
3707 | |||
3708 | status = uwb_get_radiosw(); | ||
3709 | if (status < 0) | ||
3710 | return; | ||
3711 | rfkill_force_state(tpacpi_uwb_rfkill, status); | ||
3712 | |||
3713 | vdbg_printk(TPACPI_DBG_RFKILL, | 3779 | vdbg_printk(TPACPI_DBG_RFKILL, |
3714 | "forced rfkill state to %d\n", | 3780 | "will attempt to %s UWB\n", |
3715 | status); | 3781 | (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); |
3716 | } | ||
3717 | |||
3718 | static int uwb_set_radiosw(int radio_on, int update_rfk) | ||
3719 | { | ||
3720 | int status; | ||
3721 | |||
3722 | if (!tp_features.uwb) | ||
3723 | return -ENODEV; | ||
3724 | |||
3725 | /* WLSW overrides UWB in firmware/hardware, but there is no | ||
3726 | * reason to risk weird behaviour. */ | ||
3727 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | ||
3728 | && radio_on) | ||
3729 | return -EPERM; | ||
3730 | |||
3731 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3732 | "will %s UWB\n", radio_on ? "enable" : "disable"); | ||
3733 | 3782 | ||
3734 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3783 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3735 | if (dbg_uwbemul) { | 3784 | if (dbg_uwbemul) { |
3736 | tpacpi_uwb_emulstate = !!radio_on; | 3785 | tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON); |
3737 | if (update_rfk) | ||
3738 | uwb_update_rfk(); | ||
3739 | return 0; | 3786 | return 0; |
3740 | } | 3787 | } |
3741 | #endif | 3788 | #endif |
3742 | 3789 | ||
3743 | status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0; | 3790 | if (state == TPACPI_RFK_RADIO_ON) |
3791 | status = TP_ACPI_UWB_RADIOSSW; | ||
3792 | else | ||
3793 | status = 0; | ||
3794 | |||
3744 | if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) | 3795 | if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) |
3745 | return -EIO; | 3796 | return -EIO; |
3746 | 3797 | ||
3747 | if (update_rfk) | ||
3748 | uwb_update_rfk(); | ||
3749 | |||
3750 | return 0; | 3798 | return 0; |
3751 | } | 3799 | } |
3752 | 3800 | ||
3753 | /* --------------------------------------------------------------------- */ | 3801 | /* --------------------------------------------------------------------- */ |
3754 | 3802 | ||
3755 | static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) | 3803 | static const struct tpacpi_rfk_ops uwb_tprfk_ops = { |
3756 | { | 3804 | .get_status = uwb_get_status, |
3757 | int uwbs = uwb_get_radiosw(); | 3805 | .set_status = uwb_set_status, |
3758 | 3806 | }; | |
3759 | if (uwbs < 0) | ||
3760 | return uwbs; | ||
3761 | |||
3762 | *state = uwbs; | ||
3763 | return 0; | ||
3764 | } | ||
3765 | |||
3766 | static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) | ||
3767 | { | ||
3768 | dbg_printk(TPACPI_DBG_RFKILL, | ||
3769 | "request to change radio state to %d\n", state); | ||
3770 | return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | ||
3771 | } | ||
3772 | 3807 | ||
3773 | static void uwb_exit(void) | 3808 | static void uwb_exit(void) |
3774 | { | 3809 | { |
3775 | if (tpacpi_uwb_rfkill) | 3810 | tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID); |
3776 | rfkill_unregister(tpacpi_uwb_rfkill); | ||
3777 | } | 3811 | } |
3778 | 3812 | ||
3779 | static int __init uwb_init(struct ibm_init_struct *iibm) | 3813 | static int __init uwb_init(struct ibm_init_struct *iibm) |
@@ -3813,13 +3847,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm) | |||
3813 | return 1; | 3847 | return 1; |
3814 | 3848 | ||
3815 | res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, | 3849 | res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, |
3816 | &tpacpi_uwb_rfkill, | 3850 | &uwb_tprfk_ops, |
3817 | RFKILL_TYPE_UWB, | 3851 | RFKILL_TYPE_UWB, |
3818 | TPACPI_RFK_UWB_SW_NAME, | 3852 | TPACPI_RFK_UWB_SW_NAME, |
3819 | false, | 3853 | false); |
3820 | tpacpi_uwb_rfk_set, | ||
3821 | tpacpi_uwb_rfk_get); | ||
3822 | |||
3823 | return res; | 3854 | return res; |
3824 | } | 3855 | } |
3825 | 3856 | ||
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 4345089f5171..81d31ea507d1 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #include <linux/backlight.h> | 45 | #include <linux/backlight.h> |
46 | #include <linux/platform_device.h> | 46 | #include <linux/platform_device.h> |
47 | #include <linux/rfkill.h> | 47 | #include <linux/rfkill.h> |
48 | #include <linux/input-polldev.h> | ||
49 | 48 | ||
50 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
51 | 50 | ||
@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) | |||
250 | 249 | ||
251 | struct toshiba_acpi_dev { | 250 | struct toshiba_acpi_dev { |
252 | struct platform_device *p_dev; | 251 | struct platform_device *p_dev; |
253 | struct rfkill *rfk_dev; | 252 | struct rfkill *bt_rfk; |
254 | struct input_polled_dev *poll_dev; | ||
255 | 253 | ||
256 | const char *bt_name; | 254 | const char *bt_name; |
257 | const char *rfk_name; | ||
258 | |||
259 | bool last_rfk_state; | ||
260 | 255 | ||
261 | struct mutex mutex; | 256 | struct mutex mutex; |
262 | }; | 257 | }; |
263 | 258 | ||
264 | static struct toshiba_acpi_dev toshiba_acpi = { | 259 | static struct toshiba_acpi_dev toshiba_acpi = { |
265 | .bt_name = "Toshiba Bluetooth", | 260 | .bt_name = "Toshiba Bluetooth", |
266 | .rfk_name = "Toshiba RFKill Switch", | ||
267 | .last_rfk_state = false, | ||
268 | }; | 261 | }; |
269 | 262 | ||
270 | /* Bluetooth rfkill handlers */ | 263 | /* Bluetooth rfkill handlers */ |
@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present) | |||
283 | return hci_result; | 276 | return hci_result; |
284 | } | 277 | } |
285 | 278 | ||
286 | static u32 hci_get_bt_on(bool *on) | ||
287 | { | ||
288 | u32 hci_result; | ||
289 | u32 value, value2; | ||
290 | |||
291 | value = 0; | ||
292 | value2 = 0x0001; | ||
293 | hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); | ||
294 | if (hci_result == HCI_SUCCESS) | ||
295 | *on = (value & HCI_WIRELESS_BT_POWER) && | ||
296 | (value & HCI_WIRELESS_BT_ATTACH); | ||
297 | |||
298 | return hci_result; | ||
299 | } | ||
300 | |||
301 | static u32 hci_get_radio_state(bool *radio_state) | 279 | static u32 hci_get_radio_state(bool *radio_state) |
302 | { | 280 | { |
303 | u32 hci_result; | 281 | u32 hci_result; |
@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state) | |||
311 | return hci_result; | 289 | return hci_result; |
312 | } | 290 | } |
313 | 291 | ||
314 | static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) | 292 | static int bt_rfkill_set_block(void *data, bool blocked) |
315 | { | 293 | { |
294 | struct toshiba_acpi_dev *dev = data; | ||
316 | u32 result1, result2; | 295 | u32 result1, result2; |
317 | u32 value; | 296 | u32 value; |
297 | int err; | ||
318 | bool radio_state; | 298 | bool radio_state; |
319 | struct toshiba_acpi_dev *dev = data; | ||
320 | 299 | ||
321 | value = (state == RFKILL_STATE_UNBLOCKED); | 300 | value = (blocked == false); |
322 | 301 | ||
323 | if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) | 302 | mutex_lock(&dev->mutex); |
324 | return -EFAULT; | 303 | if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) { |
304 | err = -EBUSY; | ||
305 | goto out; | ||
306 | } | ||
325 | 307 | ||
326 | switch (state) { | 308 | if (!radio_state) { |
327 | case RFKILL_STATE_UNBLOCKED: | 309 | err = 0; |
328 | if (!radio_state) | 310 | goto out; |
329 | return -EPERM; | ||
330 | break; | ||
331 | case RFKILL_STATE_SOFT_BLOCKED: | ||
332 | break; | ||
333 | default: | ||
334 | return -EINVAL; | ||
335 | } | 311 | } |
336 | 312 | ||
337 | mutex_lock(&dev->mutex); | ||
338 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); | 313 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); |
339 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); | 314 | hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); |
340 | mutex_unlock(&dev->mutex); | ||
341 | 315 | ||
342 | if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) | 316 | if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) |
343 | return -EFAULT; | 317 | err = -EBUSY; |
344 | 318 | else | |
345 | return 0; | 319 | err = 0; |
320 | out: | ||
321 | mutex_unlock(&dev->mutex); | ||
322 | return err; | ||
346 | } | 323 | } |
347 | 324 | ||
348 | static void bt_poll_rfkill(struct input_polled_dev *poll_dev) | 325 | static void bt_rfkill_poll(struct rfkill *rfkill, void *data) |
349 | { | 326 | { |
350 | bool state_changed; | ||
351 | bool new_rfk_state; | 327 | bool new_rfk_state; |
352 | bool value; | 328 | bool value; |
353 | u32 hci_result; | 329 | u32 hci_result; |
354 | struct toshiba_acpi_dev *dev = poll_dev->private; | 330 | struct toshiba_acpi_dev *dev = data; |
331 | |||
332 | mutex_lock(&dev->mutex); | ||
355 | 333 | ||
356 | hci_result = hci_get_radio_state(&value); | 334 | hci_result = hci_get_radio_state(&value); |
357 | if (hci_result != HCI_SUCCESS) | 335 | if (hci_result != HCI_SUCCESS) { |
358 | return; /* Can't do anything useful */ | 336 | /* Can't do anything useful */ |
337 | mutex_unlock(&dev->mutex); | ||
338 | } | ||
359 | 339 | ||
360 | new_rfk_state = value; | 340 | new_rfk_state = value; |
361 | 341 | ||
362 | mutex_lock(&dev->mutex); | ||
363 | state_changed = new_rfk_state != dev->last_rfk_state; | ||
364 | dev->last_rfk_state = new_rfk_state; | ||
365 | mutex_unlock(&dev->mutex); | 342 | mutex_unlock(&dev->mutex); |
366 | 343 | ||
367 | if (unlikely(state_changed)) { | 344 | if (rfkill_set_hw_state(rfkill, !new_rfk_state)) |
368 | rfkill_force_state(dev->rfk_dev, | 345 | bt_rfkill_set_block(data, true); |
369 | new_rfk_state ? | ||
370 | RFKILL_STATE_SOFT_BLOCKED : | ||
371 | RFKILL_STATE_HARD_BLOCKED); | ||
372 | input_report_switch(poll_dev->input, SW_RFKILL_ALL, | ||
373 | new_rfk_state); | ||
374 | input_sync(poll_dev->input); | ||
375 | } | ||
376 | } | 346 | } |
377 | 347 | ||
348 | static const struct rfkill_ops toshiba_rfk_ops = { | ||
349 | .set_block = bt_rfkill_set_block, | ||
350 | .poll = bt_rfkill_poll, | ||
351 | }; | ||
352 | |||
378 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; | 353 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; |
379 | static struct backlight_device *toshiba_backlight_device; | 354 | static struct backlight_device *toshiba_backlight_device; |
380 | static int force_fan; | 355 | static int force_fan; |
@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = { | |||
702 | 677 | ||
703 | static void toshiba_acpi_exit(void) | 678 | static void toshiba_acpi_exit(void) |
704 | { | 679 | { |
705 | if (toshiba_acpi.poll_dev) { | 680 | if (toshiba_acpi.bt_rfk) { |
706 | input_unregister_polled_device(toshiba_acpi.poll_dev); | 681 | rfkill_unregister(toshiba_acpi.bt_rfk); |
707 | input_free_polled_device(toshiba_acpi.poll_dev); | 682 | rfkill_destroy(toshiba_acpi.bt_rfk); |
708 | } | 683 | } |
709 | 684 | ||
710 | if (toshiba_acpi.rfk_dev) | ||
711 | rfkill_unregister(toshiba_acpi.rfk_dev); | ||
712 | |||
713 | if (toshiba_backlight_device) | 685 | if (toshiba_backlight_device) |
714 | backlight_device_unregister(toshiba_backlight_device); | 686 | backlight_device_unregister(toshiba_backlight_device); |
715 | 687 | ||
@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void) | |||
728 | acpi_status status = AE_OK; | 700 | acpi_status status = AE_OK; |
729 | u32 hci_result; | 701 | u32 hci_result; |
730 | bool bt_present; | 702 | bool bt_present; |
731 | bool bt_on; | ||
732 | bool radio_on; | ||
733 | int ret = 0; | 703 | int ret = 0; |
734 | 704 | ||
735 | if (acpi_disabled) | 705 | if (acpi_disabled) |
@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void) | |||
793 | 763 | ||
794 | /* Register rfkill switch for Bluetooth */ | 764 | /* Register rfkill switch for Bluetooth */ |
795 | if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { | 765 | if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { |
796 | toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, | 766 | toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name, |
797 | RFKILL_TYPE_BLUETOOTH); | 767 | &toshiba_acpi.p_dev->dev, |
798 | if (!toshiba_acpi.rfk_dev) { | 768 | RFKILL_TYPE_BLUETOOTH, |
769 | &toshiba_rfk_ops, | ||
770 | &toshiba_acpi); | ||
771 | if (!toshiba_acpi.bt_rfk) { | ||
799 | printk(MY_ERR "unable to allocate rfkill device\n"); | 772 | printk(MY_ERR "unable to allocate rfkill device\n"); |
800 | toshiba_acpi_exit(); | 773 | toshiba_acpi_exit(); |
801 | return -ENOMEM; | 774 | return -ENOMEM; |
802 | } | 775 | } |
803 | 776 | ||
804 | toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; | 777 | ret = rfkill_register(toshiba_acpi.bt_rfk); |
805 | toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; | ||
806 | toshiba_acpi.rfk_dev->data = &toshiba_acpi; | ||
807 | |||
808 | if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { | ||
809 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED; | ||
810 | } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS && | ||
811 | radio_on) { | ||
812 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED; | ||
813 | } else { | ||
814 | toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED; | ||
815 | } | ||
816 | |||
817 | ret = rfkill_register(toshiba_acpi.rfk_dev); | ||
818 | if (ret) { | 778 | if (ret) { |
819 | printk(MY_ERR "unable to register rfkill device\n"); | 779 | printk(MY_ERR "unable to register rfkill device\n"); |
820 | toshiba_acpi_exit(); | 780 | rfkill_destroy(toshiba_acpi.bt_rfk); |
821 | return -ENOMEM; | ||
822 | } | ||
823 | |||
824 | /* Register input device for kill switch */ | ||
825 | toshiba_acpi.poll_dev = input_allocate_polled_device(); | ||
826 | if (!toshiba_acpi.poll_dev) { | ||
827 | printk(MY_ERR | ||
828 | "unable to allocate kill-switch input device\n"); | ||
829 | toshiba_acpi_exit(); | ||
830 | return -ENOMEM; | ||
831 | } | ||
832 | toshiba_acpi.poll_dev->private = &toshiba_acpi; | ||
833 | toshiba_acpi.poll_dev->poll = bt_poll_rfkill; | ||
834 | toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */ | ||
835 | |||
836 | toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name; | ||
837 | toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST; | ||
838 | /* Toshiba USB ID */ | ||
839 | toshiba_acpi.poll_dev->input->id.vendor = 0x0930; | ||
840 | set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit); | ||
841 | set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit); | ||
842 | input_report_switch(toshiba_acpi.poll_dev->input, | ||
843 | SW_RFKILL_ALL, TRUE); | ||
844 | input_sync(toshiba_acpi.poll_dev->input); | ||
845 | |||
846 | ret = input_register_polled_device(toshiba_acpi.poll_dev); | ||
847 | if (ret) { | ||
848 | printk(MY_ERR | ||
849 | "unable to register kill-switch input device\n"); | ||
850 | toshiba_acpi_exit(); | 781 | toshiba_acpi_exit(); |
851 | return ret; | 782 | return ret; |
852 | } | 783 | } |
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h index e8852c092fea..28cc03bf19e6 100644 --- a/include/asm-generic/errno.h +++ b/include/asm-generic/errno.h | |||
@@ -106,4 +106,6 @@ | |||
106 | #define EOWNERDEAD 130 /* Owner died */ | 106 | #define EOWNERDEAD 130 /* Owner died */ |
107 | #define ENOTRECOVERABLE 131 /* State not recoverable */ | 107 | #define ENOTRECOVERABLE 131 /* State not recoverable */ |
108 | 108 | ||
109 | #define ERFKILL 132 /* Operation not possible due to RF-kill */ | ||
110 | |||
109 | #endif | 111 | #endif |
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3f0eaa397ef5..7e09c5c1ed02 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -311,6 +311,7 @@ unifdef-y += ptrace.h | |||
311 | unifdef-y += qnx4_fs.h | 311 | unifdef-y += qnx4_fs.h |
312 | unifdef-y += quota.h | 312 | unifdef-y += quota.h |
313 | unifdef-y += random.h | 313 | unifdef-y += random.h |
314 | unifdef-y += rfkill.h | ||
314 | unifdef-y += irqnr.h | 315 | unifdef-y += irqnr.h |
315 | unifdef-y += reboot.h | 316 | unifdef-y += reboot.h |
316 | unifdef-y += reiserfs_fs.h | 317 | unifdef-y += reiserfs_fs.h |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 34de8b21f6d4..a9173d5434d1 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1092,6 +1092,7 @@ enum ieee80211_key_len { | |||
1092 | WLAN_KEY_LEN_WEP104 = 13, | 1092 | WLAN_KEY_LEN_WEP104 = 13, |
1093 | WLAN_KEY_LEN_CCMP = 16, | 1093 | WLAN_KEY_LEN_CCMP = 16, |
1094 | WLAN_KEY_LEN_TKIP = 32, | 1094 | WLAN_KEY_LEN_TKIP = 32, |
1095 | WLAN_KEY_LEN_AES_CMAC = 16, | ||
1095 | }; | 1096 | }; |
1096 | 1097 | ||
1097 | /* | 1098 | /* |
diff --git a/include/linux/notifier.h b/include/linux/notifier.h index b86fa2ffca0c..81bc252dc8ac 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h | |||
@@ -198,6 +198,7 @@ static inline int notifier_to_errno(int ret) | |||
198 | #define NETDEV_CHANGENAME 0x000A | 198 | #define NETDEV_CHANGENAME 0x000A |
199 | #define NETDEV_FEAT_CHANGE 0x000B | 199 | #define NETDEV_FEAT_CHANGE 0x000B |
200 | #define NETDEV_BONDING_FAILOVER 0x000C | 200 | #define NETDEV_BONDING_FAILOVER 0x000C |
201 | #define NETDEV_PRE_UP 0x000D | ||
201 | 202 | ||
202 | #define SYS_DOWN 0x0001 /* Notify of system down */ | 203 | #define SYS_DOWN 0x0001 /* Notify of system down */ |
203 | #define SYS_RESTART SYS_DOWN | 204 | #define SYS_RESTART SYS_DOWN |
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index de18ef227e00..ee3eddea8568 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h | |||
@@ -4,6 +4,7 @@ | |||
4 | /* | 4 | /* |
5 | * Copyright (C) 2006 - 2007 Ivo van Doorn | 5 | * Copyright (C) 2006 - 2007 Ivo van Doorn |
6 | * Copyright (C) 2007 Dmitry Torokhov | 6 | * Copyright (C) 2007 Dmitry Torokhov |
7 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * 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 | * it under the terms of the GNU General Public License as published by |
@@ -22,117 +23,341 @@ | |||
22 | */ | 23 | */ |
23 | 24 | ||
24 | #include <linux/types.h> | 25 | #include <linux/types.h> |
25 | #include <linux/kernel.h> | 26 | |
26 | #include <linux/list.h> | 27 | /* define userspace visible states */ |
27 | #include <linux/mutex.h> | 28 | #define RFKILL_STATE_SOFT_BLOCKED 0 |
28 | #include <linux/device.h> | 29 | #define RFKILL_STATE_UNBLOCKED 1 |
29 | #include <linux/leds.h> | 30 | #define RFKILL_STATE_HARD_BLOCKED 2 |
30 | 31 | ||
31 | /** | 32 | /** |
32 | * enum rfkill_type - type of rfkill switch. | 33 | * enum rfkill_type - type of rfkill switch. |
33 | * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. | 34 | * |
34 | * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. | 35 | * @RFKILL_TYPE_ALL: toggles all switches (userspace only) |
35 | * RFKILL_TYPE_UWB: switch is on a ultra wideband device. | 36 | * @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. |
36 | * RFKILL_TYPE_WIMAX: switch is on a WiMAX device. | 37 | * @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. |
37 | * RFKILL_TYPE_WWAN: switch is on a wireless WAN device. | 38 | * @RFKILL_TYPE_UWB: switch is on a ultra wideband device. |
39 | * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device. | ||
40 | * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device. | ||
41 | * @NUM_RFKILL_TYPES: number of defined rfkill types | ||
38 | */ | 42 | */ |
39 | enum rfkill_type { | 43 | enum rfkill_type { |
40 | RFKILL_TYPE_WLAN , | 44 | RFKILL_TYPE_ALL = 0, |
45 | RFKILL_TYPE_WLAN, | ||
41 | RFKILL_TYPE_BLUETOOTH, | 46 | RFKILL_TYPE_BLUETOOTH, |
42 | RFKILL_TYPE_UWB, | 47 | RFKILL_TYPE_UWB, |
43 | RFKILL_TYPE_WIMAX, | 48 | RFKILL_TYPE_WIMAX, |
44 | RFKILL_TYPE_WWAN, | 49 | RFKILL_TYPE_WWAN, |
45 | RFKILL_TYPE_MAX, | 50 | NUM_RFKILL_TYPES, |
46 | }; | 51 | }; |
47 | 52 | ||
48 | enum rfkill_state { | 53 | /** |
49 | RFKILL_STATE_SOFT_BLOCKED = 0, /* Radio output blocked */ | 54 | * enum rfkill_operation - operation types |
50 | RFKILL_STATE_UNBLOCKED = 1, /* Radio output allowed */ | 55 | * @RFKILL_OP_ADD: a device was added |
51 | RFKILL_STATE_HARD_BLOCKED = 2, /* Output blocked, non-overrideable */ | 56 | * @RFKILL_OP_DEL: a device was removed |
52 | RFKILL_STATE_MAX, /* marker for last valid state */ | 57 | * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device |
58 | * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all) | ||
59 | */ | ||
60 | enum rfkill_operation { | ||
61 | RFKILL_OP_ADD = 0, | ||
62 | RFKILL_OP_DEL, | ||
63 | RFKILL_OP_CHANGE, | ||
64 | RFKILL_OP_CHANGE_ALL, | ||
53 | }; | 65 | }; |
54 | 66 | ||
55 | /** | 67 | /** |
56 | * struct rfkill - rfkill control structure. | 68 | * struct rfkill_event - events for userspace on /dev/rfkill |
57 | * @name: Name of the switch. | 69 | * @idx: index of dev rfkill |
58 | * @type: Radio type which the button controls, the value stored | 70 | * @type: type of the rfkill struct |
59 | * here should be a value from enum rfkill_type. | 71 | * @op: operation code |
60 | * @state: State of the switch, "UNBLOCKED" means radio can operate. | 72 | * @hard: hard state (0/1) |
61 | * @mutex: Guards switch state transitions. It serializes callbacks | 73 | * @soft: soft state (0/1) |
62 | * and also protects the state. | 74 | * |
63 | * @data: Pointer to the RF button drivers private data which will be | 75 | * Structure used for userspace communication on /dev/rfkill, |
64 | * passed along when toggling radio state. | 76 | * used for events from the kernel and control to the kernel. |
65 | * @toggle_radio(): Mandatory handler to control state of the radio. | 77 | */ |
66 | * only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are | 78 | struct rfkill_event { |
67 | * valid parameters. | 79 | __u32 idx; |
68 | * @get_state(): handler to read current radio state from hardware, | 80 | __u8 type; |
69 | * may be called from atomic context, should return 0 on success. | 81 | __u8 op; |
70 | * Either this handler OR judicious use of rfkill_force_state() is | 82 | __u8 soft, hard; |
71 | * MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED. | 83 | } __packed; |
72 | * @led_trigger: A LED trigger for this button's LED. | ||
73 | * @dev: Device structure integrating the switch into device tree. | ||
74 | * @node: Used to place switch into list of all switches known to the | ||
75 | * the system. | ||
76 | * | ||
77 | * This structure represents a RF switch located on a network device. | ||
78 | */ | ||
79 | struct rfkill { | ||
80 | const char *name; | ||
81 | enum rfkill_type type; | ||
82 | |||
83 | /* the mutex serializes callbacks and also protects | ||
84 | * the state */ | ||
85 | struct mutex mutex; | ||
86 | enum rfkill_state state; | ||
87 | void *data; | ||
88 | int (*toggle_radio)(void *data, enum rfkill_state state); | ||
89 | int (*get_state)(void *data, enum rfkill_state *state); | ||
90 | 84 | ||
91 | #ifdef CONFIG_RFKILL_LEDS | 85 | /* ioctl for turning off rfkill-input (if present) */ |
92 | struct led_trigger led_trigger; | 86 | #define RFKILL_IOC_MAGIC 'R' |
93 | #endif | 87 | #define RFKILL_IOC_NOINPUT 1 |
88 | #define RFKILL_IOCTL_NOINPUT _IO(RFKILL_IOC_MAGIC, RFKILL_IOC_NOINPUT) | ||
94 | 89 | ||
95 | struct device dev; | 90 | /* and that's all userspace gets */ |
96 | struct list_head node; | 91 | #ifdef __KERNEL__ |
97 | enum rfkill_state state_for_resume; | 92 | /* don't allow anyone to use these in the kernel */ |
93 | enum rfkill_user_states { | ||
94 | RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED, | ||
95 | RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED, | ||
96 | RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED, | ||
98 | }; | 97 | }; |
99 | #define to_rfkill(d) container_of(d, struct rfkill, dev) | 98 | #undef RFKILL_STATE_SOFT_BLOCKED |
99 | #undef RFKILL_STATE_UNBLOCKED | ||
100 | #undef RFKILL_STATE_HARD_BLOCKED | ||
101 | |||
102 | #include <linux/types.h> | ||
103 | #include <linux/kernel.h> | ||
104 | #include <linux/list.h> | ||
105 | #include <linux/mutex.h> | ||
106 | #include <linux/device.h> | ||
107 | #include <linux/leds.h> | ||
108 | |||
109 | /* this is opaque */ | ||
110 | struct rfkill; | ||
111 | |||
112 | /** | ||
113 | * struct rfkill_ops - rfkill driver methods | ||
114 | * | ||
115 | * @poll: poll the rfkill block state(s) -- only assign this method | ||
116 | * when you need polling. When called, simply call one of the | ||
117 | * rfkill_set{,_hw,_sw}_state family of functions. If the hw | ||
118 | * is getting unblocked you need to take into account the return | ||
119 | * value of those functions to make sure the software block is | ||
120 | * properly used. | ||
121 | * @query: query the rfkill block state(s) and call exactly one of the | ||
122 | * rfkill_set{,_hw,_sw}_state family of functions. Assign this | ||
123 | * method if input events can cause hardware state changes to make | ||
124 | * the rfkill core query your driver before setting a requested | ||
125 | * block. | ||
126 | * @set_block: turn the transmitter on (blocked == false) or off | ||
127 | * (blocked == true) -- ignore and return 0 when hard blocked. | ||
128 | * This callback must be assigned. | ||
129 | */ | ||
130 | struct rfkill_ops { | ||
131 | void (*poll)(struct rfkill *rfkill, void *data); | ||
132 | void (*query)(struct rfkill *rfkill, void *data); | ||
133 | int (*set_block)(void *data, bool blocked); | ||
134 | }; | ||
135 | |||
136 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
137 | /** | ||
138 | * rfkill_alloc - allocate rfkill structure | ||
139 | * @name: name of the struct -- the string is not copied internally | ||
140 | * @parent: device that has rf switch on it | ||
141 | * @type: type of the switch (RFKILL_TYPE_*) | ||
142 | * @ops: rfkill methods | ||
143 | * @ops_data: data passed to each method | ||
144 | * | ||
145 | * This function should be called by the transmitter driver to allocate an | ||
146 | * rfkill structure. Returns %NULL on failure. | ||
147 | */ | ||
148 | struct rfkill * __must_check rfkill_alloc(const char *name, | ||
149 | struct device *parent, | ||
150 | const enum rfkill_type type, | ||
151 | const struct rfkill_ops *ops, | ||
152 | void *ops_data); | ||
100 | 153 | ||
101 | struct rfkill * __must_check rfkill_allocate(struct device *parent, | 154 | /** |
102 | enum rfkill_type type); | 155 | * rfkill_register - Register a rfkill structure. |
103 | void rfkill_free(struct rfkill *rfkill); | 156 | * @rfkill: rfkill structure to be registered |
157 | * | ||
158 | * This function should be called by the transmitter driver to register | ||
159 | * the rfkill structure needs to be registered. Before calling this function | ||
160 | * the driver needs to be ready to service method calls from rfkill. | ||
161 | */ | ||
104 | int __must_check rfkill_register(struct rfkill *rfkill); | 162 | int __must_check rfkill_register(struct rfkill *rfkill); |
163 | |||
164 | /** | ||
165 | * rfkill_pause_polling(struct rfkill *rfkill) | ||
166 | * | ||
167 | * Pause polling -- say transmitter is off for other reasons. | ||
168 | * NOTE: not necessary for suspend/resume -- in that case the | ||
169 | * core stops polling anyway | ||
170 | */ | ||
171 | void rfkill_pause_polling(struct rfkill *rfkill); | ||
172 | |||
173 | /** | ||
174 | * rfkill_resume_polling(struct rfkill *rfkill) | ||
175 | * | ||
176 | * Pause polling -- say transmitter is off for other reasons. | ||
177 | * NOTE: not necessary for suspend/resume -- in that case the | ||
178 | * core stops polling anyway | ||
179 | */ | ||
180 | void rfkill_resume_polling(struct rfkill *rfkill); | ||
181 | |||
182 | |||
183 | /** | ||
184 | * rfkill_unregister - Unregister a rfkill structure. | ||
185 | * @rfkill: rfkill structure to be unregistered | ||
186 | * | ||
187 | * This function should be called by the network driver during device | ||
188 | * teardown to destroy rfkill structure. Until it returns, the driver | ||
189 | * needs to be able to service method calls. | ||
190 | */ | ||
105 | void rfkill_unregister(struct rfkill *rfkill); | 191 | void rfkill_unregister(struct rfkill *rfkill); |
106 | 192 | ||
107 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state); | 193 | /** |
108 | int rfkill_set_default(enum rfkill_type type, enum rfkill_state state); | 194 | * rfkill_destroy - free rfkill structure |
195 | * @rfkill: rfkill structure to be destroyed | ||
196 | * | ||
197 | * Destroys the rfkill structure. | ||
198 | */ | ||
199 | void rfkill_destroy(struct rfkill *rfkill); | ||
200 | |||
201 | /** | ||
202 | * rfkill_set_hw_state - Set the internal rfkill hardware block state | ||
203 | * @rfkill: pointer to the rfkill class to modify. | ||
204 | * @state: the current hardware block state to set | ||
205 | * | ||
206 | * rfkill drivers that get events when the hard-blocked state changes | ||
207 | * use this function to notify the rfkill core (and through that also | ||
208 | * userspace) of the current state -- they should also use this after | ||
209 | * resume if the state could have changed. | ||
210 | * | ||
211 | * You need not (but may) call this function if poll_state is assigned. | ||
212 | * | ||
213 | * This function can be called in any context, even from within rfkill | ||
214 | * callbacks. | ||
215 | * | ||
216 | * The function returns the combined block state (true if transmitter | ||
217 | * should be blocked) so that drivers need not keep track of the soft | ||
218 | * block state -- which they might not be able to. | ||
219 | */ | ||
220 | bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); | ||
221 | |||
222 | /** | ||
223 | * rfkill_set_sw_state - Set the internal rfkill software block state | ||
224 | * @rfkill: pointer to the rfkill class to modify. | ||
225 | * @state: the current software block state to set | ||
226 | * | ||
227 | * rfkill drivers that get events when the soft-blocked state changes | ||
228 | * (yes, some platforms directly act on input but allow changing again) | ||
229 | * use this function to notify the rfkill core (and through that also | ||
230 | * userspace) of the current state -- they should also use this after | ||
231 | * resume if the state could have changed. | ||
232 | * | ||
233 | * This function can be called in any context, even from within rfkill | ||
234 | * callbacks. | ||
235 | * | ||
236 | * The function returns the combined block state (true if transmitter | ||
237 | * should be blocked). | ||
238 | */ | ||
239 | bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); | ||
240 | |||
241 | /** | ||
242 | * rfkill_set_states - Set the internal rfkill block states | ||
243 | * @rfkill: pointer to the rfkill class to modify. | ||
244 | * @sw: the current software block state to set | ||
245 | * @hw: the current hardware block state to set | ||
246 | * | ||
247 | * This function can be called in any context, even from within rfkill | ||
248 | * callbacks. | ||
249 | */ | ||
250 | void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); | ||
109 | 251 | ||
110 | /** | 252 | /** |
111 | * rfkill_state_complement - return complementar state | 253 | * rfkill_set_global_sw_state - set global sw block default |
112 | * @state: state to return the complement of | 254 | * @type: rfkill type to set default for |
255 | * @blocked: default to set | ||
113 | * | 256 | * |
114 | * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED, | 257 | * This function sets the global default -- use at boot if your platform has |
115 | * returns RFKILL_STATE_UNBLOCKED otherwise. | 258 | * an rfkill switch. If not early enough this call may be ignored. |
259 | * | ||
260 | * XXX: instead of ignoring -- how about just updating all currently | ||
261 | * registered drivers? | ||
116 | */ | 262 | */ |
117 | static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state) | 263 | void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked); |
264 | |||
265 | /** | ||
266 | * rfkill_blocked - query rfkill block | ||
267 | * | ||
268 | * @rfkill: rfkill struct to query | ||
269 | */ | ||
270 | bool rfkill_blocked(struct rfkill *rfkill); | ||
271 | #else /* !RFKILL */ | ||
272 | static inline struct rfkill * __must_check | ||
273 | rfkill_alloc(const char *name, | ||
274 | struct device *parent, | ||
275 | const enum rfkill_type type, | ||
276 | const struct rfkill_ops *ops, | ||
277 | void *ops_data) | ||
278 | { | ||
279 | return ERR_PTR(-ENODEV); | ||
280 | } | ||
281 | |||
282 | static inline int __must_check rfkill_register(struct rfkill *rfkill) | ||
283 | { | ||
284 | if (rfkill == ERR_PTR(-ENODEV)) | ||
285 | return 0; | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | static inline void rfkill_pause_polling(struct rfkill *rfkill) | ||
290 | { | ||
291 | } | ||
292 | |||
293 | static inline void rfkill_resume_polling(struct rfkill *rfkill) | ||
294 | { | ||
295 | } | ||
296 | |||
297 | static inline void rfkill_unregister(struct rfkill *rfkill) | ||
298 | { | ||
299 | } | ||
300 | |||
301 | static inline void rfkill_destroy(struct rfkill *rfkill) | ||
302 | { | ||
303 | } | ||
304 | |||
305 | static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) | ||
306 | { | ||
307 | return blocked; | ||
308 | } | ||
309 | |||
310 | static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | ||
311 | { | ||
312 | return blocked; | ||
313 | } | ||
314 | |||
315 | static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) | ||
118 | { | 316 | { |
119 | return (state == RFKILL_STATE_UNBLOCKED) ? | ||
120 | RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; | ||
121 | } | 317 | } |
122 | 318 | ||
319 | static inline void rfkill_set_global_sw_state(const enum rfkill_type type, | ||
320 | bool blocked) | ||
321 | { | ||
322 | } | ||
323 | |||
324 | static inline bool rfkill_blocked(struct rfkill *rfkill) | ||
325 | { | ||
326 | return false; | ||
327 | } | ||
328 | #endif /* RFKILL || RFKILL_MODULE */ | ||
329 | |||
330 | |||
331 | #ifdef CONFIG_RFKILL_LEDS | ||
123 | /** | 332 | /** |
124 | * rfkill_get_led_name - Get the LED trigger name for the button's LED. | 333 | * rfkill_get_led_trigger_name - Get the LED trigger name for the button's LED. |
125 | * This function might return a NULL pointer if registering of the | 334 | * This function might return a NULL pointer if registering of the |
126 | * LED trigger failed. | 335 | * LED trigger failed. Use this as "default_trigger" for the LED. |
127 | * Use this as "default_trigger" for the LED. | ||
128 | */ | 336 | */ |
129 | static inline char *rfkill_get_led_name(struct rfkill *rfkill) | 337 | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill); |
130 | { | 338 | |
131 | #ifdef CONFIG_RFKILL_LEDS | 339 | /** |
132 | return (char *)(rfkill->led_trigger.name); | 340 | * rfkill_set_led_trigger_name -- set the LED trigger name |
341 | * @rfkill: rfkill struct | ||
342 | * @name: LED trigger name | ||
343 | * | ||
344 | * This function sets the LED trigger name of the radio LED | ||
345 | * trigger that rfkill creates. It is optional, but if called | ||
346 | * must be called before rfkill_register() to be effective. | ||
347 | */ | ||
348 | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name); | ||
133 | #else | 349 | #else |
350 | static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||
351 | { | ||
134 | return NULL; | 352 | return NULL; |
135 | #endif | ||
136 | } | 353 | } |
137 | 354 | ||
355 | static inline void | ||
356 | rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||
357 | { | ||
358 | } | ||
359 | #endif | ||
360 | |||
361 | #endif /* __KERNEL__ */ | ||
362 | |||
138 | #endif /* RFKILL_H */ | 363 | #endif /* RFKILL_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f20da7d63b1e..1a21895b732b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -752,6 +752,19 @@ enum wiphy_params_flags { | |||
752 | }; | 752 | }; |
753 | 753 | ||
754 | /** | 754 | /** |
755 | * enum tx_power_setting - TX power adjustment | ||
756 | * | ||
757 | * @TX_POWER_AUTOMATIC: the dbm parameter is ignored | ||
758 | * @TX_POWER_LIMITED: limit TX power by the dbm parameter | ||
759 | * @TX_POWER_FIXED: fix TX power to the dbm parameter | ||
760 | */ | ||
761 | enum tx_power_setting { | ||
762 | TX_POWER_AUTOMATIC, | ||
763 | TX_POWER_LIMITED, | ||
764 | TX_POWER_FIXED, | ||
765 | }; | ||
766 | |||
767 | /** | ||
755 | * struct cfg80211_ops - backend description for wireless configuration | 768 | * struct cfg80211_ops - backend description for wireless configuration |
756 | * | 769 | * |
757 | * This struct is registered by fullmac card drivers and/or wireless stacks | 770 | * This struct is registered by fullmac card drivers and/or wireless stacks |
@@ -837,6 +850,13 @@ enum wiphy_params_flags { | |||
837 | * @changed bitfield (see &enum wiphy_params_flags) describes which values | 850 | * @changed bitfield (see &enum wiphy_params_flags) describes which values |
838 | * have changed. The actual parameter values are available in | 851 | * have changed. The actual parameter values are available in |
839 | * struct wiphy. If returning an error, no value should be changed. | 852 | * struct wiphy. If returning an error, no value should be changed. |
853 | * | ||
854 | * @set_tx_power: set the transmit power according to the parameters | ||
855 | * @get_tx_power: store the current TX power into the dbm variable; | ||
856 | * return 0 if successful | ||
857 | * | ||
858 | * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting | ||
859 | * functions to adjust rfkill hw state | ||
840 | */ | 860 | */ |
841 | struct cfg80211_ops { | 861 | struct cfg80211_ops { |
842 | int (*suspend)(struct wiphy *wiphy); | 862 | int (*suspend)(struct wiphy *wiphy); |
@@ -928,6 +948,12 @@ struct cfg80211_ops { | |||
928 | int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); | 948 | int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); |
929 | 949 | ||
930 | int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); | 950 | int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); |
951 | |||
952 | int (*set_tx_power)(struct wiphy *wiphy, | ||
953 | enum tx_power_setting type, int dbm); | ||
954 | int (*get_tx_power)(struct wiphy *wiphy, int *dbm); | ||
955 | |||
956 | void (*rfkill_poll)(struct wiphy *wiphy); | ||
931 | }; | 957 | }; |
932 | 958 | ||
933 | /* | 959 | /* |
@@ -1451,6 +1477,12 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
1451 | int cfg80211_wext_giwencode(struct net_device *dev, | 1477 | int cfg80211_wext_giwencode(struct net_device *dev, |
1452 | struct iw_request_info *info, | 1478 | struct iw_request_info *info, |
1453 | struct iw_point *erq, char *keybuf); | 1479 | struct iw_point *erq, char *keybuf); |
1480 | int cfg80211_wext_siwtxpower(struct net_device *dev, | ||
1481 | struct iw_request_info *info, | ||
1482 | union iwreq_data *data, char *keybuf); | ||
1483 | int cfg80211_wext_giwtxpower(struct net_device *dev, | ||
1484 | struct iw_request_info *info, | ||
1485 | union iwreq_data *data, char *keybuf); | ||
1454 | 1486 | ||
1455 | /* | 1487 | /* |
1456 | * callbacks for asynchronous cfg80211 methods, notification | 1488 | * callbacks for asynchronous cfg80211 methods, notification |
@@ -1636,4 +1668,23 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, | |||
1636 | */ | 1668 | */ |
1637 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); | 1669 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); |
1638 | 1670 | ||
1671 | /** | ||
1672 | * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state | ||
1673 | * @wiphy: the wiphy | ||
1674 | * @blocked: block status | ||
1675 | */ | ||
1676 | void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked); | ||
1677 | |||
1678 | /** | ||
1679 | * wiphy_rfkill_start_polling - start polling rfkill | ||
1680 | * @wiphy: the wiphy | ||
1681 | */ | ||
1682 | void wiphy_rfkill_start_polling(struct wiphy *wiphy); | ||
1683 | |||
1684 | /** | ||
1685 | * wiphy_rfkill_stop_polling - stop polling rfkill | ||
1686 | * @wiphy: the wiphy | ||
1687 | */ | ||
1688 | void wiphy_rfkill_stop_polling(struct wiphy *wiphy); | ||
1689 | |||
1639 | #endif /* __NET_CFG80211_H */ | 1690 | #endif /* __NET_CFG80211_H */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d72346ff3247..17d61d19d912 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -526,8 +526,7 @@ enum ieee80211_conf_flags { | |||
526 | /** | 526 | /** |
527 | * enum ieee80211_conf_changed - denotes which configuration changed | 527 | * enum ieee80211_conf_changed - denotes which configuration changed |
528 | * | 528 | * |
529 | * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed | 529 | * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED |
530 | * @_IEEE80211_CONF_CHANGE_BEACON_INTERVAL: DEPRECATED | ||
531 | * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed | 530 | * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed |
532 | * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed | 531 | * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed |
533 | * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed | 532 | * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed |
@@ -537,8 +536,7 @@ enum ieee80211_conf_flags { | |||
537 | * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed | 536 | * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed |
538 | */ | 537 | */ |
539 | enum ieee80211_conf_changed { | 538 | enum ieee80211_conf_changed { |
540 | IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), | 539 | _IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), |
541 | _IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), | ||
542 | IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), | 540 | IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), |
543 | IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), | 541 | IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), |
544 | IEEE80211_CONF_CHANGE_PS = BIT(4), | 542 | IEEE80211_CONF_CHANGE_PS = BIT(4), |
@@ -549,12 +547,12 @@ enum ieee80211_conf_changed { | |||
549 | }; | 547 | }; |
550 | 548 | ||
551 | static inline __deprecated enum ieee80211_conf_changed | 549 | static inline __deprecated enum ieee80211_conf_changed |
552 | __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) | 550 | __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) |
553 | { | 551 | { |
554 | return _IEEE80211_CONF_CHANGE_BEACON_INTERVAL; | 552 | return _IEEE80211_CONF_CHANGE_RADIO_ENABLED; |
555 | } | 553 | } |
556 | #define IEEE80211_CONF_CHANGE_BEACON_INTERVAL \ | 554 | #define IEEE80211_CONF_CHANGE_RADIO_ENABLED \ |
557 | __IEEE80211_CONF_CHANGE_BEACON_INTERVAL() | 555 | __IEEE80211_CONF_CHANGE_RADIO_ENABLED() |
558 | 556 | ||
559 | /** | 557 | /** |
560 | * struct ieee80211_conf - configuration of the device | 558 | * struct ieee80211_conf - configuration of the device |
@@ -564,7 +562,7 @@ __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) | |||
564 | * @flags: configuration flags defined above | 562 | * @flags: configuration flags defined above |
565 | * | 563 | * |
566 | * @radio_enabled: when zero, driver is required to switch off the radio. | 564 | * @radio_enabled: when zero, driver is required to switch off the radio. |
567 | * @beacon_int: beacon interval (TODO make interface config) | 565 | * @beacon_int: DEPRECATED, DO NOT USE |
568 | * | 566 | * |
569 | * @listen_interval: listen interval in units of beacon interval | 567 | * @listen_interval: listen interval in units of beacon interval |
570 | * @max_sleep_period: the maximum number of beacon intervals to sleep for | 568 | * @max_sleep_period: the maximum number of beacon intervals to sleep for |
@@ -589,13 +587,13 @@ __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) | |||
589 | * number of transmissions not the number of retries | 587 | * number of transmissions not the number of retries |
590 | */ | 588 | */ |
591 | struct ieee80211_conf { | 589 | struct ieee80211_conf { |
592 | int beacon_int; | 590 | int __deprecated beacon_int; |
593 | u32 flags; | 591 | u32 flags; |
594 | int power_level, dynamic_ps_timeout; | 592 | int power_level, dynamic_ps_timeout; |
595 | int max_sleep_period; | 593 | int max_sleep_period; |
596 | 594 | ||
597 | u16 listen_interval; | 595 | u16 listen_interval; |
598 | bool radio_enabled; | 596 | bool __deprecated radio_enabled; |
599 | 597 | ||
600 | u8 long_frame_max_tx_count, short_frame_max_tx_count; | 598 | u8 long_frame_max_tx_count, short_frame_max_tx_count; |
601 | 599 | ||
@@ -1406,6 +1404,10 @@ enum ieee80211_ampdu_mlme_action { | |||
1406 | * is the first frame we expect to perform the action on. Notice | 1404 | * is the first frame we expect to perform the action on. Notice |
1407 | * that TX/RX_STOP can pass NULL for this parameter. | 1405 | * that TX/RX_STOP can pass NULL for this parameter. |
1408 | * Returns a negative error code on failure. | 1406 | * Returns a negative error code on failure. |
1407 | * | ||
1408 | * @rfkill_poll: Poll rfkill hardware state. If you need this, you also | ||
1409 | * need to set wiphy->rfkill_poll to %true before registration, | ||
1410 | * and need to call wiphy_rfkill_set_hw_state() in the callback. | ||
1409 | */ | 1411 | */ |
1410 | struct ieee80211_ops { | 1412 | struct ieee80211_ops { |
1411 | int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 1413 | int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
@@ -1454,6 +1456,8 @@ struct ieee80211_ops { | |||
1454 | int (*ampdu_action)(struct ieee80211_hw *hw, | 1456 | int (*ampdu_action)(struct ieee80211_hw *hw, |
1455 | enum ieee80211_ampdu_mlme_action action, | 1457 | enum ieee80211_ampdu_mlme_action action, |
1456 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); | 1458 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); |
1459 | |||
1460 | void (*rfkill_poll)(struct ieee80211_hw *hw); | ||
1457 | }; | 1461 | }; |
1458 | 1462 | ||
1459 | /** | 1463 | /** |
diff --git a/include/net/wimax.h b/include/net/wimax.h index 6b3824edb39e..2af7bf839f23 100644 --- a/include/net/wimax.h +++ b/include/net/wimax.h | |||
@@ -253,7 +253,6 @@ | |||
253 | struct net_device; | 253 | struct net_device; |
254 | struct genl_info; | 254 | struct genl_info; |
255 | struct wimax_dev; | 255 | struct wimax_dev; |
256 | struct input_dev; | ||
257 | 256 | ||
258 | /** | 257 | /** |
259 | * struct wimax_dev - Generic WiMAX device | 258 | * struct wimax_dev - Generic WiMAX device |
@@ -293,8 +292,8 @@ struct input_dev; | |||
293 | * See wimax_reset()'s documentation. | 292 | * See wimax_reset()'s documentation. |
294 | * | 293 | * |
295 | * @name: [fill] A way to identify this device. We need to register a | 294 | * @name: [fill] A way to identify this device. We need to register a |
296 | * name with many subsystems (input for RFKILL, workqueue | 295 | * name with many subsystems (rfkill, workqueue creation, etc). |
297 | * creation, etc). We can't use the network device name as that | 296 | * We can't use the network device name as that |
298 | * might change and in some instances we don't know it yet (until | 297 | * might change and in some instances we don't know it yet (until |
299 | * we don't call register_netdev()). So we generate an unique one | 298 | * we don't call register_netdev()). So we generate an unique one |
300 | * using the driver name and device bus id, place it here and use | 299 | * using the driver name and device bus id, place it here and use |
@@ -316,9 +315,6 @@ struct input_dev; | |||
316 | * | 315 | * |
317 | * @rfkill: [private] integration into the RF-Kill infrastructure. | 316 | * @rfkill: [private] integration into the RF-Kill infrastructure. |
318 | * | 317 | * |
319 | * @rfkill_input: [private] virtual input device to process the | ||
320 | * hardware RF Kill switches. | ||
321 | * | ||
322 | * @rf_sw: [private] State of the software radio switch (OFF/ON) | 318 | * @rf_sw: [private] State of the software radio switch (OFF/ON) |
323 | * | 319 | * |
324 | * @rf_hw: [private] State of the hardware radio switch (OFF/ON) | 320 | * @rf_hw: [private] State of the hardware radio switch (OFF/ON) |
diff --git a/net/core/dev.c b/net/core/dev.c index 34b49a6a22fd..1f38401fc028 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1048,7 +1048,7 @@ void dev_load(struct net *net, const char *name) | |||
1048 | int dev_open(struct net_device *dev) | 1048 | int dev_open(struct net_device *dev) |
1049 | { | 1049 | { |
1050 | const struct net_device_ops *ops = dev->netdev_ops; | 1050 | const struct net_device_ops *ops = dev->netdev_ops; |
1051 | int ret = 0; | 1051 | int ret; |
1052 | 1052 | ||
1053 | ASSERT_RTNL(); | 1053 | ASSERT_RTNL(); |
1054 | 1054 | ||
@@ -1065,6 +1065,11 @@ int dev_open(struct net_device *dev) | |||
1065 | if (!netif_device_present(dev)) | 1065 | if (!netif_device_present(dev)) |
1066 | return -ENODEV; | 1066 | return -ENODEV; |
1067 | 1067 | ||
1068 | ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev); | ||
1069 | ret = notifier_to_errno(ret); | ||
1070 | if (ret) | ||
1071 | return ret; | ||
1072 | |||
1068 | /* | 1073 | /* |
1069 | * Call device private open method | 1074 | * Call device private open method |
1070 | */ | 1075 | */ |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 9cbf545e95a2..ba2643a43c73 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -1,16 +1,19 @@ | |||
1 | config MAC80211 | 1 | config MAC80211 |
2 | tristate "Generic IEEE 802.11 Networking Stack (mac80211)" | 2 | tristate "Generic IEEE 802.11 Networking Stack (mac80211)" |
3 | depends on CFG80211 | ||
3 | select CRYPTO | 4 | select CRYPTO |
4 | select CRYPTO_ECB | 5 | select CRYPTO_ECB |
5 | select CRYPTO_ARC4 | 6 | select CRYPTO_ARC4 |
6 | select CRYPTO_AES | 7 | select CRYPTO_AES |
7 | select CRC32 | 8 | select CRC32 |
8 | select WIRELESS_EXT | 9 | select WIRELESS_EXT |
9 | select CFG80211 | ||
10 | ---help--- | 10 | ---help--- |
11 | This option enables the hardware independent IEEE 802.11 | 11 | This option enables the hardware independent IEEE 802.11 |
12 | networking stack. | 12 | networking stack. |
13 | 13 | ||
14 | comment "CFG80211 needs to be enabled for MAC80211" | ||
15 | depends on CFG80211=n | ||
16 | |||
14 | config MAC80211_DEFAULT_PS | 17 | config MAC80211_DEFAULT_PS |
15 | bool "enable powersave by default" | 18 | bool "enable powersave by default" |
16 | depends on MAC80211 | 19 | depends on MAC80211 |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 77e9ff5ec4f3..a9211cc183cb 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -664,18 +664,19 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
664 | spin_unlock_bh(&sta->lock); | 664 | spin_unlock_bh(&sta->lock); |
665 | 665 | ||
666 | /* | 666 | /* |
667 | * cfg80211 validates this (1-2007) and allows setting the AID | ||
668 | * only when creating a new station entry | ||
669 | */ | ||
670 | if (params->aid) | ||
671 | sta->sta.aid = params->aid; | ||
672 | |||
673 | /* | ||
667 | * FIXME: updating the following information is racy when this | 674 | * FIXME: updating the following information is racy when this |
668 | * function is called from ieee80211_change_station(). | 675 | * function is called from ieee80211_change_station(). |
669 | * However, all this information should be static so | 676 | * However, all this information should be static so |
670 | * maybe we should just reject attemps to change it. | 677 | * maybe we should just reject attemps to change it. |
671 | */ | 678 | */ |
672 | 679 | ||
673 | if (params->aid) { | ||
674 | sta->sta.aid = params->aid; | ||
675 | if (sta->sta.aid > IEEE80211_MAX_AID) | ||
676 | sta->sta.aid = 0; /* XXX: should this be an error? */ | ||
677 | } | ||
678 | |||
679 | if (params->listen_interval >= 0) | 680 | if (params->listen_interval >= 0) |
680 | sta->listen_interval = params->listen_interval; | 681 | sta->listen_interval = params->listen_interval; |
681 | 682 | ||
@@ -1255,7 +1256,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | |||
1255 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; | 1256 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; |
1256 | 1257 | ||
1257 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); | 1258 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); |
1258 | if (ret) | 1259 | if (ret && ret != -EALREADY) |
1259 | return ret; | 1260 | return ret; |
1260 | 1261 | ||
1261 | if (req->use_mfp) { | 1262 | if (req->use_mfp) { |
@@ -1333,6 +1334,53 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1333 | return 0; | 1334 | return 0; |
1334 | } | 1335 | } |
1335 | 1336 | ||
1337 | static int ieee80211_set_tx_power(struct wiphy *wiphy, | ||
1338 | enum tx_power_setting type, int dbm) | ||
1339 | { | ||
1340 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1341 | struct ieee80211_channel *chan = local->hw.conf.channel; | ||
1342 | u32 changes = 0; | ||
1343 | |||
1344 | switch (type) { | ||
1345 | case TX_POWER_AUTOMATIC: | ||
1346 | local->user_power_level = -1; | ||
1347 | break; | ||
1348 | case TX_POWER_LIMITED: | ||
1349 | if (dbm < 0) | ||
1350 | return -EINVAL; | ||
1351 | local->user_power_level = dbm; | ||
1352 | break; | ||
1353 | case TX_POWER_FIXED: | ||
1354 | if (dbm < 0) | ||
1355 | return -EINVAL; | ||
1356 | /* TODO: move to cfg80211 when it knows the channel */ | ||
1357 | if (dbm > chan->max_power) | ||
1358 | return -EINVAL; | ||
1359 | local->user_power_level = dbm; | ||
1360 | break; | ||
1361 | } | ||
1362 | |||
1363 | ieee80211_hw_config(local, changes); | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | ||
1369 | { | ||
1370 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1371 | |||
1372 | *dbm = local->hw.conf.power_level; | ||
1373 | |||
1374 | return 0; | ||
1375 | } | ||
1376 | |||
1377 | static void ieee80211_rfkill_poll(struct wiphy *wiphy) | ||
1378 | { | ||
1379 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1380 | |||
1381 | drv_rfkill_poll(local); | ||
1382 | } | ||
1383 | |||
1336 | struct cfg80211_ops mac80211_config_ops = { | 1384 | struct cfg80211_ops mac80211_config_ops = { |
1337 | .add_virtual_intf = ieee80211_add_iface, | 1385 | .add_virtual_intf = ieee80211_add_iface, |
1338 | .del_virtual_intf = ieee80211_del_iface, | 1386 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1372,4 +1420,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1372 | .join_ibss = ieee80211_join_ibss, | 1420 | .join_ibss = ieee80211_join_ibss, |
1373 | .leave_ibss = ieee80211_leave_ibss, | 1421 | .leave_ibss = ieee80211_leave_ibss, |
1374 | .set_wiphy_params = ieee80211_set_wiphy_params, | 1422 | .set_wiphy_params = ieee80211_set_wiphy_params, |
1423 | .set_tx_power = ieee80211_set_tx_power, | ||
1424 | .get_tx_power = ieee80211_get_tx_power, | ||
1425 | .rfkill_poll = ieee80211_rfkill_poll, | ||
1375 | }; | 1426 | }; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 3912b5334b9c..b13446afd48f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -181,4 +181,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, | |||
181 | sta, tid, ssn); | 181 | sta, tid, ssn); |
182 | return -EOPNOTSUPP; | 182 | return -EOPNOTSUPP; |
183 | } | 183 | } |
184 | |||
185 | |||
186 | static inline void drv_rfkill_poll(struct ieee80211_local *local) | ||
187 | { | ||
188 | if (local->ops->rfkill_poll) | ||
189 | local->ops->rfkill_poll(&local->hw); | ||
190 | } | ||
184 | #endif /* __MAC80211_DRIVER_OPS */ | 191 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8c9f1c722cdb..b7c8a4484298 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -170,7 +170,7 @@ static int ieee80211_open(struct net_device *dev) | |||
170 | goto err_del_bss; | 170 | goto err_del_bss; |
171 | /* we're brought up, everything changes */ | 171 | /* we're brought up, everything changes */ |
172 | hw_reconf_flags = ~0; | 172 | hw_reconf_flags = ~0; |
173 | ieee80211_led_radio(local, local->hw.conf.radio_enabled); | 173 | ieee80211_led_radio(local, true); |
174 | } | 174 | } |
175 | 175 | ||
176 | /* | 176 | /* |
@@ -560,7 +560,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
560 | 560 | ||
561 | drv_stop(local); | 561 | drv_stop(local); |
562 | 562 | ||
563 | ieee80211_led_radio(local, 0); | 563 | ieee80211_led_radio(local, false); |
564 | 564 | ||
565 | flush_workqueue(local->hw.workqueue); | 565 | flush_workqueue(local->hw.workqueue); |
566 | 566 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e37770ced53c..2683df918073 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -289,16 +289,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
289 | drv_bss_info_changed(local, &sdata->vif, | 289 | drv_bss_info_changed(local, &sdata->vif, |
290 | &sdata->vif.bss_conf, changed); | 290 | &sdata->vif.bss_conf, changed); |
291 | 291 | ||
292 | /* | 292 | /* DEPRECATED */ |
293 | * DEPRECATED | 293 | local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; |
294 | * | ||
295 | * ~changed is just there to not do this at resume time | ||
296 | */ | ||
297 | if (changed & BSS_CHANGED_BEACON_INT && ~changed) { | ||
298 | local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; | ||
299 | ieee80211_hw_config(local, | ||
300 | _IEEE80211_CONF_CHANGE_BEACON_INTERVAL); | ||
301 | } | ||
302 | } | 294 | } |
303 | 295 | ||
304 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 296 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d5611d8fd0d6..a360bceeba59 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -44,6 +44,15 @@ | |||
44 | * When the insertion fails (sta_info_insert()) returns non-zero), the | 44 | * When the insertion fails (sta_info_insert()) returns non-zero), the |
45 | * structure will have been freed by sta_info_insert()! | 45 | * structure will have been freed by sta_info_insert()! |
46 | * | 46 | * |
47 | * sta entries are added by mac80211 when you establish a link with a | ||
48 | * peer. This means different things for the different type of interfaces | ||
49 | * we support. For a regular station this mean we add the AP sta when we | ||
50 | * receive an assocation response from the AP. For IBSS this occurs when | ||
51 | * we receive a probe response or a beacon from target IBSS network. For | ||
52 | * WDS we add the sta for the peer imediately upon device open. When using | ||
53 | * AP mode we add stations for each respective station upon request from | ||
54 | * userspace through nl80211. | ||
55 | * | ||
47 | * Because there are debugfs entries for each station, and adding those | 56 | * Because there are debugfs entries for each station, and adding those |
48 | * must be able to sleep, it is also possible to "pin" a station entry, | 57 | * must be able to sleep, it is also possible to "pin" a station entry, |
49 | * that means it can be removed from the hash table but not be freed. | 58 | * that means it can be removed from the hash table but not be freed. |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a910148b8228..1436f747531a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1238,7 +1238,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1238 | bool txpending) | 1238 | bool txpending) |
1239 | { | 1239 | { |
1240 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1240 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1241 | struct sta_info *sta; | ||
1242 | struct ieee80211_tx_data tx; | 1241 | struct ieee80211_tx_data tx; |
1243 | ieee80211_tx_result res_prepare; | 1242 | ieee80211_tx_result res_prepare; |
1244 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1243 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -1270,7 +1269,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1270 | return; | 1269 | return; |
1271 | } | 1270 | } |
1272 | 1271 | ||
1273 | sta = tx.sta; | ||
1274 | tx.channel = local->hw.conf.channel; | 1272 | tx.channel = local->hw.conf.channel; |
1275 | info->band = tx.channel->band; | 1273 | info->band = tx.channel->band; |
1276 | 1274 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 949d857debd8..22f63815fb36 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -657,15 +657,15 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
657 | 657 | ||
658 | switch (queue) { | 658 | switch (queue) { |
659 | case 3: /* AC_BK */ | 659 | case 3: /* AC_BK */ |
660 | qparam.cw_max = aCWmin; | 660 | qparam.cw_max = aCWmax; |
661 | qparam.cw_min = aCWmax; | 661 | qparam.cw_min = aCWmin; |
662 | qparam.txop = 0; | 662 | qparam.txop = 0; |
663 | qparam.aifs = 7; | 663 | qparam.aifs = 7; |
664 | break; | 664 | break; |
665 | default: /* never happens but let's not leave undefined */ | 665 | default: /* never happens but let's not leave undefined */ |
666 | case 2: /* AC_BE */ | 666 | case 2: /* AC_BE */ |
667 | qparam.cw_max = aCWmin; | 667 | qparam.cw_max = aCWmax; |
668 | qparam.cw_min = aCWmax; | 668 | qparam.cw_min = aCWmin; |
669 | qparam.txop = 0; | 669 | qparam.txop = 0; |
670 | qparam.aifs = 3; | 670 | qparam.aifs = 3; |
671 | break; | 671 | break; |
@@ -973,7 +973,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
973 | if (local->open_count) { | 973 | if (local->open_count) { |
974 | res = drv_start(local); | 974 | res = drv_start(local); |
975 | 975 | ||
976 | ieee80211_led_radio(local, hw->conf.radio_enabled); | 976 | ieee80211_led_radio(local, true); |
977 | } | 977 | } |
978 | 978 | ||
979 | /* add interfaces */ | 979 | /* add interfaces */ |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index a01154e127f0..d2d81b103341 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -306,82 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
306 | return 0; | 306 | return 0; |
307 | } | 307 | } |
308 | 308 | ||
309 | static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | ||
310 | struct iw_request_info *info, | ||
311 | union iwreq_data *data, char *extra) | ||
312 | { | ||
313 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
314 | struct ieee80211_channel* chan = local->hw.conf.channel; | ||
315 | bool reconf = false; | ||
316 | u32 reconf_flags = 0; | ||
317 | int new_power_level; | ||
318 | |||
319 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | ||
320 | return -EINVAL; | ||
321 | if (data->txpower.flags & IW_TXPOW_RANGE) | ||
322 | return -EINVAL; | ||
323 | if (!chan) | ||
324 | return -EINVAL; | ||
325 | |||
326 | /* only change when not disabling */ | ||
327 | if (!data->txpower.disabled) { | ||
328 | if (data->txpower.fixed) { | ||
329 | if (data->txpower.value < 0) | ||
330 | return -EINVAL; | ||
331 | new_power_level = data->txpower.value; | ||
332 | /* | ||
333 | * Debatable, but we cannot do a fixed power | ||
334 | * level above the regulatory constraint. | ||
335 | * Use "iwconfig wlan0 txpower 15dBm" instead. | ||
336 | */ | ||
337 | if (new_power_level > chan->max_power) | ||
338 | return -EINVAL; | ||
339 | } else { | ||
340 | /* | ||
341 | * Automatic power level setting, max being the value | ||
342 | * passed in from userland. | ||
343 | */ | ||
344 | if (data->txpower.value < 0) | ||
345 | new_power_level = -1; | ||
346 | else | ||
347 | new_power_level = data->txpower.value; | ||
348 | } | ||
349 | |||
350 | reconf = true; | ||
351 | |||
352 | /* | ||
353 | * ieee80211_hw_config() will limit to the channel's | ||
354 | * max power and possibly power constraint from AP. | ||
355 | */ | ||
356 | local->user_power_level = new_power_level; | ||
357 | } | ||
358 | |||
359 | if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { | ||
360 | local->hw.conf.radio_enabled = !(data->txpower.disabled); | ||
361 | reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; | ||
362 | ieee80211_led_radio(local, local->hw.conf.radio_enabled); | ||
363 | } | ||
364 | |||
365 | if (reconf || reconf_flags) | ||
366 | ieee80211_hw_config(local, reconf_flags); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int ieee80211_ioctl_giwtxpower(struct net_device *dev, | ||
372 | struct iw_request_info *info, | ||
373 | union iwreq_data *data, char *extra) | ||
374 | { | ||
375 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
376 | |||
377 | data->txpower.fixed = 1; | ||
378 | data->txpower.disabled = !(local->hw.conf.radio_enabled); | ||
379 | data->txpower.value = local->hw.conf.power_level; | ||
380 | data->txpower.flags = IW_TXPOW_DBM; | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int ieee80211_ioctl_siwpower(struct net_device *dev, | 309 | static int ieee80211_ioctl_siwpower(struct net_device *dev, |
386 | struct iw_request_info *info, | 310 | struct iw_request_info *info, |
387 | struct iw_param *wrq, | 311 | struct iw_param *wrq, |
@@ -658,8 +582,8 @@ static const iw_handler ieee80211_handler[] = | |||
658 | (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ | 582 | (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ |
659 | (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ | 583 | (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ |
660 | (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ | 584 | (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ |
661 | (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ | 585 | (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ |
662 | (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ | 586 | (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ |
663 | (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ | 587 | (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ |
664 | (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ | 588 | (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ |
665 | (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ | 589 | (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ |
diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 7f807b30cfbb..fd7600d8ab14 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig | |||
@@ -10,22 +10,15 @@ menuconfig RFKILL | |||
10 | To compile this driver as a module, choose M here: the | 10 | To compile this driver as a module, choose M here: the |
11 | module will be called rfkill. | 11 | module will be called rfkill. |
12 | 12 | ||
13 | config RFKILL_INPUT | ||
14 | tristate "Input layer to RF switch connector" | ||
15 | depends on RFKILL && INPUT | ||
16 | help | ||
17 | Say Y here if you want kernel automatically toggle state | ||
18 | of RF switches on and off when user presses appropriate | ||
19 | button or a key on the keyboard. Without this module you | ||
20 | need a some kind of userspace application to control | ||
21 | state of the switches. | ||
22 | |||
23 | To compile this driver as a module, choose M here: the | ||
24 | module will be called rfkill-input. | ||
25 | |||
26 | # LED trigger support | 13 | # LED trigger support |
27 | config RFKILL_LEDS | 14 | config RFKILL_LEDS |
28 | bool | 15 | bool |
29 | depends on RFKILL && LEDS_TRIGGERS | 16 | depends on RFKILL |
17 | depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS | ||
30 | default y | 18 | default y |
31 | 19 | ||
20 | config RFKILL_INPUT | ||
21 | bool "RF switch input support" | ||
22 | depends on RFKILL | ||
23 | depends on INPUT = y || RFKILL = INPUT | ||
24 | default y if !EMBEDDED | ||
diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile index b38c430be057..662105352691 100644 --- a/net/rfkill/Makefile +++ b/net/rfkill/Makefile | |||
@@ -2,5 +2,6 @@ | |||
2 | # Makefile for the RF switch subsystem. | 2 | # Makefile for the RF switch subsystem. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_RFKILL) += rfkill.o | 5 | rfkill-y += core.o |
6 | obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o | 6 | rfkill-$(CONFIG_RFKILL_INPUT) += input.o |
7 | obj-$(CONFIG_RFKILL) += rfkill.o | ||
diff --git a/net/rfkill/core.c b/net/rfkill/core.c new file mode 100644 index 000000000000..11b7314723df --- /dev/null +++ b/net/rfkill/core.c | |||
@@ -0,0 +1,1228 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 - 2007 Ivo van Doorn | ||
3 | * Copyright (C) 2007 Dmitry Torokhov | ||
4 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the | ||
18 | * Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | #include <linux/capability.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/rfkill.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/miscdevice.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/poll.h> | ||
34 | #include <linux/fs.h> | ||
35 | |||
36 | #include "rfkill.h" | ||
37 | |||
38 | #define POLL_INTERVAL (5 * HZ) | ||
39 | |||
40 | #define RFKILL_BLOCK_HW BIT(0) | ||
41 | #define RFKILL_BLOCK_SW BIT(1) | ||
42 | #define RFKILL_BLOCK_SW_PREV BIT(2) | ||
43 | #define RFKILL_BLOCK_ANY (RFKILL_BLOCK_HW |\ | ||
44 | RFKILL_BLOCK_SW |\ | ||
45 | RFKILL_BLOCK_SW_PREV) | ||
46 | #define RFKILL_BLOCK_SW_SETCALL BIT(31) | ||
47 | |||
48 | struct rfkill { | ||
49 | spinlock_t lock; | ||
50 | |||
51 | const char *name; | ||
52 | enum rfkill_type type; | ||
53 | |||
54 | unsigned long state; | ||
55 | |||
56 | u32 idx; | ||
57 | |||
58 | bool registered; | ||
59 | bool suspended; | ||
60 | |||
61 | const struct rfkill_ops *ops; | ||
62 | void *data; | ||
63 | |||
64 | #ifdef CONFIG_RFKILL_LEDS | ||
65 | struct led_trigger led_trigger; | ||
66 | const char *ledtrigname; | ||
67 | #endif | ||
68 | |||
69 | struct device dev; | ||
70 | struct list_head node; | ||
71 | |||
72 | struct delayed_work poll_work; | ||
73 | struct work_struct uevent_work; | ||
74 | struct work_struct sync_work; | ||
75 | }; | ||
76 | #define to_rfkill(d) container_of(d, struct rfkill, dev) | ||
77 | |||
78 | struct rfkill_int_event { | ||
79 | struct list_head list; | ||
80 | struct rfkill_event ev; | ||
81 | }; | ||
82 | |||
83 | struct rfkill_data { | ||
84 | struct list_head list; | ||
85 | struct list_head events; | ||
86 | struct mutex mtx; | ||
87 | wait_queue_head_t read_wait; | ||
88 | bool input_handler; | ||
89 | }; | ||
90 | |||
91 | |||
92 | MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>"); | ||
93 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
94 | MODULE_DESCRIPTION("RF switch support"); | ||
95 | MODULE_LICENSE("GPL"); | ||
96 | |||
97 | |||
98 | /* | ||
99 | * The locking here should be made much smarter, we currently have | ||
100 | * a bit of a stupid situation because drivers might want to register | ||
101 | * the rfkill struct under their own lock, and take this lock during | ||
102 | * rfkill method calls -- which will cause an AB-BA deadlock situation. | ||
103 | * | ||
104 | * To fix that, we need to rework this code here to be mostly lock-free | ||
105 | * and only use the mutex for list manipulations, not to protect the | ||
106 | * various other global variables. Then we can avoid holding the mutex | ||
107 | * around driver operations, and all is happy. | ||
108 | */ | ||
109 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | ||
110 | static DEFINE_MUTEX(rfkill_global_mutex); | ||
111 | static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ | ||
112 | |||
113 | static unsigned int rfkill_default_state = 1; | ||
114 | module_param_named(default_state, rfkill_default_state, uint, 0444); | ||
115 | MODULE_PARM_DESC(default_state, | ||
116 | "Default initial state for all radio types, 0 = radio off"); | ||
117 | |||
118 | static struct { | ||
119 | bool cur, def; | ||
120 | } rfkill_global_states[NUM_RFKILL_TYPES]; | ||
121 | |||
122 | static unsigned long rfkill_states_default_locked; | ||
123 | |||
124 | static bool rfkill_epo_lock_active; | ||
125 | |||
126 | |||
127 | #ifdef CONFIG_RFKILL_LEDS | ||
128 | static void rfkill_led_trigger_event(struct rfkill *rfkill) | ||
129 | { | ||
130 | struct led_trigger *trigger; | ||
131 | |||
132 | if (!rfkill->registered) | ||
133 | return; | ||
134 | |||
135 | trigger = &rfkill->led_trigger; | ||
136 | |||
137 | if (rfkill->state & RFKILL_BLOCK_ANY) | ||
138 | led_trigger_event(trigger, LED_OFF); | ||
139 | else | ||
140 | led_trigger_event(trigger, LED_FULL); | ||
141 | } | ||
142 | |||
143 | static void rfkill_led_trigger_activate(struct led_classdev *led) | ||
144 | { | ||
145 | struct rfkill *rfkill; | ||
146 | |||
147 | rfkill = container_of(led->trigger, struct rfkill, led_trigger); | ||
148 | |||
149 | rfkill_led_trigger_event(rfkill); | ||
150 | } | ||
151 | |||
152 | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||
153 | { | ||
154 | return rfkill->led_trigger.name; | ||
155 | } | ||
156 | EXPORT_SYMBOL(rfkill_get_led_trigger_name); | ||
157 | |||
158 | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||
159 | { | ||
160 | BUG_ON(!rfkill); | ||
161 | |||
162 | rfkill->ledtrigname = name; | ||
163 | } | ||
164 | EXPORT_SYMBOL(rfkill_set_led_trigger_name); | ||
165 | |||
166 | static int rfkill_led_trigger_register(struct rfkill *rfkill) | ||
167 | { | ||
168 | rfkill->led_trigger.name = rfkill->ledtrigname | ||
169 | ? : dev_name(&rfkill->dev); | ||
170 | rfkill->led_trigger.activate = rfkill_led_trigger_activate; | ||
171 | return led_trigger_register(&rfkill->led_trigger); | ||
172 | } | ||
173 | |||
174 | static void rfkill_led_trigger_unregister(struct rfkill *rfkill) | ||
175 | { | ||
176 | led_trigger_unregister(&rfkill->led_trigger); | ||
177 | } | ||
178 | #else | ||
179 | static void rfkill_led_trigger_event(struct rfkill *rfkill) | ||
180 | { | ||
181 | } | ||
182 | |||
183 | static inline int rfkill_led_trigger_register(struct rfkill *rfkill) | ||
184 | { | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill) | ||
189 | { | ||
190 | } | ||
191 | #endif /* CONFIG_RFKILL_LEDS */ | ||
192 | |||
193 | static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill, | ||
194 | enum rfkill_operation op) | ||
195 | { | ||
196 | unsigned long flags; | ||
197 | |||
198 | ev->idx = rfkill->idx; | ||
199 | ev->type = rfkill->type; | ||
200 | ev->op = op; | ||
201 | |||
202 | spin_lock_irqsave(&rfkill->lock, flags); | ||
203 | ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
204 | ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW | | ||
205 | RFKILL_BLOCK_SW_PREV)); | ||
206 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
207 | } | ||
208 | |||
209 | static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) | ||
210 | { | ||
211 | struct rfkill_data *data; | ||
212 | struct rfkill_int_event *ev; | ||
213 | |||
214 | list_for_each_entry(data, &rfkill_fds, list) { | ||
215 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
216 | if (!ev) | ||
217 | continue; | ||
218 | rfkill_fill_event(&ev->ev, rfkill, op); | ||
219 | mutex_lock(&data->mtx); | ||
220 | list_add_tail(&ev->list, &data->events); | ||
221 | mutex_unlock(&data->mtx); | ||
222 | wake_up_interruptible(&data->read_wait); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static void rfkill_event(struct rfkill *rfkill) | ||
227 | { | ||
228 | if (!rfkill->registered || rfkill->suspended) | ||
229 | return; | ||
230 | |||
231 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); | ||
232 | |||
233 | /* also send event to /dev/rfkill */ | ||
234 | rfkill_send_events(rfkill, RFKILL_OP_CHANGE); | ||
235 | } | ||
236 | |||
237 | static bool __rfkill_set_hw_state(struct rfkill *rfkill, | ||
238 | bool blocked, bool *change) | ||
239 | { | ||
240 | unsigned long flags; | ||
241 | bool prev, any; | ||
242 | |||
243 | BUG_ON(!rfkill); | ||
244 | |||
245 | spin_lock_irqsave(&rfkill->lock, flags); | ||
246 | prev = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
247 | if (blocked) | ||
248 | rfkill->state |= RFKILL_BLOCK_HW; | ||
249 | else | ||
250 | rfkill->state &= ~RFKILL_BLOCK_HW; | ||
251 | *change = prev != blocked; | ||
252 | any = rfkill->state & RFKILL_BLOCK_ANY; | ||
253 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
254 | |||
255 | rfkill_led_trigger_event(rfkill); | ||
256 | |||
257 | return any; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * rfkill_set_block - wrapper for set_block method | ||
262 | * | ||
263 | * @rfkill: the rfkill struct to use | ||
264 | * @blocked: the new software state | ||
265 | * | ||
266 | * Calls the set_block method (when applicable) and handles notifications | ||
267 | * etc. as well. | ||
268 | */ | ||
269 | static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | ||
270 | { | ||
271 | unsigned long flags; | ||
272 | int err; | ||
273 | |||
274 | /* | ||
275 | * Some platforms (...!) generate input events which affect the | ||
276 | * _hard_ kill state -- whenever something tries to change the | ||
277 | * current software state query the hardware state too. | ||
278 | */ | ||
279 | if (rfkill->ops->query) | ||
280 | rfkill->ops->query(rfkill, rfkill->data); | ||
281 | |||
282 | spin_lock_irqsave(&rfkill->lock, flags); | ||
283 | if (rfkill->state & RFKILL_BLOCK_SW) | ||
284 | rfkill->state |= RFKILL_BLOCK_SW_PREV; | ||
285 | else | ||
286 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | ||
287 | |||
288 | if (blocked) | ||
289 | rfkill->state |= RFKILL_BLOCK_SW; | ||
290 | else | ||
291 | rfkill->state &= ~RFKILL_BLOCK_SW; | ||
292 | |||
293 | rfkill->state |= RFKILL_BLOCK_SW_SETCALL; | ||
294 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
295 | |||
296 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | ||
297 | return; | ||
298 | |||
299 | err = rfkill->ops->set_block(rfkill->data, blocked); | ||
300 | |||
301 | spin_lock_irqsave(&rfkill->lock, flags); | ||
302 | if (err) { | ||
303 | /* | ||
304 | * Failed -- reset status to _prev, this may be different | ||
305 | * from what set set _PREV to earlier in this function | ||
306 | * if rfkill_set_sw_state was invoked. | ||
307 | */ | ||
308 | if (rfkill->state & RFKILL_BLOCK_SW_PREV) | ||
309 | rfkill->state |= RFKILL_BLOCK_SW; | ||
310 | else | ||
311 | rfkill->state &= ~RFKILL_BLOCK_SW; | ||
312 | } | ||
313 | rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; | ||
314 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | ||
315 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
316 | |||
317 | rfkill_led_trigger_event(rfkill); | ||
318 | rfkill_event(rfkill); | ||
319 | } | ||
320 | |||
321 | #ifdef CONFIG_RFKILL_INPUT | ||
322 | static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); | ||
323 | |||
324 | /** | ||
325 | * __rfkill_switch_all - Toggle state of all switches of given type | ||
326 | * @type: type of interfaces to be affected | ||
327 | * @state: the new state | ||
328 | * | ||
329 | * This function sets the state of all switches of given type, | ||
330 | * unless a specific switch is claimed by userspace (in which case, | ||
331 | * that switch is left alone) or suspended. | ||
332 | * | ||
333 | * Caller must have acquired rfkill_global_mutex. | ||
334 | */ | ||
335 | static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) | ||
336 | { | ||
337 | struct rfkill *rfkill; | ||
338 | |||
339 | rfkill_global_states[type].cur = blocked; | ||
340 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
341 | if (rfkill->type != type) | ||
342 | continue; | ||
343 | |||
344 | rfkill_set_block(rfkill, blocked); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * rfkill_switch_all - Toggle state of all switches of given type | ||
350 | * @type: type of interfaces to be affected | ||
351 | * @state: the new state | ||
352 | * | ||
353 | * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). | ||
354 | * Please refer to __rfkill_switch_all() for details. | ||
355 | * | ||
356 | * Does nothing if the EPO lock is active. | ||
357 | */ | ||
358 | void rfkill_switch_all(enum rfkill_type type, bool blocked) | ||
359 | { | ||
360 | if (atomic_read(&rfkill_input_disabled)) | ||
361 | return; | ||
362 | |||
363 | mutex_lock(&rfkill_global_mutex); | ||
364 | |||
365 | if (!rfkill_epo_lock_active) | ||
366 | __rfkill_switch_all(type, blocked); | ||
367 | |||
368 | mutex_unlock(&rfkill_global_mutex); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * rfkill_epo - emergency power off all transmitters | ||
373 | * | ||
374 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, | ||
375 | * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. | ||
376 | * | ||
377 | * The global state before the EPO is saved and can be restored later | ||
378 | * using rfkill_restore_states(). | ||
379 | */ | ||
380 | void rfkill_epo(void) | ||
381 | { | ||
382 | struct rfkill *rfkill; | ||
383 | int i; | ||
384 | |||
385 | if (atomic_read(&rfkill_input_disabled)) | ||
386 | return; | ||
387 | |||
388 | mutex_lock(&rfkill_global_mutex); | ||
389 | |||
390 | rfkill_epo_lock_active = true; | ||
391 | list_for_each_entry(rfkill, &rfkill_list, node) | ||
392 | rfkill_set_block(rfkill, true); | ||
393 | |||
394 | for (i = 0; i < NUM_RFKILL_TYPES; i++) { | ||
395 | rfkill_global_states[i].def = rfkill_global_states[i].cur; | ||
396 | rfkill_global_states[i].cur = true; | ||
397 | } | ||
398 | |||
399 | mutex_unlock(&rfkill_global_mutex); | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * rfkill_restore_states - restore global states | ||
404 | * | ||
405 | * Restore (and sync switches to) the global state from the | ||
406 | * states in rfkill_default_states. This can undo the effects of | ||
407 | * a call to rfkill_epo(). | ||
408 | */ | ||
409 | void rfkill_restore_states(void) | ||
410 | { | ||
411 | int i; | ||
412 | |||
413 | if (atomic_read(&rfkill_input_disabled)) | ||
414 | return; | ||
415 | |||
416 | mutex_lock(&rfkill_global_mutex); | ||
417 | |||
418 | rfkill_epo_lock_active = false; | ||
419 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
420 | __rfkill_switch_all(i, rfkill_global_states[i].def); | ||
421 | mutex_unlock(&rfkill_global_mutex); | ||
422 | } | ||
423 | |||
424 | /** | ||
425 | * rfkill_remove_epo_lock - unlock state changes | ||
426 | * | ||
427 | * Used by rfkill-input manually unlock state changes, when | ||
428 | * the EPO switch is deactivated. | ||
429 | */ | ||
430 | void rfkill_remove_epo_lock(void) | ||
431 | { | ||
432 | if (atomic_read(&rfkill_input_disabled)) | ||
433 | return; | ||
434 | |||
435 | mutex_lock(&rfkill_global_mutex); | ||
436 | rfkill_epo_lock_active = false; | ||
437 | mutex_unlock(&rfkill_global_mutex); | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * rfkill_is_epo_lock_active - returns true EPO is active | ||
442 | * | ||
443 | * Returns 0 (false) if there is NOT an active EPO contidion, | ||
444 | * and 1 (true) if there is an active EPO contition, which | ||
445 | * locks all radios in one of the BLOCKED states. | ||
446 | * | ||
447 | * Can be called in atomic context. | ||
448 | */ | ||
449 | bool rfkill_is_epo_lock_active(void) | ||
450 | { | ||
451 | return rfkill_epo_lock_active; | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * rfkill_get_global_sw_state - returns global state for a type | ||
456 | * @type: the type to get the global state of | ||
457 | * | ||
458 | * Returns the current global state for a given wireless | ||
459 | * device type. | ||
460 | */ | ||
461 | bool rfkill_get_global_sw_state(const enum rfkill_type type) | ||
462 | { | ||
463 | return rfkill_global_states[type].cur; | ||
464 | } | ||
465 | #endif | ||
466 | |||
467 | void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) | ||
468 | { | ||
469 | BUG_ON(type == RFKILL_TYPE_ALL); | ||
470 | |||
471 | mutex_lock(&rfkill_global_mutex); | ||
472 | |||
473 | /* don't allow unblock when epo */ | ||
474 | if (rfkill_epo_lock_active && !blocked) | ||
475 | goto out; | ||
476 | |||
477 | /* too late */ | ||
478 | if (rfkill_states_default_locked & BIT(type)) | ||
479 | goto out; | ||
480 | |||
481 | rfkill_states_default_locked |= BIT(type); | ||
482 | |||
483 | rfkill_global_states[type].cur = blocked; | ||
484 | rfkill_global_states[type].def = blocked; | ||
485 | out: | ||
486 | mutex_unlock(&rfkill_global_mutex); | ||
487 | } | ||
488 | EXPORT_SYMBOL(rfkill_set_global_sw_state); | ||
489 | |||
490 | |||
491 | bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) | ||
492 | { | ||
493 | bool ret, change; | ||
494 | |||
495 | ret = __rfkill_set_hw_state(rfkill, blocked, &change); | ||
496 | |||
497 | if (!rfkill->registered) | ||
498 | return ret; | ||
499 | |||
500 | if (change) | ||
501 | schedule_work(&rfkill->uevent_work); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | EXPORT_SYMBOL(rfkill_set_hw_state); | ||
506 | |||
507 | static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | ||
508 | { | ||
509 | u32 bit = RFKILL_BLOCK_SW; | ||
510 | |||
511 | /* if in a ops->set_block right now, use other bit */ | ||
512 | if (rfkill->state & RFKILL_BLOCK_SW_SETCALL) | ||
513 | bit = RFKILL_BLOCK_SW_PREV; | ||
514 | |||
515 | if (blocked) | ||
516 | rfkill->state |= bit; | ||
517 | else | ||
518 | rfkill->state &= ~bit; | ||
519 | } | ||
520 | |||
521 | bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | ||
522 | { | ||
523 | unsigned long flags; | ||
524 | bool prev, hwblock; | ||
525 | |||
526 | BUG_ON(!rfkill); | ||
527 | |||
528 | spin_lock_irqsave(&rfkill->lock, flags); | ||
529 | prev = !!(rfkill->state & RFKILL_BLOCK_SW); | ||
530 | __rfkill_set_sw_state(rfkill, blocked); | ||
531 | hwblock = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
532 | blocked = blocked || hwblock; | ||
533 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
534 | |||
535 | if (!rfkill->registered) | ||
536 | return blocked; | ||
537 | |||
538 | if (prev != blocked && !hwblock) | ||
539 | schedule_work(&rfkill->uevent_work); | ||
540 | |||
541 | rfkill_led_trigger_event(rfkill); | ||
542 | |||
543 | return blocked; | ||
544 | } | ||
545 | EXPORT_SYMBOL(rfkill_set_sw_state); | ||
546 | |||
547 | void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) | ||
548 | { | ||
549 | unsigned long flags; | ||
550 | bool swprev, hwprev; | ||
551 | |||
552 | BUG_ON(!rfkill); | ||
553 | |||
554 | spin_lock_irqsave(&rfkill->lock, flags); | ||
555 | |||
556 | /* | ||
557 | * No need to care about prev/setblock ... this is for uevent only | ||
558 | * and that will get triggered by rfkill_set_block anyway. | ||
559 | */ | ||
560 | swprev = !!(rfkill->state & RFKILL_BLOCK_SW); | ||
561 | hwprev = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
562 | __rfkill_set_sw_state(rfkill, sw); | ||
563 | |||
564 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
565 | |||
566 | if (!rfkill->registered) | ||
567 | return; | ||
568 | |||
569 | if (swprev != sw || hwprev != hw) | ||
570 | schedule_work(&rfkill->uevent_work); | ||
571 | |||
572 | rfkill_led_trigger_event(rfkill); | ||
573 | } | ||
574 | EXPORT_SYMBOL(rfkill_set_states); | ||
575 | |||
576 | static ssize_t rfkill_name_show(struct device *dev, | ||
577 | struct device_attribute *attr, | ||
578 | char *buf) | ||
579 | { | ||
580 | struct rfkill *rfkill = to_rfkill(dev); | ||
581 | |||
582 | return sprintf(buf, "%s\n", rfkill->name); | ||
583 | } | ||
584 | |||
585 | static const char *rfkill_get_type_str(enum rfkill_type type) | ||
586 | { | ||
587 | switch (type) { | ||
588 | case RFKILL_TYPE_WLAN: | ||
589 | return "wlan"; | ||
590 | case RFKILL_TYPE_BLUETOOTH: | ||
591 | return "bluetooth"; | ||
592 | case RFKILL_TYPE_UWB: | ||
593 | return "ultrawideband"; | ||
594 | case RFKILL_TYPE_WIMAX: | ||
595 | return "wimax"; | ||
596 | case RFKILL_TYPE_WWAN: | ||
597 | return "wwan"; | ||
598 | default: | ||
599 | BUG(); | ||
600 | } | ||
601 | |||
602 | BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1); | ||
603 | } | ||
604 | |||
605 | static ssize_t rfkill_type_show(struct device *dev, | ||
606 | struct device_attribute *attr, | ||
607 | char *buf) | ||
608 | { | ||
609 | struct rfkill *rfkill = to_rfkill(dev); | ||
610 | |||
611 | return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); | ||
612 | } | ||
613 | |||
614 | static ssize_t rfkill_idx_show(struct device *dev, | ||
615 | struct device_attribute *attr, | ||
616 | char *buf) | ||
617 | { | ||
618 | struct rfkill *rfkill = to_rfkill(dev); | ||
619 | |||
620 | return sprintf(buf, "%d\n", rfkill->idx); | ||
621 | } | ||
622 | |||
623 | static u8 user_state_from_blocked(unsigned long state) | ||
624 | { | ||
625 | if (state & RFKILL_BLOCK_HW) | ||
626 | return RFKILL_USER_STATE_HARD_BLOCKED; | ||
627 | if (state & RFKILL_BLOCK_SW) | ||
628 | return RFKILL_USER_STATE_SOFT_BLOCKED; | ||
629 | |||
630 | return RFKILL_USER_STATE_UNBLOCKED; | ||
631 | } | ||
632 | |||
633 | static ssize_t rfkill_state_show(struct device *dev, | ||
634 | struct device_attribute *attr, | ||
635 | char *buf) | ||
636 | { | ||
637 | struct rfkill *rfkill = to_rfkill(dev); | ||
638 | unsigned long flags; | ||
639 | u32 state; | ||
640 | |||
641 | spin_lock_irqsave(&rfkill->lock, flags); | ||
642 | state = rfkill->state; | ||
643 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
644 | |||
645 | return sprintf(buf, "%d\n", user_state_from_blocked(state)); | ||
646 | } | ||
647 | |||
648 | static ssize_t rfkill_state_store(struct device *dev, | ||
649 | struct device_attribute *attr, | ||
650 | const char *buf, size_t count) | ||
651 | { | ||
652 | /* | ||
653 | * The intention was that userspace can only take control over | ||
654 | * a given device when/if rfkill-input doesn't control it due | ||
655 | * to user_claim. Since user_claim is currently unsupported, | ||
656 | * we never support changing the state from userspace -- this | ||
657 | * can be implemented again later. | ||
658 | */ | ||
659 | |||
660 | return -EPERM; | ||
661 | } | ||
662 | |||
663 | static ssize_t rfkill_claim_show(struct device *dev, | ||
664 | struct device_attribute *attr, | ||
665 | char *buf) | ||
666 | { | ||
667 | return sprintf(buf, "%d\n", 0); | ||
668 | } | ||
669 | |||
670 | static ssize_t rfkill_claim_store(struct device *dev, | ||
671 | struct device_attribute *attr, | ||
672 | const char *buf, size_t count) | ||
673 | { | ||
674 | return -EOPNOTSUPP; | ||
675 | } | ||
676 | |||
677 | static struct device_attribute rfkill_dev_attrs[] = { | ||
678 | __ATTR(name, S_IRUGO, rfkill_name_show, NULL), | ||
679 | __ATTR(type, S_IRUGO, rfkill_type_show, NULL), | ||
680 | __ATTR(index, S_IRUGO, rfkill_idx_show, NULL), | ||
681 | __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), | ||
682 | __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), | ||
683 | __ATTR_NULL | ||
684 | }; | ||
685 | |||
686 | static void rfkill_release(struct device *dev) | ||
687 | { | ||
688 | struct rfkill *rfkill = to_rfkill(dev); | ||
689 | |||
690 | kfree(rfkill); | ||
691 | } | ||
692 | |||
693 | static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
694 | { | ||
695 | struct rfkill *rfkill = to_rfkill(dev); | ||
696 | unsigned long flags; | ||
697 | u32 state; | ||
698 | int error; | ||
699 | |||
700 | error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); | ||
701 | if (error) | ||
702 | return error; | ||
703 | error = add_uevent_var(env, "RFKILL_TYPE=%s", | ||
704 | rfkill_get_type_str(rfkill->type)); | ||
705 | if (error) | ||
706 | return error; | ||
707 | spin_lock_irqsave(&rfkill->lock, flags); | ||
708 | state = rfkill->state; | ||
709 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
710 | error = add_uevent_var(env, "RFKILL_STATE=%d", | ||
711 | user_state_from_blocked(state)); | ||
712 | return error; | ||
713 | } | ||
714 | |||
715 | void rfkill_pause_polling(struct rfkill *rfkill) | ||
716 | { | ||
717 | BUG_ON(!rfkill); | ||
718 | |||
719 | if (!rfkill->ops->poll) | ||
720 | return; | ||
721 | |||
722 | cancel_delayed_work_sync(&rfkill->poll_work); | ||
723 | } | ||
724 | EXPORT_SYMBOL(rfkill_pause_polling); | ||
725 | |||
726 | void rfkill_resume_polling(struct rfkill *rfkill) | ||
727 | { | ||
728 | BUG_ON(!rfkill); | ||
729 | |||
730 | if (!rfkill->ops->poll) | ||
731 | return; | ||
732 | |||
733 | schedule_work(&rfkill->poll_work.work); | ||
734 | } | ||
735 | EXPORT_SYMBOL(rfkill_resume_polling); | ||
736 | |||
737 | static int rfkill_suspend(struct device *dev, pm_message_t state) | ||
738 | { | ||
739 | struct rfkill *rfkill = to_rfkill(dev); | ||
740 | |||
741 | rfkill_pause_polling(rfkill); | ||
742 | |||
743 | rfkill->suspended = true; | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int rfkill_resume(struct device *dev) | ||
749 | { | ||
750 | struct rfkill *rfkill = to_rfkill(dev); | ||
751 | bool cur; | ||
752 | |||
753 | mutex_lock(&rfkill_global_mutex); | ||
754 | cur = rfkill_global_states[rfkill->type].cur; | ||
755 | rfkill_set_block(rfkill, cur); | ||
756 | mutex_unlock(&rfkill_global_mutex); | ||
757 | |||
758 | rfkill->suspended = false; | ||
759 | |||
760 | schedule_work(&rfkill->uevent_work); | ||
761 | |||
762 | rfkill_resume_polling(rfkill); | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | static struct class rfkill_class = { | ||
768 | .name = "rfkill", | ||
769 | .dev_release = rfkill_release, | ||
770 | .dev_attrs = rfkill_dev_attrs, | ||
771 | .dev_uevent = rfkill_dev_uevent, | ||
772 | .suspend = rfkill_suspend, | ||
773 | .resume = rfkill_resume, | ||
774 | }; | ||
775 | |||
776 | bool rfkill_blocked(struct rfkill *rfkill) | ||
777 | { | ||
778 | unsigned long flags; | ||
779 | u32 state; | ||
780 | |||
781 | spin_lock_irqsave(&rfkill->lock, flags); | ||
782 | state = rfkill->state; | ||
783 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
784 | |||
785 | return !!(state & RFKILL_BLOCK_ANY); | ||
786 | } | ||
787 | EXPORT_SYMBOL(rfkill_blocked); | ||
788 | |||
789 | |||
790 | struct rfkill * __must_check rfkill_alloc(const char *name, | ||
791 | struct device *parent, | ||
792 | const enum rfkill_type type, | ||
793 | const struct rfkill_ops *ops, | ||
794 | void *ops_data) | ||
795 | { | ||
796 | struct rfkill *rfkill; | ||
797 | struct device *dev; | ||
798 | |||
799 | if (WARN_ON(!ops)) | ||
800 | return NULL; | ||
801 | |||
802 | if (WARN_ON(!ops->set_block)) | ||
803 | return NULL; | ||
804 | |||
805 | if (WARN_ON(!name)) | ||
806 | return NULL; | ||
807 | |||
808 | if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES)) | ||
809 | return NULL; | ||
810 | |||
811 | rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); | ||
812 | if (!rfkill) | ||
813 | return NULL; | ||
814 | |||
815 | spin_lock_init(&rfkill->lock); | ||
816 | INIT_LIST_HEAD(&rfkill->node); | ||
817 | rfkill->type = type; | ||
818 | rfkill->name = name; | ||
819 | rfkill->ops = ops; | ||
820 | rfkill->data = ops_data; | ||
821 | |||
822 | dev = &rfkill->dev; | ||
823 | dev->class = &rfkill_class; | ||
824 | dev->parent = parent; | ||
825 | device_initialize(dev); | ||
826 | |||
827 | return rfkill; | ||
828 | } | ||
829 | EXPORT_SYMBOL(rfkill_alloc); | ||
830 | |||
831 | static void rfkill_poll(struct work_struct *work) | ||
832 | { | ||
833 | struct rfkill *rfkill; | ||
834 | |||
835 | rfkill = container_of(work, struct rfkill, poll_work.work); | ||
836 | |||
837 | /* | ||
838 | * Poll hardware state -- driver will use one of the | ||
839 | * rfkill_set{,_hw,_sw}_state functions and use its | ||
840 | * return value to update the current status. | ||
841 | */ | ||
842 | rfkill->ops->poll(rfkill, rfkill->data); | ||
843 | |||
844 | schedule_delayed_work(&rfkill->poll_work, | ||
845 | round_jiffies_relative(POLL_INTERVAL)); | ||
846 | } | ||
847 | |||
848 | static void rfkill_uevent_work(struct work_struct *work) | ||
849 | { | ||
850 | struct rfkill *rfkill; | ||
851 | |||
852 | rfkill = container_of(work, struct rfkill, uevent_work); | ||
853 | |||
854 | mutex_lock(&rfkill_global_mutex); | ||
855 | rfkill_event(rfkill); | ||
856 | mutex_unlock(&rfkill_global_mutex); | ||
857 | } | ||
858 | |||
859 | static void rfkill_sync_work(struct work_struct *work) | ||
860 | { | ||
861 | struct rfkill *rfkill; | ||
862 | bool cur; | ||
863 | |||
864 | rfkill = container_of(work, struct rfkill, sync_work); | ||
865 | |||
866 | mutex_lock(&rfkill_global_mutex); | ||
867 | cur = rfkill_global_states[rfkill->type].cur; | ||
868 | rfkill_set_block(rfkill, cur); | ||
869 | mutex_unlock(&rfkill_global_mutex); | ||
870 | } | ||
871 | |||
872 | int __must_check rfkill_register(struct rfkill *rfkill) | ||
873 | { | ||
874 | static unsigned long rfkill_no; | ||
875 | struct device *dev = &rfkill->dev; | ||
876 | int error; | ||
877 | |||
878 | BUG_ON(!rfkill); | ||
879 | |||
880 | mutex_lock(&rfkill_global_mutex); | ||
881 | |||
882 | if (rfkill->registered) { | ||
883 | error = -EALREADY; | ||
884 | goto unlock; | ||
885 | } | ||
886 | |||
887 | rfkill->idx = rfkill_no; | ||
888 | dev_set_name(dev, "rfkill%lu", rfkill_no); | ||
889 | rfkill_no++; | ||
890 | |||
891 | if (!(rfkill_states_default_locked & BIT(rfkill->type))) { | ||
892 | /* first of its kind */ | ||
893 | BUILD_BUG_ON(NUM_RFKILL_TYPES > | ||
894 | sizeof(rfkill_states_default_locked) * 8); | ||
895 | rfkill_states_default_locked |= BIT(rfkill->type); | ||
896 | rfkill_global_states[rfkill->type].cur = | ||
897 | rfkill_global_states[rfkill->type].def; | ||
898 | } | ||
899 | |||
900 | list_add_tail(&rfkill->node, &rfkill_list); | ||
901 | |||
902 | error = device_add(dev); | ||
903 | if (error) | ||
904 | goto remove; | ||
905 | |||
906 | error = rfkill_led_trigger_register(rfkill); | ||
907 | if (error) | ||
908 | goto devdel; | ||
909 | |||
910 | rfkill->registered = true; | ||
911 | |||
912 | INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); | ||
913 | INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); | ||
914 | INIT_WORK(&rfkill->sync_work, rfkill_sync_work); | ||
915 | |||
916 | if (rfkill->ops->poll) | ||
917 | schedule_delayed_work(&rfkill->poll_work, | ||
918 | round_jiffies_relative(POLL_INTERVAL)); | ||
919 | schedule_work(&rfkill->sync_work); | ||
920 | |||
921 | rfkill_send_events(rfkill, RFKILL_OP_ADD); | ||
922 | |||
923 | mutex_unlock(&rfkill_global_mutex); | ||
924 | return 0; | ||
925 | |||
926 | devdel: | ||
927 | device_del(&rfkill->dev); | ||
928 | remove: | ||
929 | list_del_init(&rfkill->node); | ||
930 | unlock: | ||
931 | mutex_unlock(&rfkill_global_mutex); | ||
932 | return error; | ||
933 | } | ||
934 | EXPORT_SYMBOL(rfkill_register); | ||
935 | |||
936 | void rfkill_unregister(struct rfkill *rfkill) | ||
937 | { | ||
938 | BUG_ON(!rfkill); | ||
939 | |||
940 | if (rfkill->ops->poll) | ||
941 | cancel_delayed_work_sync(&rfkill->poll_work); | ||
942 | |||
943 | cancel_work_sync(&rfkill->uevent_work); | ||
944 | cancel_work_sync(&rfkill->sync_work); | ||
945 | |||
946 | rfkill->registered = false; | ||
947 | |||
948 | device_del(&rfkill->dev); | ||
949 | |||
950 | mutex_lock(&rfkill_global_mutex); | ||
951 | rfkill_send_events(rfkill, RFKILL_OP_DEL); | ||
952 | list_del_init(&rfkill->node); | ||
953 | mutex_unlock(&rfkill_global_mutex); | ||
954 | |||
955 | rfkill_led_trigger_unregister(rfkill); | ||
956 | } | ||
957 | EXPORT_SYMBOL(rfkill_unregister); | ||
958 | |||
959 | void rfkill_destroy(struct rfkill *rfkill) | ||
960 | { | ||
961 | if (rfkill) | ||
962 | put_device(&rfkill->dev); | ||
963 | } | ||
964 | EXPORT_SYMBOL(rfkill_destroy); | ||
965 | |||
966 | static int rfkill_fop_open(struct inode *inode, struct file *file) | ||
967 | { | ||
968 | struct rfkill_data *data; | ||
969 | struct rfkill *rfkill; | ||
970 | struct rfkill_int_event *ev, *tmp; | ||
971 | |||
972 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
973 | if (!data) | ||
974 | return -ENOMEM; | ||
975 | |||
976 | INIT_LIST_HEAD(&data->events); | ||
977 | mutex_init(&data->mtx); | ||
978 | init_waitqueue_head(&data->read_wait); | ||
979 | |||
980 | mutex_lock(&rfkill_global_mutex); | ||
981 | mutex_lock(&data->mtx); | ||
982 | /* | ||
983 | * start getting events from elsewhere but hold mtx to get | ||
984 | * startup events added first | ||
985 | */ | ||
986 | list_add(&data->list, &rfkill_fds); | ||
987 | |||
988 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
989 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
990 | if (!ev) | ||
991 | goto free; | ||
992 | rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); | ||
993 | list_add_tail(&ev->list, &data->events); | ||
994 | } | ||
995 | mutex_unlock(&data->mtx); | ||
996 | mutex_unlock(&rfkill_global_mutex); | ||
997 | |||
998 | file->private_data = data; | ||
999 | |||
1000 | return nonseekable_open(inode, file); | ||
1001 | |||
1002 | free: | ||
1003 | mutex_unlock(&data->mtx); | ||
1004 | mutex_unlock(&rfkill_global_mutex); | ||
1005 | mutex_destroy(&data->mtx); | ||
1006 | list_for_each_entry_safe(ev, tmp, &data->events, list) | ||
1007 | kfree(ev); | ||
1008 | kfree(data); | ||
1009 | return -ENOMEM; | ||
1010 | } | ||
1011 | |||
1012 | static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) | ||
1013 | { | ||
1014 | struct rfkill_data *data = file->private_data; | ||
1015 | unsigned int res = POLLOUT | POLLWRNORM; | ||
1016 | |||
1017 | poll_wait(file, &data->read_wait, wait); | ||
1018 | |||
1019 | mutex_lock(&data->mtx); | ||
1020 | if (!list_empty(&data->events)) | ||
1021 | res = POLLIN | POLLRDNORM; | ||
1022 | mutex_unlock(&data->mtx); | ||
1023 | |||
1024 | return res; | ||
1025 | } | ||
1026 | |||
1027 | static bool rfkill_readable(struct rfkill_data *data) | ||
1028 | { | ||
1029 | bool r; | ||
1030 | |||
1031 | mutex_lock(&data->mtx); | ||
1032 | r = !list_empty(&data->events); | ||
1033 | mutex_unlock(&data->mtx); | ||
1034 | |||
1035 | return r; | ||
1036 | } | ||
1037 | |||
1038 | static ssize_t rfkill_fop_read(struct file *file, char __user *buf, | ||
1039 | size_t count, loff_t *pos) | ||
1040 | { | ||
1041 | struct rfkill_data *data = file->private_data; | ||
1042 | struct rfkill_int_event *ev; | ||
1043 | unsigned long sz; | ||
1044 | int ret; | ||
1045 | |||
1046 | mutex_lock(&data->mtx); | ||
1047 | |||
1048 | while (list_empty(&data->events)) { | ||
1049 | if (file->f_flags & O_NONBLOCK) { | ||
1050 | ret = -EAGAIN; | ||
1051 | goto out; | ||
1052 | } | ||
1053 | mutex_unlock(&data->mtx); | ||
1054 | ret = wait_event_interruptible(data->read_wait, | ||
1055 | rfkill_readable(data)); | ||
1056 | mutex_lock(&data->mtx); | ||
1057 | |||
1058 | if (ret) | ||
1059 | goto out; | ||
1060 | } | ||
1061 | |||
1062 | ev = list_first_entry(&data->events, struct rfkill_int_event, | ||
1063 | list); | ||
1064 | |||
1065 | sz = min_t(unsigned long, sizeof(ev->ev), count); | ||
1066 | ret = sz; | ||
1067 | if (copy_to_user(buf, &ev->ev, sz)) | ||
1068 | ret = -EFAULT; | ||
1069 | |||
1070 | list_del(&ev->list); | ||
1071 | kfree(ev); | ||
1072 | out: | ||
1073 | mutex_unlock(&data->mtx); | ||
1074 | return ret; | ||
1075 | } | ||
1076 | |||
1077 | static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, | ||
1078 | size_t count, loff_t *pos) | ||
1079 | { | ||
1080 | struct rfkill *rfkill; | ||
1081 | struct rfkill_event ev; | ||
1082 | |||
1083 | /* we don't need the 'hard' variable but accept it */ | ||
1084 | if (count < sizeof(ev) - 1) | ||
1085 | return -EINVAL; | ||
1086 | |||
1087 | if (copy_from_user(&ev, buf, sizeof(ev) - 1)) | ||
1088 | return -EFAULT; | ||
1089 | |||
1090 | if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL) | ||
1091 | return -EINVAL; | ||
1092 | |||
1093 | if (ev.type >= NUM_RFKILL_TYPES) | ||
1094 | return -EINVAL; | ||
1095 | |||
1096 | mutex_lock(&rfkill_global_mutex); | ||
1097 | |||
1098 | if (ev.op == RFKILL_OP_CHANGE_ALL) { | ||
1099 | if (ev.type == RFKILL_TYPE_ALL) { | ||
1100 | enum rfkill_type i; | ||
1101 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
1102 | rfkill_global_states[i].cur = ev.soft; | ||
1103 | } else { | ||
1104 | rfkill_global_states[ev.type].cur = ev.soft; | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
1109 | if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL) | ||
1110 | continue; | ||
1111 | |||
1112 | if (rfkill->type != ev.type && ev.type != RFKILL_TYPE_ALL) | ||
1113 | continue; | ||
1114 | |||
1115 | rfkill_set_block(rfkill, ev.soft); | ||
1116 | } | ||
1117 | mutex_unlock(&rfkill_global_mutex); | ||
1118 | |||
1119 | return count; | ||
1120 | } | ||
1121 | |||
1122 | static int rfkill_fop_release(struct inode *inode, struct file *file) | ||
1123 | { | ||
1124 | struct rfkill_data *data = file->private_data; | ||
1125 | struct rfkill_int_event *ev, *tmp; | ||
1126 | |||
1127 | mutex_lock(&rfkill_global_mutex); | ||
1128 | list_del(&data->list); | ||
1129 | mutex_unlock(&rfkill_global_mutex); | ||
1130 | |||
1131 | mutex_destroy(&data->mtx); | ||
1132 | list_for_each_entry_safe(ev, tmp, &data->events, list) | ||
1133 | kfree(ev); | ||
1134 | |||
1135 | #ifdef CONFIG_RFKILL_INPUT | ||
1136 | if (data->input_handler) | ||
1137 | atomic_dec(&rfkill_input_disabled); | ||
1138 | #endif | ||
1139 | |||
1140 | kfree(data); | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | #ifdef CONFIG_RFKILL_INPUT | ||
1146 | static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, | ||
1147 | unsigned long arg) | ||
1148 | { | ||
1149 | struct rfkill_data *data = file->private_data; | ||
1150 | |||
1151 | if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC) | ||
1152 | return -ENOSYS; | ||
1153 | |||
1154 | if (_IOC_NR(cmd) != RFKILL_IOC_NOINPUT) | ||
1155 | return -ENOSYS; | ||
1156 | |||
1157 | mutex_lock(&data->mtx); | ||
1158 | |||
1159 | if (!data->input_handler) { | ||
1160 | atomic_inc(&rfkill_input_disabled); | ||
1161 | data->input_handler = true; | ||
1162 | } | ||
1163 | |||
1164 | mutex_unlock(&data->mtx); | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | #endif | ||
1169 | |||
1170 | static const struct file_operations rfkill_fops = { | ||
1171 | .open = rfkill_fop_open, | ||
1172 | .read = rfkill_fop_read, | ||
1173 | .write = rfkill_fop_write, | ||
1174 | .poll = rfkill_fop_poll, | ||
1175 | .release = rfkill_fop_release, | ||
1176 | #ifdef CONFIG_RFKILL_INPUT | ||
1177 | .unlocked_ioctl = rfkill_fop_ioctl, | ||
1178 | .compat_ioctl = rfkill_fop_ioctl, | ||
1179 | #endif | ||
1180 | }; | ||
1181 | |||
1182 | static struct miscdevice rfkill_miscdev = { | ||
1183 | .name = "rfkill", | ||
1184 | .fops = &rfkill_fops, | ||
1185 | .minor = MISC_DYNAMIC_MINOR, | ||
1186 | }; | ||
1187 | |||
1188 | static int __init rfkill_init(void) | ||
1189 | { | ||
1190 | int error; | ||
1191 | int i; | ||
1192 | |||
1193 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
1194 | rfkill_global_states[i].def = !rfkill_default_state; | ||
1195 | |||
1196 | error = class_register(&rfkill_class); | ||
1197 | if (error) | ||
1198 | goto out; | ||
1199 | |||
1200 | error = misc_register(&rfkill_miscdev); | ||
1201 | if (error) { | ||
1202 | class_unregister(&rfkill_class); | ||
1203 | goto out; | ||
1204 | } | ||
1205 | |||
1206 | #ifdef CONFIG_RFKILL_INPUT | ||
1207 | error = rfkill_handler_init(); | ||
1208 | if (error) { | ||
1209 | misc_deregister(&rfkill_miscdev); | ||
1210 | class_unregister(&rfkill_class); | ||
1211 | goto out; | ||
1212 | } | ||
1213 | #endif | ||
1214 | |||
1215 | out: | ||
1216 | return error; | ||
1217 | } | ||
1218 | subsys_initcall(rfkill_init); | ||
1219 | |||
1220 | static void __exit rfkill_exit(void) | ||
1221 | { | ||
1222 | #ifdef CONFIG_RFKILL_INPUT | ||
1223 | rfkill_handler_exit(); | ||
1224 | #endif | ||
1225 | misc_deregister(&rfkill_miscdev); | ||
1226 | class_unregister(&rfkill_class); | ||
1227 | } | ||
1228 | module_exit(rfkill_exit); | ||
diff --git a/net/rfkill/input.c b/net/rfkill/input.c new file mode 100644 index 000000000000..a7295ad5f9cb --- /dev/null +++ b/net/rfkill/input.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * Input layer to RF Kill interface connector | ||
3 | * | ||
4 | * Copyright (c) 2007 Dmitry Torokhov | ||
5 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | * | ||
11 | * If you ever run into a situation in which you have a SW_ type rfkill | ||
12 | * input device, then you can revive code that was removed in the patch | ||
13 | * "rfkill-input: remove unused code". | ||
14 | */ | ||
15 | |||
16 | #include <linux/input.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/workqueue.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/rfkill.h> | ||
21 | #include <linux/sched.h> | ||
22 | |||
23 | #include "rfkill.h" | ||
24 | |||
25 | enum rfkill_input_master_mode { | ||
26 | RFKILL_INPUT_MASTER_UNLOCK = 0, | ||
27 | RFKILL_INPUT_MASTER_RESTORE = 1, | ||
28 | RFKILL_INPUT_MASTER_UNBLOCKALL = 2, | ||
29 | NUM_RFKILL_INPUT_MASTER_MODES | ||
30 | }; | ||
31 | |||
32 | /* Delay (in ms) between consecutive switch ops */ | ||
33 | #define RFKILL_OPS_DELAY 200 | ||
34 | |||
35 | static enum rfkill_input_master_mode rfkill_master_switch_mode = | ||
36 | RFKILL_INPUT_MASTER_UNBLOCKALL; | ||
37 | module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); | ||
38 | MODULE_PARM_DESC(master_switch_mode, | ||
39 | "SW_RFKILL_ALL ON should: 0=do nothing (only unlock); 1=restore; 2=unblock all"); | ||
40 | |||
41 | static spinlock_t rfkill_op_lock; | ||
42 | static bool rfkill_op_pending; | ||
43 | static unsigned long rfkill_sw_pending[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; | ||
44 | static unsigned long rfkill_sw_state[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; | ||
45 | |||
46 | enum rfkill_sched_op { | ||
47 | RFKILL_GLOBAL_OP_EPO = 0, | ||
48 | RFKILL_GLOBAL_OP_RESTORE, | ||
49 | RFKILL_GLOBAL_OP_UNLOCK, | ||
50 | RFKILL_GLOBAL_OP_UNBLOCK, | ||
51 | }; | ||
52 | |||
53 | static enum rfkill_sched_op rfkill_master_switch_op; | ||
54 | static enum rfkill_sched_op rfkill_op; | ||
55 | |||
56 | static void __rfkill_handle_global_op(enum rfkill_sched_op op) | ||
57 | { | ||
58 | unsigned int i; | ||
59 | |||
60 | switch (op) { | ||
61 | case RFKILL_GLOBAL_OP_EPO: | ||
62 | rfkill_epo(); | ||
63 | break; | ||
64 | case RFKILL_GLOBAL_OP_RESTORE: | ||
65 | rfkill_restore_states(); | ||
66 | break; | ||
67 | case RFKILL_GLOBAL_OP_UNLOCK: | ||
68 | rfkill_remove_epo_lock(); | ||
69 | break; | ||
70 | case RFKILL_GLOBAL_OP_UNBLOCK: | ||
71 | rfkill_remove_epo_lock(); | ||
72 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
73 | rfkill_switch_all(i, false); | ||
74 | break; | ||
75 | default: | ||
76 | /* memory corruption or bug, fail safely */ | ||
77 | rfkill_epo(); | ||
78 | WARN(1, "Unknown requested operation %d! " | ||
79 | "rfkill Emergency Power Off activated\n", | ||
80 | op); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static void __rfkill_handle_normal_op(const enum rfkill_type type, | ||
85 | const bool complement) | ||
86 | { | ||
87 | bool blocked; | ||
88 | |||
89 | blocked = rfkill_get_global_sw_state(type); | ||
90 | if (complement) | ||
91 | blocked = !blocked; | ||
92 | |||
93 | rfkill_switch_all(type, blocked); | ||
94 | } | ||
95 | |||
96 | static void rfkill_op_handler(struct work_struct *work) | ||
97 | { | ||
98 | unsigned int i; | ||
99 | bool c; | ||
100 | |||
101 | spin_lock_irq(&rfkill_op_lock); | ||
102 | do { | ||
103 | if (rfkill_op_pending) { | ||
104 | enum rfkill_sched_op op = rfkill_op; | ||
105 | rfkill_op_pending = false; | ||
106 | memset(rfkill_sw_pending, 0, | ||
107 | sizeof(rfkill_sw_pending)); | ||
108 | spin_unlock_irq(&rfkill_op_lock); | ||
109 | |||
110 | __rfkill_handle_global_op(op); | ||
111 | |||
112 | spin_lock_irq(&rfkill_op_lock); | ||
113 | |||
114 | /* | ||
115 | * handle global ops first -- during unlocked period | ||
116 | * we might have gotten a new global op. | ||
117 | */ | ||
118 | if (rfkill_op_pending) | ||
119 | continue; | ||
120 | } | ||
121 | |||
122 | if (rfkill_is_epo_lock_active()) | ||
123 | continue; | ||
124 | |||
125 | for (i = 0; i < NUM_RFKILL_TYPES; i++) { | ||
126 | if (__test_and_clear_bit(i, rfkill_sw_pending)) { | ||
127 | c = __test_and_clear_bit(i, rfkill_sw_state); | ||
128 | spin_unlock_irq(&rfkill_op_lock); | ||
129 | |||
130 | __rfkill_handle_normal_op(i, c); | ||
131 | |||
132 | spin_lock_irq(&rfkill_op_lock); | ||
133 | } | ||
134 | } | ||
135 | } while (rfkill_op_pending); | ||
136 | spin_unlock_irq(&rfkill_op_lock); | ||
137 | } | ||
138 | |||
139 | static DECLARE_DELAYED_WORK(rfkill_op_work, rfkill_op_handler); | ||
140 | static unsigned long rfkill_last_scheduled; | ||
141 | |||
142 | static unsigned long rfkill_ratelimit(const unsigned long last) | ||
143 | { | ||
144 | const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); | ||
145 | return (time_after(jiffies, last + delay)) ? 0 : delay; | ||
146 | } | ||
147 | |||
148 | static void rfkill_schedule_ratelimited(void) | ||
149 | { | ||
150 | if (delayed_work_pending(&rfkill_op_work)) | ||
151 | return; | ||
152 | schedule_delayed_work(&rfkill_op_work, | ||
153 | rfkill_ratelimit(rfkill_last_scheduled)); | ||
154 | rfkill_last_scheduled = jiffies; | ||
155 | } | ||
156 | |||
157 | static void rfkill_schedule_global_op(enum rfkill_sched_op op) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | |||
161 | spin_lock_irqsave(&rfkill_op_lock, flags); | ||
162 | rfkill_op = op; | ||
163 | rfkill_op_pending = true; | ||
164 | if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { | ||
165 | /* bypass the limiter for EPO */ | ||
166 | cancel_delayed_work(&rfkill_op_work); | ||
167 | schedule_delayed_work(&rfkill_op_work, 0); | ||
168 | rfkill_last_scheduled = jiffies; | ||
169 | } else | ||
170 | rfkill_schedule_ratelimited(); | ||
171 | spin_unlock_irqrestore(&rfkill_op_lock, flags); | ||
172 | } | ||
173 | |||
174 | static void rfkill_schedule_toggle(enum rfkill_type type) | ||
175 | { | ||
176 | unsigned long flags; | ||
177 | |||
178 | if (rfkill_is_epo_lock_active()) | ||
179 | return; | ||
180 | |||
181 | spin_lock_irqsave(&rfkill_op_lock, flags); | ||
182 | if (!rfkill_op_pending) { | ||
183 | __set_bit(type, rfkill_sw_pending); | ||
184 | __change_bit(type, rfkill_sw_state); | ||
185 | rfkill_schedule_ratelimited(); | ||
186 | } | ||
187 | spin_unlock_irqrestore(&rfkill_op_lock, flags); | ||
188 | } | ||
189 | |||
190 | static void rfkill_schedule_evsw_rfkillall(int state) | ||
191 | { | ||
192 | if (state) | ||
193 | rfkill_schedule_global_op(rfkill_master_switch_op); | ||
194 | else | ||
195 | rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); | ||
196 | } | ||
197 | |||
198 | static void rfkill_event(struct input_handle *handle, unsigned int type, | ||
199 | unsigned int code, int data) | ||
200 | { | ||
201 | if (type == EV_KEY && data == 1) { | ||
202 | switch (code) { | ||
203 | case KEY_WLAN: | ||
204 | rfkill_schedule_toggle(RFKILL_TYPE_WLAN); | ||
205 | break; | ||
206 | case KEY_BLUETOOTH: | ||
207 | rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH); | ||
208 | break; | ||
209 | case KEY_UWB: | ||
210 | rfkill_schedule_toggle(RFKILL_TYPE_UWB); | ||
211 | break; | ||
212 | case KEY_WIMAX: | ||
213 | rfkill_schedule_toggle(RFKILL_TYPE_WIMAX); | ||
214 | break; | ||
215 | } | ||
216 | } else if (type == EV_SW && code == SW_RFKILL_ALL) | ||
217 | rfkill_schedule_evsw_rfkillall(data); | ||
218 | } | ||
219 | |||
220 | static int rfkill_connect(struct input_handler *handler, struct input_dev *dev, | ||
221 | const struct input_device_id *id) | ||
222 | { | ||
223 | struct input_handle *handle; | ||
224 | int error; | ||
225 | |||
226 | handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); | ||
227 | if (!handle) | ||
228 | return -ENOMEM; | ||
229 | |||
230 | handle->dev = dev; | ||
231 | handle->handler = handler; | ||
232 | handle->name = "rfkill"; | ||
233 | |||
234 | /* causes rfkill_start() to be called */ | ||
235 | error = input_register_handle(handle); | ||
236 | if (error) | ||
237 | goto err_free_handle; | ||
238 | |||
239 | error = input_open_device(handle); | ||
240 | if (error) | ||
241 | goto err_unregister_handle; | ||
242 | |||
243 | return 0; | ||
244 | |||
245 | err_unregister_handle: | ||
246 | input_unregister_handle(handle); | ||
247 | err_free_handle: | ||
248 | kfree(handle); | ||
249 | return error; | ||
250 | } | ||
251 | |||
252 | static void rfkill_start(struct input_handle *handle) | ||
253 | { | ||
254 | /* | ||
255 | * Take event_lock to guard against configuration changes, we | ||
256 | * should be able to deal with concurrency with rfkill_event() | ||
257 | * just fine (which event_lock will also avoid). | ||
258 | */ | ||
259 | spin_lock_irq(&handle->dev->event_lock); | ||
260 | |||
261 | if (test_bit(EV_SW, handle->dev->evbit) && | ||
262 | test_bit(SW_RFKILL_ALL, handle->dev->swbit)) | ||
263 | rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, | ||
264 | handle->dev->sw)); | ||
265 | |||
266 | spin_unlock_irq(&handle->dev->event_lock); | ||
267 | } | ||
268 | |||
269 | static void rfkill_disconnect(struct input_handle *handle) | ||
270 | { | ||
271 | input_close_device(handle); | ||
272 | input_unregister_handle(handle); | ||
273 | kfree(handle); | ||
274 | } | ||
275 | |||
276 | static const struct input_device_id rfkill_ids[] = { | ||
277 | { | ||
278 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
279 | .evbit = { BIT_MASK(EV_KEY) }, | ||
280 | .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, | ||
281 | }, | ||
282 | { | ||
283 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
284 | .evbit = { BIT_MASK(EV_KEY) }, | ||
285 | .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, | ||
286 | }, | ||
287 | { | ||
288 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
289 | .evbit = { BIT_MASK(EV_KEY) }, | ||
290 | .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, | ||
291 | }, | ||
292 | { | ||
293 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
294 | .evbit = { BIT_MASK(EV_KEY) }, | ||
295 | .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, | ||
296 | }, | ||
297 | { | ||
298 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, | ||
299 | .evbit = { BIT(EV_SW) }, | ||
300 | .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, | ||
301 | }, | ||
302 | { } | ||
303 | }; | ||
304 | |||
305 | static struct input_handler rfkill_handler = { | ||
306 | .name = "rfkill", | ||
307 | .event = rfkill_event, | ||
308 | .connect = rfkill_connect, | ||
309 | .start = rfkill_start, | ||
310 | .disconnect = rfkill_disconnect, | ||
311 | .id_table = rfkill_ids, | ||
312 | }; | ||
313 | |||
314 | int __init rfkill_handler_init(void) | ||
315 | { | ||
316 | switch (rfkill_master_switch_mode) { | ||
317 | case RFKILL_INPUT_MASTER_UNBLOCKALL: | ||
318 | rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNBLOCK; | ||
319 | break; | ||
320 | case RFKILL_INPUT_MASTER_RESTORE: | ||
321 | rfkill_master_switch_op = RFKILL_GLOBAL_OP_RESTORE; | ||
322 | break; | ||
323 | case RFKILL_INPUT_MASTER_UNLOCK: | ||
324 | rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNLOCK; | ||
325 | break; | ||
326 | default: | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | spin_lock_init(&rfkill_op_lock); | ||
331 | |||
332 | /* Avoid delay at first schedule */ | ||
333 | rfkill_last_scheduled = | ||
334 | jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; | ||
335 | return input_register_handler(&rfkill_handler); | ||
336 | } | ||
337 | |||
338 | void __exit rfkill_handler_exit(void) | ||
339 | { | ||
340 | input_unregister_handler(&rfkill_handler); | ||
341 | cancel_delayed_work_sync(&rfkill_op_work); | ||
342 | } | ||
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c deleted file mode 100644 index 60a34f3b5f65..000000000000 --- a/net/rfkill/rfkill-input.c +++ /dev/null | |||
@@ -1,390 +0,0 @@ | |||
1 | /* | ||
2 | * Input layer to RF Kill interface connector | ||
3 | * | ||
4 | * Copyright (c) 2007 Dmitry Torokhov | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published | ||
10 | * by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/input.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/workqueue.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/rfkill.h> | ||
19 | #include <linux/sched.h> | ||
20 | |||
21 | #include "rfkill-input.h" | ||
22 | |||
23 | MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | ||
24 | MODULE_DESCRIPTION("Input layer to RF switch connector"); | ||
25 | MODULE_LICENSE("GPL"); | ||
26 | |||
27 | enum rfkill_input_master_mode { | ||
28 | RFKILL_INPUT_MASTER_DONOTHING = 0, | ||
29 | RFKILL_INPUT_MASTER_RESTORE = 1, | ||
30 | RFKILL_INPUT_MASTER_UNBLOCKALL = 2, | ||
31 | RFKILL_INPUT_MASTER_MAX, /* marker */ | ||
32 | }; | ||
33 | |||
34 | /* Delay (in ms) between consecutive switch ops */ | ||
35 | #define RFKILL_OPS_DELAY 200 | ||
36 | |||
37 | static enum rfkill_input_master_mode rfkill_master_switch_mode = | ||
38 | RFKILL_INPUT_MASTER_UNBLOCKALL; | ||
39 | module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); | ||
40 | MODULE_PARM_DESC(master_switch_mode, | ||
41 | "SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all"); | ||
42 | |||
43 | enum rfkill_global_sched_op { | ||
44 | RFKILL_GLOBAL_OP_EPO = 0, | ||
45 | RFKILL_GLOBAL_OP_RESTORE, | ||
46 | RFKILL_GLOBAL_OP_UNLOCK, | ||
47 | RFKILL_GLOBAL_OP_UNBLOCK, | ||
48 | }; | ||
49 | |||
50 | struct rfkill_task { | ||
51 | struct delayed_work dwork; | ||
52 | |||
53 | /* ensures that task is serialized */ | ||
54 | struct mutex mutex; | ||
55 | |||
56 | /* protects everything below */ | ||
57 | spinlock_t lock; | ||
58 | |||
59 | /* pending regular switch operations (1=pending) */ | ||
60 | unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | ||
61 | |||
62 | /* should the state be complemented (1=yes) */ | ||
63 | unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | ||
64 | |||
65 | bool global_op_pending; | ||
66 | enum rfkill_global_sched_op op; | ||
67 | |||
68 | /* last time it was scheduled */ | ||
69 | unsigned long last_scheduled; | ||
70 | }; | ||
71 | |||
72 | static void __rfkill_handle_global_op(enum rfkill_global_sched_op op) | ||
73 | { | ||
74 | unsigned int i; | ||
75 | |||
76 | switch (op) { | ||
77 | case RFKILL_GLOBAL_OP_EPO: | ||
78 | rfkill_epo(); | ||
79 | break; | ||
80 | case RFKILL_GLOBAL_OP_RESTORE: | ||
81 | rfkill_restore_states(); | ||
82 | break; | ||
83 | case RFKILL_GLOBAL_OP_UNLOCK: | ||
84 | rfkill_remove_epo_lock(); | ||
85 | break; | ||
86 | case RFKILL_GLOBAL_OP_UNBLOCK: | ||
87 | rfkill_remove_epo_lock(); | ||
88 | for (i = 0; i < RFKILL_TYPE_MAX; i++) | ||
89 | rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED); | ||
90 | break; | ||
91 | default: | ||
92 | /* memory corruption or bug, fail safely */ | ||
93 | rfkill_epo(); | ||
94 | WARN(1, "Unknown requested operation %d! " | ||
95 | "rfkill Emergency Power Off activated\n", | ||
96 | op); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static void __rfkill_handle_normal_op(const enum rfkill_type type, | ||
101 | const bool c) | ||
102 | { | ||
103 | enum rfkill_state state; | ||
104 | |||
105 | state = rfkill_get_global_state(type); | ||
106 | if (c) | ||
107 | state = rfkill_state_complement(state); | ||
108 | |||
109 | rfkill_switch_all(type, state); | ||
110 | } | ||
111 | |||
112 | static void rfkill_task_handler(struct work_struct *work) | ||
113 | { | ||
114 | struct rfkill_task *task = container_of(work, | ||
115 | struct rfkill_task, dwork.work); | ||
116 | bool doit = true; | ||
117 | |||
118 | mutex_lock(&task->mutex); | ||
119 | |||
120 | spin_lock_irq(&task->lock); | ||
121 | while (doit) { | ||
122 | if (task->global_op_pending) { | ||
123 | enum rfkill_global_sched_op op = task->op; | ||
124 | task->global_op_pending = false; | ||
125 | memset(task->sw_pending, 0, sizeof(task->sw_pending)); | ||
126 | spin_unlock_irq(&task->lock); | ||
127 | |||
128 | __rfkill_handle_global_op(op); | ||
129 | |||
130 | /* make sure we do at least one pass with | ||
131 | * !task->global_op_pending */ | ||
132 | spin_lock_irq(&task->lock); | ||
133 | continue; | ||
134 | } else if (!rfkill_is_epo_lock_active()) { | ||
135 | unsigned int i = 0; | ||
136 | |||
137 | while (!task->global_op_pending && | ||
138 | i < RFKILL_TYPE_MAX) { | ||
139 | if (test_and_clear_bit(i, task->sw_pending)) { | ||
140 | bool c; | ||
141 | c = test_and_clear_bit(i, | ||
142 | task->sw_togglestate); | ||
143 | spin_unlock_irq(&task->lock); | ||
144 | |||
145 | __rfkill_handle_normal_op(i, c); | ||
146 | |||
147 | spin_lock_irq(&task->lock); | ||
148 | } | ||
149 | i++; | ||
150 | } | ||
151 | } | ||
152 | doit = task->global_op_pending; | ||
153 | } | ||
154 | spin_unlock_irq(&task->lock); | ||
155 | |||
156 | mutex_unlock(&task->mutex); | ||
157 | } | ||
158 | |||
159 | static struct rfkill_task rfkill_task = { | ||
160 | .dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork, | ||
161 | rfkill_task_handler), | ||
162 | .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex), | ||
163 | .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock), | ||
164 | }; | ||
165 | |||
166 | static unsigned long rfkill_ratelimit(const unsigned long last) | ||
167 | { | ||
168 | const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); | ||
169 | return (time_after(jiffies, last + delay)) ? 0 : delay; | ||
170 | } | ||
171 | |||
172 | static void rfkill_schedule_ratelimited(void) | ||
173 | { | ||
174 | if (!delayed_work_pending(&rfkill_task.dwork)) { | ||
175 | schedule_delayed_work(&rfkill_task.dwork, | ||
176 | rfkill_ratelimit(rfkill_task.last_scheduled)); | ||
177 | rfkill_task.last_scheduled = jiffies; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static void rfkill_schedule_global_op(enum rfkill_global_sched_op op) | ||
182 | { | ||
183 | unsigned long flags; | ||
184 | |||
185 | spin_lock_irqsave(&rfkill_task.lock, flags); | ||
186 | rfkill_task.op = op; | ||
187 | rfkill_task.global_op_pending = true; | ||
188 | if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { | ||
189 | /* bypass the limiter for EPO */ | ||
190 | cancel_delayed_work(&rfkill_task.dwork); | ||
191 | schedule_delayed_work(&rfkill_task.dwork, 0); | ||
192 | rfkill_task.last_scheduled = jiffies; | ||
193 | } else | ||
194 | rfkill_schedule_ratelimited(); | ||
195 | spin_unlock_irqrestore(&rfkill_task.lock, flags); | ||
196 | } | ||
197 | |||
198 | static void rfkill_schedule_toggle(enum rfkill_type type) | ||
199 | { | ||
200 | unsigned long flags; | ||
201 | |||
202 | if (rfkill_is_epo_lock_active()) | ||
203 | return; | ||
204 | |||
205 | spin_lock_irqsave(&rfkill_task.lock, flags); | ||
206 | if (!rfkill_task.global_op_pending) { | ||
207 | set_bit(type, rfkill_task.sw_pending); | ||
208 | change_bit(type, rfkill_task.sw_togglestate); | ||
209 | rfkill_schedule_ratelimited(); | ||
210 | } | ||
211 | spin_unlock_irqrestore(&rfkill_task.lock, flags); | ||
212 | } | ||
213 | |||
214 | static void rfkill_schedule_evsw_rfkillall(int state) | ||
215 | { | ||
216 | if (state) { | ||
217 | switch (rfkill_master_switch_mode) { | ||
218 | case RFKILL_INPUT_MASTER_UNBLOCKALL: | ||
219 | rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK); | ||
220 | break; | ||
221 | case RFKILL_INPUT_MASTER_RESTORE: | ||
222 | rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE); | ||
223 | break; | ||
224 | case RFKILL_INPUT_MASTER_DONOTHING: | ||
225 | rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK); | ||
226 | break; | ||
227 | default: | ||
228 | /* memory corruption or driver bug! fail safely */ | ||
229 | rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); | ||
230 | WARN(1, "Unknown rfkill_master_switch_mode (%d), " | ||
231 | "driver bug or memory corruption detected!\n", | ||
232 | rfkill_master_switch_mode); | ||
233 | break; | ||
234 | } | ||
235 | } else | ||
236 | rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); | ||
237 | } | ||
238 | |||
239 | static void rfkill_event(struct input_handle *handle, unsigned int type, | ||
240 | unsigned int code, int data) | ||
241 | { | ||
242 | if (type == EV_KEY && data == 1) { | ||
243 | enum rfkill_type t; | ||
244 | |||
245 | switch (code) { | ||
246 | case KEY_WLAN: | ||
247 | t = RFKILL_TYPE_WLAN; | ||
248 | break; | ||
249 | case KEY_BLUETOOTH: | ||
250 | t = RFKILL_TYPE_BLUETOOTH; | ||
251 | break; | ||
252 | case KEY_UWB: | ||
253 | t = RFKILL_TYPE_UWB; | ||
254 | break; | ||
255 | case KEY_WIMAX: | ||
256 | t = RFKILL_TYPE_WIMAX; | ||
257 | break; | ||
258 | default: | ||
259 | return; | ||
260 | } | ||
261 | rfkill_schedule_toggle(t); | ||
262 | return; | ||
263 | } else if (type == EV_SW) { | ||
264 | switch (code) { | ||
265 | case SW_RFKILL_ALL: | ||
266 | rfkill_schedule_evsw_rfkillall(data); | ||
267 | return; | ||
268 | default: | ||
269 | return; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static int rfkill_connect(struct input_handler *handler, struct input_dev *dev, | ||
275 | const struct input_device_id *id) | ||
276 | { | ||
277 | struct input_handle *handle; | ||
278 | int error; | ||
279 | |||
280 | handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); | ||
281 | if (!handle) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | handle->dev = dev; | ||
285 | handle->handler = handler; | ||
286 | handle->name = "rfkill"; | ||
287 | |||
288 | /* causes rfkill_start() to be called */ | ||
289 | error = input_register_handle(handle); | ||
290 | if (error) | ||
291 | goto err_free_handle; | ||
292 | |||
293 | error = input_open_device(handle); | ||
294 | if (error) | ||
295 | goto err_unregister_handle; | ||
296 | |||
297 | return 0; | ||
298 | |||
299 | err_unregister_handle: | ||
300 | input_unregister_handle(handle); | ||
301 | err_free_handle: | ||
302 | kfree(handle); | ||
303 | return error; | ||
304 | } | ||
305 | |||
306 | static void rfkill_start(struct input_handle *handle) | ||
307 | { | ||
308 | /* Take event_lock to guard against configuration changes, we | ||
309 | * should be able to deal with concurrency with rfkill_event() | ||
310 | * just fine (which event_lock will also avoid). */ | ||
311 | spin_lock_irq(&handle->dev->event_lock); | ||
312 | |||
313 | if (test_bit(EV_SW, handle->dev->evbit)) { | ||
314 | if (test_bit(SW_RFKILL_ALL, handle->dev->swbit)) | ||
315 | rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, | ||
316 | handle->dev->sw)); | ||
317 | /* add resync for further EV_SW events here */ | ||
318 | } | ||
319 | |||
320 | spin_unlock_irq(&handle->dev->event_lock); | ||
321 | } | ||
322 | |||
323 | static void rfkill_disconnect(struct input_handle *handle) | ||
324 | { | ||
325 | input_close_device(handle); | ||
326 | input_unregister_handle(handle); | ||
327 | kfree(handle); | ||
328 | } | ||
329 | |||
330 | static const struct input_device_id rfkill_ids[] = { | ||
331 | { | ||
332 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
333 | .evbit = { BIT_MASK(EV_KEY) }, | ||
334 | .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, | ||
335 | }, | ||
336 | { | ||
337 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
338 | .evbit = { BIT_MASK(EV_KEY) }, | ||
339 | .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, | ||
340 | }, | ||
341 | { | ||
342 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
343 | .evbit = { BIT_MASK(EV_KEY) }, | ||
344 | .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, | ||
345 | }, | ||
346 | { | ||
347 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
348 | .evbit = { BIT_MASK(EV_KEY) }, | ||
349 | .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, | ||
350 | }, | ||
351 | { | ||
352 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, | ||
353 | .evbit = { BIT(EV_SW) }, | ||
354 | .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, | ||
355 | }, | ||
356 | { } | ||
357 | }; | ||
358 | |||
359 | static struct input_handler rfkill_handler = { | ||
360 | .event = rfkill_event, | ||
361 | .connect = rfkill_connect, | ||
362 | .disconnect = rfkill_disconnect, | ||
363 | .start = rfkill_start, | ||
364 | .name = "rfkill", | ||
365 | .id_table = rfkill_ids, | ||
366 | }; | ||
367 | |||
368 | static int __init rfkill_handler_init(void) | ||
369 | { | ||
370 | if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX) | ||
371 | return -EINVAL; | ||
372 | |||
373 | /* | ||
374 | * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay | ||
375 | * at the first use. Acceptable, but if we can avoid it, why not? | ||
376 | */ | ||
377 | rfkill_task.last_scheduled = | ||
378 | jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; | ||
379 | return input_register_handler(&rfkill_handler); | ||
380 | } | ||
381 | |||
382 | static void __exit rfkill_handler_exit(void) | ||
383 | { | ||
384 | input_unregister_handler(&rfkill_handler); | ||
385 | cancel_delayed_work_sync(&rfkill_task.dwork); | ||
386 | rfkill_remove_epo_lock(); | ||
387 | } | ||
388 | |||
389 | module_init(rfkill_handler_init); | ||
390 | module_exit(rfkill_handler_exit); | ||
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c deleted file mode 100644 index 4f5a83183c95..000000000000 --- a/net/rfkill/rfkill.c +++ /dev/null | |||
@@ -1,855 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 - 2007 Ivo van Doorn | ||
3 | * Copyright (C) 2007 Dmitry Torokhov | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/capability.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/rfkill.h> | ||
29 | |||
30 | /* Get declaration of rfkill_switch_all() to shut up sparse. */ | ||
31 | #include "rfkill-input.h" | ||
32 | |||
33 | |||
34 | MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>"); | ||
35 | MODULE_VERSION("1.0"); | ||
36 | MODULE_DESCRIPTION("RF switch support"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | ||
40 | static DEFINE_MUTEX(rfkill_global_mutex); | ||
41 | |||
42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; | ||
43 | module_param_named(default_state, rfkill_default_state, uint, 0444); | ||
44 | MODULE_PARM_DESC(default_state, | ||
45 | "Default initial state for all radio types, 0 = radio off"); | ||
46 | |||
47 | struct rfkill_gsw_state { | ||
48 | enum rfkill_state current_state; | ||
49 | enum rfkill_state default_state; | ||
50 | }; | ||
51 | |||
52 | static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX]; | ||
53 | static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | ||
54 | static bool rfkill_epo_lock_active; | ||
55 | |||
56 | |||
57 | #ifdef CONFIG_RFKILL_LEDS | ||
58 | static void rfkill_led_trigger(struct rfkill *rfkill, | ||
59 | enum rfkill_state state) | ||
60 | { | ||
61 | struct led_trigger *led = &rfkill->led_trigger; | ||
62 | |||
63 | if (!led->name) | ||
64 | return; | ||
65 | if (state != RFKILL_STATE_UNBLOCKED) | ||
66 | led_trigger_event(led, LED_OFF); | ||
67 | else | ||
68 | led_trigger_event(led, LED_FULL); | ||
69 | } | ||
70 | |||
71 | static void rfkill_led_trigger_activate(struct led_classdev *led) | ||
72 | { | ||
73 | struct rfkill *rfkill = container_of(led->trigger, | ||
74 | struct rfkill, led_trigger); | ||
75 | |||
76 | rfkill_led_trigger(rfkill, rfkill->state); | ||
77 | } | ||
78 | #else | ||
79 | static inline void rfkill_led_trigger(struct rfkill *rfkill, | ||
80 | enum rfkill_state state) | ||
81 | { | ||
82 | } | ||
83 | #endif /* CONFIG_RFKILL_LEDS */ | ||
84 | |||
85 | static void rfkill_uevent(struct rfkill *rfkill) | ||
86 | { | ||
87 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); | ||
88 | } | ||
89 | |||
90 | static void update_rfkill_state(struct rfkill *rfkill) | ||
91 | { | ||
92 | enum rfkill_state newstate, oldstate; | ||
93 | |||
94 | if (rfkill->get_state) { | ||
95 | mutex_lock(&rfkill->mutex); | ||
96 | if (!rfkill->get_state(rfkill->data, &newstate)) { | ||
97 | oldstate = rfkill->state; | ||
98 | rfkill->state = newstate; | ||
99 | if (oldstate != newstate) | ||
100 | rfkill_uevent(rfkill); | ||
101 | } | ||
102 | mutex_unlock(&rfkill->mutex); | ||
103 | } | ||
104 | rfkill_led_trigger(rfkill, rfkill->state); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * rfkill_toggle_radio - wrapper for toggle_radio hook | ||
109 | * @rfkill: the rfkill struct to use | ||
110 | * @force: calls toggle_radio even if cache says it is not needed, | ||
111 | * and also makes sure notifications of the state will be | ||
112 | * sent even if it didn't change | ||
113 | * @state: the new state to call toggle_radio() with | ||
114 | * | ||
115 | * Calls rfkill->toggle_radio, enforcing the API for toggle_radio | ||
116 | * calls and handling all the red tape such as issuing notifications | ||
117 | * if the call is successful. | ||
118 | * | ||
119 | * Suspended devices are not touched at all, and -EAGAIN is returned. | ||
120 | * | ||
121 | * Note that the @force parameter cannot override a (possibly cached) | ||
122 | * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of | ||
123 | * RFKILL_STATE_HARD_BLOCKED implements either get_state() or | ||
124 | * rfkill_force_state(), so the cache either is bypassed or valid. | ||
125 | * | ||
126 | * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED | ||
127 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to | ||
128 | * give the driver a hint that it should double-BLOCK the transmitter. | ||
129 | * | ||
130 | * Caller must have acquired rfkill->mutex. | ||
131 | */ | ||
132 | static int rfkill_toggle_radio(struct rfkill *rfkill, | ||
133 | enum rfkill_state state, | ||
134 | int force) | ||
135 | { | ||
136 | int retval = 0; | ||
137 | enum rfkill_state oldstate, newstate; | ||
138 | |||
139 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | ||
140 | return -EBUSY; | ||
141 | |||
142 | oldstate = rfkill->state; | ||
143 | |||
144 | if (rfkill->get_state && !force && | ||
145 | !rfkill->get_state(rfkill->data, &newstate)) { | ||
146 | rfkill->state = newstate; | ||
147 | } | ||
148 | |||
149 | switch (state) { | ||
150 | case RFKILL_STATE_HARD_BLOCKED: | ||
151 | /* typically happens when refreshing hardware state, | ||
152 | * such as on resume */ | ||
153 | state = RFKILL_STATE_SOFT_BLOCKED; | ||
154 | break; | ||
155 | case RFKILL_STATE_UNBLOCKED: | ||
156 | /* force can't override this, only rfkill_force_state() can */ | ||
157 | if (rfkill->state == RFKILL_STATE_HARD_BLOCKED) | ||
158 | return -EPERM; | ||
159 | break; | ||
160 | case RFKILL_STATE_SOFT_BLOCKED: | ||
161 | /* nothing to do, we want to give drivers the hint to double | ||
162 | * BLOCK even a transmitter that is already in state | ||
163 | * RFKILL_STATE_HARD_BLOCKED */ | ||
164 | break; | ||
165 | default: | ||
166 | WARN(1, KERN_WARNING | ||
167 | "rfkill: illegal state %d passed as parameter " | ||
168 | "to rfkill_toggle_radio\n", state); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | if (force || state != rfkill->state) { | ||
173 | retval = rfkill->toggle_radio(rfkill->data, state); | ||
174 | /* never allow a HARD->SOFT downgrade! */ | ||
175 | if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED) | ||
176 | rfkill->state = state; | ||
177 | } | ||
178 | |||
179 | if (force || rfkill->state != oldstate) | ||
180 | rfkill_uevent(rfkill); | ||
181 | |||
182 | rfkill_led_trigger(rfkill, rfkill->state); | ||
183 | return retval; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * __rfkill_switch_all - Toggle state of all switches of given type | ||
188 | * @type: type of interfaces to be affected | ||
189 | * @state: the new state | ||
190 | * | ||
191 | * This function toggles the state of all switches of given type, | ||
192 | * unless a specific switch is claimed by userspace (in which case, | ||
193 | * that switch is left alone) or suspended. | ||
194 | * | ||
195 | * Caller must have acquired rfkill_global_mutex. | ||
196 | */ | ||
197 | static void __rfkill_switch_all(const enum rfkill_type type, | ||
198 | const enum rfkill_state state) | ||
199 | { | ||
200 | struct rfkill *rfkill; | ||
201 | |||
202 | if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), | ||
203 | KERN_WARNING | ||
204 | "rfkill: illegal state %d or type %d " | ||
205 | "passed as parameter to __rfkill_switch_all\n", | ||
206 | state, type)) | ||
207 | return; | ||
208 | |||
209 | rfkill_global_states[type].current_state = state; | ||
210 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
211 | if (rfkill->type == type) { | ||
212 | mutex_lock(&rfkill->mutex); | ||
213 | rfkill_toggle_radio(rfkill, state, 0); | ||
214 | mutex_unlock(&rfkill->mutex); | ||
215 | rfkill_led_trigger(rfkill, rfkill->state); | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * rfkill_switch_all - Toggle state of all switches of given type | ||
222 | * @type: type of interfaces to be affected | ||
223 | * @state: the new state | ||
224 | * | ||
225 | * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). | ||
226 | * Please refer to __rfkill_switch_all() for details. | ||
227 | * | ||
228 | * Does nothing if the EPO lock is active. | ||
229 | */ | ||
230 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | ||
231 | { | ||
232 | mutex_lock(&rfkill_global_mutex); | ||
233 | if (!rfkill_epo_lock_active) | ||
234 | __rfkill_switch_all(type, state); | ||
235 | mutex_unlock(&rfkill_global_mutex); | ||
236 | } | ||
237 | EXPORT_SYMBOL(rfkill_switch_all); | ||
238 | |||
239 | /** | ||
240 | * rfkill_epo - emergency power off all transmitters | ||
241 | * | ||
242 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, | ||
243 | * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. | ||
244 | * | ||
245 | * The global state before the EPO is saved and can be restored later | ||
246 | * using rfkill_restore_states(). | ||
247 | */ | ||
248 | void rfkill_epo(void) | ||
249 | { | ||
250 | struct rfkill *rfkill; | ||
251 | int i; | ||
252 | |||
253 | mutex_lock(&rfkill_global_mutex); | ||
254 | |||
255 | rfkill_epo_lock_active = true; | ||
256 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
257 | mutex_lock(&rfkill->mutex); | ||
258 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
259 | mutex_unlock(&rfkill->mutex); | ||
260 | } | ||
261 | for (i = 0; i < RFKILL_TYPE_MAX; i++) { | ||
262 | rfkill_global_states[i].default_state = | ||
263 | rfkill_global_states[i].current_state; | ||
264 | rfkill_global_states[i].current_state = | ||
265 | RFKILL_STATE_SOFT_BLOCKED; | ||
266 | } | ||
267 | mutex_unlock(&rfkill_global_mutex); | ||
268 | rfkill_led_trigger(rfkill, rfkill->state); | ||
269 | } | ||
270 | EXPORT_SYMBOL_GPL(rfkill_epo); | ||
271 | |||
272 | /** | ||
273 | * rfkill_restore_states - restore global states | ||
274 | * | ||
275 | * Restore (and sync switches to) the global state from the | ||
276 | * states in rfkill_default_states. This can undo the effects of | ||
277 | * a call to rfkill_epo(). | ||
278 | */ | ||
279 | void rfkill_restore_states(void) | ||
280 | { | ||
281 | int i; | ||
282 | |||
283 | mutex_lock(&rfkill_global_mutex); | ||
284 | |||
285 | rfkill_epo_lock_active = false; | ||
286 | for (i = 0; i < RFKILL_TYPE_MAX; i++) | ||
287 | __rfkill_switch_all(i, rfkill_global_states[i].default_state); | ||
288 | mutex_unlock(&rfkill_global_mutex); | ||
289 | } | ||
290 | EXPORT_SYMBOL_GPL(rfkill_restore_states); | ||
291 | |||
292 | /** | ||
293 | * rfkill_remove_epo_lock - unlock state changes | ||
294 | * | ||
295 | * Used by rfkill-input manually unlock state changes, when | ||
296 | * the EPO switch is deactivated. | ||
297 | */ | ||
298 | void rfkill_remove_epo_lock(void) | ||
299 | { | ||
300 | mutex_lock(&rfkill_global_mutex); | ||
301 | rfkill_epo_lock_active = false; | ||
302 | mutex_unlock(&rfkill_global_mutex); | ||
303 | } | ||
304 | EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock); | ||
305 | |||
306 | /** | ||
307 | * rfkill_is_epo_lock_active - returns true EPO is active | ||
308 | * | ||
309 | * Returns 0 (false) if there is NOT an active EPO contidion, | ||
310 | * and 1 (true) if there is an active EPO contition, which | ||
311 | * locks all radios in one of the BLOCKED states. | ||
312 | * | ||
313 | * Can be called in atomic context. | ||
314 | */ | ||
315 | bool rfkill_is_epo_lock_active(void) | ||
316 | { | ||
317 | return rfkill_epo_lock_active; | ||
318 | } | ||
319 | EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active); | ||
320 | |||
321 | /** | ||
322 | * rfkill_get_global_state - returns global state for a type | ||
323 | * @type: the type to get the global state of | ||
324 | * | ||
325 | * Returns the current global state for a given wireless | ||
326 | * device type. | ||
327 | */ | ||
328 | enum rfkill_state rfkill_get_global_state(const enum rfkill_type type) | ||
329 | { | ||
330 | return rfkill_global_states[type].current_state; | ||
331 | } | ||
332 | EXPORT_SYMBOL_GPL(rfkill_get_global_state); | ||
333 | |||
334 | /** | ||
335 | * rfkill_force_state - Force the internal rfkill radio state | ||
336 | * @rfkill: pointer to the rfkill class to modify. | ||
337 | * @state: the current radio state the class should be forced to. | ||
338 | * | ||
339 | * This function updates the internal state of the radio cached | ||
340 | * by the rfkill class. It should be used when the driver gets | ||
341 | * a notification by the firmware/hardware of the current *real* | ||
342 | * state of the radio rfkill switch. | ||
343 | * | ||
344 | * Devices which are subject to external changes on their rfkill | ||
345 | * state (such as those caused by a hardware rfkill line) MUST | ||
346 | * have their driver arrange to call rfkill_force_state() as soon | ||
347 | * as possible after such a change. | ||
348 | * | ||
349 | * This function may not be called from an atomic context. | ||
350 | */ | ||
351 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | ||
352 | { | ||
353 | enum rfkill_state oldstate; | ||
354 | |||
355 | BUG_ON(!rfkill); | ||
356 | if (WARN((state >= RFKILL_STATE_MAX), | ||
357 | KERN_WARNING | ||
358 | "rfkill: illegal state %d passed as parameter " | ||
359 | "to rfkill_force_state\n", state)) | ||
360 | return -EINVAL; | ||
361 | |||
362 | mutex_lock(&rfkill->mutex); | ||
363 | |||
364 | oldstate = rfkill->state; | ||
365 | rfkill->state = state; | ||
366 | |||
367 | if (state != oldstate) | ||
368 | rfkill_uevent(rfkill); | ||
369 | |||
370 | mutex_unlock(&rfkill->mutex); | ||
371 | rfkill_led_trigger(rfkill, rfkill->state); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | EXPORT_SYMBOL(rfkill_force_state); | ||
376 | |||
377 | static ssize_t rfkill_name_show(struct device *dev, | ||
378 | struct device_attribute *attr, | ||
379 | char *buf) | ||
380 | { | ||
381 | struct rfkill *rfkill = to_rfkill(dev); | ||
382 | |||
383 | return sprintf(buf, "%s\n", rfkill->name); | ||
384 | } | ||
385 | |||
386 | static const char *rfkill_get_type_str(enum rfkill_type type) | ||
387 | { | ||
388 | switch (type) { | ||
389 | case RFKILL_TYPE_WLAN: | ||
390 | return "wlan"; | ||
391 | case RFKILL_TYPE_BLUETOOTH: | ||
392 | return "bluetooth"; | ||
393 | case RFKILL_TYPE_UWB: | ||
394 | return "ultrawideband"; | ||
395 | case RFKILL_TYPE_WIMAX: | ||
396 | return "wimax"; | ||
397 | case RFKILL_TYPE_WWAN: | ||
398 | return "wwan"; | ||
399 | default: | ||
400 | BUG(); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | static ssize_t rfkill_type_show(struct device *dev, | ||
405 | struct device_attribute *attr, | ||
406 | char *buf) | ||
407 | { | ||
408 | struct rfkill *rfkill = to_rfkill(dev); | ||
409 | |||
410 | return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); | ||
411 | } | ||
412 | |||
413 | static ssize_t rfkill_state_show(struct device *dev, | ||
414 | struct device_attribute *attr, | ||
415 | char *buf) | ||
416 | { | ||
417 | struct rfkill *rfkill = to_rfkill(dev); | ||
418 | |||
419 | update_rfkill_state(rfkill); | ||
420 | return sprintf(buf, "%d\n", rfkill->state); | ||
421 | } | ||
422 | |||
423 | static ssize_t rfkill_state_store(struct device *dev, | ||
424 | struct device_attribute *attr, | ||
425 | const char *buf, size_t count) | ||
426 | { | ||
427 | struct rfkill *rfkill = to_rfkill(dev); | ||
428 | unsigned long state; | ||
429 | int error; | ||
430 | |||
431 | if (!capable(CAP_NET_ADMIN)) | ||
432 | return -EPERM; | ||
433 | |||
434 | error = strict_strtoul(buf, 0, &state); | ||
435 | if (error) | ||
436 | return error; | ||
437 | |||
438 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ | ||
439 | if (state != RFKILL_STATE_UNBLOCKED && | ||
440 | state != RFKILL_STATE_SOFT_BLOCKED) | ||
441 | return -EINVAL; | ||
442 | |||
443 | error = mutex_lock_killable(&rfkill->mutex); | ||
444 | if (error) | ||
445 | return error; | ||
446 | |||
447 | if (!rfkill_epo_lock_active) | ||
448 | error = rfkill_toggle_radio(rfkill, state, 0); | ||
449 | else | ||
450 | error = -EPERM; | ||
451 | |||
452 | mutex_unlock(&rfkill->mutex); | ||
453 | |||
454 | return error ? error : count; | ||
455 | } | ||
456 | |||
457 | static ssize_t rfkill_claim_show(struct device *dev, | ||
458 | struct device_attribute *attr, | ||
459 | char *buf) | ||
460 | { | ||
461 | return sprintf(buf, "%d\n", 0); | ||
462 | } | ||
463 | |||
464 | static ssize_t rfkill_claim_store(struct device *dev, | ||
465 | struct device_attribute *attr, | ||
466 | const char *buf, size_t count) | ||
467 | { | ||
468 | return -EOPNOTSUPP; | ||
469 | } | ||
470 | |||
471 | static struct device_attribute rfkill_dev_attrs[] = { | ||
472 | __ATTR(name, S_IRUGO, rfkill_name_show, NULL), | ||
473 | __ATTR(type, S_IRUGO, rfkill_type_show, NULL), | ||
474 | __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), | ||
475 | __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), | ||
476 | __ATTR_NULL | ||
477 | }; | ||
478 | |||
479 | static void rfkill_release(struct device *dev) | ||
480 | { | ||
481 | struct rfkill *rfkill = to_rfkill(dev); | ||
482 | |||
483 | kfree(rfkill); | ||
484 | module_put(THIS_MODULE); | ||
485 | } | ||
486 | |||
487 | #ifdef CONFIG_PM | ||
488 | static int rfkill_suspend(struct device *dev, pm_message_t state) | ||
489 | { | ||
490 | struct rfkill *rfkill = to_rfkill(dev); | ||
491 | |||
492 | /* mark class device as suspended */ | ||
493 | if (dev->power.power_state.event != state.event) | ||
494 | dev->power.power_state = state; | ||
495 | |||
496 | /* store state for the resume handler */ | ||
497 | rfkill->state_for_resume = rfkill->state; | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int rfkill_resume(struct device *dev) | ||
503 | { | ||
504 | struct rfkill *rfkill = to_rfkill(dev); | ||
505 | enum rfkill_state newstate; | ||
506 | |||
507 | if (dev->power.power_state.event != PM_EVENT_ON) { | ||
508 | mutex_lock(&rfkill->mutex); | ||
509 | |||
510 | dev->power.power_state.event = PM_EVENT_ON; | ||
511 | |||
512 | /* | ||
513 | * rfkill->state could have been modified before we got | ||
514 | * called, and won't be updated by rfkill_toggle_radio() | ||
515 | * in force mode. Sync it FIRST. | ||
516 | */ | ||
517 | if (rfkill->get_state && | ||
518 | !rfkill->get_state(rfkill->data, &newstate)) | ||
519 | rfkill->state = newstate; | ||
520 | |||
521 | /* | ||
522 | * If we are under EPO, kick transmitter offline, | ||
523 | * otherwise restore to pre-suspend state. | ||
524 | * | ||
525 | * Issue a notification in any case | ||
526 | */ | ||
527 | rfkill_toggle_radio(rfkill, | ||
528 | rfkill_epo_lock_active ? | ||
529 | RFKILL_STATE_SOFT_BLOCKED : | ||
530 | rfkill->state_for_resume, | ||
531 | 1); | ||
532 | |||
533 | mutex_unlock(&rfkill->mutex); | ||
534 | rfkill_led_trigger(rfkill, rfkill->state); | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | #else | ||
540 | #define rfkill_suspend NULL | ||
541 | #define rfkill_resume NULL | ||
542 | #endif | ||
543 | |||
544 | static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
545 | { | ||
546 | struct rfkill *rfkill = to_rfkill(dev); | ||
547 | int error; | ||
548 | |||
549 | error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); | ||
550 | if (error) | ||
551 | return error; | ||
552 | error = add_uevent_var(env, "RFKILL_TYPE=%s", | ||
553 | rfkill_get_type_str(rfkill->type)); | ||
554 | if (error) | ||
555 | return error; | ||
556 | error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state); | ||
557 | return error; | ||
558 | } | ||
559 | |||
560 | static struct class rfkill_class = { | ||
561 | .name = "rfkill", | ||
562 | .dev_release = rfkill_release, | ||
563 | .dev_attrs = rfkill_dev_attrs, | ||
564 | .suspend = rfkill_suspend, | ||
565 | .resume = rfkill_resume, | ||
566 | .dev_uevent = rfkill_dev_uevent, | ||
567 | }; | ||
568 | |||
569 | static int rfkill_check_duplicity(const struct rfkill *rfkill) | ||
570 | { | ||
571 | struct rfkill *p; | ||
572 | unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | ||
573 | |||
574 | memset(seen, 0, sizeof(seen)); | ||
575 | |||
576 | list_for_each_entry(p, &rfkill_list, node) { | ||
577 | if (WARN((p == rfkill), KERN_WARNING | ||
578 | "rfkill: illegal attempt to register " | ||
579 | "an already registered rfkill struct\n")) | ||
580 | return -EEXIST; | ||
581 | set_bit(p->type, seen); | ||
582 | } | ||
583 | |||
584 | /* 0: first switch of its kind */ | ||
585 | return (test_bit(rfkill->type, seen)) ? 1 : 0; | ||
586 | } | ||
587 | |||
588 | static int rfkill_add_switch(struct rfkill *rfkill) | ||
589 | { | ||
590 | int error; | ||
591 | |||
592 | mutex_lock(&rfkill_global_mutex); | ||
593 | |||
594 | error = rfkill_check_duplicity(rfkill); | ||
595 | if (error < 0) | ||
596 | goto unlock_out; | ||
597 | |||
598 | if (!error) { | ||
599 | /* lock default after first use */ | ||
600 | set_bit(rfkill->type, rfkill_states_lockdflt); | ||
601 | rfkill_global_states[rfkill->type].current_state = | ||
602 | rfkill_global_states[rfkill->type].default_state; | ||
603 | } | ||
604 | |||
605 | rfkill_toggle_radio(rfkill, | ||
606 | rfkill_global_states[rfkill->type].current_state, | ||
607 | 0); | ||
608 | |||
609 | list_add_tail(&rfkill->node, &rfkill_list); | ||
610 | |||
611 | error = 0; | ||
612 | unlock_out: | ||
613 | mutex_unlock(&rfkill_global_mutex); | ||
614 | |||
615 | return error; | ||
616 | } | ||
617 | |||
618 | static void rfkill_remove_switch(struct rfkill *rfkill) | ||
619 | { | ||
620 | mutex_lock(&rfkill_global_mutex); | ||
621 | list_del_init(&rfkill->node); | ||
622 | mutex_unlock(&rfkill_global_mutex); | ||
623 | |||
624 | mutex_lock(&rfkill->mutex); | ||
625 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
626 | mutex_unlock(&rfkill->mutex); | ||
627 | } | ||
628 | |||
629 | /** | ||
630 | * rfkill_allocate - allocate memory for rfkill structure. | ||
631 | * @parent: device that has rf switch on it | ||
632 | * @type: type of the switch (RFKILL_TYPE_*) | ||
633 | * | ||
634 | * This function should be called by the network driver when it needs | ||
635 | * rfkill structure. Once the structure is allocated the driver should | ||
636 | * finish its initialization by setting the name, private data, enable_radio | ||
637 | * and disable_radio methods and then register it with rfkill_register(). | ||
638 | * | ||
639 | * NOTE: If registration fails the structure shoudl be freed by calling | ||
640 | * rfkill_free() otherwise rfkill_unregister() should be used. | ||
641 | */ | ||
642 | struct rfkill * __must_check rfkill_allocate(struct device *parent, | ||
643 | enum rfkill_type type) | ||
644 | { | ||
645 | struct rfkill *rfkill; | ||
646 | struct device *dev; | ||
647 | |||
648 | if (WARN((type >= RFKILL_TYPE_MAX), | ||
649 | KERN_WARNING | ||
650 | "rfkill: illegal type %d passed as parameter " | ||
651 | "to rfkill_allocate\n", type)) | ||
652 | return NULL; | ||
653 | |||
654 | rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); | ||
655 | if (!rfkill) | ||
656 | return NULL; | ||
657 | |||
658 | mutex_init(&rfkill->mutex); | ||
659 | INIT_LIST_HEAD(&rfkill->node); | ||
660 | rfkill->type = type; | ||
661 | |||
662 | dev = &rfkill->dev; | ||
663 | dev->class = &rfkill_class; | ||
664 | dev->parent = parent; | ||
665 | device_initialize(dev); | ||
666 | |||
667 | __module_get(THIS_MODULE); | ||
668 | |||
669 | return rfkill; | ||
670 | } | ||
671 | EXPORT_SYMBOL(rfkill_allocate); | ||
672 | |||
673 | /** | ||
674 | * rfkill_free - Mark rfkill structure for deletion | ||
675 | * @rfkill: rfkill structure to be destroyed | ||
676 | * | ||
677 | * Decrements reference count of the rfkill structure so it is destroyed. | ||
678 | * Note that rfkill_free() should _not_ be called after rfkill_unregister(). | ||
679 | */ | ||
680 | void rfkill_free(struct rfkill *rfkill) | ||
681 | { | ||
682 | if (rfkill) | ||
683 | put_device(&rfkill->dev); | ||
684 | } | ||
685 | EXPORT_SYMBOL(rfkill_free); | ||
686 | |||
687 | static void rfkill_led_trigger_register(struct rfkill *rfkill) | ||
688 | { | ||
689 | #ifdef CONFIG_RFKILL_LEDS | ||
690 | int error; | ||
691 | |||
692 | if (!rfkill->led_trigger.name) | ||
693 | rfkill->led_trigger.name = dev_name(&rfkill->dev); | ||
694 | if (!rfkill->led_trigger.activate) | ||
695 | rfkill->led_trigger.activate = rfkill_led_trigger_activate; | ||
696 | error = led_trigger_register(&rfkill->led_trigger); | ||
697 | if (error) | ||
698 | rfkill->led_trigger.name = NULL; | ||
699 | #endif /* CONFIG_RFKILL_LEDS */ | ||
700 | } | ||
701 | |||
702 | static void rfkill_led_trigger_unregister(struct rfkill *rfkill) | ||
703 | { | ||
704 | #ifdef CONFIG_RFKILL_LEDS | ||
705 | if (rfkill->led_trigger.name) { | ||
706 | led_trigger_unregister(&rfkill->led_trigger); | ||
707 | rfkill->led_trigger.name = NULL; | ||
708 | } | ||
709 | #endif | ||
710 | } | ||
711 | |||
712 | /** | ||
713 | * rfkill_register - Register a rfkill structure. | ||
714 | * @rfkill: rfkill structure to be registered | ||
715 | * | ||
716 | * This function should be called by the network driver when the rfkill | ||
717 | * structure needs to be registered. Immediately from registration the | ||
718 | * switch driver should be able to service calls to toggle_radio. | ||
719 | */ | ||
720 | int __must_check rfkill_register(struct rfkill *rfkill) | ||
721 | { | ||
722 | static atomic_t rfkill_no = ATOMIC_INIT(0); | ||
723 | struct device *dev = &rfkill->dev; | ||
724 | int error; | ||
725 | |||
726 | if (WARN((!rfkill || !rfkill->toggle_radio || | ||
727 | rfkill->type >= RFKILL_TYPE_MAX || | ||
728 | rfkill->state >= RFKILL_STATE_MAX), | ||
729 | KERN_WARNING | ||
730 | "rfkill: attempt to register a " | ||
731 | "badly initialized rfkill struct\n")) | ||
732 | return -EINVAL; | ||
733 | |||
734 | dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1); | ||
735 | |||
736 | rfkill_led_trigger_register(rfkill); | ||
737 | |||
738 | error = rfkill_add_switch(rfkill); | ||
739 | if (error) { | ||
740 | rfkill_led_trigger_unregister(rfkill); | ||
741 | return error; | ||
742 | } | ||
743 | |||
744 | error = device_add(dev); | ||
745 | if (error) { | ||
746 | rfkill_remove_switch(rfkill); | ||
747 | rfkill_led_trigger_unregister(rfkill); | ||
748 | return error; | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | EXPORT_SYMBOL(rfkill_register); | ||
754 | |||
755 | /** | ||
756 | * rfkill_unregister - Unregister a rfkill structure. | ||
757 | * @rfkill: rfkill structure to be unregistered | ||
758 | * | ||
759 | * This function should be called by the network driver during device | ||
760 | * teardown to destroy rfkill structure. Note that rfkill_free() should | ||
761 | * _not_ be called after rfkill_unregister(). | ||
762 | */ | ||
763 | void rfkill_unregister(struct rfkill *rfkill) | ||
764 | { | ||
765 | BUG_ON(!rfkill); | ||
766 | device_del(&rfkill->dev); | ||
767 | rfkill_remove_switch(rfkill); | ||
768 | rfkill_led_trigger_unregister(rfkill); | ||
769 | put_device(&rfkill->dev); | ||
770 | } | ||
771 | EXPORT_SYMBOL(rfkill_unregister); | ||
772 | |||
773 | /** | ||
774 | * rfkill_set_default - set initial value for a switch type | ||
775 | * @type - the type of switch to set the default state of | ||
776 | * @state - the new default state for that group of switches | ||
777 | * | ||
778 | * Sets the initial state rfkill should use for a given type. | ||
779 | * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED | ||
780 | * and RFKILL_STATE_UNBLOCKED. | ||
781 | * | ||
782 | * This function is meant to be used by platform drivers for platforms | ||
783 | * that can save switch state across power down/reboot. | ||
784 | * | ||
785 | * The default state for each switch type can be changed exactly once. | ||
786 | * After a switch of that type is registered, the default state cannot | ||
787 | * be changed anymore. This guards against multiple drivers it the | ||
788 | * same platform trying to set the initial switch default state, which | ||
789 | * is not allowed. | ||
790 | * | ||
791 | * Returns -EPERM if the state has already been set once or is in use, | ||
792 | * so drivers likely want to either ignore or at most printk(KERN_NOTICE) | ||
793 | * if this function returns -EPERM. | ||
794 | * | ||
795 | * Returns 0 if the new default state was set, or an error if it | ||
796 | * could not be set. | ||
797 | */ | ||
798 | int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) | ||
799 | { | ||
800 | int error; | ||
801 | |||
802 | if (WARN((type >= RFKILL_TYPE_MAX || | ||
803 | (state != RFKILL_STATE_SOFT_BLOCKED && | ||
804 | state != RFKILL_STATE_UNBLOCKED)), | ||
805 | KERN_WARNING | ||
806 | "rfkill: illegal state %d or type %d passed as " | ||
807 | "parameter to rfkill_set_default\n", state, type)) | ||
808 | return -EINVAL; | ||
809 | |||
810 | mutex_lock(&rfkill_global_mutex); | ||
811 | |||
812 | if (!test_and_set_bit(type, rfkill_states_lockdflt)) { | ||
813 | rfkill_global_states[type].default_state = state; | ||
814 | rfkill_global_states[type].current_state = state; | ||
815 | error = 0; | ||
816 | } else | ||
817 | error = -EPERM; | ||
818 | |||
819 | mutex_unlock(&rfkill_global_mutex); | ||
820 | return error; | ||
821 | } | ||
822 | EXPORT_SYMBOL_GPL(rfkill_set_default); | ||
823 | |||
824 | /* | ||
825 | * Rfkill module initialization/deinitialization. | ||
826 | */ | ||
827 | static int __init rfkill_init(void) | ||
828 | { | ||
829 | int error; | ||
830 | int i; | ||
831 | |||
832 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ | ||
833 | if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED && | ||
834 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) | ||
835 | return -EINVAL; | ||
836 | |||
837 | for (i = 0; i < RFKILL_TYPE_MAX; i++) | ||
838 | rfkill_global_states[i].default_state = rfkill_default_state; | ||
839 | |||
840 | error = class_register(&rfkill_class); | ||
841 | if (error) { | ||
842 | printk(KERN_ERR "rfkill: unable to register rfkill class\n"); | ||
843 | return error; | ||
844 | } | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | static void __exit rfkill_exit(void) | ||
850 | { | ||
851 | class_unregister(&rfkill_class); | ||
852 | } | ||
853 | |||
854 | subsys_initcall(rfkill_init); | ||
855 | module_exit(rfkill_exit); | ||
diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill.h index fe8df6b5b935..d1117cb6e4de 100644 --- a/net/rfkill/rfkill-input.h +++ b/net/rfkill/rfkill.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007 Ivo van Doorn | 2 | * Copyright (C) 2007 Ivo van Doorn |
3 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
3 | */ | 4 | */ |
4 | 5 | ||
5 | /* | 6 | /* |
@@ -11,11 +12,16 @@ | |||
11 | #ifndef __RFKILL_INPUT_H | 12 | #ifndef __RFKILL_INPUT_H |
12 | #define __RFKILL_INPUT_H | 13 | #define __RFKILL_INPUT_H |
13 | 14 | ||
14 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); | 15 | /* core code */ |
16 | void rfkill_switch_all(const enum rfkill_type type, bool blocked); | ||
15 | void rfkill_epo(void); | 17 | void rfkill_epo(void); |
16 | void rfkill_restore_states(void); | 18 | void rfkill_restore_states(void); |
17 | void rfkill_remove_epo_lock(void); | 19 | void rfkill_remove_epo_lock(void); |
18 | bool rfkill_is_epo_lock_active(void); | 20 | bool rfkill_is_epo_lock_active(void); |
19 | enum rfkill_state rfkill_get_global_state(const enum rfkill_type type); | 21 | bool rfkill_get_global_sw_state(const enum rfkill_type type); |
22 | |||
23 | /* input handler */ | ||
24 | int rfkill_handler_init(void); | ||
25 | void rfkill_handler_exit(void); | ||
20 | 26 | ||
21 | #endif /* __RFKILL_INPUT_H */ | 27 | #endif /* __RFKILL_INPUT_H */ |
diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig index 1b46747a5f5a..e4d97ab476d5 100644 --- a/net/wimax/Kconfig +++ b/net/wimax/Kconfig | |||
@@ -1,23 +1,10 @@ | |||
1 | # | 1 | # |
2 | # WiMAX LAN device configuration | 2 | # WiMAX LAN device configuration |
3 | # | 3 | # |
4 | # Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a | ||
5 | # module if WIMAX is to be linked in. The WiMAX code is done in such a | ||
6 | # way that it doesn't require and explicit dependency on RFKILL in | ||
7 | # case an embedded system wants to rip it out. | ||
8 | # | ||
9 | # As well, enablement of the RFKILL code means we need the INPUT layer | ||
10 | # support to inject events coming from hw rfkill switches. That | ||
11 | # dependency could be killed if input.h provided appropriate means to | ||
12 | # work when input is disabled. | ||
13 | |||
14 | comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled" | ||
15 | depends on INPUT = n && RFKILL != n | ||
16 | 4 | ||
17 | menuconfig WIMAX | 5 | menuconfig WIMAX |
18 | tristate "WiMAX Wireless Broadband support" | 6 | tristate "WiMAX Wireless Broadband support" |
19 | depends on (y && RFKILL != m) || m | 7 | depends on RFKILL || !RFKILL |
20 | depends on (INPUT && RFKILL != n) || RFKILL = n | ||
21 | help | 8 | help |
22 | 9 | ||
23 | Select to configure support for devices that provide | 10 | Select to configure support for devices that provide |
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index a3616e2ccb8a..bb102e4aa3e9 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c | |||
@@ -29,8 +29,8 @@ | |||
29 | * A non-polled generic rfkill device is embedded into the WiMAX | 29 | * A non-polled generic rfkill device is embedded into the WiMAX |
30 | * subsystem's representation of a device. | 30 | * subsystem's representation of a device. |
31 | * | 31 | * |
32 | * FIXME: Need polled support? use a timer or add the implementation | 32 | * FIXME: Need polled support? Let drivers provide a poll routine |
33 | * to the stack. | 33 | * and hand it to rfkill ops then? |
34 | * | 34 | * |
35 | * All device drivers have to do is after wimax_dev_init(), call | 35 | * All device drivers have to do is after wimax_dev_init(), call |
36 | * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update | 36 | * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update |
@@ -43,7 +43,7 @@ | |||
43 | * wimax_rfkill() Kernel calling wimax_rfkill() | 43 | * wimax_rfkill() Kernel calling wimax_rfkill() |
44 | * __wimax_rf_toggle_radio() | 44 | * __wimax_rf_toggle_radio() |
45 | * | 45 | * |
46 | * wimax_rfkill_toggle_radio() RF-Kill subsytem calling | 46 | * wimax_rfkill_set_radio_block() RF-Kill subsytem calling |
47 | * __wimax_rf_toggle_radio() | 47 | * __wimax_rf_toggle_radio() |
48 | * | 48 | * |
49 | * __wimax_rf_toggle_radio() | 49 | * __wimax_rf_toggle_radio() |
@@ -65,15 +65,11 @@ | |||
65 | #include <linux/wimax.h> | 65 | #include <linux/wimax.h> |
66 | #include <linux/security.h> | 66 | #include <linux/security.h> |
67 | #include <linux/rfkill.h> | 67 | #include <linux/rfkill.h> |
68 | #include <linux/input.h> | ||
69 | #include "wimax-internal.h" | 68 | #include "wimax-internal.h" |
70 | 69 | ||
71 | #define D_SUBMODULE op_rfkill | 70 | #define D_SUBMODULE op_rfkill |
72 | #include "debug-levels.h" | 71 | #include "debug-levels.h" |
73 | 72 | ||
74 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
75 | |||
76 | |||
77 | /** | 73 | /** |
78 | * wimax_report_rfkill_hw - Reports changes in the hardware RF switch | 74 | * wimax_report_rfkill_hw - Reports changes in the hardware RF switch |
79 | * | 75 | * |
@@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, | |||
99 | int result; | 95 | int result; |
100 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 96 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
101 | enum wimax_st wimax_state; | 97 | enum wimax_st wimax_state; |
102 | enum rfkill_state rfkill_state; | ||
103 | 98 | ||
104 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); | 99 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); |
105 | BUG_ON(state == WIMAX_RF_QUERY); | 100 | BUG_ON(state == WIMAX_RF_QUERY); |
@@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, | |||
112 | 107 | ||
113 | if (state != wimax_dev->rf_hw) { | 108 | if (state != wimax_dev->rf_hw) { |
114 | wimax_dev->rf_hw = state; | 109 | wimax_dev->rf_hw = state; |
115 | rfkill_state = state == WIMAX_RF_ON ? | ||
116 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | ||
117 | if (wimax_dev->rf_hw == WIMAX_RF_ON | 110 | if (wimax_dev->rf_hw == WIMAX_RF_ON |
118 | && wimax_dev->rf_sw == WIMAX_RF_ON) | 111 | && wimax_dev->rf_sw == WIMAX_RF_ON) |
119 | wimax_state = WIMAX_ST_READY; | 112 | wimax_state = WIMAX_ST_READY; |
120 | else | 113 | else |
121 | wimax_state = WIMAX_ST_RADIO_OFF; | 114 | wimax_state = WIMAX_ST_RADIO_OFF; |
115 | |||
116 | rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | ||
117 | |||
122 | __wimax_state_change(wimax_dev, wimax_state); | 118 | __wimax_state_change(wimax_dev, wimax_state); |
123 | input_report_key(wimax_dev->rfkill_input, KEY_WIMAX, | ||
124 | rfkill_state); | ||
125 | } | 119 | } |
126 | error_not_ready: | 120 | error_not_ready: |
127 | mutex_unlock(&wimax_dev->mutex); | 121 | mutex_unlock(&wimax_dev->mutex); |
@@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, | |||
174 | else | 168 | else |
175 | wimax_state = WIMAX_ST_RADIO_OFF; | 169 | wimax_state = WIMAX_ST_RADIO_OFF; |
176 | __wimax_state_change(wimax_dev, wimax_state); | 170 | __wimax_state_change(wimax_dev, wimax_state); |
171 | rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | ||
177 | } | 172 | } |
178 | error_not_ready: | 173 | error_not_ready: |
179 | mutex_unlock(&wimax_dev->mutex); | 174 | mutex_unlock(&wimax_dev->mutex); |
@@ -249,36 +244,31 @@ out_no_change: | |||
249 | * | 244 | * |
250 | * NOTE: This call will block until the operation is completed. | 245 | * NOTE: This call will block until the operation is completed. |
251 | */ | 246 | */ |
252 | static | 247 | static int wimax_rfkill_set_radio_block(void *data, bool blocked) |
253 | int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state) | ||
254 | { | 248 | { |
255 | int result; | 249 | int result; |
256 | struct wimax_dev *wimax_dev = data; | 250 | struct wimax_dev *wimax_dev = data; |
257 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 251 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
258 | enum wimax_rf_state rf_state; | 252 | enum wimax_rf_state rf_state; |
259 | 253 | ||
260 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); | 254 | d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked); |
261 | switch (state) { | 255 | rf_state = WIMAX_RF_ON; |
262 | case RFKILL_STATE_SOFT_BLOCKED: | 256 | if (blocked) |
263 | rf_state = WIMAX_RF_OFF; | 257 | rf_state = WIMAX_RF_OFF; |
264 | break; | ||
265 | case RFKILL_STATE_UNBLOCKED: | ||
266 | rf_state = WIMAX_RF_ON; | ||
267 | break; | ||
268 | default: | ||
269 | BUG(); | ||
270 | } | ||
271 | mutex_lock(&wimax_dev->mutex); | 258 | mutex_lock(&wimax_dev->mutex); |
272 | if (wimax_dev->state <= __WIMAX_ST_QUIESCING) | 259 | if (wimax_dev->state <= __WIMAX_ST_QUIESCING) |
273 | result = 0; /* just pretend it didn't happen */ | 260 | result = 0; |
274 | else | 261 | else |
275 | result = __wimax_rf_toggle_radio(wimax_dev, rf_state); | 262 | result = __wimax_rf_toggle_radio(wimax_dev, rf_state); |
276 | mutex_unlock(&wimax_dev->mutex); | 263 | mutex_unlock(&wimax_dev->mutex); |
277 | d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", | 264 | d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n", |
278 | wimax_dev, state, result); | 265 | wimax_dev, blocked, result); |
279 | return result; | 266 | return result; |
280 | } | 267 | } |
281 | 268 | ||
269 | static const struct rfkill_ops wimax_rfkill_ops = { | ||
270 | .set_block = wimax_rfkill_set_radio_block, | ||
271 | }; | ||
282 | 272 | ||
283 | /** | 273 | /** |
284 | * wimax_rfkill - Set the software RF switch state for a WiMAX device | 274 | * wimax_rfkill - Set the software RF switch state for a WiMAX device |
@@ -322,6 +312,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) | |||
322 | result = __wimax_rf_toggle_radio(wimax_dev, state); | 312 | result = __wimax_rf_toggle_radio(wimax_dev, state); |
323 | if (result < 0) | 313 | if (result < 0) |
324 | goto error; | 314 | goto error; |
315 | rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | ||
325 | break; | 316 | break; |
326 | case WIMAX_RF_QUERY: | 317 | case WIMAX_RF_QUERY: |
327 | break; | 318 | break; |
@@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) | |||
349 | { | 340 | { |
350 | int result; | 341 | int result; |
351 | struct rfkill *rfkill; | 342 | struct rfkill *rfkill; |
352 | struct input_dev *input_dev; | ||
353 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 343 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
354 | 344 | ||
355 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); | 345 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); |
356 | /* Initialize RF Kill */ | 346 | /* Initialize RF Kill */ |
357 | result = -ENOMEM; | 347 | result = -ENOMEM; |
358 | rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX); | 348 | rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX, |
349 | &wimax_rfkill_ops, wimax_dev); | ||
359 | if (rfkill == NULL) | 350 | if (rfkill == NULL) |
360 | goto error_rfkill_allocate; | 351 | goto error_rfkill_allocate; |
352 | |||
353 | d_printf(1, dev, "rfkill %p\n", rfkill); | ||
354 | |||
361 | wimax_dev->rfkill = rfkill; | 355 | wimax_dev->rfkill = rfkill; |
362 | 356 | ||
363 | rfkill->name = wimax_dev->name; | ||
364 | rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
365 | rfkill->data = wimax_dev; | ||
366 | rfkill->toggle_radio = wimax_rfkill_toggle_radio; | ||
367 | |||
368 | /* Initialize the input device for the hw key */ | ||
369 | input_dev = input_allocate_device(); | ||
370 | if (input_dev == NULL) | ||
371 | goto error_input_allocate; | ||
372 | wimax_dev->rfkill_input = input_dev; | ||
373 | d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev); | ||
374 | |||
375 | input_dev->name = wimax_dev->name; | ||
376 | /* FIXME: get a real device bus ID and stuff? do we care? */ | ||
377 | input_dev->id.bustype = BUS_HOST; | ||
378 | input_dev->id.vendor = 0xffff; | ||
379 | input_dev->evbit[0] = BIT(EV_KEY); | ||
380 | set_bit(KEY_WIMAX, input_dev->keybit); | ||
381 | |||
382 | /* Register both */ | ||
383 | result = input_register_device(wimax_dev->rfkill_input); | ||
384 | if (result < 0) | ||
385 | goto error_input_register; | ||
386 | result = rfkill_register(wimax_dev->rfkill); | 357 | result = rfkill_register(wimax_dev->rfkill); |
387 | if (result < 0) | 358 | if (result < 0) |
388 | goto error_rfkill_register; | 359 | goto error_rfkill_register; |
@@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) | |||
394 | d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); | 365 | d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); |
395 | return 0; | 366 | return 0; |
396 | 367 | ||
397 | /* if rfkill_register() suceeds, can't use rfkill_free() any | ||
398 | * more, only rfkill_unregister() [it owns the refcount]; with | ||
399 | * the input device we have the same issue--hence the if. */ | ||
400 | error_rfkill_register: | 368 | error_rfkill_register: |
401 | input_unregister_device(wimax_dev->rfkill_input); | 369 | rfkill_destroy(wimax_dev->rfkill); |
402 | wimax_dev->rfkill_input = NULL; | ||
403 | error_input_register: | ||
404 | if (wimax_dev->rfkill_input) | ||
405 | input_free_device(wimax_dev->rfkill_input); | ||
406 | error_input_allocate: | ||
407 | rfkill_free(wimax_dev->rfkill); | ||
408 | error_rfkill_allocate: | 370 | error_rfkill_allocate: |
409 | d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); | 371 | d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); |
410 | return result; | 372 | return result; |
@@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev) | |||
423 | { | 385 | { |
424 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 386 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
425 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); | 387 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); |
426 | rfkill_unregister(wimax_dev->rfkill); /* frees */ | 388 | rfkill_unregister(wimax_dev->rfkill); |
427 | input_unregister_device(wimax_dev->rfkill_input); | 389 | rfkill_destroy(wimax_dev->rfkill); |
428 | d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); | 390 | d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); |
429 | } | 391 | } |
430 | 392 | ||
431 | 393 | ||
432 | #else /* #ifdef CONFIG_RFKILL */ | ||
433 | |||
434 | void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, | ||
435 | enum wimax_rf_state state) | ||
436 | { | ||
437 | } | ||
438 | EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw); | ||
439 | |||
440 | void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, | ||
441 | enum wimax_rf_state state) | ||
442 | { | ||
443 | } | ||
444 | EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw); | ||
445 | |||
446 | int wimax_rfkill(struct wimax_dev *wimax_dev, | ||
447 | enum wimax_rf_state state) | ||
448 | { | ||
449 | return WIMAX_RF_ON << 1 | WIMAX_RF_ON; | ||
450 | } | ||
451 | EXPORT_SYMBOL_GPL(wimax_rfkill); | ||
452 | |||
453 | int wimax_rfkill_add(struct wimax_dev *wimax_dev) | ||
454 | { | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | void wimax_rfkill_rm(struct wimax_dev *wimax_dev) | ||
459 | { | ||
460 | } | ||
461 | |||
462 | #endif /* #ifdef CONFIG_RFKILL */ | ||
463 | |||
464 | |||
465 | /* | 394 | /* |
466 | * Exporting to user space over generic netlink | 395 | * Exporting to user space over generic netlink |
467 | * | 396 | * |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 45005497c634..4428dd5e911d 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config CFG80211 | 1 | config CFG80211 |
2 | tristate "Improved wireless configuration API" | 2 | tristate "Improved wireless configuration API" |
3 | depends on RFKILL || !RFKILL | ||
3 | 4 | ||
4 | config CFG80211_REG_DEBUG | 5 | config CFG80211_REG_DEBUG |
5 | bool "cfg80211 regulatory debugging" | 6 | bool "cfg80211 regulatory debugging" |
diff --git a/net/wireless/core.c b/net/wireless/core.c index a5dbea1da476..3b74b88e10a3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
13 | #include <linux/notifier.h> | 13 | #include <linux/notifier.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/rtnetlink.h> | ||
15 | #include <net/genetlink.h> | 16 | #include <net/genetlink.h> |
16 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
17 | #include "nl80211.h" | 18 | #include "nl80211.h" |
@@ -227,6 +228,41 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
227 | return 0; | 228 | return 0; |
228 | } | 229 | } |
229 | 230 | ||
231 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | ||
232 | { | ||
233 | struct cfg80211_registered_device *drv = data; | ||
234 | |||
235 | drv->ops->rfkill_poll(&drv->wiphy); | ||
236 | } | ||
237 | |||
238 | static int cfg80211_rfkill_set_block(void *data, bool blocked) | ||
239 | { | ||
240 | struct cfg80211_registered_device *drv = data; | ||
241 | struct wireless_dev *wdev; | ||
242 | |||
243 | if (!blocked) | ||
244 | return 0; | ||
245 | |||
246 | rtnl_lock(); | ||
247 | mutex_lock(&drv->devlist_mtx); | ||
248 | |||
249 | list_for_each_entry(wdev, &drv->netdev_list, list) | ||
250 | dev_close(wdev->netdev); | ||
251 | |||
252 | mutex_unlock(&drv->devlist_mtx); | ||
253 | rtnl_unlock(); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static void cfg80211_rfkill_sync_work(struct work_struct *work) | ||
259 | { | ||
260 | struct cfg80211_registered_device *drv; | ||
261 | |||
262 | drv = container_of(work, struct cfg80211_registered_device, rfkill_sync); | ||
263 | cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); | ||
264 | } | ||
265 | |||
230 | /* exported functions */ | 266 | /* exported functions */ |
231 | 267 | ||
232 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 268 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
@@ -274,6 +310,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
274 | drv->wiphy.dev.class = &ieee80211_class; | 310 | drv->wiphy.dev.class = &ieee80211_class; |
275 | drv->wiphy.dev.platform_data = drv; | 311 | drv->wiphy.dev.platform_data = drv; |
276 | 312 | ||
313 | drv->rfkill_ops.set_block = cfg80211_rfkill_set_block; | ||
314 | drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev), | ||
315 | &drv->wiphy.dev, RFKILL_TYPE_WLAN, | ||
316 | &drv->rfkill_ops, drv); | ||
317 | |||
318 | if (!drv->rfkill) { | ||
319 | kfree(drv); | ||
320 | return NULL; | ||
321 | } | ||
322 | |||
323 | INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); | ||
324 | |||
277 | /* | 325 | /* |
278 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. | 326 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. |
279 | * Fragmentation and RTS threshold are disabled by default with the | 327 | * Fragmentation and RTS threshold are disabled by default with the |
@@ -356,6 +404,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
356 | if (res) | 404 | if (res) |
357 | goto out_unlock; | 405 | goto out_unlock; |
358 | 406 | ||
407 | res = rfkill_register(drv->rfkill); | ||
408 | if (res) | ||
409 | goto out_rm_dev; | ||
410 | |||
359 | list_add(&drv->list, &cfg80211_drv_list); | 411 | list_add(&drv->list, &cfg80211_drv_list); |
360 | 412 | ||
361 | /* add to debugfs */ | 413 | /* add to debugfs */ |
@@ -379,16 +431,41 @@ int wiphy_register(struct wiphy *wiphy) | |||
379 | cfg80211_debugfs_drv_add(drv); | 431 | cfg80211_debugfs_drv_add(drv); |
380 | 432 | ||
381 | res = 0; | 433 | res = 0; |
382 | out_unlock: | 434 | goto out_unlock; |
435 | |||
436 | out_rm_dev: | ||
437 | device_del(&drv->wiphy.dev); | ||
438 | out_unlock: | ||
383 | mutex_unlock(&cfg80211_mutex); | 439 | mutex_unlock(&cfg80211_mutex); |
384 | return res; | 440 | return res; |
385 | } | 441 | } |
386 | EXPORT_SYMBOL(wiphy_register); | 442 | EXPORT_SYMBOL(wiphy_register); |
387 | 443 | ||
444 | void wiphy_rfkill_start_polling(struct wiphy *wiphy) | ||
445 | { | ||
446 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); | ||
447 | |||
448 | if (!drv->ops->rfkill_poll) | ||
449 | return; | ||
450 | drv->rfkill_ops.poll = cfg80211_rfkill_poll; | ||
451 | rfkill_resume_polling(drv->rfkill); | ||
452 | } | ||
453 | EXPORT_SYMBOL(wiphy_rfkill_start_polling); | ||
454 | |||
455 | void wiphy_rfkill_stop_polling(struct wiphy *wiphy) | ||
456 | { | ||
457 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); | ||
458 | |||
459 | rfkill_pause_polling(drv->rfkill); | ||
460 | } | ||
461 | EXPORT_SYMBOL(wiphy_rfkill_stop_polling); | ||
462 | |||
388 | void wiphy_unregister(struct wiphy *wiphy) | 463 | void wiphy_unregister(struct wiphy *wiphy) |
389 | { | 464 | { |
390 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); | 465 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); |
391 | 466 | ||
467 | rfkill_unregister(drv->rfkill); | ||
468 | |||
392 | /* protect the device list */ | 469 | /* protect the device list */ |
393 | mutex_lock(&cfg80211_mutex); | 470 | mutex_lock(&cfg80211_mutex); |
394 | 471 | ||
@@ -425,6 +502,7 @@ EXPORT_SYMBOL(wiphy_unregister); | |||
425 | void cfg80211_dev_free(struct cfg80211_registered_device *drv) | 502 | void cfg80211_dev_free(struct cfg80211_registered_device *drv) |
426 | { | 503 | { |
427 | struct cfg80211_internal_bss *scan, *tmp; | 504 | struct cfg80211_internal_bss *scan, *tmp; |
505 | rfkill_destroy(drv->rfkill); | ||
428 | mutex_destroy(&drv->mtx); | 506 | mutex_destroy(&drv->mtx); |
429 | mutex_destroy(&drv->devlist_mtx); | 507 | mutex_destroy(&drv->devlist_mtx); |
430 | list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) | 508 | list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) |
@@ -438,6 +516,15 @@ void wiphy_free(struct wiphy *wiphy) | |||
438 | } | 516 | } |
439 | EXPORT_SYMBOL(wiphy_free); | 517 | EXPORT_SYMBOL(wiphy_free); |
440 | 518 | ||
519 | void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) | ||
520 | { | ||
521 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); | ||
522 | |||
523 | if (rfkill_set_hw_state(drv->rfkill, blocked)) | ||
524 | schedule_work(&drv->rfkill_sync); | ||
525 | } | ||
526 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); | ||
527 | |||
441 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | 528 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, |
442 | unsigned long state, | 529 | unsigned long state, |
443 | void *ndev) | 530 | void *ndev) |
@@ -446,7 +533,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
446 | struct cfg80211_registered_device *rdev; | 533 | struct cfg80211_registered_device *rdev; |
447 | 534 | ||
448 | if (!dev->ieee80211_ptr) | 535 | if (!dev->ieee80211_ptr) |
449 | return 0; | 536 | return NOTIFY_DONE; |
450 | 537 | ||
451 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); | 538 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); |
452 | 539 | ||
@@ -492,9 +579,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
492 | } | 579 | } |
493 | mutex_unlock(&rdev->devlist_mtx); | 580 | mutex_unlock(&rdev->devlist_mtx); |
494 | break; | 581 | break; |
582 | case NETDEV_PRE_UP: | ||
583 | if (rfkill_blocked(rdev->rfkill)) | ||
584 | return notifier_from_errno(-ERFKILL); | ||
585 | break; | ||
495 | } | 586 | } |
496 | 587 | ||
497 | return 0; | 588 | return NOTIFY_DONE; |
498 | } | 589 | } |
499 | 590 | ||
500 | static struct notifier_block cfg80211_netdev_notifier = { | 591 | static struct notifier_block cfg80211_netdev_notifier = { |
diff --git a/net/wireless/core.h b/net/wireless/core.h index ab512bcd8153..bfa340c7abb5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <linux/kref.h> | 11 | #include <linux/kref.h> |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | ||
15 | #include <linux/workqueue.h> | ||
14 | #include <net/genetlink.h> | 16 | #include <net/genetlink.h> |
15 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
16 | #include "reg.h" | 18 | #include "reg.h" |
@@ -24,6 +26,11 @@ struct cfg80211_registered_device { | |||
24 | * any call is in progress */ | 26 | * any call is in progress */ |
25 | struct mutex mtx; | 27 | struct mutex mtx; |
26 | 28 | ||
29 | /* rfkill support */ | ||
30 | struct rfkill_ops rfkill_ops; | ||
31 | struct rfkill *rfkill; | ||
32 | struct work_struct rfkill_sync; | ||
33 | |||
27 | /* ISO / IEC 3166 alpha2 for which this device is receiving | 34 | /* ISO / IEC 3166 alpha2 for which this device is receiving |
28 | * country IEs on, this can help disregard country IEs from APs | 35 | * country IEs on, this can help disregard country IEs from APs |
29 | * on the same alpha2 quickly. The alpha2 may differ from | 36 | * on the same alpha2 quickly. The alpha2 may differ from |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4b4d3c8a1aed..24168560ebae 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1687,6 +1687,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1687 | if (err) | 1687 | if (err) |
1688 | goto out_rtnl; | 1688 | goto out_rtnl; |
1689 | 1689 | ||
1690 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1691 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | ||
1692 | err = -EINVAL; | ||
1693 | goto out; | ||
1694 | } | ||
1695 | |||
1690 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1696 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1691 | if (err) | 1697 | if (err) |
1692 | goto out; | 1698 | goto out; |
@@ -1738,7 +1744,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1738 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1744 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1739 | params.listen_interval = | 1745 | params.listen_interval = |
1740 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1746 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
1747 | |||
1741 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 1748 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
1749 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | ||
1750 | return -EINVAL; | ||
1751 | |||
1742 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1752 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
1743 | params.ht_capa = | 1753 | params.ht_capa = |
1744 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1754 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
@@ -3559,11 +3569,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
3559 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 3569 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); |
3560 | } | 3570 | } |
3561 | 3571 | ||
3572 | static int nl80211_add_scan_req(struct sk_buff *msg, | ||
3573 | struct cfg80211_registered_device *rdev) | ||
3574 | { | ||
3575 | struct cfg80211_scan_request *req = rdev->scan_req; | ||
3576 | struct nlattr *nest; | ||
3577 | int i; | ||
3578 | |||
3579 | if (WARN_ON(!req)) | ||
3580 | return 0; | ||
3581 | |||
3582 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); | ||
3583 | if (!nest) | ||
3584 | goto nla_put_failure; | ||
3585 | for (i = 0; i < req->n_ssids; i++) | ||
3586 | NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); | ||
3587 | nla_nest_end(msg, nest); | ||
3588 | |||
3589 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
3590 | if (!nest) | ||
3591 | goto nla_put_failure; | ||
3592 | for (i = 0; i < req->n_channels; i++) | ||
3593 | NLA_PUT_U32(msg, i, req->channels[i]->center_freq); | ||
3594 | nla_nest_end(msg, nest); | ||
3595 | |||
3596 | if (req->ie) | ||
3597 | NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); | ||
3598 | |||
3599 | return 0; | ||
3600 | nla_put_failure: | ||
3601 | return -ENOBUFS; | ||
3602 | } | ||
3603 | |||
3562 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, | 3604 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, |
3563 | struct cfg80211_registered_device *rdev, | 3605 | struct cfg80211_registered_device *rdev, |
3564 | struct net_device *netdev, | 3606 | struct net_device *netdev, |
3565 | u32 pid, u32 seq, int flags, | 3607 | u32 pid, u32 seq, int flags, |
3566 | u32 cmd) | 3608 | u32 cmd) |
3567 | { | 3609 | { |
3568 | void *hdr; | 3610 | void *hdr; |
3569 | 3611 | ||
@@ -3574,7 +3616,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, | |||
3574 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 3616 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
3575 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 3617 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
3576 | 3618 | ||
3577 | /* XXX: we should probably bounce back the request? */ | 3619 | /* ignore errors and send incomplete event anyway */ |
3620 | nl80211_add_scan_req(msg, rdev); | ||
3578 | 3621 | ||
3579 | return genlmsg_end(msg, hdr); | 3622 | return genlmsg_end(msg, hdr); |
3580 | 3623 | ||
@@ -3828,7 +3871,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | |||
3828 | struct sk_buff *msg; | 3871 | struct sk_buff *msg; |
3829 | void *hdr; | 3872 | void *hdr; |
3830 | 3873 | ||
3831 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 3874 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
3832 | if (!msg) | 3875 | if (!msg) |
3833 | return; | 3876 | return; |
3834 | 3877 | ||
@@ -3852,7 +3895,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | |||
3852 | return; | 3895 | return; |
3853 | } | 3896 | } |
3854 | 3897 | ||
3855 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | 3898 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); |
3856 | return; | 3899 | return; |
3857 | 3900 | ||
3858 | nla_put_failure: | 3901 | nla_put_failure: |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f87ac1df2df5..ea4c299fbe3b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -2171,7 +2171,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2171 | * the country IE rd with what CRDA believes that country should have | 2171 | * the country IE rd with what CRDA believes that country should have |
2172 | */ | 2172 | */ |
2173 | 2173 | ||
2174 | BUG_ON(!country_ie_regdomain); | 2174 | /* |
2175 | * Userspace could have sent two replies with only | ||
2176 | * one kernel request. By the second reply we would have | ||
2177 | * already processed and consumed the country_ie_regdomain. | ||
2178 | */ | ||
2179 | if (!country_ie_regdomain) | ||
2180 | return -EALREADY; | ||
2175 | BUG_ON(rd == country_ie_regdomain); | 2181 | BUG_ON(rd == country_ie_regdomain); |
2176 | 2182 | ||
2177 | /* | 2183 | /* |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index df59440290e5..e95b638b919f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -29,13 +29,14 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | |||
29 | goto out; | 29 | goto out; |
30 | 30 | ||
31 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 31 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); |
32 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | ||
33 | 32 | ||
34 | if (aborted) | 33 | if (aborted) |
35 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); | 34 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); |
36 | else | 35 | else |
37 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); | 36 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); |
38 | 37 | ||
38 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | ||
39 | |||
39 | #ifdef CONFIG_WIRELESS_EXT | 40 | #ifdef CONFIG_WIRELESS_EXT |
40 | if (!aborted) { | 41 | if (!aborted) { |
41 | memset(&wrqu, 0, sizeof(wrqu)); | 42 | memset(&wrqu, 0, sizeof(wrqu)); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d072bff463aa..25550692dda6 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -157,26 +157,25 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | |||
157 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 157 | params->cipher != WLAN_CIPHER_SUITE_WEP104) |
158 | return -EINVAL; | 158 | return -EINVAL; |
159 | 159 | ||
160 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
161 | switch (params->cipher) { | 160 | switch (params->cipher) { |
162 | case WLAN_CIPHER_SUITE_WEP40: | 161 | case WLAN_CIPHER_SUITE_WEP40: |
163 | if (params->key_len != 5) | 162 | if (params->key_len != WLAN_KEY_LEN_WEP40) |
164 | return -EINVAL; | 163 | return -EINVAL; |
165 | break; | 164 | break; |
166 | case WLAN_CIPHER_SUITE_TKIP: | 165 | case WLAN_CIPHER_SUITE_TKIP: |
167 | if (params->key_len != 32) | 166 | if (params->key_len != WLAN_KEY_LEN_TKIP) |
168 | return -EINVAL; | 167 | return -EINVAL; |
169 | break; | 168 | break; |
170 | case WLAN_CIPHER_SUITE_CCMP: | 169 | case WLAN_CIPHER_SUITE_CCMP: |
171 | if (params->key_len != 16) | 170 | if (params->key_len != WLAN_KEY_LEN_CCMP) |
172 | return -EINVAL; | 171 | return -EINVAL; |
173 | break; | 172 | break; |
174 | case WLAN_CIPHER_SUITE_WEP104: | 173 | case WLAN_CIPHER_SUITE_WEP104: |
175 | if (params->key_len != 13) | 174 | if (params->key_len != WLAN_KEY_LEN_WEP104) |
176 | return -EINVAL; | 175 | return -EINVAL; |
177 | break; | 176 | break; |
178 | case WLAN_CIPHER_SUITE_AES_CMAC: | 177 | case WLAN_CIPHER_SUITE_AES_CMAC: |
179 | if (params->key_len != 16) | 178 | if (params->key_len != WLAN_KEY_LEN_AES_CMAC) |
180 | return -EINVAL; | 179 | return -EINVAL; |
181 | break; | 180 | break; |
182 | default: | 181 | default: |
@@ -259,7 +258,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | |||
259 | } | 258 | } |
260 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 259 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
261 | 260 | ||
262 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | 261 | static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) |
263 | { | 262 | { |
264 | int ae = meshhdr->flags & MESH_FLAGS_AE; | 263 | int ae = meshhdr->flags & MESH_FLAGS_AE; |
265 | /* 7.1.3.5a.2 */ | 264 | /* 7.1.3.5a.2 */ |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 711e00a0c9b5..d030c5315672 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -744,3 +744,86 @@ int cfg80211_wext_giwencode(struct net_device *dev, | |||
744 | return err; | 744 | return err; |
745 | } | 745 | } |
746 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | 746 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); |
747 | |||
748 | int cfg80211_wext_siwtxpower(struct net_device *dev, | ||
749 | struct iw_request_info *info, | ||
750 | union iwreq_data *data, char *extra) | ||
751 | { | ||
752 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
753 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
754 | enum tx_power_setting type; | ||
755 | int dbm = 0; | ||
756 | |||
757 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | ||
758 | return -EINVAL; | ||
759 | if (data->txpower.flags & IW_TXPOW_RANGE) | ||
760 | return -EINVAL; | ||
761 | |||
762 | if (!rdev->ops->set_tx_power) | ||
763 | return -EOPNOTSUPP; | ||
764 | |||
765 | /* only change when not disabling */ | ||
766 | if (!data->txpower.disabled) { | ||
767 | rfkill_set_sw_state(rdev->rfkill, false); | ||
768 | |||
769 | if (data->txpower.fixed) { | ||
770 | /* | ||
771 | * wext doesn't support negative values, see | ||
772 | * below where it's for automatic | ||
773 | */ | ||
774 | if (data->txpower.value < 0) | ||
775 | return -EINVAL; | ||
776 | dbm = data->txpower.value; | ||
777 | type = TX_POWER_FIXED; | ||
778 | /* TODO: do regulatory check! */ | ||
779 | } else { | ||
780 | /* | ||
781 | * Automatic power level setting, max being the value | ||
782 | * passed in from userland. | ||
783 | */ | ||
784 | if (data->txpower.value < 0) { | ||
785 | type = TX_POWER_AUTOMATIC; | ||
786 | } else { | ||
787 | dbm = data->txpower.value; | ||
788 | type = TX_POWER_LIMITED; | ||
789 | } | ||
790 | } | ||
791 | } else { | ||
792 | rfkill_set_sw_state(rdev->rfkill, true); | ||
793 | schedule_work(&rdev->rfkill_sync); | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);; | ||
798 | } | ||
799 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); | ||
800 | |||
801 | int cfg80211_wext_giwtxpower(struct net_device *dev, | ||
802 | struct iw_request_info *info, | ||
803 | union iwreq_data *data, char *extra) | ||
804 | { | ||
805 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
806 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
807 | int err, val; | ||
808 | |||
809 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | ||
810 | return -EINVAL; | ||
811 | if (data->txpower.flags & IW_TXPOW_RANGE) | ||
812 | return -EINVAL; | ||
813 | |||
814 | if (!rdev->ops->get_tx_power) | ||
815 | return -EOPNOTSUPP; | ||
816 | |||
817 | err = rdev->ops->get_tx_power(wdev->wiphy, &val); | ||
818 | if (err) | ||
819 | return err; | ||
820 | |||
821 | /* well... oh well */ | ||
822 | data->txpower.fixed = 1; | ||
823 | data->txpower.disabled = rfkill_blocked(rdev->rfkill); | ||
824 | data->txpower.value = val; | ||
825 | data->txpower.flags = IW_TXPOW_DBM; | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); | ||