~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-updates

« back to all changes in this revision

Viewing changes to updates/compat-wireless-2.6.36/drivers/net/wireless/b43/leds.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 
3
 
  Broadcom B43 wireless driver
4
 
  LED control
5
 
 
6
 
  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
7
 
  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
8
 
  Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
9
 
  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
10
 
  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
11
 
 
12
 
  This program is free software; you can redistribute it and/or modify
13
 
  it under the terms of the GNU General Public License as published by
14
 
  the Free Software Foundation; either version 2 of the License, or
15
 
  (at your option) any later version.
16
 
 
17
 
  This program is distributed in the hope that it will be useful,
18
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 
  GNU General Public License for more details.
21
 
 
22
 
  You should have received a copy of the GNU General Public License
23
 
  along with this program; see the file COPYING.  If not, write to
24
 
  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
25
 
  Boston, MA 02110-1301, USA.
26
 
 
27
 
*/
28
 
 
29
 
#include "b43.h"
30
 
#include "leds.h"
31
 
#include "rfkill.h"
32
 
 
33
 
 
34
 
static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
35
 
                            bool activelow)
36
 
{
37
 
        u16 ctl;
38
 
 
39
 
        ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
40
 
        if (activelow)
41
 
                ctl &= ~(1 << led_index);
42
 
        else
43
 
                ctl |= (1 << led_index);
44
 
        b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
45
 
}
46
 
 
47
 
static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
48
 
                             bool activelow)
49
 
{
50
 
        u16 ctl;
51
 
 
52
 
        ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
53
 
        if (activelow)
54
 
                ctl |= (1 << led_index);
55
 
        else
56
 
                ctl &= ~(1 << led_index);
57
 
        b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
58
 
}
59
 
 
60
 
static void b43_led_update(struct b43_wldev *dev,
61
 
                           struct b43_led *led)
62
 
{
63
 
        bool radio_enabled;
64
 
        bool turn_on;
65
 
 
66
 
        if (!led->wl)
67
 
                return;
68
 
 
69
 
        radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
70
 
 
71
 
        /* The led->state read is racy, but we don't care. In case we raced
72
 
         * with the brightness_set handler, we will be called again soon
73
 
         * to fixup our state. */
74
 
        if (radio_enabled)
75
 
                turn_on = atomic_read(&led->state) != LED_OFF;
76
 
        else
77
 
                turn_on = 0;
78
 
        if (turn_on == led->hw_state)
79
 
                return;
80
 
        led->hw_state = turn_on;
81
 
 
82
 
        if (turn_on)
83
 
                b43_led_turn_on(dev, led->index, led->activelow);
84
 
        else
85
 
                b43_led_turn_off(dev, led->index, led->activelow);
86
 
}
87
 
 
88
 
static void b43_leds_work(struct work_struct *work)
89
 
{
90
 
        struct b43_leds *leds = container_of(work, struct b43_leds, work);
91
 
        struct b43_wl *wl = container_of(leds, struct b43_wl, leds);
92
 
        struct b43_wldev *dev;
93
 
 
94
 
        mutex_lock(&wl->mutex);
95
 
        dev = wl->current_dev;
96
 
        if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED))
97
 
                goto out_unlock;
98
 
 
99
 
        b43_led_update(dev, &wl->leds.led_tx);
100
 
        b43_led_update(dev, &wl->leds.led_rx);
101
 
        b43_led_update(dev, &wl->leds.led_radio);
102
 
        b43_led_update(dev, &wl->leds.led_assoc);
103
 
 
104
 
out_unlock:
105
 
        mutex_unlock(&wl->mutex);
106
 
}
107
 
 
108
 
/* Callback from the LED subsystem. */
109
 
static void b43_led_brightness_set(struct led_classdev *led_dev,
110
 
                                   enum led_brightness brightness)
111
 
{
112
 
        struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
113
 
        struct b43_wl *wl = led->wl;
114
 
 
115
 
        if (likely(!wl->leds.stop)) {
116
 
                atomic_set(&led->state, brightness);
117
 
                ieee80211_queue_work(wl->hw, &wl->leds.work);
118
 
        }
119
 
}
120
 
 
121
 
static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
122
 
                            const char *name, const char *default_trigger,
123
 
                            u8 led_index, bool activelow)
124
 
{
125
 
        int err;
126
 
 
127
 
        if (led->wl)
128
 
                return -EEXIST;
129
 
        if (!default_trigger)
130
 
                return -EINVAL;
131
 
        led->wl = dev->wl;
132
 
        led->index = led_index;
133
 
        led->activelow = activelow;
134
 
        strncpy(led->name, name, sizeof(led->name));
135
 
        atomic_set(&led->state, 0);
136
 
 
137
 
        led->led_dev.name = led->name;
138
 
        led->led_dev.default_trigger = default_trigger;
139
 
        led->led_dev.brightness_set = b43_led_brightness_set;
140
 
 
141
 
        err = led_classdev_register(dev->dev->dev, &led->led_dev);
142
 
        if (err) {
143
 
                b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
144
 
                led->wl = NULL;
145
 
                return err;
146
 
        }
147
 
 
148
 
        return 0;
149
 
}
150
 
 
151
 
static void b43_unregister_led(struct b43_led *led)
152
 
{
153
 
        if (!led->wl)
154
 
                return;
155
 
        led_classdev_unregister(&led->led_dev);
156
 
        led->wl = NULL;
157
 
}
158
 
 
159
 
static void b43_map_led(struct b43_wldev *dev,
160
 
                        u8 led_index,
161
 
                        enum b43_led_behaviour behaviour,
162
 
                        bool activelow)
163
 
{
164
 
        struct ieee80211_hw *hw = dev->wl->hw;
165
 
        char name[B43_LED_MAX_NAME_LEN + 1];
166
 
 
167
 
        /* Map the b43 specific LED behaviour value to the
168
 
         * generic LED triggers. */
169
 
        switch (behaviour) {
170
 
        case B43_LED_INACTIVE:
171
 
        case B43_LED_OFF:
172
 
        case B43_LED_ON:
173
 
                break;
174
 
        case B43_LED_ACTIVITY:
175
 
        case B43_LED_TRANSFER:
176
 
        case B43_LED_APTRANSFER:
177
 
                snprintf(name, sizeof(name),
178
 
                         "b43-%s::tx", wiphy_name(hw->wiphy));
179
 
                b43_register_led(dev, &dev->wl->leds.led_tx, name,
180
 
                                 ieee80211_get_tx_led_name(hw),
181
 
                                 led_index, activelow);
182
 
                snprintf(name, sizeof(name),
183
 
                         "b43-%s::rx", wiphy_name(hw->wiphy));
184
 
                b43_register_led(dev, &dev->wl->leds.led_rx, name,
185
 
                                 ieee80211_get_rx_led_name(hw),
186
 
                                 led_index, activelow);
187
 
                break;
188
 
        case B43_LED_RADIO_ALL:
189
 
        case B43_LED_RADIO_A:
190
 
        case B43_LED_RADIO_B:
191
 
        case B43_LED_MODE_BG:
192
 
                snprintf(name, sizeof(name),
193
 
                         "b43-%s::radio", wiphy_name(hw->wiphy));
194
 
                b43_register_led(dev, &dev->wl->leds.led_radio, name,
195
 
                                 ieee80211_get_radio_led_name(hw),
196
 
                                 led_index, activelow);
197
 
                break;
198
 
        case B43_LED_WEIRD:
199
 
        case B43_LED_ASSOC:
200
 
                snprintf(name, sizeof(name),
201
 
                         "b43-%s::assoc", wiphy_name(hw->wiphy));
202
 
                b43_register_led(dev, &dev->wl->leds.led_assoc, name,
203
 
                                 ieee80211_get_assoc_led_name(hw),
204
 
                                 led_index, activelow);
205
 
                break;
206
 
        default:
207
 
                b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n",
208
 
                        behaviour);
209
 
                break;
210
 
        }
211
 
}
212
 
 
213
 
static void b43_led_get_sprominfo(struct b43_wldev *dev,
214
 
                                  unsigned int led_index,
215
 
                                  enum b43_led_behaviour *behaviour,
216
 
                                  bool *activelow)
217
 
{
218
 
        struct ssb_bus *bus = dev->dev->bus;
219
 
        u8 sprom[4];
220
 
 
221
 
        sprom[0] = bus->sprom.gpio0;
222
 
        sprom[1] = bus->sprom.gpio1;
223
 
        sprom[2] = bus->sprom.gpio2;
224
 
        sprom[3] = bus->sprom.gpio3;
225
 
 
226
 
        if (sprom[led_index] == 0xFF) {
227
 
                /* There is no LED information in the SPROM
228
 
                 * for this LED. Hardcode it here. */
229
 
                *activelow = 0;
230
 
                switch (led_index) {
231
 
                case 0:
232
 
                        *behaviour = B43_LED_ACTIVITY;
233
 
                        *activelow = 1;
234
 
                        if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
235
 
                                *behaviour = B43_LED_RADIO_ALL;
236
 
                        break;
237
 
                case 1:
238
 
                        *behaviour = B43_LED_RADIO_B;
239
 
                        if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
240
 
                                *behaviour = B43_LED_ASSOC;
241
 
                        break;
242
 
                case 2:
243
 
                        *behaviour = B43_LED_RADIO_A;
244
 
                        break;
245
 
                case 3:
246
 
                        *behaviour = B43_LED_OFF;
247
 
                        break;
248
 
                default:
249
 
                        *behaviour = B43_LED_OFF;
250
 
                        B43_WARN_ON(1);
251
 
                        return;
252
 
                }
253
 
        } else {
254
 
                *behaviour = sprom[led_index] & B43_LED_BEHAVIOUR;
255
 
                *activelow = !!(sprom[led_index] & B43_LED_ACTIVELOW);
256
 
        }
257
 
}
258
 
 
259
 
void b43_leds_init(struct b43_wldev *dev)
260
 
{
261
 
        struct b43_led *led;
262
 
        unsigned int i;
263
 
        enum b43_led_behaviour behaviour;
264
 
        bool activelow;
265
 
 
266
 
        /* Sync the RF-kill LED state (if we have one) with radio and switch states. */
267
 
        led = &dev->wl->leds.led_radio;
268
 
        if (led->wl) {
269
 
                if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) {
270
 
                        b43_led_turn_on(dev, led->index, led->activelow);
271
 
                        led->hw_state = 1;
272
 
                        atomic_set(&led->state, 1);
273
 
                } else {
274
 
                        b43_led_turn_off(dev, led->index, led->activelow);
275
 
                        led->hw_state = 0;
276
 
                        atomic_set(&led->state, 0);
277
 
                }
278
 
        }
279
 
 
280
 
        /* Initialize TX/RX/ASSOC leds */
281
 
        led = &dev->wl->leds.led_tx;
282
 
        if (led->wl) {
283
 
                b43_led_turn_off(dev, led->index, led->activelow);
284
 
                led->hw_state = 0;
285
 
                atomic_set(&led->state, 0);
286
 
        }
287
 
        led = &dev->wl->leds.led_rx;
288
 
        if (led->wl) {
289
 
                b43_led_turn_off(dev, led->index, led->activelow);
290
 
                led->hw_state = 0;
291
 
                atomic_set(&led->state, 0);
292
 
        }
293
 
        led = &dev->wl->leds.led_assoc;
294
 
        if (led->wl) {
295
 
                b43_led_turn_off(dev, led->index, led->activelow);
296
 
                led->hw_state = 0;
297
 
                atomic_set(&led->state, 0);
298
 
        }
299
 
 
300
 
        /* Initialize other LED states. */
301
 
        for (i = 0; i < B43_MAX_NR_LEDS; i++) {
302
 
                b43_led_get_sprominfo(dev, i, &behaviour, &activelow);
303
 
                switch (behaviour) {
304
 
                case B43_LED_OFF:
305
 
                        b43_led_turn_off(dev, i, activelow);
306
 
                        break;
307
 
                case B43_LED_ON:
308
 
                        b43_led_turn_on(dev, i, activelow);
309
 
                        break;
310
 
                default:
311
 
                        /* Leave others as-is. */
312
 
                        break;
313
 
                }
314
 
        }
315
 
 
316
 
        dev->wl->leds.stop = 0;
317
 
}
318
 
 
319
 
void b43_leds_exit(struct b43_wldev *dev)
320
 
{
321
 
        struct b43_leds *leds = &dev->wl->leds;
322
 
 
323
 
        b43_led_turn_off(dev, leds->led_tx.index, leds->led_tx.activelow);
324
 
        b43_led_turn_off(dev, leds->led_rx.index, leds->led_rx.activelow);
325
 
        b43_led_turn_off(dev, leds->led_assoc.index, leds->led_assoc.activelow);
326
 
        b43_led_turn_off(dev, leds->led_radio.index, leds->led_radio.activelow);
327
 
}
328
 
 
329
 
void b43_leds_stop(struct b43_wldev *dev)
330
 
{
331
 
        struct b43_leds *leds = &dev->wl->leds;
332
 
 
333
 
        leds->stop = 1;
334
 
        cancel_work_sync(&leds->work);
335
 
}
336
 
 
337
 
void b43_leds_register(struct b43_wldev *dev)
338
 
{
339
 
        unsigned int i;
340
 
        enum b43_led_behaviour behaviour;
341
 
        bool activelow;
342
 
 
343
 
        INIT_WORK(&dev->wl->leds.work, b43_leds_work);
344
 
 
345
 
        /* Register the LEDs to the LED subsystem. */
346
 
        for (i = 0; i < B43_MAX_NR_LEDS; i++) {
347
 
                b43_led_get_sprominfo(dev, i, &behaviour, &activelow);
348
 
                b43_map_led(dev, i, behaviour, activelow);
349
 
        }
350
 
}
351
 
 
352
 
void b43_leds_unregister(struct b43_wl *wl)
353
 
{
354
 
        struct b43_leds *leds = &wl->leds;
355
 
 
356
 
        b43_unregister_led(&leds->led_tx);
357
 
        b43_unregister_led(&leds->led_rx);
358
 
        b43_unregister_led(&leds->led_assoc);
359
 
        b43_unregister_led(&leds->led_radio);
360
 
}