b43legacy: Use input-polldev for the rfkill switch
[safe/jmp/linux-2.6] / drivers / net / wireless / b43legacy / rfkill.c
1 /*
2
3   Broadcom B43 wireless driver
4   RFKILL support
5
6   Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; see the file COPYING.  If not, write to
20   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21   Boston, MA 02110-1301, USA.
22
23 */
24
25 #include "rfkill.h"
26 #include "radio.h"
27 #include "b43legacy.h"
28
29
30 /* Returns TRUE, if the radio is enabled in hardware. */
31 static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
32 {
33         if (dev->phy.rev >= 3) {
34                 if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
35                       & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
36                         return 1;
37         } else {
38                 if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
39                     & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
40                         return 1;
41         }
42         return 0;
43 }
44
45 /* The poll callback for the hardware button. */
46 static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
47 {
48         struct b43legacy_wldev *dev = poll_dev->private;
49         struct b43legacy_wl *wl = dev->wl;
50         bool enabled;
51
52         mutex_lock(&wl->mutex);
53         B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED);
54         enabled = b43legacy_is_hw_radio_enabled(dev);
55         if (unlikely(enabled != dev->radio_hw_enable)) {
56                 dev->radio_hw_enable = enabled;
57                 b43legacyinfo(wl, "Radio hardware status changed to %s\n",
58                         enabled ? "ENABLED" : "DISABLED");
59                 mutex_unlock(&wl->mutex);
60                 input_report_key(poll_dev->input, KEY_WLAN, enabled);
61         } else
62                 mutex_unlock(&wl->mutex);
63 }
64
65 /* Called when the RFKILL toggled in software.
66  * This is called without locking. */
67 static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
68 {
69         struct b43legacy_wldev *dev = data;
70         struct b43legacy_wl *wl = dev->wl;
71         int err = 0;
72
73         mutex_lock(&wl->mutex);
74         if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
75                 goto out_unlock;
76
77         switch (state) {
78         case RFKILL_STATE_ON:
79                 if (!dev->radio_hw_enable) {
80                         /* No luck. We can't toggle the hardware RF-kill
81                          * button from software. */
82                         err = -EBUSY;
83                         goto out_unlock;
84                 }
85                 if (!dev->phy.radio_on)
86                         b43legacy_radio_turn_on(dev);
87                 break;
88         case RFKILL_STATE_OFF:
89                 if (dev->phy.radio_on)
90                         b43legacy_radio_turn_off(dev, 0);
91                 break;
92         }
93
94 out_unlock:
95         mutex_unlock(&wl->mutex);
96
97         return err;
98 }
99
100 char * b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
101 {
102         struct b43legacy_wl *wl = dev->wl;
103
104         if (!wl->rfkill.rfkill)
105                 return NULL;
106         return rfkill_get_led_name(wl->rfkill.rfkill);
107 }
108
109 void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
110 {
111         struct b43legacy_wl *wl = dev->wl;
112         struct b43legacy_rfkill *rfk = &(wl->rfkill);
113         int err;
114
115         if (rfk->rfkill) {
116                 err = rfkill_register(rfk->rfkill);
117                 if (err) {
118                         b43legacywarn(wl, "Failed to register RF-kill button\n");
119                         goto err_free_rfk;
120                 }
121         }
122         if (rfk->poll_dev) {
123                 err = input_register_polled_device(rfk->poll_dev);
124                 if (err) {
125                         b43legacywarn(wl, "Failed to register RF-kill polldev\n");
126                         goto err_free_polldev;
127                 }
128         }
129
130         return;
131 err_free_rfk:
132         rfkill_free(rfk->rfkill);
133         rfk->rfkill = NULL;
134 err_free_polldev:
135         input_free_polled_device(rfk->poll_dev);
136         rfk->poll_dev = NULL;
137 }
138
139 void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
140 {
141         struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
142
143         if (rfk->poll_dev)
144                 input_unregister_polled_device(rfk->poll_dev);
145         if (rfk->rfkill)
146                 rfkill_unregister(rfk->rfkill);
147 }
148
149 void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev)
150 {
151         struct b43legacy_wl *wl = dev->wl;
152         struct b43legacy_rfkill *rfk = &(wl->rfkill);
153
154         snprintf(rfk->name, sizeof(rfk->name),
155                  "b43legacy-%s", wiphy_name(wl->hw->wiphy));
156
157         rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
158         if (!rfk->rfkill) {
159                 b43legacywarn(wl, "Failed to allocate RF-kill button\n");
160                 return;
161         }
162         rfk->rfkill->name = rfk->name;
163         rfk->rfkill->state = RFKILL_STATE_ON;
164         rfk->rfkill->data = dev;
165         rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle;
166         rfk->rfkill->user_claim_unsupported = 1;
167
168         rfk->poll_dev = input_allocate_polled_device();
169         if (rfk->poll_dev) {
170                 rfk->poll_dev->private = dev;
171                 rfk->poll_dev->poll = b43legacy_rfkill_poll;
172                 rfk->poll_dev->poll_interval = 1000; /* msecs */
173         } else
174                 b43legacywarn(wl, "Failed to allocate RF-kill polldev\n");
175 }
176
177 void b43legacy_rfkill_free(struct b43legacy_wldev *dev)
178 {
179         struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
180
181         input_free_polled_device(rfk->poll_dev);
182         rfk->poll_dev = NULL;
183         rfkill_free(rfk->rfkill);
184         rfk->rfkill = NULL;
185 }