Commit | Line | Data |
---|---|---|
00b3ed16 GKH |
1 | #include "hfa384x_usb.c" |
2 | #include "prism2mgmt.c" | |
3 | #include "prism2mib.c" | |
4 | #include "prism2sta.c" | |
76e3e7c4 | 5 | #include "prism2fw.c" |
00b3ed16 | 6 | |
bbb591a7 DP |
7 | #define PRISM_DEV(vid, pid, name) \ |
8 | { USB_DEVICE(vid, pid), \ | |
e2911905 | 9 | .driver_info = (unsigned long)name } |
00b3ed16 GKH |
10 | |
11 | static struct usb_device_id usb_prism_tbl[] = { | |
bbb591a7 DP |
12 | PRISM_DEV(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS"), |
13 | PRISM_DEV(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11"), | |
14 | PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter"), | |
15 | PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"), | |
16 | PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"), | |
17 | PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter"), | |
18 | PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter"), | |
19 | PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter"), | |
20 | PRISM_DEV(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter"), | |
21 | PRISM_DEV(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"), | |
22 | PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter"), | |
23 | PRISM_DEV(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"), | |
24 | PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter"), | |
25 | PRISM_DEV(0x0967, 0x0204, "Acer Warplink USB Adapter"), | |
26 | PRISM_DEV(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated"), | |
27 | PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter"), | |
28 | PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter"), | |
29 | PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter"), | |
30 | PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter"), | |
31 | PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter"), | |
32 | PRISM_DEV(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter"), | |
33 | PRISM_DEV(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter"), | |
34 | PRISM_DEV(0x0846, 0x4110, "NetGear MA111"), | |
35 | PRISM_DEV(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter"), | |
36 | PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 Wireless USB Adapter"), | |
37 | PRISM_DEV(0x2001, 0x3700, "DWL-122 Wireless USB Adapter"), | |
38 | PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter"), | |
39 | PRISM_DEV(0x50c2, 0x4013, "Averatec USB WLAN Adapter"), | |
40 | PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter"), | |
41 | PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter"), | |
42 | PRISM_DEV(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter"), | |
43 | PRISM_DEV(0x2821, 0x3300, "Hawking HighDB USB Adapter"), | |
44 | PRISM_DEV(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter"), | |
45 | PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter"), | |
46 | PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter"), | |
47 | PRISM_DEV(0x0bb2, 0x0302, "Ambit Microsystems Corp."), | |
48 | PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter"), | |
49 | PRISM_DEV(0x0543, 0x0f01, | |
50 | "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)"), | |
51 | PRISM_DEV(0x067c, 0x1022, | |
52 | "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter"), | |
53 | PRISM_DEV(0x049f, 0x0033, | |
54 | "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter"), | |
55 | { } /* terminator */ | |
00b3ed16 | 56 | }; |
00b3ed16 GKH |
57 | MODULE_DEVICE_TABLE(usb, usb_prism_tbl); |
58 | ||
f4ee0f42 MM |
59 | static int prism2sta_probe_usb(struct usb_interface *interface, |
60 | const struct usb_device_id *id) | |
00b3ed16 | 61 | { |
00b3ed16 | 62 | struct usb_device *dev; |
00b3ed16 | 63 | |
f4ee0f42 MM |
64 | wlandevice_t *wlandev = NULL; |
65 | hfa384x_t *hw = NULL; | |
66 | int result = 0; | |
00b3ed16 | 67 | |
00b3ed16 | 68 | dev = interface_to_usbdev(interface); |
297f06ce MT |
69 | wlandev = create_wlan(); |
70 | if (wlandev == NULL) { | |
318e16b9 | 71 | dev_err(&interface->dev, "Memory allocation failure.\n"); |
00b3ed16 GKH |
72 | result = -EIO; |
73 | goto failed; | |
74 | } | |
75 | hw = wlandev->priv; | |
76 | ||
cb3126e6 | 77 | if (wlan_setup(wlandev, &(interface->dev)) != 0) { |
318e16b9 | 78 | dev_err(&interface->dev, "wlan_setup() failed.\n"); |
00b3ed16 GKH |
79 | result = -EIO; |
80 | goto failed; | |
81 | } | |
82 | ||
83 | /* Initialize the hw data */ | |
84 | hfa384x_create(hw, dev); | |
85 | hw->wlandev = wlandev; | |
86 | ||
87 | /* Register the wlandev, this gets us a name and registers the | |
88 | * linux netdevice. | |
89 | */ | |
00b3ed16 | 90 | SET_NETDEV_DEV(wlandev->netdev, &(interface->dev)); |
00b3ed16 GKH |
91 | |
92 | /* Do a chip-level reset on the MAC */ | |
93 | if (prism2_doreset) { | |
94 | result = hfa384x_corereset(hw, | |
f4ee0f42 MM |
95 | prism2_reset_holdtime, |
96 | prism2_reset_settletime, 0); | |
00b3ed16 | 97 | if (result != 0) { |
00b3ed16 | 98 | result = -EIO; |
58612c60 DP |
99 | dev_err(&interface->dev, |
100 | "hfa384x_corereset() failed.\n"); | |
b76ed59f | 101 | goto failed_reset; |
00b3ed16 GKH |
102 | } |
103 | } | |
104 | ||
00b3ed16 | 105 | usb_get_dev(dev); |
00b3ed16 GKH |
106 | |
107 | wlandev->msdstate = WLAN_MSD_HWPRESENT; | |
108 | ||
76e3e7c4 KR |
109 | /* Try and load firmware, then enable card before we register */ |
110 | prism2_fwtry(dev, wlandev); | |
111 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); | |
112 | ||
f4ee0f42 | 113 | if (register_wlandev(wlandev) != 0) { |
318e16b9 | 114 | dev_err(&interface->dev, "register_wlandev() failed.\n"); |
1d1b6985 | 115 | result = -EIO; |
b76ed59f | 116 | goto failed_register; |
f4ee0f42 | 117 | } |
1d1b6985 | 118 | |
00b3ed16 GKH |
119 | goto done; |
120 | ||
b76ed59f AK |
121 | failed_register: |
122 | usb_put_dev(dev); | |
123 | failed_reset: | |
124 | wlan_unsetup(wlandev); | |
f4ee0f42 | 125 | failed: |
7c98f718 MM |
126 | kfree(wlandev); |
127 | kfree(hw); | |
00b3ed16 GKH |
128 | wlandev = NULL; |
129 | ||
f4ee0f42 | 130 | done: |
00b3ed16 GKH |
131 | usb_set_intfdata(interface, wlandev); |
132 | return result; | |
00b3ed16 GKH |
133 | } |
134 | ||
f4ee0f42 | 135 | static void prism2sta_disconnect_usb(struct usb_interface *interface) |
00b3ed16 | 136 | { |
f4ee0f42 | 137 | wlandevice_t *wlandev; |
00b3ed16 | 138 | |
e2911905 | 139 | wlandev = (wlandevice_t *)usb_get_intfdata(interface); |
f4ee0f42 | 140 | if (wlandev != NULL) { |
00b3ed16 | 141 | LIST_HEAD(cleanlist); |
f4ee0f42 MM |
142 | struct list_head *entry; |
143 | struct list_head *temp; | |
144 | unsigned long flags; | |
00b3ed16 | 145 | |
f4ee0f42 | 146 | hfa384x_t *hw = wlandev->priv; |
00b3ed16 GKH |
147 | |
148 | if (!hw) | |
149 | goto exit; | |
150 | ||
151 | spin_lock_irqsave(&hw->ctlxq.lock, flags); | |
152 | ||
153 | p80211netdev_hwremoved(wlandev); | |
154 | list_splice_init(&hw->ctlxq.reapable, &cleanlist); | |
155 | list_splice_init(&hw->ctlxq.completing, &cleanlist); | |
156 | list_splice_init(&hw->ctlxq.pending, &cleanlist); | |
157 | list_splice_init(&hw->ctlxq.active, &cleanlist); | |
158 | ||
159 | spin_unlock_irqrestore(&hw->ctlxq.lock, flags); | |
160 | ||
161 | /* There's no hardware to shutdown, but the driver | |
162 | * might have some tasks or tasklets that must be | |
163 | * stopped before we can tear everything down. | |
164 | */ | |
165 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); | |
166 | ||
167 | del_singleshot_timer_sync(&hw->throttle); | |
168 | del_singleshot_timer_sync(&hw->reqtimer); | |
169 | del_singleshot_timer_sync(&hw->resptimer); | |
170 | ||
171 | /* Unlink all the URBs. This "removes the wheels" | |
172 | * from the entire CTLX handling mechanism. | |
173 | */ | |
174 | usb_kill_urb(&hw->rx_urb); | |
175 | usb_kill_urb(&hw->tx_urb); | |
176 | usb_kill_urb(&hw->ctlx_urb); | |
177 | ||
178 | tasklet_kill(&hw->completion_bh); | |
179 | tasklet_kill(&hw->reaper_bh); | |
180 | ||
181 | flush_scheduled_work(); | |
182 | ||
183 | /* Now we complete any outstanding commands | |
184 | * and tell everyone who is waiting for their | |
185 | * responses that we have shut down. | |
186 | */ | |
187 | list_for_each(entry, &cleanlist) { | |
f4ee0f42 | 188 | hfa384x_usbctlx_t *ctlx; |
00b3ed16 GKH |
189 | |
190 | ctlx = list_entry(entry, hfa384x_usbctlx_t, list); | |
191 | complete(&ctlx->done); | |
192 | } | |
193 | ||
194 | /* Give any outstanding synchronous commands | |
195 | * a chance to complete. All they need to do | |
196 | * is "wake up", so that's easy. | |
197 | * (I'd like a better way to do this, really.) | |
198 | */ | |
199 | msleep(100); | |
200 | ||
201 | /* Now delete the CTLXs, because no-one else can now. */ | |
202 | list_for_each_safe(entry, temp, &cleanlist) { | |
203 | hfa384x_usbctlx_t *ctlx; | |
204 | ||
205 | ctlx = list_entry(entry, hfa384x_usbctlx_t, list); | |
206 | kfree(ctlx); | |
207 | } | |
208 | ||
209 | /* Unhook the wlandev */ | |
210 | unregister_wlandev(wlandev); | |
211 | wlan_unsetup(wlandev); | |
212 | ||
00b3ed16 | 213 | usb_put_dev(hw->usb); |
00b3ed16 GKH |
214 | |
215 | hfa384x_destroy(hw); | |
216 | kfree(hw); | |
217 | ||
218 | kfree(wlandev); | |
219 | } | |
220 | ||
f4ee0f42 | 221 | exit: |
00b3ed16 | 222 | usb_set_intfdata(interface, NULL); |
00b3ed16 GKH |
223 | } |
224 | ||
59497bba CF |
225 | #ifdef CONFIG_PM |
226 | static int prism2sta_suspend(struct usb_interface *interface, | |
227 | pm_message_t message) | |
228 | { | |
229 | hfa384x_t *hw = NULL; | |
230 | wlandevice_t *wlandev; | |
58612c60 | 231 | |
e2911905 | 232 | wlandev = (wlandevice_t *)usb_get_intfdata(interface); |
59497bba CF |
233 | if (!wlandev) |
234 | return -ENODEV; | |
235 | ||
236 | hw = wlandev->priv; | |
237 | if (!hw) | |
238 | return -ENODEV; | |
239 | ||
240 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); | |
241 | ||
242 | usb_kill_urb(&hw->rx_urb); | |
243 | usb_kill_urb(&hw->tx_urb); | |
244 | usb_kill_urb(&hw->ctlx_urb); | |
245 | ||
246 | return 0; | |
247 | } | |
248 | ||
249 | static int prism2sta_resume(struct usb_interface *interface) | |
250 | { | |
251 | int result = 0; | |
252 | hfa384x_t *hw = NULL; | |
253 | wlandevice_t *wlandev; | |
58612c60 | 254 | |
e2911905 | 255 | wlandev = (wlandevice_t *)usb_get_intfdata(interface); |
59497bba CF |
256 | if (!wlandev) |
257 | return -ENODEV; | |
258 | ||
259 | hw = wlandev->priv; | |
260 | if (!hw) | |
261 | return -ENODEV; | |
262 | ||
263 | /* Do a chip-level reset on the MAC */ | |
264 | if (prism2_doreset) { | |
265 | result = hfa384x_corereset(hw, | |
266 | prism2_reset_holdtime, | |
267 | prism2_reset_settletime, 0); | |
268 | if (result != 0) { | |
269 | unregister_wlandev(wlandev); | |
270 | hfa384x_destroy(hw); | |
318e16b9 | 271 | dev_err(&interface->dev, "hfa384x_corereset() failed.\n"); |
59497bba CF |
272 | kfree(wlandev); |
273 | kfree(hw); | |
274 | wlandev = NULL; | |
275 | return -ENODEV; | |
276 | } | |
277 | } | |
278 | ||
279 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); | |
280 | ||
281 | return 0; | |
282 | } | |
283 | #else | |
284 | #define prism2sta_suspend NULL | |
285 | #define prism2sta_resume NULL | |
286 | #endif /* CONFIG_PM */ | |
287 | ||
00b3ed16 | 288 | static struct usb_driver prism2_usb_driver = { |
00b3ed16 GKH |
289 | .name = "prism2_usb", |
290 | .probe = prism2sta_probe_usb, | |
291 | .disconnect = prism2sta_disconnect_usb, | |
292 | .id_table = usb_prism_tbl, | |
59497bba CF |
293 | .suspend = prism2sta_suspend, |
294 | .resume = prism2sta_resume, | |
295 | .reset_resume = prism2sta_resume, | |
00b3ed16 GKH |
296 | /* fops, minor? */ |
297 | }; | |
298 | ||
bac2c126 | 299 | module_usb_driver(prism2_usb_driver); |