Add rt2x00-mac80211 snapshot (#1916)
[openwrt.git] / package / rt2x00 / src / rt2x00rfkill.c
1 /*
2         Copyright (C) 2004 - 2007 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: rt2x00lib
23         Abstract: rt2x00 rfkill specific routines.
24         Supported chipsets: RT2460, RT2560, rt2561, rt2561s, rt2661.
25  */
26
27 /*
28  * Set enviroment defines for rt2x00.h
29  */
30 #define DRV_NAME "rt2x00lib"
31
32 #include <linux/rfkill.h>
33
34 #include "rt2x00.h"
35
36 static int rt2x00lib_toggle_radio(void *data, enum rfkill_state state)
37 {
38         struct rt2x00_dev* rt2x00dev = data;
39         int retval = 0;
40
41         if (unlikely(!rt2x00dev))
42                 return 0;
43
44         /*
45          * Only continue if we have an active interface,
46          * either monitor or non-monitor should be present.
47          */
48         if (!is_interface_present(&rt2x00dev->interface) &&
49             !is_monitor_present(&rt2x00dev->interface))
50                 return 0;
51
52         if (state == RFKILL_STATE_ON) {
53                 INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
54                 __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags);
55                 retval = rt2x00lib_enable_radio(rt2x00dev);
56         } else if (state == RFKILL_STATE_OFF) {
57                 INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
58                 __clear_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags);
59                 rt2x00lib_disable_radio(rt2x00dev);
60         }
61
62         return retval;
63 }
64
65 static void rt2x00lib_rfkill_poll(struct work_struct *work)
66 {
67         struct rt2x00_dev *rt2x00dev =
68                 container_of(work, struct rt2x00_dev, rfkill_work.work);
69
70         rfkill_switch_all(rt2x00dev->rfkill->type,
71                 rt2x00dev->ops->lib->rfkill_poll(rt2x00dev));
72
73         queue_delayed_work(rt2x00dev->workqueue, &rt2x00dev->rfkill_work,
74                 RFKILL_POLL_INTERVAL);
75 }
76
77 int rt2x00lib_register_rfkill(struct rt2x00_dev *rt2x00dev)
78 {
79         int status = rfkill_register(rt2x00dev->rfkill);
80         if (status) {
81                 ERROR(rt2x00dev, "Failed to register rfkill handler.\n");
82                 return status;
83         }
84
85         rt2x00lib_rfkill_poll(&rt2x00dev->rfkill_work.work);
86
87         return !schedule_delayed_work(&rt2x00dev->rfkill_work,
88                 RFKILL_POLL_INTERVAL);
89 }
90
91 void rt2x00lib_unregister_rfkill(struct rt2x00_dev *rt2x00dev)
92 {
93         if (delayed_work_pending(&rt2x00dev->rfkill_work))
94                 cancel_rearming_delayed_workqueue(
95                         rt2x00dev->workqueue, &rt2x00dev->rfkill_work);
96
97         rfkill_unregister(rt2x00dev->rfkill);
98 }
99
100 int rt2x00lib_allocate_rfkill(struct rt2x00_dev *rt2x00dev)
101 {
102         struct rfkill *rfkill;
103
104         if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
105                 return 0;
106
107         rfkill = rfkill_allocate(rt2x00dev->device, RFKILL_TYPE_WLAN);
108         if (!rfkill) {
109                 ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
110                 return -ENOMEM;
111         }
112
113         rfkill->name = rt2x00dev->ops->name;
114         rfkill->data = rt2x00dev;
115         rfkill->toggle_radio = rt2x00lib_toggle_radio;
116         rt2x00dev->rfkill = rfkill;
117
118         INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00lib_rfkill_poll);
119
120         return 0;
121 }
122
123 void rt2x00lib_free_rfkill(struct rt2x00_dev *rt2x00dev)
124 {
125         if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
126                 return;
127
128         rfkill_free(rt2x00dev->rfkill);
129 }