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 | 69 | wlandev = create_wlan(); |
e2e77528 | 70 | if (!wlandev) { |
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); |
57477bf0 | 142 | hfa384x_usbctlx_t *ctlx, *temp; |
f4ee0f42 | 143 | unsigned long flags; |
00b3ed16 | 144 | |
f4ee0f42 | 145 | hfa384x_t *hw = wlandev->priv; |
00b3ed16 GKH |
146 | |
147 | if (!hw) | |
148 | goto exit; | |
149 | ||
150 | spin_lock_irqsave(&hw->ctlxq.lock, flags); | |
151 | ||
152 | p80211netdev_hwremoved(wlandev); | |
153 | list_splice_init(&hw->ctlxq.reapable, &cleanlist); | |
154 | list_splice_init(&hw->ctlxq.completing, &cleanlist); | |
155 | list_splice_init(&hw->ctlxq.pending, &cleanlist); | |
156 | list_splice_init(&hw->ctlxq.active, &cleanlist); | |
157 | ||
158 | spin_unlock_irqrestore(&hw->ctlxq.lock, flags); | |
159 | ||
160 | /* There's no hardware to shutdown, but the driver | |
161 | * might have some tasks or tasklets that must be | |
162 | * stopped before we can tear everything down. | |
163 | */ | |
164 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); | |
165 | ||
166 | del_singleshot_timer_sync(&hw->throttle); | |
167 | del_singleshot_timer_sync(&hw->reqtimer); | |
168 | del_singleshot_timer_sync(&hw->resptimer); | |
169 | ||
170 | /* Unlink all the URBs. This "removes the wheels" | |
171 | * from the entire CTLX handling mechanism. | |
172 | */ | |
173 | usb_kill_urb(&hw->rx_urb); | |
174 | usb_kill_urb(&hw->tx_urb); | |
175 | usb_kill_urb(&hw->ctlx_urb); | |
176 | ||
177 | tasklet_kill(&hw->completion_bh); | |
178 | tasklet_kill(&hw->reaper_bh); | |
179 | ||
5be2f42b AKC |
180 | cancel_work_sync(&hw->link_bh); |
181 | cancel_work_sync(&hw->commsqual_bh); | |
00b3ed16 GKH |
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 | */ | |
57477bf0 | 187 | list_for_each_entry(ctlx, &cleanlist, list) |
00b3ed16 | 188 | complete(&ctlx->done); |
00b3ed16 GKH |
189 | |
190 | /* Give any outstanding synchronous commands | |
191 | * a chance to complete. All they need to do | |
192 | * is "wake up", so that's easy. | |
193 | * (I'd like a better way to do this, really.) | |
194 | */ | |
195 | msleep(100); | |
196 | ||
197 | /* Now delete the CTLXs, because no-one else can now. */ | |
57477bf0 | 198 | list_for_each_entry_safe(ctlx, temp, &cleanlist, list) |
00b3ed16 | 199 | kfree(ctlx); |
00b3ed16 GKH |
200 | |
201 | /* Unhook the wlandev */ | |
202 | unregister_wlandev(wlandev); | |
203 | wlan_unsetup(wlandev); | |
204 | ||
00b3ed16 | 205 | usb_put_dev(hw->usb); |
00b3ed16 GKH |
206 | |
207 | hfa384x_destroy(hw); | |
208 | kfree(hw); | |
209 | ||
210 | kfree(wlandev); | |
211 | } | |
212 | ||
f4ee0f42 | 213 | exit: |
00b3ed16 | 214 | usb_set_intfdata(interface, NULL); |
00b3ed16 GKH |
215 | } |
216 | ||
59497bba CF |
217 | #ifdef CONFIG_PM |
218 | static int prism2sta_suspend(struct usb_interface *interface, | |
219 | pm_message_t message) | |
220 | { | |
221 | hfa384x_t *hw = NULL; | |
222 | wlandevice_t *wlandev; | |
58612c60 | 223 | |
e2911905 | 224 | wlandev = (wlandevice_t *)usb_get_intfdata(interface); |
59497bba CF |
225 | if (!wlandev) |
226 | return -ENODEV; | |
227 | ||
228 | hw = wlandev->priv; | |
229 | if (!hw) | |
230 | return -ENODEV; | |
231 | ||
232 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); | |
233 | ||
234 | usb_kill_urb(&hw->rx_urb); | |
235 | usb_kill_urb(&hw->tx_urb); | |
236 | usb_kill_urb(&hw->ctlx_urb); | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
241 | static int prism2sta_resume(struct usb_interface *interface) | |
242 | { | |
243 | int result = 0; | |
244 | hfa384x_t *hw = NULL; | |
245 | wlandevice_t *wlandev; | |
58612c60 | 246 | |
e2911905 | 247 | wlandev = (wlandevice_t *)usb_get_intfdata(interface); |
59497bba CF |
248 | if (!wlandev) |
249 | return -ENODEV; | |
250 | ||
251 | hw = wlandev->priv; | |
252 | if (!hw) | |
253 | return -ENODEV; | |
254 | ||
255 | /* Do a chip-level reset on the MAC */ | |
256 | if (prism2_doreset) { | |
257 | result = hfa384x_corereset(hw, | |
258 | prism2_reset_holdtime, | |
259 | prism2_reset_settletime, 0); | |
260 | if (result != 0) { | |
261 | unregister_wlandev(wlandev); | |
262 | hfa384x_destroy(hw); | |
318e16b9 | 263 | dev_err(&interface->dev, "hfa384x_corereset() failed.\n"); |
59497bba CF |
264 | kfree(wlandev); |
265 | kfree(hw); | |
266 | wlandev = NULL; | |
267 | return -ENODEV; | |
268 | } | |
269 | } | |
270 | ||
271 | prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); | |
272 | ||
273 | return 0; | |
274 | } | |
275 | #else | |
276 | #define prism2sta_suspend NULL | |
277 | #define prism2sta_resume NULL | |
278 | #endif /* CONFIG_PM */ | |
279 | ||
00b3ed16 | 280 | static struct usb_driver prism2_usb_driver = { |
00b3ed16 GKH |
281 | .name = "prism2_usb", |
282 | .probe = prism2sta_probe_usb, | |
283 | .disconnect = prism2sta_disconnect_usb, | |
284 | .id_table = usb_prism_tbl, | |
59497bba CF |
285 | .suspend = prism2sta_suspend, |
286 | .resume = prism2sta_resume, | |
287 | .reset_resume = prism2sta_resume, | |
00b3ed16 GKH |
288 | /* fops, minor? */ |
289 | }; | |
290 | ||
bac2c126 | 291 | module_usb_driver(prism2_usb_driver); |