]>
Commit | Line | Data |
---|---|---|
93bb7f3a LF |
1 | /* |
2 | ||
6be50837 | 3 | Broadcom B43 wireless driver |
93bb7f3a LF |
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 | ||
4ad36d78 LF |
29 | #include <linux/kmod.h> |
30 | ||
93bb7f3a | 31 | |
6be50837 LF |
32 | /* Returns TRUE, if the radio is enabled in hardware. */ |
33 | static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) | |
93bb7f3a | 34 | { |
6be50837 LF |
35 | if (dev->phy.rev >= 3) { |
36 | if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) | |
37 | & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) | |
38 | return 1; | |
39 | } else { | |
40 | if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) | |
41 | & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) | |
42 | return 1; | |
93bb7f3a | 43 | } |
6be50837 | 44 | return 0; |
93bb7f3a LF |
45 | } |
46 | ||
6be50837 | 47 | /* The poll callback for the hardware button. */ |
19d337df | 48 | static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) |
93bb7f3a | 49 | { |
19d337df | 50 | struct b43legacy_wldev *dev = data; |
93bb7f3a | 51 | struct b43legacy_wl *wl = dev->wl; |
6be50837 | 52 | bool enabled; |
93bb7f3a | 53 | |
6be50837 | 54 | mutex_lock(&wl->mutex); |
4ad36d78 LF |
55 | if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { |
56 | mutex_unlock(&wl->mutex); | |
57 | return; | |
58 | } | |
6be50837 LF |
59 | enabled = b43legacy_is_hw_radio_enabled(dev); |
60 | if (unlikely(enabled != dev->radio_hw_enable)) { | |
61 | dev->radio_hw_enable = enabled; | |
62 | b43legacyinfo(wl, "Radio hardware status changed to %s\n", | |
63 | enabled ? "ENABLED" : "DISABLED"); | |
19d337df JB |
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 | } | |
db9683fb SB |
71 | } |
72 | mutex_unlock(&wl->mutex); | |
93bb7f3a LF |
73 | } |
74 | ||
75 | /* Called when the RFKILL toggled in software. | |
76 | * This is called without locking. */ | |
19d337df | 77 | static int b43legacy_rfkill_soft_set(void *data, bool blocked) |
93bb7f3a LF |
78 | { |
79 | struct b43legacy_wldev *dev = data; | |
80 | struct b43legacy_wl *wl = dev->wl; | |
19d337df | 81 | int ret = -EINVAL; |
93bb7f3a | 82 | |
db9683fb | 83 | if (!wl->rfkill.registered) |
19d337df | 84 | return -EINVAL; |
93bb7f3a | 85 | |
db9683fb | 86 | mutex_lock(&wl->mutex); |
4ad36d78 LF |
87 | if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) |
88 | goto out_unlock; | |
19d337df JB |
89 | |
90 | if (!dev->radio_hw_enable) | |
91 | goto out_unlock; | |
92 | ||
93 | if (!blocked != dev->phy.radio_on) { | |
94 | if (!blocked) | |
93bb7f3a | 95 | b43legacy_radio_turn_on(dev); |
19d337df | 96 | else |
93bb7f3a | 97 | b43legacy_radio_turn_off(dev, 0); |
93bb7f3a | 98 | } |
19d337df | 99 | ret = 0; |
93bb7f3a LF |
100 | |
101 | out_unlock: | |
102 | mutex_unlock(&wl->mutex); | |
19d337df | 103 | return ret; |
93bb7f3a LF |
104 | } |
105 | ||
19d337df | 106 | const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) |
93bb7f3a | 107 | { |
4ad36d78 | 108 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); |
93bb7f3a | 109 | |
4ad36d78 | 110 | if (!rfk->registered) |
93bb7f3a | 111 | return NULL; |
19d337df | 112 | return rfkill_get_led_trigger_name(rfk->rfkill); |
93bb7f3a LF |
113 | } |
114 | ||
19d337df JB |
115 | static const struct rfkill_ops b43legacy_rfkill_ops = { |
116 | .set_block = b43legacy_rfkill_soft_set, | |
117 | .poll = b43legacy_rfkill_poll, | |
118 | }; | |
119 | ||
93bb7f3a LF |
120 | void b43legacy_rfkill_init(struct b43legacy_wldev *dev) |
121 | { | |
122 | struct b43legacy_wl *wl = dev->wl; | |
123 | struct b43legacy_rfkill *rfk = &(wl->rfkill); | |
124 | int err; | |
125 | ||
4ad36d78 | 126 | rfk->registered = 0; |
6be50837 | 127 | |
93bb7f3a LF |
128 | snprintf(rfk->name, sizeof(rfk->name), |
129 | "b43legacy-%s", wiphy_name(wl->hw->wiphy)); | |
19d337df JB |
130 | rfk->rfkill = rfkill_alloc(rfk->name, |
131 | dev->dev->dev, | |
132 | RFKILL_TYPE_WLAN, | |
133 | &b43legacy_rfkill_ops, dev); | |
134 | if (!rfk->rfkill) | |
135 | goto out_error; | |
4ad36d78 LF |
136 | |
137 | err = rfkill_register(rfk->rfkill); | |
138 | if (err) | |
19d337df | 139 | goto err_free; |
4ad36d78 LF |
140 | |
141 | rfk->registered = 1; | |
142 | ||
143 | return; | |
19d337df JB |
144 | err_free: |
145 | rfkill_destroy(rfk->rfkill); | |
146 | out_error: | |
4ad36d78 LF |
147 | rfk->registered = 0; |
148 | b43legacywarn(wl, "RF-kill button init failed\n"); | |
93bb7f3a LF |
149 | } |
150 | ||
4ad36d78 | 151 | void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) |
93bb7f3a LF |
152 | { |
153 | struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); | |
154 | ||
4ad36d78 LF |
155 | if (!rfk->registered) |
156 | return; | |
157 | rfk->registered = 0; | |
158 | ||
4ad36d78 | 159 | rfkill_unregister(rfk->rfkill); |
19d337df | 160 | rfkill_destroy(rfk->rfkill); |
93bb7f3a LF |
161 | rfk->rfkill = NULL; |
162 | } | |
4ad36d78 | 163 |