Merge git://git.kernel.org/pub/scm/linux/kernel/git/arjan/linux-2.6-async
[linux-2.6] / drivers / net / wireless / rt2x00 / rt2x00rfkill.c
1 /*
2         Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
3         <http://rt2x00.serialmonkey.com>
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 /*
22         Module: rt2x00rfkill
23         Abstract: rt2x00 rfkill routines.
24  */
25
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/rfkill.h>
29
30 #include "rt2x00.h"
31 #include "rt2x00lib.h"
32
33 static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
34 {
35         struct rt2x00_dev *rt2x00dev = data;
36         int retval = 0;
37
38         if (unlikely(!rt2x00dev))
39                 return 0;
40
41         /*
42          * Only continue if there are enabled interfaces.
43          */
44         if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
45                 return 0;
46
47         if (state == RFKILL_STATE_UNBLOCKED) {
48                 INFO(rt2x00dev, "RFKILL event: enabling radio.\n");
49                 clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
50                 retval = rt2x00lib_enable_radio(rt2x00dev);
51         } else if (state == RFKILL_STATE_SOFT_BLOCKED) {
52                 INFO(rt2x00dev, "RFKILL event: disabling radio.\n");
53                 set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
54                 rt2x00lib_disable_radio(rt2x00dev);
55         } else {
56                 WARNING(rt2x00dev, "RFKILL event: unknown state %d.\n", state);
57         }
58
59         return retval;
60 }
61
62 static int rt2x00rfkill_get_state(void *data, enum rfkill_state *state)
63 {
64         struct rt2x00_dev *rt2x00dev = data;
65
66         /*
67          * rfkill_poll reports 1 when the key has been pressed and the
68          * radio should be blocked.
69          */
70         *state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ?
71             RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
72
73         return 0;
74 }
75
76 static void rt2x00rfkill_poll(struct work_struct *work)
77 {
78         struct rt2x00_dev *rt2x00dev =
79             container_of(work, struct rt2x00_dev, rfkill_work.work);
80         enum rfkill_state state;
81
82         if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
83             !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
84                 return;
85
86         /*
87          * Poll latest state and report it to rfkill who should sort
88          * out if the state should be toggled or not.
89          */
90         if (!rt2x00rfkill_get_state(rt2x00dev, &state))
91                 rfkill_force_state(rt2x00dev->rfkill, state);
92
93         queue_delayed_work(rt2x00dev->hw->workqueue,
94                            &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL);
95 }
96
97 void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
98 {
99         if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
100             test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
101                 return;
102
103         if (rfkill_register(rt2x00dev->rfkill)) {
104                 ERROR(rt2x00dev, "Failed to register rfkill handler.\n");
105                 return;
106         }
107
108         __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
109
110         /*
111          * Force initial poll which will detect the initial device state,
112          * and correctly sends the signal to the rfkill layer about this
113          * state.
114          */
115         rt2x00rfkill_poll(&rt2x00dev->rfkill_work.work);
116 }
117
118 void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
119 {
120         if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
121             !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
122                 return;
123
124         cancel_delayed_work_sync(&rt2x00dev->rfkill_work);
125
126         rfkill_unregister(rt2x00dev->rfkill);
127
128         __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
129 }
130
131 void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
132 {
133         struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy);
134
135         if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state))
136                 return;
137
138         rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN);
139         if (!rt2x00dev->rfkill) {
140                 ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
141                 return;
142         }
143
144         __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
145
146         rt2x00dev->rfkill->name = rt2x00dev->ops->name;
147         rt2x00dev->rfkill->data = rt2x00dev;
148         rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
149         if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) {
150                 rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state;
151                 rt2x00dev->rfkill->state =
152                         rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ?
153                             RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
154         } else {
155                 rt2x00dev->rfkill->state = RFKILL_STATE_UNBLOCKED;
156         }
157
158         INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll);
159
160         return;
161 }
162
163 void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
164 {
165         if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->flags))
166                 return;
167
168         cancel_delayed_work_sync(&rt2x00dev->rfkill_work);
169
170         rfkill_free(rt2x00dev->rfkill);
171         rt2x00dev->rfkill = NULL;
172 }