blob: 67121427a5bd73ff00c3836071317eea1f49c85d [file] [log] [blame]
Ivo van Doorn95ea3622007-09-25 17:57:13 -07001/*
Ivo van Doorn811aa9c2008-02-03 15:42:53 +01002 Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
Ivo van Doorn95ea3622007-09-25 17:57:13 -07003 <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
Ivo van Doorn95ea3622007-09-25 17:57:13 -070026#include <linux/input-polldev.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/rfkill.h>
30
31#include "rt2x00.h"
32#include "rt2x00lib.h"
33
34static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
35{
36 struct rt2x00_dev *rt2x00dev = data;
37 int retval = 0;
38
39 if (unlikely(!rt2x00dev))
40 return 0;
41
42 /*
Ivo van Doorn066cb632007-09-25 20:55:39 +020043 * Only continue if there are enabled interfaces.
Ivo van Doorn95ea3622007-09-25 17:57:13 -070044 */
Ivo van Doorn066cb632007-09-25 20:55:39 +020045 if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
Ivo van Doorn95ea3622007-09-25 17:57:13 -070046 return 0;
47
48 if (state == RFKILL_STATE_ON) {
49 INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
Ivo van Doorn81873e92007-10-06 14:14:06 +020050 __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
Ivo van Doorn95ea3622007-09-25 17:57:13 -070051 retval = rt2x00lib_enable_radio(rt2x00dev);
52 } else if (state == RFKILL_STATE_OFF) {
53 INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
Ivo van Doorn81873e92007-10-06 14:14:06 +020054 __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
Ivo van Doorn95ea3622007-09-25 17:57:13 -070055 rt2x00lib_disable_radio(rt2x00dev);
56 }
57
58 return retval;
59}
60
61static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
62{
63 struct rt2x00_dev *rt2x00dev = poll_dev->private;
64 int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
65
Ivo van Doorn4300beb2007-10-27 13:40:25 +020066 if (rt2x00dev->rfkill->state != state) {
Ivo van Doorn95ea3622007-09-25 17:57:13 -070067 input_report_key(poll_dev->input, KEY_WLAN, 1);
Ivo van Doorn4300beb2007-10-27 13:40:25 +020068 input_report_key(poll_dev->input, KEY_WLAN, 0);
69 }
Ivo van Doorn95ea3622007-09-25 17:57:13 -070070}
71
72int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
73{
74 int retval;
75
Ivo van Doorn066cb632007-09-25 20:55:39 +020076 if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
Ivo van Doorn95ea3622007-09-25 17:57:13 -070077 return 0;
78
79 retval = rfkill_register(rt2x00dev->rfkill);
80 if (retval) {
81 ERROR(rt2x00dev, "Failed to register rfkill handler.\n");
82 return retval;
83 }
84
85 retval = input_register_polled_device(rt2x00dev->poll_dev);
86 if (retval) {
87 ERROR(rt2x00dev, "Failed to register polled device.\n");
88 rfkill_unregister(rt2x00dev->rfkill);
89 return retval;
90 }
91
Ivo van Doornd9890b82007-10-27 13:40:51 +020092 /*
93 * Force initial poll which will detect the initial device state,
94 * and correctly sends the signal to the rfkill layer about this
95 * state.
96 */
97 rt2x00rfkill_poll(rt2x00dev->poll_dev);
98
Ivo van Doorn95ea3622007-09-25 17:57:13 -070099 return 0;
100}
101
102void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
103{
Ivo van Doorn066cb632007-09-25 20:55:39 +0200104 if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700105 return;
106
107 input_unregister_polled_device(rt2x00dev->poll_dev);
108 rfkill_unregister(rt2x00dev->rfkill);
109}
110
111int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
112{
113 struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
114
Ivo van Doorn066cb632007-09-25 20:55:39 +0200115 if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700116 return 0;
117
118 rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
119 if (!rt2x00dev->rfkill) {
120 ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
Ivo van Doorn4300beb2007-10-27 13:40:25 +0200121 goto exit;
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700122 }
123
124 rt2x00dev->rfkill->name = rt2x00dev->ops->name;
125 rt2x00dev->rfkill->data = rt2x00dev;
Ivo van Doornd9890b82007-10-27 13:40:51 +0200126 rt2x00dev->rfkill->state = -1;
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700127 rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
128
129 rt2x00dev->poll_dev = input_allocate_polled_device();
130 if (!rt2x00dev->poll_dev) {
131 ERROR(rt2x00dev, "Failed to allocate polled device.\n");
Ivo van Doorn4300beb2007-10-27 13:40:25 +0200132 goto exit_free_rfkill;
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700133 }
134
135 rt2x00dev->poll_dev->private = rt2x00dev;
136 rt2x00dev->poll_dev->poll = rt2x00rfkill_poll;
137 rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
138
Ivo van Doorn4300beb2007-10-27 13:40:25 +0200139 rt2x00dev->poll_dev->input->name = rt2x00dev->ops->name;
140 rt2x00dev->poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
141 rt2x00dev->poll_dev->input->id.bustype = BUS_HOST;
142 rt2x00dev->poll_dev->input->id.vendor = 0x1814;
143 rt2x00dev->poll_dev->input->id.product = rt2x00dev->chip.rt;
144 rt2x00dev->poll_dev->input->id.version = rt2x00dev->chip.rev;
145 rt2x00dev->poll_dev->input->dev.parent = device;
146 rt2x00dev->poll_dev->input->evbit[0] = BIT(EV_KEY);
147 set_bit(KEY_WLAN, rt2x00dev->poll_dev->input->keybit);
148
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700149 return 0;
Ivo van Doorn4300beb2007-10-27 13:40:25 +0200150
Ivo van Doorn4300beb2007-10-27 13:40:25 +0200151exit_free_rfkill:
152 rfkill_free(rt2x00dev->rfkill);
153
154exit:
155 return -ENOMEM;
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700156}
157
158void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
159{
Ivo van Doorn066cb632007-09-25 20:55:39 +0200160 if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700161 return;
162
Ivo van Doorn95ea3622007-09-25 17:57:13 -0700163 input_free_polled_device(rt2x00dev->poll_dev);
164 rfkill_free(rt2x00dev->rfkill);
165}