diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-02-03 09:54:11 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-29 15:37:00 -0500 |
commit | 3b640f21af4b6b36b546fecbd3fe5109981360da (patch) | |
tree | 5fce049b149283f8864d60b5b265a12b08827b3f /drivers/net/wireless | |
parent | a9450b70a755abf093600035ef5361c53343fe9a (diff) |
rt2x00: Enable LED class support for rt2500usb/rt73usb
Add kerneldoc for vendor request functions in rt2x00usb.
Add asynchroneous vendor request function in rt2x00usb.
With the availability of the asynchroneuous vendor request
we can now enable LED class support for rt2500usb and rt73usb.
Since LED handling is not important, it doesn't really matter
if a register call fails (This solution is better then no
LED class support at all).
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/rt2x00/Kconfig | 14 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00leds.c | 217 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00leds.h | 63 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 52 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.h | 129 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 21 |
7 files changed, 463 insertions, 53 deletions
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 88a6ef69386..51adb2f37c5 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig | |||
@@ -133,6 +133,13 @@ config RT2500USB | |||
133 | 133 | ||
134 | When compiled as a module, this driver will be called "rt2500usb.ko". | 134 | When compiled as a module, this driver will be called "rt2500usb.ko". |
135 | 135 | ||
136 | config RT2500USB_LEDS | ||
137 | bool "RT2500 leds support" | ||
138 | depends on RT2500USB | ||
139 | select RT2X00_LIB_LEDS | ||
140 | ---help--- | ||
141 | This adds support for led triggers provided my mac80211. | ||
142 | |||
136 | config RT73USB | 143 | config RT73USB |
137 | tristate "Ralink rt73 usb support" | 144 | tristate "Ralink rt73 usb support" |
138 | depends on RT2X00 && USB | 145 | depends on RT2X00 && USB |
@@ -143,6 +150,13 @@ config RT73USB | |||
143 | 150 | ||
144 | When compiled as a module, this driver will be called "rt73usb.ko". | 151 | When compiled as a module, this driver will be called "rt73usb.ko". |
145 | 152 | ||
153 | config RT73USB_LEDS | ||
154 | bool "RT73 leds support" | ||
155 | depends on RT73USB | ||
156 | select RT2X00_LIB_LEDS | ||
157 | ---help--- | ||
158 | This adds support for led triggers provided my mac80211. | ||
159 | |||
146 | config RT2X00_LIB_DEBUGFS | 160 | config RT2X00_LIB_DEBUGFS |
147 | bool "Ralink debugfs support" | 161 | bool "Ralink debugfs support" |
148 | depends on RT2X00_LIB && MAC80211_DEBUGFS | 162 | depends on RT2X00_LIB && MAC80211_DEBUGFS |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6352ebe8cb4..a64b62b2005 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -291,17 +291,16 @@ static void rt2500usb_led_brightness(struct led_classdev *led_cdev, | |||
291 | unsigned int enabled = brightness != LED_OFF; | 291 | unsigned int enabled = brightness != LED_OFF; |
292 | unsigned int activity = | 292 | unsigned int activity = |
293 | led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY; | 293 | led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY; |
294 | u16 reg; | ||
295 | |||
296 | rt2500usb_register_read(led->rt2x00dev, MAC_CSR20, ®); | ||
297 | 294 | ||
298 | if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) { | 295 | if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) { |
299 | rt2x00_set_field16(®, MAC_CSR20_LINK, enabled); | 296 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, |
300 | rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, | 297 | MAC_CSR20_LINK, enabled); |
301 | enabled && activity); | 298 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, |
299 | MAC_CSR20_ACTIVITY, enabled && activity); | ||
302 | } | 300 | } |
303 | 301 | ||
304 | rt2500usb_register_write(led->rt2x00dev, MAC_CSR20, reg); | 302 | rt2x00usb_vendor_request_async(led->rt2x00dev, USB_SINGLE_WRITE, |
303 | MAC_CSR20, led->rt2x00dev->led_mcu_reg); | ||
305 | } | 304 | } |
306 | #else | 305 | #else |
307 | #define rt2500usb_led_brightness NULL | 306 | #define rt2500usb_led_brightness NULL |
@@ -1377,6 +1376,13 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1377 | rt2x00dev->led_flags = LED_SUPPORT_RADIO; | 1376 | rt2x00dev->led_flags = LED_SUPPORT_RADIO; |
1378 | break; | 1377 | break; |
1379 | } | 1378 | } |
1379 | |||
1380 | /* | ||
1381 | * Store the current led register value, we need it later | ||
1382 | * in set_brightness but that is called in irq context which | ||
1383 | * means we can't use rt2500usb_register_read() at that time. | ||
1384 | */ | ||
1385 | rt2500usb_register_read(rt2x00dev, MAC_CSR20, &rt2x00dev->led_mcu_reg); | ||
1380 | #endif /* CONFIG_RT2500USB_LEDS */ | 1386 | #endif /* CONFIG_RT2500USB_LEDS */ |
1381 | 1387 | ||
1382 | /* | 1388 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c new file mode 100644 index 00000000000..9c29d17e0cc --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c | |||
@@ -0,0 +1,217 @@ | |||
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: rt2x00lib | ||
23 | Abstract: rt2x00 led specific routines. | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | |||
29 | #include "rt2x00.h" | ||
30 | #include "rt2x00lib.h" | ||
31 | |||
32 | void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi) | ||
33 | { | ||
34 | if (!rt2x00dev->trigger_qual.registered) | ||
35 | return; | ||
36 | |||
37 | /* | ||
38 | * Led handling requires a positive value for the rssi, | ||
39 | * to do that correctly we need to add the correction. | ||
40 | */ | ||
41 | rssi += rt2x00dev->rssi_offset; | ||
42 | |||
43 | /* | ||
44 | * Get the rssi level, this is used to convert the rssi | ||
45 | * to a LED value inside the range LED_OFF - LED_FULL. | ||
46 | */ | ||
47 | if (rssi <= 30) | ||
48 | rssi = 0; | ||
49 | else if (rssi <= 39) | ||
50 | rssi = 1; | ||
51 | else if (rssi <= 49) | ||
52 | rssi = 2; | ||
53 | else if (rssi <= 53) | ||
54 | rssi = 3; | ||
55 | else if (rssi <= 63) | ||
56 | rssi = 4; | ||
57 | else | ||
58 | rssi = 5; | ||
59 | |||
60 | /* | ||
61 | * Note that we must _not_ send LED_OFF since the driver | ||
62 | * is going to calculate the value and might use it in a | ||
63 | * division. | ||
64 | */ | ||
65 | led_trigger_event(&rt2x00dev->trigger_qual.trigger, | ||
66 | ((LED_FULL / 6) * rssi) + 1); | ||
67 | } | ||
68 | |||
69 | static int rt2x00leds_register_trigger(struct rt2x00_dev *rt2x00dev, | ||
70 | struct rt2x00_trigger *trigger, | ||
71 | const char *name) | ||
72 | { | ||
73 | int retval; | ||
74 | |||
75 | trigger->trigger.name = name; | ||
76 | retval = led_trigger_register(&trigger->trigger); | ||
77 | if (retval) { | ||
78 | ERROR(rt2x00dev, "Failed to register led trigger.\n"); | ||
79 | return retval; | ||
80 | } | ||
81 | |||
82 | trigger->registered = 1; | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, | ||
88 | struct rt2x00_led *led, | ||
89 | enum led_type type, | ||
90 | const char *name, char *trigger) | ||
91 | { | ||
92 | struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); | ||
93 | int retval; | ||
94 | |||
95 | led->led_dev.name = name; | ||
96 | led->led_dev.brightness_set = rt2x00dev->ops->lib->led_brightness; | ||
97 | led->led_dev.default_trigger = trigger; | ||
98 | |||
99 | retval = led_classdev_register(device, &led->led_dev); | ||
100 | if (retval) { | ||
101 | ERROR(rt2x00dev, "Failed to register led handler.\n"); | ||
102 | return retval; | ||
103 | } | ||
104 | |||
105 | led->rt2x00dev = rt2x00dev; | ||
106 | led->type = type; | ||
107 | led->registered = 1; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | int rt2x00leds_register(struct rt2x00_dev *rt2x00dev) | ||
113 | { | ||
114 | char *trigger; | ||
115 | char dev_name[16]; | ||
116 | char name[32]; | ||
117 | int retval; | ||
118 | |||
119 | if (!rt2x00dev->ops->lib->led_brightness) | ||
120 | return 0; | ||
121 | |||
122 | snprintf(dev_name, sizeof(dev_name), "%s-%s", | ||
123 | rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy)); | ||
124 | |||
125 | if (rt2x00dev->led_flags & LED_SUPPORT_RADIO) { | ||
126 | trigger = ieee80211_get_radio_led_name(rt2x00dev->hw); | ||
127 | snprintf(name, sizeof(name), "%s:radio", dev_name); | ||
128 | |||
129 | retval = rt2x00leds_register_led(rt2x00dev, | ||
130 | &rt2x00dev->led_radio, | ||
131 | LED_TYPE_RADIO, | ||
132 | name, trigger); | ||
133 | if (retval) | ||
134 | goto exit_fail; | ||
135 | } | ||
136 | |||
137 | if (rt2x00dev->led_flags & LED_SUPPORT_ASSOC) { | ||
138 | trigger = ieee80211_get_assoc_led_name(rt2x00dev->hw); | ||
139 | snprintf(name, sizeof(name), "%s:assoc", dev_name); | ||
140 | |||
141 | retval = rt2x00leds_register_led(rt2x00dev, | ||
142 | &rt2x00dev->led_assoc, | ||
143 | LED_TYPE_ASSOC, | ||
144 | name, trigger); | ||
145 | if (retval) | ||
146 | goto exit_fail; | ||
147 | } | ||
148 | |||
149 | if (rt2x00dev->led_flags & LED_SUPPORT_QUALITY) { | ||
150 | snprintf(name, sizeof(name), "%s:quality", dev_name); | ||
151 | |||
152 | retval = rt2x00leds_register_trigger(rt2x00dev, | ||
153 | &rt2x00dev->trigger_qual, | ||
154 | name); | ||
155 | |||
156 | retval = rt2x00leds_register_led(rt2x00dev, | ||
157 | &rt2x00dev->led_qual, | ||
158 | LED_TYPE_QUALITY, | ||
159 | name, name); | ||
160 | if (retval) | ||
161 | goto exit_fail; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | |||
166 | exit_fail: | ||
167 | rt2x00leds_unregister(rt2x00dev); | ||
168 | return retval; | ||
169 | } | ||
170 | |||
171 | static void rt2x00leds_unregister_trigger(struct rt2x00_trigger *trigger) | ||
172 | { | ||
173 | if (!trigger->registered) | ||
174 | return; | ||
175 | |||
176 | led_trigger_unregister(&trigger->trigger); | ||
177 | trigger->registered = 0; | ||
178 | } | ||
179 | |||
180 | static void rt2x00leds_unregister_led(struct rt2x00_led *led) | ||
181 | { | ||
182 | if (!led->registered) | ||
183 | return; | ||
184 | |||
185 | led_classdev_unregister(&led->led_dev); | ||
186 | |||
187 | led->led_dev.brightness_set(&led->led_dev, LED_OFF); | ||
188 | led->registered = 0; | ||
189 | } | ||
190 | |||
191 | void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) | ||
192 | { | ||
193 | rt2x00leds_unregister_trigger(&rt2x00dev->trigger_qual); | ||
194 | rt2x00leds_unregister_led(&rt2x00dev->led_qual); | ||
195 | rt2x00leds_unregister_led(&rt2x00dev->led_assoc); | ||
196 | rt2x00leds_unregister_led(&rt2x00dev->led_radio); | ||
197 | } | ||
198 | |||
199 | void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) | ||
200 | { | ||
201 | if (rt2x00dev->led_qual.registered) | ||
202 | led_classdev_suspend(&rt2x00dev->led_qual.led_dev); | ||
203 | if (rt2x00dev->led_assoc.registered) | ||
204 | led_classdev_suspend(&rt2x00dev->led_assoc.led_dev); | ||
205 | if (rt2x00dev->led_radio.registered) | ||
206 | led_classdev_suspend(&rt2x00dev->led_radio.led_dev); | ||
207 | } | ||
208 | |||
209 | void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) | ||
210 | { | ||
211 | if (rt2x00dev->led_radio.registered) | ||
212 | led_classdev_resume(&rt2x00dev->led_radio.led_dev); | ||
213 | if (rt2x00dev->led_assoc.registered) | ||
214 | led_classdev_resume(&rt2x00dev->led_assoc.led_dev); | ||
215 | if (rt2x00dev->led_qual.registered) | ||
216 | led_classdev_resume(&rt2x00dev->led_qual.led_dev); | ||
217 | } | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.h b/drivers/net/wireless/rt2x00/rt2x00leds.h new file mode 100644 index 00000000000..11e71e9ce85 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00leds.h | |||
@@ -0,0 +1,63 @@ | |||
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: rt2x00lib | ||
23 | Abstract: rt2x00 led datastructures and routines | ||
24 | */ | ||
25 | |||
26 | #ifndef RT2X00LEDS_H | ||
27 | #define RT2X00LEDS_H | ||
28 | |||
29 | /* | ||
30 | * Flags used by driver to indicate which | ||
31 | * which led types are supported. | ||
32 | */ | ||
33 | #define LED_SUPPORT_RADIO 0x000001 | ||
34 | #define LED_SUPPORT_ASSOC 0x000002 | ||
35 | #define LED_SUPPORT_ACTIVITY 0x000004 | ||
36 | #define LED_SUPPORT_QUALITY 0x000008 | ||
37 | |||
38 | enum led_type { | ||
39 | LED_TYPE_RADIO, | ||
40 | LED_TYPE_ASSOC, | ||
41 | LED_TYPE_QUALITY, | ||
42 | }; | ||
43 | |||
44 | #ifdef CONFIG_RT2X00_LIB_LEDS | ||
45 | |||
46 | struct rt2x00_led { | ||
47 | struct rt2x00_dev *rt2x00dev; | ||
48 | struct led_classdev led_dev; | ||
49 | |||
50 | enum led_type type; | ||
51 | unsigned int registered; | ||
52 | }; | ||
53 | |||
54 | struct rt2x00_trigger { | ||
55 | struct led_trigger trigger; | ||
56 | |||
57 | enum led_type type; | ||
58 | unsigned int registered; | ||
59 | }; | ||
60 | |||
61 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | ||
62 | |||
63 | #endif /* RT2X00LEDS_H */ | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index fc606448908..44ab2167c6e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -122,6 +122,58 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, | |||
122 | } | 122 | } |
123 | EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); | 123 | EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); |
124 | 124 | ||
125 | static void rt2x00usb_vendor_request_async_complete(struct urb *urb) | ||
126 | { | ||
127 | /* | ||
128 | * We're done with it, descrease usage count and let the | ||
129 | * usb layer delete it as soon as it is done with it. | ||
130 | */ | ||
131 | usb_put_urb(urb); | ||
132 | } | ||
133 | |||
134 | int rt2x00usb_vendor_request_async(struct rt2x00_dev *rt2x00dev, | ||
135 | const u8 request, const u16 offset, | ||
136 | const u16 value) | ||
137 | { | ||
138 | struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); | ||
139 | struct usb_ctrlrequest *ctrl; | ||
140 | struct urb *urb; | ||
141 | int status; | ||
142 | |||
143 | urb = usb_alloc_urb(0, GFP_NOIO); | ||
144 | if (!urb) | ||
145 | return -ENOMEM; | ||
146 | |||
147 | ctrl = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); | ||
148 | if (!ctrl) { | ||
149 | status = -ENOMEM; | ||
150 | goto exit; | ||
151 | } | ||
152 | |||
153 | ctrl->bRequestType= USB_VENDOR_REQUEST_OUT; | ||
154 | ctrl->bRequest = request; | ||
155 | ctrl->wValue = cpu_to_le16p(&value); | ||
156 | ctrl->wIndex = cpu_to_le16p(&offset); | ||
157 | ctrl->wLength = 0; | ||
158 | |||
159 | usb_fill_control_urb(urb, usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
160 | (unsigned char *)ctrl, NULL, 0, | ||
161 | rt2x00usb_vendor_request_async_complete, NULL); | ||
162 | |||
163 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
164 | if (!status) | ||
165 | goto exit; | ||
166 | |||
167 | return 0; | ||
168 | |||
169 | exit: | ||
170 | usb_put_urb(urb); | ||
171 | kfree(ctrl); | ||
172 | |||
173 | return status; | ||
174 | } | ||
175 | EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_async); | ||
176 | |||
125 | /* | 177 | /* |
126 | * TX data handlers. | 178 | * TX data handlers. |
127 | */ | 179 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index af606638e22..275b089a2a4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h | |||
@@ -60,34 +60,47 @@ | |||
60 | #define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST ) | 60 | #define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST ) |
61 | #define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST ) | 61 | #define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST ) |
62 | 62 | ||
63 | /* | 63 | /** |
64 | * USB vendor commands. | 64 | * enum rt2x00usb_vendor_request: USB vendor commands. |
65 | */ | 65 | */ |
66 | #define USB_DEVICE_MODE 0x01 | 66 | enum rt2x00usb_vendor_request { |
67 | #define USB_SINGLE_WRITE 0x02 | 67 | USB_DEVICE_MODE = 1, |
68 | #define USB_SINGLE_READ 0x03 | 68 | USB_SINGLE_WRITE = 2, |
69 | #define USB_MULTI_WRITE 0x06 | 69 | USB_SINGLE_READ = 3, |
70 | #define USB_MULTI_READ 0x07 | 70 | USB_MULTI_WRITE = 6, |
71 | #define USB_EEPROM_WRITE 0x08 | 71 | USB_MULTI_READ = 7, |
72 | #define USB_EEPROM_READ 0x09 | 72 | USB_EEPROM_WRITE = 8, |
73 | #define USB_LED_CONTROL 0x0a /* RT73USB */ | 73 | USB_EEPROM_READ = 9, |
74 | #define USB_RX_CONTROL 0x0c | 74 | USB_LED_CONTROL = 10, /* RT73USB */ |
75 | USB_RX_CONTROL = 12, | ||
76 | }; | ||
75 | 77 | ||
76 | /* | 78 | /** |
77 | * Device modes offset | 79 | * enum rt2x00usb_mode_offset: Device modes offset. |
78 | */ | 80 | */ |
79 | #define USB_MODE_RESET 0x01 | 81 | enum rt2x00usb_mode_offset { |
80 | #define USB_MODE_UNPLUG 0x02 | 82 | USB_MODE_RESET = 1, |
81 | #define USB_MODE_FUNCTION 0x03 | 83 | USB_MODE_UNPLUG = 2, |
82 | #define USB_MODE_TEST 0x04 | 84 | USB_MODE_FUNCTION = 3, |
83 | #define USB_MODE_SLEEP 0x07 /* RT73USB */ | 85 | USB_MODE_TEST = 4, |
84 | #define USB_MODE_FIRMWARE 0x08 /* RT73USB */ | 86 | USB_MODE_SLEEP = 7, /* RT73USB */ |
85 | #define USB_MODE_WAKEUP 0x09 /* RT73USB */ | 87 | USB_MODE_FIRMWARE = 8, /* RT73USB */ |
88 | USB_MODE_WAKEUP = 9, /* RT73USB */ | ||
89 | }; | ||
86 | 90 | ||
87 | /* | 91 | /** |
88 | * Used to read/write from/to the device. | 92 | * rt2x00usb_vendor_request - Send register command to device |
93 | * @rt2x00dev: Pointer to &struct rt2x00_dev | ||
94 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | ||
95 | * @requesttype: Request type &USB_VENDOR_REQUEST_* | ||
96 | * @offset: Register offset to perform action on | ||
97 | * @value: Value to write to device | ||
98 | * @buffer: Buffer where information will be read/written to by device | ||
99 | * @buffer_length: Size of &buffer | ||
100 | * @timeout: Operation timeout | ||
101 | * | ||
89 | * This is the main function to communicate with the device, | 102 | * This is the main function to communicate with the device, |
90 | * the buffer argument _must_ either be NULL or point to | 103 | * the &buffer argument _must_ either be NULL or point to |
91 | * a buffer allocated by kmalloc. Failure to do so can lead | 104 | * a buffer allocated by kmalloc. Failure to do so can lead |
92 | * to unexpected behavior depending on the architecture. | 105 | * to unexpected behavior depending on the architecture. |
93 | */ | 106 | */ |
@@ -97,13 +110,21 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, | |||
97 | void *buffer, const u16 buffer_length, | 110 | void *buffer, const u16 buffer_length, |
98 | const int timeout); | 111 | const int timeout); |
99 | 112 | ||
100 | /* | 113 | /** |
101 | * Used to read/write from/to the device. | 114 | * rt2x00usb_vendor_request_buff - Send register command to device (buffered) |
115 | * @rt2x00dev: Pointer to &struct rt2x00_dev | ||
116 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | ||
117 | * @requesttype: Request type &USB_VENDOR_REQUEST_* | ||
118 | * @offset: Register offset to perform action on | ||
119 | * @buffer: Buffer where information will be read/written to by device | ||
120 | * @buffer_length: Size of &buffer | ||
121 | * @timeout: Operation timeout | ||
122 | * | ||
102 | * This function will use a previously with kmalloc allocated cache | 123 | * This function will use a previously with kmalloc allocated cache |
103 | * to communicate with the device. The contents of the buffer pointer | 124 | * to communicate with the device. The contents of the buffer pointer |
104 | * will be copied to this cache when writing, or read from the cache | 125 | * will be copied to this cache when writing, or read from the cache |
105 | * when reading. | 126 | * when reading. |
106 | * Buffers send to rt2x00usb_vendor_request _must_ be allocated with | 127 | * Buffers send to &rt2x00usb_vendor_request _must_ be allocated with |
107 | * kmalloc. Hence the reason for using a previously allocated cache | 128 | * kmalloc. Hence the reason for using a previously allocated cache |
108 | * which has been allocated properly. | 129 | * which has been allocated properly. |
109 | */ | 130 | */ |
@@ -112,15 +133,32 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, | |||
112 | const u16 offset, void *buffer, | 133 | const u16 offset, void *buffer, |
113 | const u16 buffer_length, const int timeout); | 134 | const u16 buffer_length, const int timeout); |
114 | 135 | ||
115 | /* | 136 | /** |
116 | * A version of rt2x00usb_vendor_request_buff which must be called | 137 | * rt2x00usb_vendor_request_buff - Send register command to device (buffered) |
117 | * if the usb_cache_mutex is already held. */ | 138 | * @rt2x00dev: Pointer to &struct rt2x00_dev |
139 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | ||
140 | * @requesttype: Request type &USB_VENDOR_REQUEST_* | ||
141 | * @offset: Register offset to perform action on | ||
142 | * @buffer: Buffer where information will be read/written to by device | ||
143 | * @buffer_length: Size of &buffer | ||
144 | * @timeout: Operation timeout | ||
145 | * | ||
146 | * A version of &rt2x00usb_vendor_request_buff which must be called | ||
147 | * if the usb_cache_mutex is already held. | ||
148 | */ | ||
118 | int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, | 149 | int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, |
119 | const u8 request, const u8 requesttype, | 150 | const u8 request, const u8 requesttype, |
120 | const u16 offset, void *buffer, | 151 | const u16 offset, void *buffer, |
121 | const u16 buffer_length, const int timeout); | 152 | const u16 buffer_length, const int timeout); |
122 | 153 | ||
123 | /* | 154 | /** |
155 | * rt2x00usb_vendor_request_sw - Send single register command to device | ||
156 | * @rt2x00dev: Pointer to &struct rt2x00_dev | ||
157 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | ||
158 | * @offset: Register offset to perform action on | ||
159 | * @value: Value to write to device | ||
160 | * @timeout: Operation timeout | ||
161 | * | ||
124 | * Simple wrapper around rt2x00usb_vendor_request to write a single | 162 | * Simple wrapper around rt2x00usb_vendor_request to write a single |
125 | * command to the device. Since we don't use the buffer argument we | 163 | * command to the device. Since we don't use the buffer argument we |
126 | * don't have to worry about kmalloc here. | 164 | * don't have to worry about kmalloc here. |
@@ -136,7 +174,12 @@ static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev, | |||
136 | value, NULL, 0, timeout); | 174 | value, NULL, 0, timeout); |
137 | } | 175 | } |
138 | 176 | ||
139 | /* | 177 | /** |
178 | * rt2x00usb_eeprom_read - Read eeprom from device | ||
179 | * @rt2x00dev: Pointer to &struct rt2x00_dev | ||
180 | * @eeprom: Pointer to eeprom array to store the information in | ||
181 | * @length: Number of bytes to read from the eeprom | ||
182 | * | ||
140 | * Simple wrapper around rt2x00usb_vendor_request to read the eeprom | 183 | * Simple wrapper around rt2x00usb_vendor_request to read the eeprom |
141 | * from the device. Note that the eeprom argument _must_ be allocated using | 184 | * from the device. Note that the eeprom argument _must_ be allocated using |
142 | * kmalloc for correct handling inside the kernel USB layer. | 185 | * kmalloc for correct handling inside the kernel USB layer. |
@@ -147,10 +190,28 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, | |||
147 | int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); | 190 | int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); |
148 | 191 | ||
149 | return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, | 192 | return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, |
150 | USB_VENDOR_REQUEST_IN, 0x0000, | 193 | USB_VENDOR_REQUEST_IN, 0, 0, |
151 | 0x0000, eeprom, lenght, timeout); | 194 | eeprom, lenght, timeout); |
152 | } | 195 | } |
153 | 196 | ||
197 | /** | ||
198 | * rt2x00usb_vendor_request_async - Send register command to device (async) | ||
199 | * @rt2x00dev: Pointer to &struct rt2x00_dev | ||
200 | * @request: USB vendor command (See &enum rt2x00usb_vendor_request) | ||
201 | * @offset: Register offset to perform action on | ||
202 | * @value: Value to write to device | ||
203 | * | ||
204 | * Asynchroneous version of &rt2x00usb_vendor_request this is required | ||
205 | * for some routines where the driver cannot sleep because it is in | ||
206 | * irq context. Note that with this function the driver will not be | ||
207 | * notified on failure or timeout of the command. It will only be notified | ||
208 | * if the start of the command succeeded or not. This means it should not be | ||
209 | * used when the command must succeed. | ||
210 | */ | ||
211 | int rt2x00usb_vendor_request_async(struct rt2x00_dev *rt2x00dev, | ||
212 | const u8 request, const u16 offset, | ||
213 | const u16 value); | ||
214 | |||
154 | /* | 215 | /* |
155 | * Radio handlers | 216 | * Radio handlers |
156 | */ | 217 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ca5a9855adb..92c8f601296 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -294,28 +294,25 @@ static void rt73usb_led_brightness(struct led_classdev *led_cdev, | |||
294 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, | 294 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, |
295 | MCU_LEDCS_RADIO_STATUS, enabled); | 295 | MCU_LEDCS_RADIO_STATUS, enabled); |
296 | 296 | ||
297 | rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL, 0, | 297 | rt2x00usb_vendor_request_async(led->rt2x00dev, USB_LED_CONTROL, |
298 | led->rt2x00dev->led_mcu_reg, | 298 | 0, led->rt2x00dev->led_mcu_reg); |
299 | REGISTER_TIMEOUT); | ||
300 | } else if (led->type == LED_TYPE_ASSOC) { | 299 | } else if (led->type == LED_TYPE_ASSOC) { |
301 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, | 300 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, |
302 | MCU_LEDCS_LINK_BG_STATUS, bg_mode); | 301 | MCU_LEDCS_LINK_BG_STATUS, bg_mode); |
303 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, | 302 | rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, |
304 | MCU_LEDCS_LINK_A_STATUS, a_mode); | 303 | MCU_LEDCS_LINK_A_STATUS, a_mode); |
305 | 304 | ||
306 | rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL, 0, | 305 | rt2x00usb_vendor_request_async(led->rt2x00dev, USB_LED_CONTROL, |
307 | led->rt2x00dev->led_mcu_reg, | 306 | 0, led->rt2x00dev->led_mcu_reg); |
308 | REGISTER_TIMEOUT); | ||
309 | } else if (led->type == LED_TYPE_QUALITY) { | 307 | } else if (led->type == LED_TYPE_QUALITY) { |
310 | /* | 308 | /* |
311 | * The brightness is divided into 6 levels (0 - 5), | 309 | * The brightness is divided into 6 levels (0 - 5), |
312 | * this means we need to convert the brightness | 310 | * this means we need to convert the brightness |
313 | * argument into the matching level within that range. | 311 | * argument into the matching level within that range. |
314 | */ | 312 | */ |
315 | rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL, | 313 | rt2x00usb_vendor_request_async(led->rt2x00dev, USB_LED_CONTROL, |
316 | brightness / (LED_FULL / 6), | 314 | brightness / (LED_FULL / 6), |
317 | led->rt2x00dev->led_mcu_reg, | 315 | led->rt2x00dev->led_mcu_reg); |
318 | REGISTER_TIMEOUT); | ||
319 | } | 316 | } |
320 | } | 317 | } |
321 | #else | 318 | #else |
@@ -871,7 +868,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, | |||
871 | 868 | ||
872 | rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, | 869 | rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, |
873 | USB_VENDOR_REQUEST_OUT, | 870 | USB_VENDOR_REQUEST_OUT, |
874 | FIRMWARE_IMAGE_BASE + i, 0x0000, | 871 | FIRMWARE_IMAGE_BASE + i, 0, |
875 | cache, buflen, timeout); | 872 | cache, buflen, timeout); |
876 | 873 | ||
877 | ptr += buflen; | 874 | ptr += buflen; |
@@ -884,7 +881,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, | |||
884 | * we need to specify a long timeout time. | 881 | * we need to specify a long timeout time. |
885 | */ | 882 | */ |
886 | status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, | 883 | status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, |
887 | 0x0000, USB_MODE_FIRMWARE, | 884 | 0, USB_MODE_FIRMWARE, |
888 | REGISTER_TIMEOUT_FIRMWARE); | 885 | REGISTER_TIMEOUT_FIRMWARE); |
889 | if (status < 0) { | 886 | if (status < 0) { |
890 | ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); | 887 | ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); |