diff options
46 files changed, 2536 insertions, 3273 deletions
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 40c3a3f10816..de941e309d47 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt | |||
| @@ -1,571 +1,130 @@ | |||
| 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 | 35 | ||
| 374 | 5. The wireless device driver MUST NOT leave the transmitter enabled during | 36 | The rfkill class code also notifies userspace of state changes, this is |
| 375 | suspend and hibernation unless: | 37 | achieved via uevents. It also provides some sysfs files for userspace to |
| 38 | check the status of radio transmitters. See the "Userspace support" section | ||
| 39 | below. | ||
| 376 | 40 | ||
| 377 | 5.1. The transmitter has to be enabled for some sort of functionality | ||
| 378 | like wake-on-wireless-packet or autonomous packed forwarding in a mesh | ||
| 379 | network, and that functionality is enabled for this suspend/hibernation | ||
| 380 | cycle. | ||
| 381 | 41 | ||
| 382 | AND | 42 | The rfkill-input code implements a basic response to rfkill buttons -- it |
| 43 | implements turning on/off all devices of a certain class (or all). | ||
| 383 | 44 | ||
| 384 | 5.2. The device was not on a user-requested BLOCKED state before | 45 | When the device is hard-blocked (either by a call to rfkill_set_hw_state() |
| 385 | the suspend (i.e. the driver must NOT unblock a device, not even | 46 | or from query_hw_block) set_block() will be invoked but drivers can well |
| 386 | to support wake-on-wireless-packet or remain in the mesh). | 47 | ignore the method call since they can use the return value of the function |
| 48 | rfkill_set_hw_state() to sync the software state instead of keeping track | ||
| 49 | of calls to set_block(). | ||
| 387 | 50 | ||
| 388 | In other words, there is absolutely no allowed scenario where a driver can | ||
| 389 | automatically take action to unblock a rfkill controller (obviously, this deals | ||
| 390 | with scenarios where soft-blocking or both soft and hard blocking is happening. | ||
| 391 | Scenarios where hardware rfkill lines are the only ones blocking the | ||
| 392 | transmitter are outside of this rule, since the wireless device driver does not | ||
| 393 | control its input hardware rfkill lines in the first place). | ||
| 394 | 51 | ||
| 395 | 6. During resume, rfkill will try to restore its previous state. | 52 | The entire functionality is spread over more than one subsystem: |
| 396 | 53 | ||
| 397 | 7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio | 54 | * The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and |
| 398 | until it is resumed. | 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) | ||
| 399 | 59 | ||
| 60 | * The rfkill-input code hooks up to these events and switches the soft-block | ||
| 61 | of the various radio transmitters, depending on the button type. | ||
| 400 | 62 | ||
| 401 | Example of a WLAN wireless driver connected to the rfkill subsystem: | 63 | * The rfkill drivers turn off/on their transmitters as requested. |
| 402 | -------------------------------------------------------------------- | ||
| 403 | 64 | ||
| 404 | A certain WLAN card has one input pin that causes it to block the transmitter | 65 | * The rfkill class will generate userspace notifications (uevents) to tell |
| 405 | and makes the status of that input pin available (only for reading!) to the | 66 | userspace what the current state is. |
| 406 | kernel driver. This is a hard rfkill input line (it cannot be overridden by | ||
| 407 | the kernel driver). | ||
| 408 | 67 | ||
| 409 | The card also has one PCI register that, if manipulated by the driver, causes | ||
| 410 | it to block the transmitter. This is a soft rfkill input line. | ||
| 411 | 68 | ||
| 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 | 69 | ||
| 416 | If either one of these rfkill lines are active, the transmitter is blocked by | 70 | 3. Kernel driver guidelines |
| 417 | the hardware and forced offline. | ||
| 418 | 71 | ||
| 419 | The driver should allocate and attach to its struct device *ONE* instance of | ||
| 420 | the rfkill class (there is only one transmitter). | ||
| 421 | 72 | ||
| 422 | It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if | 73 | Drivers for radio transmitters normally implement only the rfkill class. |
| 423 | either one of its two hard rfkill input lines are active. If the two hard | 74 | These drivers may not unblock the transmitter based on own decisions, they |
| 424 | rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft | 75 | should act on information provided by the rfkill class only. |
| 425 | rfkill input line is active. Only if none of the rfkill input lines are | ||
| 426 | active, will it return RFKILL_STATE_UNBLOCKED. | ||
| 427 | 76 | ||
| 428 | Since the device has a hardware rfkill line, it IS subject to state changes | 77 | Platform drivers might implement input devices if the rfkill button is just |
| 429 | external to rfkill. Therefore, the driver must make sure that it calls | 78 | that, a button. If that button influences the hardware then you need to |
| 430 | rfkill_force_state() to keep the status always up-to-date, and it must do a | 79 | implement an rfkill class instead. This also applies if the platform provides |
| 431 | rfkill_force_state() on resume from sleep. | 80 | a way to turn on/off the transmitter(s). |
| 432 | 81 | ||
| 433 | Every time the driver gets a notification from the card that one of its rfkill | 82 | During suspend/hibernation, transmitters should only be left enabled when |
| 434 | lines changed state (polling might be needed on badly designed cards that don't | 83 | wake-on wlan or similar functionality requires it and the device wasn't |
| 435 | generate interrupts for such events), it recomputes the rfkill state as per | 84 | blocked before suspend/hibernate. Note that it may be necessary to update |
| 436 | above, and calls rfkill_force_state() to update it. | 85 | the rfkill subsystem's idea of what the current state is at resume time if |
| 86 | the state may have changed over suspend. | ||
| 437 | 87 | ||
| 438 | The driver should implement the toggle_radio() hook, that: | ||
| 439 | 88 | ||
| 440 | 1. Returns an error if one of the hardware rfkill lines are active, and the | ||
| 441 | caller asked for RFKILL_STATE_UNBLOCKED. | ||
| 442 | 89 | ||
| 443 | 2. Activates the soft rfkill line if the caller asked for state | 90 | 4. Kernel API |
| 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 | |||
| 447 | 3. Deactivates the soft rfkill line if none of the hardware rfkill lines are | ||
| 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 | 103 | ||
| 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 | 104 | ||
| 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 | 105 | ||
| 496 | If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED | 106 | 5. Userspace support |
| 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 | 107 | ||
| 514 | The ABI for these variables is defined by the sysfs attributes. It is best | 108 | The following sysfs entries exist for every rfkill device: |
| 515 | to take a quick look at the source to make sure of the possible values. | ||
| 516 | |||
| 517 | It is expected that HAL will trap those, and bridge them to DBUS, etc. These | ||
| 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 | transmiter 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. | ||
| 565 | |||
| 566 | A note about input devices and EV_SW events: | ||
| 567 | |||
| 568 | In order to know the current state of an input device switch (like | ||
| 569 | SW_RFKILL_ALL), you will need to use an IOCTL. That information is not | ||
| 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/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/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/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-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/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c index 4ca8b495f82d..8ee2c3c09a02 100644 --- a/drivers/net/wireless/iwmc3200wifi/rfkill.c +++ b/drivers/net/wireless/iwmc3200wifi/rfkill.c | |||
| @@ -25,47 +25,42 @@ | |||
| 25 | 25 | ||
| 26 | #include "iwm.h" | 26 | #include "iwm.h" |
| 27 | 27 | ||
| 28 | static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) | 28 | static int iwm_rfkill_set_block(void *data, bool blocked) |
| 29 | { | 29 | { |
| 30 | struct iwm_priv *iwm = data; | 30 | struct iwm_priv *iwm = data; |
| 31 | 31 | ||
| 32 | switch (state) { | 32 | if (!blocked) { |
| 33 | case RFKILL_STATE_UNBLOCKED: | ||
| 34 | if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) | 33 | if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) |
| 35 | return -EBUSY; | 34 | return -EBUSY; |
| 36 | 35 | ||
| 37 | if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && | 36 | if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && |
| 38 | (iwm_to_ndev(iwm)->flags & IFF_UP)) | 37 | (iwm_to_ndev(iwm)->flags & IFF_UP)) |
| 39 | iwm_up(iwm); | 38 | return iwm_up(iwm); |
| 40 | 39 | } else { | |
| 41 | break; | ||
| 42 | case RFKILL_STATE_SOFT_BLOCKED: | ||
| 43 | if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) | 40 | if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) |
| 44 | iwm_down(iwm); | 41 | return iwm_down(iwm); |
| 45 | |||
| 46 | break; | ||
| 47 | default: | ||
| 48 | break; | ||
| 49 | } | 42 | } |
| 50 | 43 | ||
| 51 | return 0; | 44 | return 0; |
| 52 | } | 45 | } |
| 53 | 46 | ||
| 47 | static const struct rfkill_ops iwm_rfkill_ops = { | ||
| 48 | .set_block = iwm_rfkill_set_block, | ||
| 49 | }; | ||
| 50 | |||
| 54 | int iwm_rfkill_init(struct iwm_priv *iwm) | 51 | int iwm_rfkill_init(struct iwm_priv *iwm) |
| 55 | { | 52 | { |
| 56 | int ret; | 53 | int ret; |
| 57 | 54 | ||
| 58 | iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); | 55 | iwm->rfkill = rfkill_alloc(KBUILD_MODNAME, |
| 56 | iwm_to_dev(iwm), | ||
| 57 | RFKILL_TYPE_WLAN, | ||
| 58 | &iwm_rfkill_ops, iwm); | ||
| 59 | if (!iwm->rfkill) { | 59 | if (!iwm->rfkill) { |
| 60 | IWM_ERR(iwm, "Unable to allocate rfkill device\n"); | 60 | IWM_ERR(iwm, "Unable to allocate rfkill device\n"); |
| 61 | return -ENOMEM; | 61 | return -ENOMEM; |
| 62 | } | 62 | } |
| 63 | 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); | 64 | ret = rfkill_register(iwm->rfkill); |
| 70 | if (ret) { | 65 | if (ret) { |
| 71 | IWM_ERR(iwm, "Failed to register rfkill device\n"); | 66 | IWM_ERR(iwm, "Failed to register rfkill device\n"); |
| @@ -74,15 +69,15 @@ int iwm_rfkill_init(struct iwm_priv *iwm) | |||
| 74 | 69 | ||
| 75 | return 0; | 70 | return 0; |
| 76 | fail: | 71 | fail: |
| 77 | rfkill_free(iwm->rfkill); | 72 | rfkill_destroy(iwm->rfkill); |
| 78 | return ret; | 73 | return ret; |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | void iwm_rfkill_exit(struct iwm_priv *iwm) | 76 | void iwm_rfkill_exit(struct iwm_priv *iwm) |
| 82 | { | 77 | { |
| 83 | if (iwm->rfkill) | 78 | if (iwm->rfkill) { |
| 84 | rfkill_unregister(iwm->rfkill); | 79 | rfkill_unregister(iwm->rfkill); |
| 85 | 80 | rfkill_destroy(iwm->rfkill); | |
| 86 | rfkill_free(iwm->rfkill); | 81 | } |
| 87 | iwm->rfkill = NULL; | 82 | iwm->rfkill = NULL; |
| 88 | } | 83 | } |
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/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/rfkill.h b/include/linux/rfkill.h index de18ef227e00..090852c8de7a 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 |
| @@ -21,6 +22,24 @@ | |||
| 21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 22 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 22 | */ | 23 | */ |
| 23 | 24 | ||
| 25 | |||
| 26 | /* define userspace visible states */ | ||
| 27 | #define RFKILL_STATE_SOFT_BLOCKED 0 | ||
| 28 | #define RFKILL_STATE_UNBLOCKED 1 | ||
| 29 | #define RFKILL_STATE_HARD_BLOCKED 2 | ||
| 30 | |||
| 31 | /* and that's all userspace gets */ | ||
| 32 | #ifdef __KERNEL__ | ||
| 33 | /* don't allow anyone to use these in the kernel */ | ||
| 34 | enum rfkill_user_states { | ||
| 35 | RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED, | ||
| 36 | RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED, | ||
| 37 | RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED, | ||
| 38 | }; | ||
| 39 | #undef RFKILL_STATE_SOFT_BLOCKED | ||
| 40 | #undef RFKILL_STATE_UNBLOCKED | ||
| 41 | #undef RFKILL_STATE_HARD_BLOCKED | ||
| 42 | |||
| 24 | #include <linux/types.h> | 43 | #include <linux/types.h> |
| 25 | #include <linux/kernel.h> | 44 | #include <linux/kernel.h> |
| 26 | #include <linux/list.h> | 45 | #include <linux/list.h> |
| @@ -30,109 +49,267 @@ | |||
| 30 | 49 | ||
| 31 | /** | 50 | /** |
| 32 | * enum rfkill_type - type of rfkill switch. | 51 | * enum rfkill_type - type of rfkill switch. |
| 33 | * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. | 52 | * |
| 34 | * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. | 53 | * @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. |
| 35 | * RFKILL_TYPE_UWB: switch is on a ultra wideband device. | 54 | * @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. |
| 36 | * RFKILL_TYPE_WIMAX: switch is on a WiMAX device. | 55 | * @RFKILL_TYPE_UWB: switch is on a ultra wideband device. |
| 37 | * RFKILL_TYPE_WWAN: switch is on a wireless WAN device. | 56 | * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device. |
| 57 | * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device. | ||
| 58 | * @NUM_RFKILL_TYPES: number of defined rfkill types | ||
| 38 | */ | 59 | */ |
| 39 | enum rfkill_type { | 60 | enum rfkill_type { |
| 40 | RFKILL_TYPE_WLAN , | 61 | RFKILL_TYPE_WLAN, |
| 41 | RFKILL_TYPE_BLUETOOTH, | 62 | RFKILL_TYPE_BLUETOOTH, |
| 42 | RFKILL_TYPE_UWB, | 63 | RFKILL_TYPE_UWB, |
| 43 | RFKILL_TYPE_WIMAX, | 64 | RFKILL_TYPE_WIMAX, |
| 44 | RFKILL_TYPE_WWAN, | 65 | RFKILL_TYPE_WWAN, |
| 45 | RFKILL_TYPE_MAX, | 66 | NUM_RFKILL_TYPES, |
| 46 | }; | 67 | }; |
| 47 | 68 | ||
| 48 | enum rfkill_state { | 69 | /* this is opaque */ |
| 49 | RFKILL_STATE_SOFT_BLOCKED = 0, /* Radio output blocked */ | 70 | struct rfkill; |
| 50 | RFKILL_STATE_UNBLOCKED = 1, /* Radio output allowed */ | 71 | |
| 51 | RFKILL_STATE_HARD_BLOCKED = 2, /* Output blocked, non-overrideable */ | 72 | /** |
| 52 | RFKILL_STATE_MAX, /* marker for last valid state */ | 73 | * struct rfkill_ops - rfkill driver methods |
| 74 | * | ||
| 75 | * @poll: poll the rfkill block state(s) -- only assign this method | ||
| 76 | * when you need polling. When called, simply call one of the | ||
| 77 | * rfkill_set{,_hw,_sw}_state family of functions. If the hw | ||
| 78 | * is getting unblocked you need to take into account the return | ||
| 79 | * value of those functions to make sure the software block is | ||
| 80 | * properly used. | ||
| 81 | * @query: query the rfkill block state(s) and call exactly one of the | ||
| 82 | * rfkill_set{,_hw,_sw}_state family of functions. Assign this | ||
| 83 | * method if input events can cause hardware state changes to make | ||
| 84 | * the rfkill core query your driver before setting a requested | ||
| 85 | * block. | ||
| 86 | * @set_block: turn the transmitter on (blocked == false) or off | ||
| 87 | * (blocked == true) -- this is called only while the transmitter | ||
| 88 | * is not hard-blocked, but note that the core's view of whether | ||
| 89 | * the transmitter is hard-blocked might differ from your driver's | ||
| 90 | * view due to race conditions, so it is possible that it is still | ||
| 91 | * called at the same time as you are calling rfkill_set_hw_state(). | ||
| 92 | * This callback must be assigned. | ||
| 93 | */ | ||
| 94 | struct rfkill_ops { | ||
| 95 | void (*poll)(struct rfkill *rfkill, void *data); | ||
| 96 | void (*query)(struct rfkill *rfkill, void *data); | ||
| 97 | int (*set_block)(void *data, bool blocked); | ||
| 53 | }; | 98 | }; |
| 54 | 99 | ||
| 100 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
| 55 | /** | 101 | /** |
| 56 | * struct rfkill - rfkill control structure. | 102 | * rfkill_alloc - allocate rfkill structure |
| 57 | * @name: Name of the switch. | 103 | * @name: name of the struct -- the string is not copied internally |
| 58 | * @type: Radio type which the button controls, the value stored | 104 | * @parent: device that has rf switch on it |
| 59 | * here should be a value from enum rfkill_type. | 105 | * @type: type of the switch (RFKILL_TYPE_*) |
| 60 | * @state: State of the switch, "UNBLOCKED" means radio can operate. | 106 | * @ops: rfkill methods |
| 61 | * @mutex: Guards switch state transitions. It serializes callbacks | 107 | * @ops_data: data passed to each method |
| 62 | * and also protects the state. | 108 | * |
| 63 | * @data: Pointer to the RF button drivers private data which will be | 109 | * This function should be called by the transmitter driver to allocate an |
| 64 | * passed along when toggling radio state. | 110 | * rfkill structure. Returns %NULL on failure. |
| 65 | * @toggle_radio(): Mandatory handler to control state of the radio. | ||
| 66 | * only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are | ||
| 67 | * valid parameters. | ||
| 68 | * @get_state(): handler to read current radio state from hardware, | ||
| 69 | * may be called from atomic context, should return 0 on success. | ||
| 70 | * Either this handler OR judicious use of rfkill_force_state() is | ||
| 71 | * MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED. | ||
| 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 | */ | 111 | */ |
| 79 | struct rfkill { | 112 | struct rfkill * __must_check rfkill_alloc(const char *name, |
| 80 | const char *name; | 113 | struct device *parent, |
| 81 | enum rfkill_type type; | 114 | const enum rfkill_type type, |
| 82 | 115 | const struct rfkill_ops *ops, | |
| 83 | /* the mutex serializes callbacks and also protects | 116 | void *ops_data); |
| 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 | 117 | ||
| 91 | #ifdef CONFIG_RFKILL_LEDS | 118 | /** |
| 92 | struct led_trigger led_trigger; | 119 | * rfkill_register - Register a rfkill structure. |
| 93 | #endif | 120 | * @rfkill: rfkill structure to be registered |
| 121 | * | ||
| 122 | * This function should be called by the transmitter driver to register | ||
| 123 | * the rfkill structure needs to be registered. Before calling this function | ||
| 124 | * the driver needs to be ready to service method calls from rfkill. | ||
| 125 | */ | ||
| 126 | int __must_check rfkill_register(struct rfkill *rfkill); | ||
| 94 | 127 | ||
| 95 | struct device dev; | 128 | /** |
| 96 | struct list_head node; | 129 | * rfkill_pause_polling(struct rfkill *rfkill) |
| 97 | enum rfkill_state state_for_resume; | 130 | * |
| 98 | }; | 131 | * Pause polling -- say transmitter is off for other reasons. |
| 99 | #define to_rfkill(d) container_of(d, struct rfkill, dev) | 132 | * NOTE: not necessary for suspend/resume -- in that case the |
| 133 | * core stops polling anyway | ||
| 134 | */ | ||
| 135 | void rfkill_pause_polling(struct rfkill *rfkill); | ||
| 100 | 136 | ||
| 101 | struct rfkill * __must_check rfkill_allocate(struct device *parent, | 137 | /** |
| 102 | enum rfkill_type type); | 138 | * rfkill_resume_polling(struct rfkill *rfkill) |
| 103 | void rfkill_free(struct rfkill *rfkill); | 139 | * |
| 104 | int __must_check rfkill_register(struct rfkill *rfkill); | 140 | * Pause polling -- say transmitter is off for other reasons. |
| 141 | * NOTE: not necessary for suspend/resume -- in that case the | ||
| 142 | * core stops polling anyway | ||
| 143 | */ | ||
| 144 | void rfkill_resume_polling(struct rfkill *rfkill); | ||
| 145 | |||
| 146 | |||
| 147 | /** | ||
| 148 | * rfkill_unregister - Unregister a rfkill structure. | ||
| 149 | * @rfkill: rfkill structure to be unregistered | ||
| 150 | * | ||
| 151 | * This function should be called by the network driver during device | ||
| 152 | * teardown to destroy rfkill structure. Until it returns, the driver | ||
| 153 | * needs to be able to service method calls. | ||
| 154 | */ | ||
| 105 | void rfkill_unregister(struct rfkill *rfkill); | 155 | void rfkill_unregister(struct rfkill *rfkill); |
| 106 | 156 | ||
| 107 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state); | 157 | /** |
| 108 | int rfkill_set_default(enum rfkill_type type, enum rfkill_state state); | 158 | * rfkill_destroy - free rfkill structure |
| 159 | * @rfkill: rfkill structure to be destroyed | ||
| 160 | * | ||
| 161 | * Destroys the rfkill structure. | ||
| 162 | */ | ||
| 163 | void rfkill_destroy(struct rfkill *rfkill); | ||
| 164 | |||
| 165 | /** | ||
| 166 | * rfkill_set_hw_state - Set the internal rfkill hardware block state | ||
| 167 | * @rfkill: pointer to the rfkill class to modify. | ||
| 168 | * @state: the current hardware block state to set | ||
| 169 | * | ||
| 170 | * rfkill drivers that get events when the hard-blocked state changes | ||
| 171 | * use this function to notify the rfkill core (and through that also | ||
| 172 | * userspace) of the current state -- they should also use this after | ||
| 173 | * resume if the state could have changed. | ||
| 174 | * | ||
| 175 | * You need not (but may) call this function if poll_state is assigned. | ||
| 176 | * | ||
| 177 | * This function can be called in any context, even from within rfkill | ||
| 178 | * callbacks. | ||
| 179 | * | ||
| 180 | * The function returns the combined block state (true if transmitter | ||
| 181 | * should be blocked) so that drivers need not keep track of the soft | ||
| 182 | * block state -- which they might not be able to. | ||
| 183 | */ | ||
| 184 | bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); | ||
| 185 | |||
| 186 | /** | ||
| 187 | * rfkill_set_sw_state - Set the internal rfkill software block state | ||
| 188 | * @rfkill: pointer to the rfkill class to modify. | ||
| 189 | * @state: the current software block state to set | ||
| 190 | * | ||
| 191 | * rfkill drivers that get events when the soft-blocked state changes | ||
| 192 | * (yes, some platforms directly act on input but allow changing again) | ||
| 193 | * use this function to notify the rfkill core (and through that also | ||
| 194 | * userspace) of the current state -- they should also use this after | ||
| 195 | * resume if the state could have changed. | ||
| 196 | * | ||
| 197 | * This function can be called in any context, even from within rfkill | ||
| 198 | * callbacks. | ||
| 199 | * | ||
| 200 | * The function returns the combined block state (true if transmitter | ||
| 201 | * should be blocked). | ||
| 202 | */ | ||
| 203 | bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); | ||
| 204 | |||
| 205 | /** | ||
| 206 | * rfkill_set_states - Set the internal rfkill block states | ||
| 207 | * @rfkill: pointer to the rfkill class to modify. | ||
| 208 | * @sw: the current software block state to set | ||
| 209 | * @hw: the current hardware block state to set | ||
| 210 | * | ||
| 211 | * This function can be called in any context, even from within rfkill | ||
| 212 | * callbacks. | ||
| 213 | */ | ||
| 214 | void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); | ||
| 109 | 215 | ||
| 110 | /** | 216 | /** |
| 111 | * rfkill_state_complement - return complementar state | 217 | * rfkill_set_global_sw_state - set global sw block default |
| 112 | * @state: state to return the complement of | 218 | * @type: rfkill type to set default for |
| 219 | * @blocked: default to set | ||
| 113 | * | 220 | * |
| 114 | * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED, | 221 | * This function sets the global default -- use at boot if your platform has |
| 115 | * returns RFKILL_STATE_UNBLOCKED otherwise. | 222 | * an rfkill switch. If not early enough this call may be ignored. |
| 223 | * | ||
| 224 | * XXX: instead of ignoring -- how about just updating all currently | ||
| 225 | * registered drivers? | ||
| 116 | */ | 226 | */ |
| 117 | static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state) | 227 | void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked); |
| 228 | #else /* !RFKILL */ | ||
| 229 | static inline struct rfkill * __must_check | ||
| 230 | rfkill_alloc(const char *name, | ||
| 231 | struct device *parent, | ||
| 232 | const enum rfkill_type type, | ||
| 233 | const struct rfkill_ops *ops, | ||
| 234 | void *ops_data) | ||
| 235 | { | ||
| 236 | return ERR_PTR(-ENODEV); | ||
| 237 | } | ||
| 238 | |||
| 239 | static inline int __must_check rfkill_register(struct rfkill *rfkill) | ||
| 240 | { | ||
| 241 | if (rfkill == ERR_PTR(-ENODEV)) | ||
| 242 | return 0; | ||
| 243 | return -EINVAL; | ||
| 244 | } | ||
| 245 | |||
| 246 | static inline void rfkill_pause_polling(struct rfkill *rfkill) | ||
| 247 | { | ||
| 248 | } | ||
| 249 | |||
| 250 | static inline void rfkill_resume_polling(struct rfkill *rfkill) | ||
| 251 | { | ||
| 252 | } | ||
| 253 | |||
| 254 | static inline void rfkill_unregister(struct rfkill *rfkill) | ||
| 255 | { | ||
| 256 | } | ||
| 257 | |||
| 258 | static inline void rfkill_destroy(struct rfkill *rfkill) | ||
| 259 | { | ||
| 260 | } | ||
| 261 | |||
| 262 | static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) | ||
| 263 | { | ||
| 264 | return blocked; | ||
| 265 | } | ||
| 266 | |||
| 267 | static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | ||
| 268 | { | ||
| 269 | return blocked; | ||
| 270 | } | ||
| 271 | |||
| 272 | static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) | ||
| 273 | { | ||
| 274 | } | ||
| 275 | |||
| 276 | static inline void rfkill_set_global_sw_state(const enum rfkill_type type, | ||
| 277 | bool blocked) | ||
| 118 | { | 278 | { |
| 119 | return (state == RFKILL_STATE_UNBLOCKED) ? | ||
| 120 | RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; | ||
| 121 | } | 279 | } |
| 280 | #endif /* RFKILL || RFKILL_MODULE */ | ||
| 281 | |||
| 122 | 282 | ||
| 283 | #ifdef CONFIG_RFKILL_LEDS | ||
| 123 | /** | 284 | /** |
| 124 | * rfkill_get_led_name - Get the LED trigger name for the button's LED. | 285 | * 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 | 286 | * This function might return a NULL pointer if registering of the |
| 126 | * LED trigger failed. | 287 | * LED trigger failed. Use this as "default_trigger" for the LED. |
| 127 | * Use this as "default_trigger" for the LED. | ||
| 128 | */ | 288 | */ |
| 129 | static inline char *rfkill_get_led_name(struct rfkill *rfkill) | 289 | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill); |
| 130 | { | 290 | |
| 131 | #ifdef CONFIG_RFKILL_LEDS | 291 | /** |
| 132 | return (char *)(rfkill->led_trigger.name); | 292 | * rfkill_set_led_trigger_name -- set the LED trigger name |
| 293 | * @rfkill: rfkill struct | ||
| 294 | * @name: LED trigger name | ||
| 295 | * | ||
| 296 | * This function sets the LED trigger name of the radio LED | ||
| 297 | * trigger that rfkill creates. It is optional, but if called | ||
| 298 | * must be called before rfkill_register() to be effective. | ||
| 299 | */ | ||
| 300 | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name); | ||
| 133 | #else | 301 | #else |
| 302 | static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||
| 303 | { | ||
| 134 | return NULL; | 304 | return NULL; |
| 135 | #endif | ||
| 136 | } | 305 | } |
| 137 | 306 | ||
| 307 | static inline void | ||
| 308 | rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||
| 309 | { | ||
| 310 | } | ||
| 311 | #endif | ||
| 312 | |||
| 313 | #endif /* __KERNEL__ */ | ||
| 314 | |||
| 138 | #endif /* RFKILL_H */ | 315 | #endif /* RFKILL_H */ |
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/rfkill/Kconfig b/net/rfkill/Kconfig index 7f807b30cfbb..b47f72fae05d 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 | ||
| 22 | depends on RFKILL | ||
| 23 | depends on INPUT = y || RFKILL = INPUT | ||
| 24 | default y | ||
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..30a6f8d819b2 --- /dev/null +++ b/net/rfkill/core.c | |||
| @@ -0,0 +1,896 @@ | |||
| 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 | |||
| 32 | #include "rfkill.h" | ||
| 33 | |||
| 34 | #define POLL_INTERVAL (5 * HZ) | ||
| 35 | |||
| 36 | #define RFKILL_BLOCK_HW BIT(0) | ||
| 37 | #define RFKILL_BLOCK_SW BIT(1) | ||
| 38 | #define RFKILL_BLOCK_SW_PREV BIT(2) | ||
| 39 | #define RFKILL_BLOCK_ANY (RFKILL_BLOCK_HW |\ | ||
| 40 | RFKILL_BLOCK_SW |\ | ||
| 41 | RFKILL_BLOCK_SW_PREV) | ||
| 42 | #define RFKILL_BLOCK_SW_SETCALL BIT(31) | ||
| 43 | |||
| 44 | struct rfkill { | ||
| 45 | spinlock_t lock; | ||
| 46 | |||
| 47 | const char *name; | ||
| 48 | enum rfkill_type type; | ||
| 49 | |||
| 50 | unsigned long state; | ||
| 51 | |||
| 52 | bool registered; | ||
| 53 | bool suspended; | ||
| 54 | |||
| 55 | const struct rfkill_ops *ops; | ||
| 56 | void *data; | ||
| 57 | |||
| 58 | #ifdef CONFIG_RFKILL_LEDS | ||
| 59 | struct led_trigger led_trigger; | ||
| 60 | const char *ledtrigname; | ||
| 61 | #endif | ||
| 62 | |||
| 63 | struct device dev; | ||
| 64 | struct list_head node; | ||
| 65 | |||
| 66 | struct delayed_work poll_work; | ||
| 67 | struct work_struct uevent_work; | ||
| 68 | struct work_struct sync_work; | ||
| 69 | }; | ||
| 70 | #define to_rfkill(d) container_of(d, struct rfkill, dev) | ||
| 71 | |||
| 72 | |||
| 73 | |||
| 74 | MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>"); | ||
| 75 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 76 | MODULE_DESCRIPTION("RF switch support"); | ||
| 77 | MODULE_LICENSE("GPL"); | ||
| 78 | |||
| 79 | |||
| 80 | /* | ||
| 81 | * The locking here should be made much smarter, we currently have | ||
| 82 | * a bit of a stupid situation because drivers might want to register | ||
| 83 | * the rfkill struct under their own lock, and take this lock during | ||
| 84 | * rfkill method calls -- which will cause an AB-BA deadlock situation. | ||
| 85 | * | ||
| 86 | * To fix that, we need to rework this code here to be mostly lock-free | ||
| 87 | * and only use the mutex for list manipulations, not to protect the | ||
| 88 | * various other global variables. Then we can avoid holding the mutex | ||
| 89 | * around driver operations, and all is happy. | ||
| 90 | */ | ||
| 91 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | ||
| 92 | static DEFINE_MUTEX(rfkill_global_mutex); | ||
| 93 | |||
| 94 | static unsigned int rfkill_default_state = 1; | ||
| 95 | module_param_named(default_state, rfkill_default_state, uint, 0444); | ||
| 96 | MODULE_PARM_DESC(default_state, | ||
| 97 | "Default initial state for all radio types, 0 = radio off"); | ||
| 98 | |||
| 99 | static struct { | ||
| 100 | bool cur, def; | ||
| 101 | } rfkill_global_states[NUM_RFKILL_TYPES]; | ||
| 102 | |||
| 103 | static unsigned long rfkill_states_default_locked; | ||
| 104 | |||
| 105 | static bool rfkill_epo_lock_active; | ||
| 106 | |||
| 107 | |||
| 108 | #ifdef CONFIG_RFKILL_LEDS | ||
| 109 | static void rfkill_led_trigger_event(struct rfkill *rfkill) | ||
| 110 | { | ||
| 111 | struct led_trigger *trigger; | ||
| 112 | |||
| 113 | if (!rfkill->registered) | ||
| 114 | return; | ||
| 115 | |||
| 116 | trigger = &rfkill->led_trigger; | ||
| 117 | |||
| 118 | if (rfkill->state & RFKILL_BLOCK_ANY) | ||
| 119 | led_trigger_event(trigger, LED_OFF); | ||
| 120 | else | ||
| 121 | led_trigger_event(trigger, LED_FULL); | ||
| 122 | } | ||
| 123 | |||
| 124 | static void rfkill_led_trigger_activate(struct led_classdev *led) | ||
| 125 | { | ||
| 126 | struct rfkill *rfkill; | ||
| 127 | |||
| 128 | rfkill = container_of(led->trigger, struct rfkill, led_trigger); | ||
| 129 | |||
| 130 | rfkill_led_trigger_event(rfkill); | ||
| 131 | } | ||
| 132 | |||
| 133 | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||
| 134 | { | ||
| 135 | return rfkill->led_trigger.name; | ||
| 136 | } | ||
| 137 | EXPORT_SYMBOL(rfkill_get_led_trigger_name); | ||
| 138 | |||
| 139 | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||
| 140 | { | ||
| 141 | BUG_ON(!rfkill); | ||
| 142 | |||
| 143 | rfkill->ledtrigname = name; | ||
| 144 | } | ||
| 145 | EXPORT_SYMBOL(rfkill_set_led_trigger_name); | ||
| 146 | |||
| 147 | static int rfkill_led_trigger_register(struct rfkill *rfkill) | ||
| 148 | { | ||
| 149 | rfkill->led_trigger.name = rfkill->ledtrigname | ||
| 150 | ? : dev_name(&rfkill->dev); | ||
| 151 | rfkill->led_trigger.activate = rfkill_led_trigger_activate; | ||
| 152 | return led_trigger_register(&rfkill->led_trigger); | ||
| 153 | } | ||
| 154 | |||
| 155 | static void rfkill_led_trigger_unregister(struct rfkill *rfkill) | ||
| 156 | { | ||
| 157 | led_trigger_unregister(&rfkill->led_trigger); | ||
| 158 | } | ||
| 159 | #else | ||
| 160 | static void rfkill_led_trigger_event(struct rfkill *rfkill) | ||
| 161 | { | ||
| 162 | } | ||
| 163 | |||
| 164 | static inline int rfkill_led_trigger_register(struct rfkill *rfkill) | ||
| 165 | { | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill) | ||
| 170 | { | ||
| 171 | } | ||
| 172 | #endif /* CONFIG_RFKILL_LEDS */ | ||
| 173 | |||
| 174 | static void rfkill_uevent(struct rfkill *rfkill) | ||
| 175 | { | ||
| 176 | if (!rfkill->registered || rfkill->suspended) | ||
| 177 | return; | ||
| 178 | |||
| 179 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); | ||
| 180 | } | ||
| 181 | |||
| 182 | static bool __rfkill_set_hw_state(struct rfkill *rfkill, | ||
| 183 | bool blocked, bool *change) | ||
| 184 | { | ||
| 185 | unsigned long flags; | ||
| 186 | bool prev, any; | ||
| 187 | |||
| 188 | BUG_ON(!rfkill); | ||
| 189 | |||
| 190 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 191 | prev = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
| 192 | if (blocked) | ||
| 193 | rfkill->state |= RFKILL_BLOCK_HW; | ||
| 194 | else | ||
| 195 | rfkill->state &= ~RFKILL_BLOCK_HW; | ||
| 196 | *change = prev != blocked; | ||
| 197 | any = rfkill->state & RFKILL_BLOCK_ANY; | ||
| 198 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 199 | |||
| 200 | rfkill_led_trigger_event(rfkill); | ||
| 201 | |||
| 202 | return any; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * rfkill_set_block - wrapper for set_block method | ||
| 207 | * | ||
| 208 | * @rfkill: the rfkill struct to use | ||
| 209 | * @blocked: the new software state | ||
| 210 | * | ||
| 211 | * Calls the set_block method (when applicable) and handles notifications | ||
| 212 | * etc. as well. | ||
| 213 | */ | ||
| 214 | static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | ||
| 215 | { | ||
| 216 | unsigned long flags; | ||
| 217 | int err; | ||
| 218 | |||
| 219 | /* | ||
| 220 | * Some platforms (...!) generate input events which affect the | ||
| 221 | * _hard_ kill state -- whenever something tries to change the | ||
| 222 | * current software state query the hardware state too. | ||
| 223 | */ | ||
| 224 | if (rfkill->ops->query) | ||
| 225 | rfkill->ops->query(rfkill, rfkill->data); | ||
| 226 | |||
| 227 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 228 | if (rfkill->state & RFKILL_BLOCK_SW) | ||
| 229 | rfkill->state |= RFKILL_BLOCK_SW_PREV; | ||
| 230 | else | ||
| 231 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | ||
| 232 | |||
| 233 | if (blocked) | ||
| 234 | rfkill->state |= RFKILL_BLOCK_SW; | ||
| 235 | else | ||
| 236 | rfkill->state &= ~RFKILL_BLOCK_SW; | ||
| 237 | |||
| 238 | rfkill->state |= RFKILL_BLOCK_SW_SETCALL; | ||
| 239 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 240 | |||
| 241 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | ||
| 242 | return; | ||
| 243 | |||
| 244 | err = rfkill->ops->set_block(rfkill->data, blocked); | ||
| 245 | |||
| 246 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 247 | if (err) { | ||
| 248 | /* | ||
| 249 | * Failed -- reset status to _prev, this may be different | ||
| 250 | * from what set set _PREV to earlier in this function | ||
| 251 | * if rfkill_set_sw_state was invoked. | ||
| 252 | */ | ||
| 253 | if (rfkill->state & RFKILL_BLOCK_SW_PREV) | ||
| 254 | rfkill->state |= RFKILL_BLOCK_SW; | ||
| 255 | else | ||
| 256 | rfkill->state &= ~RFKILL_BLOCK_SW; | ||
| 257 | } | ||
| 258 | rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; | ||
| 259 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | ||
| 260 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 261 | |||
| 262 | rfkill_led_trigger_event(rfkill); | ||
| 263 | rfkill_uevent(rfkill); | ||
| 264 | } | ||
| 265 | |||
| 266 | /** | ||
| 267 | * __rfkill_switch_all - Toggle state of all switches of given type | ||
| 268 | * @type: type of interfaces to be affected | ||
| 269 | * @state: the new state | ||
| 270 | * | ||
| 271 | * This function sets the state of all switches of given type, | ||
| 272 | * unless a specific switch is claimed by userspace (in which case, | ||
| 273 | * that switch is left alone) or suspended. | ||
| 274 | * | ||
| 275 | * Caller must have acquired rfkill_global_mutex. | ||
| 276 | */ | ||
| 277 | static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) | ||
| 278 | { | ||
| 279 | struct rfkill *rfkill; | ||
| 280 | |||
| 281 | rfkill_global_states[type].cur = blocked; | ||
| 282 | list_for_each_entry(rfkill, &rfkill_list, node) { | ||
| 283 | if (rfkill->type != type) | ||
| 284 | continue; | ||
| 285 | |||
| 286 | rfkill_set_block(rfkill, blocked); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | /** | ||
| 291 | * rfkill_switch_all - Toggle state of all switches of given type | ||
| 292 | * @type: type of interfaces to be affected | ||
| 293 | * @state: the new state | ||
| 294 | * | ||
| 295 | * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). | ||
| 296 | * Please refer to __rfkill_switch_all() for details. | ||
| 297 | * | ||
| 298 | * Does nothing if the EPO lock is active. | ||
| 299 | */ | ||
| 300 | void rfkill_switch_all(enum rfkill_type type, bool blocked) | ||
| 301 | { | ||
| 302 | mutex_lock(&rfkill_global_mutex); | ||
| 303 | |||
| 304 | if (!rfkill_epo_lock_active) | ||
| 305 | __rfkill_switch_all(type, blocked); | ||
| 306 | |||
| 307 | mutex_unlock(&rfkill_global_mutex); | ||
| 308 | } | ||
| 309 | |||
| 310 | /** | ||
| 311 | * rfkill_epo - emergency power off all transmitters | ||
| 312 | * | ||
| 313 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, | ||
| 314 | * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. | ||
| 315 | * | ||
| 316 | * The global state before the EPO is saved and can be restored later | ||
| 317 | * using rfkill_restore_states(). | ||
| 318 | */ | ||
| 319 | void rfkill_epo(void) | ||
| 320 | { | ||
| 321 | struct rfkill *rfkill; | ||
| 322 | int i; | ||
| 323 | |||
| 324 | mutex_lock(&rfkill_global_mutex); | ||
| 325 | |||
| 326 | rfkill_epo_lock_active = true; | ||
| 327 | list_for_each_entry(rfkill, &rfkill_list, node) | ||
| 328 | rfkill_set_block(rfkill, true); | ||
| 329 | |||
| 330 | for (i = 0; i < NUM_RFKILL_TYPES; i++) { | ||
| 331 | rfkill_global_states[i].def = rfkill_global_states[i].cur; | ||
| 332 | rfkill_global_states[i].cur = true; | ||
| 333 | } | ||
| 334 | mutex_unlock(&rfkill_global_mutex); | ||
| 335 | } | ||
| 336 | |||
| 337 | /** | ||
| 338 | * rfkill_restore_states - restore global states | ||
| 339 | * | ||
| 340 | * Restore (and sync switches to) the global state from the | ||
| 341 | * states in rfkill_default_states. This can undo the effects of | ||
| 342 | * a call to rfkill_epo(). | ||
| 343 | */ | ||
| 344 | void rfkill_restore_states(void) | ||
| 345 | { | ||
| 346 | int i; | ||
| 347 | |||
| 348 | mutex_lock(&rfkill_global_mutex); | ||
| 349 | |||
| 350 | rfkill_epo_lock_active = false; | ||
| 351 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
| 352 | __rfkill_switch_all(i, rfkill_global_states[i].def); | ||
| 353 | mutex_unlock(&rfkill_global_mutex); | ||
| 354 | } | ||
| 355 | |||
| 356 | /** | ||
| 357 | * rfkill_remove_epo_lock - unlock state changes | ||
| 358 | * | ||
| 359 | * Used by rfkill-input manually unlock state changes, when | ||
| 360 | * the EPO switch is deactivated. | ||
| 361 | */ | ||
| 362 | void rfkill_remove_epo_lock(void) | ||
| 363 | { | ||
| 364 | mutex_lock(&rfkill_global_mutex); | ||
| 365 | rfkill_epo_lock_active = false; | ||
| 366 | mutex_unlock(&rfkill_global_mutex); | ||
| 367 | } | ||
| 368 | |||
| 369 | /** | ||
| 370 | * rfkill_is_epo_lock_active - returns true EPO is active | ||
| 371 | * | ||
| 372 | * Returns 0 (false) if there is NOT an active EPO contidion, | ||
| 373 | * and 1 (true) if there is an active EPO contition, which | ||
| 374 | * locks all radios in one of the BLOCKED states. | ||
| 375 | * | ||
| 376 | * Can be called in atomic context. | ||
| 377 | */ | ||
| 378 | bool rfkill_is_epo_lock_active(void) | ||
| 379 | { | ||
| 380 | return rfkill_epo_lock_active; | ||
| 381 | } | ||
| 382 | |||
| 383 | /** | ||
| 384 | * rfkill_get_global_sw_state - returns global state for a type | ||
| 385 | * @type: the type to get the global state of | ||
| 386 | * | ||
| 387 | * Returns the current global state for a given wireless | ||
| 388 | * device type. | ||
| 389 | */ | ||
| 390 | bool rfkill_get_global_sw_state(const enum rfkill_type type) | ||
| 391 | { | ||
| 392 | return rfkill_global_states[type].cur; | ||
| 393 | } | ||
| 394 | |||
| 395 | void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) | ||
| 396 | { | ||
| 397 | mutex_lock(&rfkill_global_mutex); | ||
| 398 | |||
| 399 | /* don't allow unblock when epo */ | ||
| 400 | if (rfkill_epo_lock_active && !blocked) | ||
| 401 | goto out; | ||
| 402 | |||
| 403 | /* too late */ | ||
| 404 | if (rfkill_states_default_locked & BIT(type)) | ||
| 405 | goto out; | ||
| 406 | |||
| 407 | rfkill_states_default_locked |= BIT(type); | ||
| 408 | |||
| 409 | rfkill_global_states[type].cur = blocked; | ||
| 410 | rfkill_global_states[type].def = blocked; | ||
| 411 | out: | ||
| 412 | mutex_unlock(&rfkill_global_mutex); | ||
| 413 | } | ||
| 414 | EXPORT_SYMBOL(rfkill_set_global_sw_state); | ||
| 415 | |||
| 416 | |||
| 417 | bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) | ||
| 418 | { | ||
| 419 | bool ret, change; | ||
| 420 | |||
| 421 | ret = __rfkill_set_hw_state(rfkill, blocked, &change); | ||
| 422 | |||
| 423 | if (!rfkill->registered) | ||
| 424 | return ret; | ||
| 425 | |||
| 426 | if (change) | ||
| 427 | schedule_work(&rfkill->uevent_work); | ||
| 428 | |||
| 429 | return ret; | ||
| 430 | } | ||
| 431 | EXPORT_SYMBOL(rfkill_set_hw_state); | ||
| 432 | |||
| 433 | static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | ||
| 434 | { | ||
| 435 | u32 bit = RFKILL_BLOCK_SW; | ||
| 436 | |||
| 437 | /* if in a ops->set_block right now, use other bit */ | ||
| 438 | if (rfkill->state & RFKILL_BLOCK_SW_SETCALL) | ||
| 439 | bit = RFKILL_BLOCK_SW_PREV; | ||
| 440 | |||
| 441 | if (blocked) | ||
| 442 | rfkill->state |= bit; | ||
| 443 | else | ||
| 444 | rfkill->state &= ~bit; | ||
| 445 | } | ||
| 446 | |||
| 447 | bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | ||
| 448 | { | ||
| 449 | unsigned long flags; | ||
| 450 | bool prev, hwblock; | ||
| 451 | |||
| 452 | BUG_ON(!rfkill); | ||
| 453 | |||
| 454 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 455 | prev = !!(rfkill->state & RFKILL_BLOCK_SW); | ||
| 456 | __rfkill_set_sw_state(rfkill, blocked); | ||
| 457 | hwblock = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
| 458 | blocked = blocked || hwblock; | ||
| 459 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 460 | |||
| 461 | if (!rfkill->registered) | ||
| 462 | return blocked; | ||
| 463 | |||
| 464 | if (prev != blocked && !hwblock) | ||
| 465 | schedule_work(&rfkill->uevent_work); | ||
| 466 | |||
| 467 | rfkill_led_trigger_event(rfkill); | ||
| 468 | |||
| 469 | return blocked; | ||
| 470 | } | ||
| 471 | EXPORT_SYMBOL(rfkill_set_sw_state); | ||
| 472 | |||
| 473 | void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) | ||
| 474 | { | ||
| 475 | unsigned long flags; | ||
| 476 | bool swprev, hwprev; | ||
| 477 | |||
| 478 | BUG_ON(!rfkill); | ||
| 479 | |||
| 480 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 481 | |||
| 482 | /* | ||
| 483 | * No need to care about prev/setblock ... this is for uevent only | ||
| 484 | * and that will get triggered by rfkill_set_block anyway. | ||
| 485 | */ | ||
| 486 | swprev = !!(rfkill->state & RFKILL_BLOCK_SW); | ||
| 487 | hwprev = !!(rfkill->state & RFKILL_BLOCK_HW); | ||
| 488 | __rfkill_set_sw_state(rfkill, sw); | ||
| 489 | |||
| 490 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 491 | |||
| 492 | if (!rfkill->registered) | ||
| 493 | return; | ||
| 494 | |||
| 495 | if (swprev != sw || hwprev != hw) | ||
| 496 | schedule_work(&rfkill->uevent_work); | ||
| 497 | |||
| 498 | rfkill_led_trigger_event(rfkill); | ||
| 499 | } | ||
| 500 | EXPORT_SYMBOL(rfkill_set_states); | ||
| 501 | |||
| 502 | static ssize_t rfkill_name_show(struct device *dev, | ||
| 503 | struct device_attribute *attr, | ||
| 504 | char *buf) | ||
| 505 | { | ||
| 506 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 507 | |||
| 508 | return sprintf(buf, "%s\n", rfkill->name); | ||
| 509 | } | ||
| 510 | |||
| 511 | static const char *rfkill_get_type_str(enum rfkill_type type) | ||
| 512 | { | ||
| 513 | switch (type) { | ||
| 514 | case RFKILL_TYPE_WLAN: | ||
| 515 | return "wlan"; | ||
| 516 | case RFKILL_TYPE_BLUETOOTH: | ||
| 517 | return "bluetooth"; | ||
| 518 | case RFKILL_TYPE_UWB: | ||
| 519 | return "ultrawideband"; | ||
| 520 | case RFKILL_TYPE_WIMAX: | ||
| 521 | return "wimax"; | ||
| 522 | case RFKILL_TYPE_WWAN: | ||
| 523 | return "wwan"; | ||
| 524 | default: | ||
| 525 | BUG(); | ||
| 526 | } | ||
| 527 | |||
| 528 | BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1); | ||
| 529 | } | ||
| 530 | |||
| 531 | static ssize_t rfkill_type_show(struct device *dev, | ||
| 532 | struct device_attribute *attr, | ||
| 533 | char *buf) | ||
| 534 | { | ||
| 535 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 536 | |||
| 537 | return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); | ||
| 538 | } | ||
| 539 | |||
| 540 | static u8 user_state_from_blocked(unsigned long state) | ||
| 541 | { | ||
| 542 | if (state & RFKILL_BLOCK_HW) | ||
| 543 | return RFKILL_USER_STATE_HARD_BLOCKED; | ||
| 544 | if (state & RFKILL_BLOCK_SW) | ||
| 545 | return RFKILL_USER_STATE_SOFT_BLOCKED; | ||
| 546 | |||
| 547 | return RFKILL_USER_STATE_UNBLOCKED; | ||
| 548 | } | ||
| 549 | |||
| 550 | static ssize_t rfkill_state_show(struct device *dev, | ||
| 551 | struct device_attribute *attr, | ||
| 552 | char *buf) | ||
| 553 | { | ||
| 554 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 555 | unsigned long flags; | ||
| 556 | u32 state; | ||
| 557 | |||
| 558 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 559 | state = rfkill->state; | ||
| 560 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 561 | |||
| 562 | return sprintf(buf, "%d\n", user_state_from_blocked(state)); | ||
| 563 | } | ||
| 564 | |||
| 565 | static ssize_t rfkill_state_store(struct device *dev, | ||
| 566 | struct device_attribute *attr, | ||
| 567 | const char *buf, size_t count) | ||
| 568 | { | ||
| 569 | /* | ||
| 570 | * The intention was that userspace can only take control over | ||
| 571 | * a given device when/if rfkill-input doesn't control it due | ||
| 572 | * to user_claim. Since user_claim is currently unsupported, | ||
| 573 | * we never support changing the state from userspace -- this | ||
| 574 | * can be implemented again later. | ||
| 575 | */ | ||
| 576 | |||
| 577 | return -EPERM; | ||
| 578 | } | ||
| 579 | |||
| 580 | static ssize_t rfkill_claim_show(struct device *dev, | ||
| 581 | struct device_attribute *attr, | ||
| 582 | char *buf) | ||
| 583 | { | ||
| 584 | return sprintf(buf, "%d\n", 0); | ||
| 585 | } | ||
| 586 | |||
| 587 | static ssize_t rfkill_claim_store(struct device *dev, | ||
| 588 | struct device_attribute *attr, | ||
| 589 | const char *buf, size_t count) | ||
| 590 | { | ||
| 591 | return -EOPNOTSUPP; | ||
| 592 | } | ||
| 593 | |||
| 594 | static struct device_attribute rfkill_dev_attrs[] = { | ||
| 595 | __ATTR(name, S_IRUGO, rfkill_name_show, NULL), | ||
| 596 | __ATTR(type, S_IRUGO, rfkill_type_show, NULL), | ||
| 597 | __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), | ||
| 598 | __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), | ||
| 599 | __ATTR_NULL | ||
| 600 | }; | ||
| 601 | |||
| 602 | static void rfkill_release(struct device *dev) | ||
| 603 | { | ||
| 604 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 605 | |||
| 606 | kfree(rfkill); | ||
| 607 | } | ||
| 608 | |||
| 609 | static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 610 | { | ||
| 611 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 612 | unsigned long flags; | ||
| 613 | u32 state; | ||
| 614 | int error; | ||
| 615 | |||
| 616 | error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); | ||
| 617 | if (error) | ||
| 618 | return error; | ||
| 619 | error = add_uevent_var(env, "RFKILL_TYPE=%s", | ||
| 620 | rfkill_get_type_str(rfkill->type)); | ||
| 621 | if (error) | ||
| 622 | return error; | ||
| 623 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 624 | state = rfkill->state; | ||
| 625 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 626 | error = add_uevent_var(env, "RFKILL_STATE=%d", | ||
| 627 | user_state_from_blocked(state)); | ||
| 628 | return error; | ||
| 629 | } | ||
| 630 | |||
| 631 | void rfkill_pause_polling(struct rfkill *rfkill) | ||
| 632 | { | ||
| 633 | BUG_ON(!rfkill); | ||
| 634 | |||
| 635 | if (!rfkill->ops->poll) | ||
| 636 | return; | ||
| 637 | |||
| 638 | cancel_delayed_work_sync(&rfkill->poll_work); | ||
| 639 | } | ||
| 640 | EXPORT_SYMBOL(rfkill_pause_polling); | ||
| 641 | |||
| 642 | void rfkill_resume_polling(struct rfkill *rfkill) | ||
| 643 | { | ||
| 644 | BUG_ON(!rfkill); | ||
| 645 | |||
| 646 | if (!rfkill->ops->poll) | ||
| 647 | return; | ||
| 648 | |||
| 649 | schedule_work(&rfkill->poll_work.work); | ||
| 650 | } | ||
| 651 | EXPORT_SYMBOL(rfkill_resume_polling); | ||
| 652 | |||
| 653 | static int rfkill_suspend(struct device *dev, pm_message_t state) | ||
| 654 | { | ||
| 655 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 656 | |||
| 657 | rfkill_pause_polling(rfkill); | ||
| 658 | |||
| 659 | rfkill->suspended = true; | ||
| 660 | |||
| 661 | return 0; | ||
| 662 | } | ||
| 663 | |||
| 664 | static int rfkill_resume(struct device *dev) | ||
| 665 | { | ||
| 666 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 667 | bool cur; | ||
| 668 | |||
| 669 | mutex_lock(&rfkill_global_mutex); | ||
| 670 | cur = rfkill_global_states[rfkill->type].cur; | ||
| 671 | rfkill_set_block(rfkill, cur); | ||
| 672 | mutex_unlock(&rfkill_global_mutex); | ||
| 673 | |||
| 674 | rfkill->suspended = false; | ||
| 675 | |||
| 676 | schedule_work(&rfkill->uevent_work); | ||
| 677 | |||
| 678 | rfkill_resume_polling(rfkill); | ||
| 679 | |||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | |||
| 683 | static struct class rfkill_class = { | ||
| 684 | .name = "rfkill", | ||
| 685 | .dev_release = rfkill_release, | ||
| 686 | .dev_attrs = rfkill_dev_attrs, | ||
| 687 | .dev_uevent = rfkill_dev_uevent, | ||
| 688 | .suspend = rfkill_suspend, | ||
| 689 | .resume = rfkill_resume, | ||
| 690 | }; | ||
| 691 | |||
| 692 | |||
| 693 | struct rfkill * __must_check rfkill_alloc(const char *name, | ||
| 694 | struct device *parent, | ||
| 695 | const enum rfkill_type type, | ||
| 696 | const struct rfkill_ops *ops, | ||
| 697 | void *ops_data) | ||
| 698 | { | ||
| 699 | struct rfkill *rfkill; | ||
| 700 | struct device *dev; | ||
| 701 | |||
| 702 | if (WARN_ON(!ops)) | ||
| 703 | return NULL; | ||
| 704 | |||
| 705 | if (WARN_ON(!ops->set_block)) | ||
| 706 | return NULL; | ||
| 707 | |||
| 708 | if (WARN_ON(!name)) | ||
| 709 | return NULL; | ||
| 710 | |||
| 711 | if (WARN_ON(type >= NUM_RFKILL_TYPES)) | ||
| 712 | return NULL; | ||
| 713 | |||
| 714 | rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); | ||
| 715 | if (!rfkill) | ||
| 716 | return NULL; | ||
| 717 | |||
| 718 | spin_lock_init(&rfkill->lock); | ||
| 719 | INIT_LIST_HEAD(&rfkill->node); | ||
| 720 | rfkill->type = type; | ||
| 721 | rfkill->name = name; | ||
| 722 | rfkill->ops = ops; | ||
| 723 | rfkill->data = ops_data; | ||
| 724 | |||
| 725 | dev = &rfkill->dev; | ||
| 726 | dev->class = &rfkill_class; | ||
| 727 | dev->parent = parent; | ||
| 728 | device_initialize(dev); | ||
| 729 | |||
| 730 | return rfkill; | ||
| 731 | } | ||
| 732 | EXPORT_SYMBOL(rfkill_alloc); | ||
| 733 | |||
| 734 | static void rfkill_poll(struct work_struct *work) | ||
| 735 | { | ||
| 736 | struct rfkill *rfkill; | ||
| 737 | |||
| 738 | rfkill = container_of(work, struct rfkill, poll_work.work); | ||
| 739 | |||
| 740 | /* | ||
| 741 | * Poll hardware state -- driver will use one of the | ||
| 742 | * rfkill_set{,_hw,_sw}_state functions and use its | ||
| 743 | * return value to update the current status. | ||
| 744 | */ | ||
| 745 | rfkill->ops->poll(rfkill, rfkill->data); | ||
| 746 | |||
| 747 | schedule_delayed_work(&rfkill->poll_work, | ||
| 748 | round_jiffies_relative(POLL_INTERVAL)); | ||
| 749 | } | ||
| 750 | |||
| 751 | static void rfkill_uevent_work(struct work_struct *work) | ||
| 752 | { | ||
| 753 | struct rfkill *rfkill; | ||
| 754 | |||
| 755 | rfkill = container_of(work, struct rfkill, uevent_work); | ||
| 756 | |||
| 757 | rfkill_uevent(rfkill); | ||
| 758 | } | ||
| 759 | |||
| 760 | static void rfkill_sync_work(struct work_struct *work) | ||
| 761 | { | ||
| 762 | struct rfkill *rfkill; | ||
| 763 | bool cur; | ||
| 764 | |||
| 765 | rfkill = container_of(work, struct rfkill, sync_work); | ||
| 766 | |||
| 767 | mutex_lock(&rfkill_global_mutex); | ||
| 768 | cur = rfkill_global_states[rfkill->type].cur; | ||
| 769 | rfkill_set_block(rfkill, cur); | ||
| 770 | mutex_unlock(&rfkill_global_mutex); | ||
| 771 | } | ||
| 772 | |||
| 773 | int __must_check rfkill_register(struct rfkill *rfkill) | ||
| 774 | { | ||
| 775 | static unsigned long rfkill_no; | ||
| 776 | struct device *dev = &rfkill->dev; | ||
| 777 | int error; | ||
| 778 | |||
| 779 | BUG_ON(!rfkill); | ||
| 780 | |||
| 781 | mutex_lock(&rfkill_global_mutex); | ||
| 782 | |||
| 783 | if (rfkill->registered) { | ||
| 784 | error = -EALREADY; | ||
| 785 | goto unlock; | ||
| 786 | } | ||
| 787 | |||
| 788 | dev_set_name(dev, "rfkill%lu", rfkill_no); | ||
| 789 | rfkill_no++; | ||
| 790 | |||
| 791 | if (!(rfkill_states_default_locked & BIT(rfkill->type))) { | ||
| 792 | /* first of its kind */ | ||
| 793 | BUILD_BUG_ON(NUM_RFKILL_TYPES > | ||
| 794 | sizeof(rfkill_states_default_locked) * 8); | ||
| 795 | rfkill_states_default_locked |= BIT(rfkill->type); | ||
| 796 | rfkill_global_states[rfkill->type].cur = | ||
| 797 | rfkill_global_states[rfkill->type].def; | ||
| 798 | } | ||
| 799 | |||
| 800 | list_add_tail(&rfkill->node, &rfkill_list); | ||
| 801 | |||
| 802 | error = device_add(dev); | ||
| 803 | if (error) | ||
| 804 | goto remove; | ||
| 805 | |||
| 806 | error = rfkill_led_trigger_register(rfkill); | ||
| 807 | if (error) | ||
| 808 | goto devdel; | ||
| 809 | |||
| 810 | rfkill->registered = true; | ||
| 811 | |||
| 812 | if (rfkill->ops->poll) { | ||
| 813 | INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); | ||
| 814 | schedule_delayed_work(&rfkill->poll_work, | ||
| 815 | round_jiffies_relative(POLL_INTERVAL)); | ||
| 816 | } | ||
| 817 | |||
| 818 | INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); | ||
| 819 | |||
| 820 | INIT_WORK(&rfkill->sync_work, rfkill_sync_work); | ||
| 821 | schedule_work(&rfkill->sync_work); | ||
| 822 | |||
| 823 | mutex_unlock(&rfkill_global_mutex); | ||
| 824 | return 0; | ||
| 825 | |||
| 826 | devdel: | ||
| 827 | device_del(&rfkill->dev); | ||
| 828 | remove: | ||
| 829 | list_del_init(&rfkill->node); | ||
| 830 | unlock: | ||
| 831 | mutex_unlock(&rfkill_global_mutex); | ||
| 832 | return error; | ||
| 833 | } | ||
| 834 | EXPORT_SYMBOL(rfkill_register); | ||
| 835 | |||
| 836 | void rfkill_unregister(struct rfkill *rfkill) | ||
| 837 | { | ||
| 838 | BUG_ON(!rfkill); | ||
| 839 | |||
| 840 | if (rfkill->ops->poll) | ||
| 841 | cancel_delayed_work_sync(&rfkill->poll_work); | ||
| 842 | |||
| 843 | cancel_work_sync(&rfkill->uevent_work); | ||
| 844 | cancel_work_sync(&rfkill->sync_work); | ||
| 845 | |||
| 846 | rfkill->registered = false; | ||
| 847 | |||
| 848 | device_del(&rfkill->dev); | ||
| 849 | |||
| 850 | mutex_lock(&rfkill_global_mutex); | ||
| 851 | list_del_init(&rfkill->node); | ||
| 852 | mutex_unlock(&rfkill_global_mutex); | ||
| 853 | |||
| 854 | rfkill_led_trigger_unregister(rfkill); | ||
| 855 | } | ||
| 856 | EXPORT_SYMBOL(rfkill_unregister); | ||
| 857 | |||
| 858 | void rfkill_destroy(struct rfkill *rfkill) | ||
| 859 | { | ||
| 860 | if (rfkill) | ||
| 861 | put_device(&rfkill->dev); | ||
| 862 | } | ||
| 863 | EXPORT_SYMBOL(rfkill_destroy); | ||
| 864 | |||
| 865 | |||
| 866 | static int __init rfkill_init(void) | ||
| 867 | { | ||
| 868 | int error; | ||
| 869 | int i; | ||
| 870 | |||
| 871 | for (i = 0; i < NUM_RFKILL_TYPES; i++) | ||
| 872 | rfkill_global_states[i].def = !rfkill_default_state; | ||
| 873 | |||
| 874 | error = class_register(&rfkill_class); | ||
| 875 | if (error) | ||
| 876 | goto out; | ||
| 877 | |||
| 878 | #ifdef CONFIG_RFKILL_INPUT | ||
| 879 | error = rfkill_handler_init(); | ||
| 880 | if (error) | ||
| 881 | class_unregister(&rfkill_class); | ||
| 882 | #endif | ||
| 883 | |||
| 884 | out: | ||
| 885 | return error; | ||
| 886 | } | ||
| 887 | subsys_initcall(rfkill_init); | ||
| 888 | |||
| 889 | static void __exit rfkill_exit(void) | ||
| 890 | { | ||
| 891 | #ifdef CONFIG_RFKILL_INPUT | ||
| 892 | rfkill_handler_exit(); | ||
| 893 | #endif | ||
| 894 | class_unregister(&rfkill_class); | ||
| 895 | } | ||
| 896 | 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..0bdbb6928205 100644 --- a/net/wimax/Kconfig +++ b/net/wimax/Kconfig | |||
| @@ -1,23 +1,9 @@ | |||
| 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 | ||
| 20 | depends on (INPUT && RFKILL != n) || RFKILL = n | ||
| 21 | help | 7 | help |
| 22 | 8 | ||
| 23 | Select to configure support for devices that provide | 9 | 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 | * |
