1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | |
3 | /* |
4 | * Linux device driver for USB based Prism54 |
5 | * |
6 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
7 | * |
8 | * Based on the islsm (softmac prism54) driver, which is: |
9 | * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. |
10 | */ |
11 | |
12 | #include <linux/usb.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/firmware.h> |
16 | #include <linux/etherdevice.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/crc32.h> |
19 | #include <linux/module.h> |
20 | #include <net/mac80211.h> |
21 | |
22 | #include "p54.h" |
23 | #include "lmac.h" |
24 | #include "p54usb.h" |
25 | |
26 | MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>" ); |
27 | MODULE_DESCRIPTION("Prism54 USB wireless driver" ); |
28 | MODULE_LICENSE("GPL" ); |
29 | MODULE_ALIAS("prism54usb" ); |
30 | MODULE_FIRMWARE("isl3886usb" ); |
31 | MODULE_FIRMWARE("isl3887usb" ); |
32 | |
33 | static struct usb_driver p54u_driver; |
34 | |
35 | /* |
36 | * Note: |
37 | * |
38 | * Always update our wiki's device list (located at: |
39 | * http://wireless.wiki.kernel.org/en/users/Drivers/p54/devices ), |
40 | * whenever you add a new device. |
41 | */ |
42 | |
43 | static const struct usb_device_id p54u_table[] = { |
44 | /* Version 1 devices (pci chip + net2280) */ |
45 | {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ |
46 | {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ |
47 | {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ |
48 | {USB_DEVICE(0x0675, 0x0530)}, /* DrayTek Vigor 530 */ |
49 | {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ |
50 | {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ |
51 | {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */ |
52 | {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ |
53 | {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ |
54 | {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */ |
55 | {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ |
56 | {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ |
57 | {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ |
58 | {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ |
59 | {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */ |
60 | {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ |
61 | {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */ |
62 | {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ |
63 | {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ |
64 | {USB_DEVICE(0x124a, 0x4026)}, /* AirVasT USB wireless device */ |
65 | {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */ |
66 | {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */ |
67 | {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */ |
68 | {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */ |
69 | {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ |
70 | {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ |
71 | {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ |
72 | {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */ |
73 | {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */ |
74 | {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */ |
75 | {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ |
76 | |
77 | /* Version 2 devices (3887) */ |
78 | {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */ |
79 | {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */ |
80 | {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */ |
81 | {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */ |
82 | {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */ |
83 | {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ |
84 | {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ |
85 | {USB_DEVICE(0x07aa, 0x0020)}, /* Corega WLUSB2GTST USB */ |
86 | {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ |
87 | {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ |
88 | {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */ |
89 | {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ |
90 | {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ |
91 | {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ |
92 | {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */ |
93 | {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */ |
94 | {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/ |
95 | {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/ |
96 | /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above, |
97 | * just noting it here for clarity */ |
98 | {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ |
99 | {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */ |
100 | {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ |
101 | {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */ |
102 | {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */ |
103 | {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */ |
104 | {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ |
105 | {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */ |
106 | {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ |
107 | /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */ |
108 | {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */ |
109 | {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */ |
110 | {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ |
111 | {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */ |
112 | {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */ |
113 | {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ |
114 | {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ |
115 | {} |
116 | }; |
117 | |
118 | MODULE_DEVICE_TABLE(usb, p54u_table); |
119 | |
120 | static const struct { |
121 | u32 intf; |
122 | enum p54u_hw_type type; |
123 | const char *fw; |
124 | char hw[20]; |
125 | } p54u_fwlist[__NUM_P54U_HWTYPES] = { |
126 | { |
127 | .type = P54U_NET2280, |
128 | .intf = FW_LM86, |
129 | .fw = "isl3886usb" , |
130 | .hw = "ISL3886 + net2280" , |
131 | }, |
132 | { |
133 | .type = P54U_3887, |
134 | .intf = FW_LM87, |
135 | .fw = "isl3887usb" , |
136 | .hw = "ISL3887" , |
137 | }, |
138 | }; |
139 | |
140 | static void p54u_rx_cb(struct urb *urb) |
141 | { |
142 | struct sk_buff *skb = (struct sk_buff *) urb->context; |
143 | struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb; |
144 | struct ieee80211_hw *dev = info->dev; |
145 | struct p54u_priv *priv = dev->priv; |
146 | |
147 | skb_unlink(skb, list: &priv->rx_queue); |
148 | |
149 | if (unlikely(urb->status)) { |
150 | dev_kfree_skb_irq(skb); |
151 | return; |
152 | } |
153 | |
154 | skb_put(skb, len: urb->actual_length); |
155 | |
156 | if (priv->hw_type == P54U_NET2280) |
157 | skb_pull(skb, len: priv->common.tx_hdr_len); |
158 | if (priv->common.fw_interface == FW_LM87) { |
159 | skb_pull(skb, len: 4); |
160 | skb_put(skb, len: 4); |
161 | } |
162 | |
163 | if (p54_rx(dev, skb)) { |
164 | skb = dev_alloc_skb(length: priv->common.rx_mtu + 32); |
165 | if (unlikely(!skb)) { |
166 | /* TODO check rx queue length and refill *somewhere* */ |
167 | return; |
168 | } |
169 | |
170 | info = (struct p54u_rx_info *) skb->cb; |
171 | info->urb = urb; |
172 | info->dev = dev; |
173 | urb->transfer_buffer = skb_tail_pointer(skb); |
174 | urb->context = skb; |
175 | } else { |
176 | if (priv->hw_type == P54U_NET2280) |
177 | skb_push(skb, len: priv->common.tx_hdr_len); |
178 | if (priv->common.fw_interface == FW_LM87) { |
179 | skb_push(skb, len: 4); |
180 | skb_put(skb, len: 4); |
181 | } |
182 | skb_reset_tail_pointer(skb); |
183 | skb_trim(skb, len: 0); |
184 | urb->transfer_buffer = skb_tail_pointer(skb); |
185 | } |
186 | skb_queue_tail(list: &priv->rx_queue, newsk: skb); |
187 | usb_anchor_urb(urb, anchor: &priv->submitted); |
188 | if (usb_submit_urb(urb, GFP_ATOMIC)) { |
189 | skb_unlink(skb, list: &priv->rx_queue); |
190 | usb_unanchor_urb(urb); |
191 | dev_kfree_skb_irq(skb); |
192 | } |
193 | } |
194 | |
195 | static void p54u_tx_cb(struct urb *urb) |
196 | { |
197 | struct sk_buff *skb = urb->context; |
198 | struct ieee80211_hw *dev = |
199 | usb_get_intfdata(intf: usb_ifnum_to_if(dev: urb->dev, ifnum: 0)); |
200 | |
201 | p54_free_skb(dev, skb); |
202 | } |
203 | |
204 | static void p54u_tx_dummy_cb(struct urb *urb) { } |
205 | |
206 | static void p54u_free_urbs(struct ieee80211_hw *dev) |
207 | { |
208 | struct p54u_priv *priv = dev->priv; |
209 | usb_kill_anchored_urbs(anchor: &priv->submitted); |
210 | } |
211 | |
212 | static void p54u_stop(struct ieee80211_hw *dev) |
213 | { |
214 | /* |
215 | * TODO: figure out how to reliably stop the 3887 and net2280 so |
216 | * the hardware is still usable next time we want to start it. |
217 | * until then, we just stop listening to the hardware.. |
218 | */ |
219 | p54u_free_urbs(dev); |
220 | } |
221 | |
222 | static int p54u_init_urbs(struct ieee80211_hw *dev) |
223 | { |
224 | struct p54u_priv *priv = dev->priv; |
225 | struct urb *entry = NULL; |
226 | struct sk_buff *skb; |
227 | struct p54u_rx_info *info; |
228 | int ret = 0; |
229 | |
230 | while (skb_queue_len(list_: &priv->rx_queue) < 32) { |
231 | skb = __dev_alloc_skb(length: priv->common.rx_mtu + 32, GFP_KERNEL); |
232 | if (!skb) { |
233 | ret = -ENOMEM; |
234 | goto err; |
235 | } |
236 | entry = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
237 | if (!entry) { |
238 | ret = -ENOMEM; |
239 | goto err; |
240 | } |
241 | |
242 | usb_fill_bulk_urb(urb: entry, dev: priv->udev, |
243 | usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), |
244 | transfer_buffer: skb_tail_pointer(skb), |
245 | buffer_length: priv->common.rx_mtu + 32, complete_fn: p54u_rx_cb, context: skb); |
246 | info = (struct p54u_rx_info *) skb->cb; |
247 | info->urb = entry; |
248 | info->dev = dev; |
249 | skb_queue_tail(list: &priv->rx_queue, newsk: skb); |
250 | |
251 | usb_anchor_urb(urb: entry, anchor: &priv->submitted); |
252 | ret = usb_submit_urb(urb: entry, GFP_KERNEL); |
253 | if (ret) { |
254 | skb_unlink(skb, list: &priv->rx_queue); |
255 | usb_unanchor_urb(urb: entry); |
256 | goto err; |
257 | } |
258 | usb_free_urb(urb: entry); |
259 | entry = NULL; |
260 | } |
261 | |
262 | return 0; |
263 | |
264 | err: |
265 | usb_free_urb(urb: entry); |
266 | kfree_skb(skb); |
267 | p54u_free_urbs(dev); |
268 | return ret; |
269 | } |
270 | |
271 | static int p54u_open(struct ieee80211_hw *dev) |
272 | { |
273 | /* |
274 | * TODO: Because we don't know how to reliably stop the 3887 and |
275 | * the isl3886+net2280, other than brutally cut off all |
276 | * communications. We have to reinitialize the urbs on every start. |
277 | */ |
278 | return p54u_init_urbs(dev); |
279 | } |
280 | |
281 | static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) |
282 | { |
283 | u32 chk = 0; |
284 | |
285 | length >>= 2; |
286 | while (length--) { |
287 | chk ^= le32_to_cpu(*data++); |
288 | chk = (chk >> 5) ^ (chk << 3); |
289 | } |
290 | |
291 | return cpu_to_le32(chk); |
292 | } |
293 | |
294 | static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) |
295 | { |
296 | struct p54u_priv *priv = dev->priv; |
297 | struct urb *data_urb; |
298 | struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); |
299 | |
300 | data_urb = usb_alloc_urb(iso_packets: 0, GFP_ATOMIC); |
301 | if (!data_urb) { |
302 | p54_free_skb(dev, skb); |
303 | return; |
304 | } |
305 | |
306 | hdr->chksum = p54u_lm87_chksum(data: (__le32 *)skb->data, length: skb->len); |
307 | hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; |
308 | |
309 | usb_fill_bulk_urb(urb: data_urb, dev: priv->udev, |
310 | usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), |
311 | transfer_buffer: hdr, buffer_length: skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ? |
312 | p54u_tx_cb : p54u_tx_dummy_cb, context: skb); |
313 | data_urb->transfer_flags |= URB_ZERO_PACKET; |
314 | |
315 | usb_anchor_urb(urb: data_urb, anchor: &priv->submitted); |
316 | if (usb_submit_urb(urb: data_urb, GFP_ATOMIC)) { |
317 | usb_unanchor_urb(urb: data_urb); |
318 | p54_free_skb(dev, skb); |
319 | } |
320 | usb_free_urb(urb: data_urb); |
321 | } |
322 | |
323 | static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) |
324 | { |
325 | struct p54u_priv *priv = dev->priv; |
326 | struct urb *int_urb = NULL, *data_urb = NULL; |
327 | struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); |
328 | struct net2280_reg_write *reg = NULL; |
329 | int err = -ENOMEM; |
330 | |
331 | reg = kmalloc(size: sizeof(*reg), GFP_ATOMIC); |
332 | if (!reg) |
333 | goto out; |
334 | |
335 | int_urb = usb_alloc_urb(iso_packets: 0, GFP_ATOMIC); |
336 | if (!int_urb) |
337 | goto out; |
338 | |
339 | data_urb = usb_alloc_urb(iso_packets: 0, GFP_ATOMIC); |
340 | if (!data_urb) |
341 | goto out; |
342 | |
343 | reg->port = cpu_to_le16(NET2280_DEV_U32); |
344 | reg->addr = cpu_to_le32(P54U_DEV_BASE); |
345 | reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); |
346 | |
347 | memset(hdr, 0, sizeof(*hdr)); |
348 | hdr->len = cpu_to_le16(skb->len); |
349 | hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id; |
350 | |
351 | usb_fill_bulk_urb(urb: int_urb, dev: priv->udev, |
352 | usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), transfer_buffer: reg, buffer_length: sizeof(*reg), |
353 | complete_fn: p54u_tx_dummy_cb, context: dev); |
354 | |
355 | /* |
356 | * URB_FREE_BUFFER triggers a code path in the USB subsystem that will |
357 | * free what is inside the transfer_buffer after the last reference to |
358 | * the int_urb is dropped. |
359 | */ |
360 | int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET; |
361 | reg = NULL; |
362 | |
363 | usb_fill_bulk_urb(urb: data_urb, dev: priv->udev, |
364 | usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), |
365 | transfer_buffer: hdr, buffer_length: skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ? |
366 | p54u_tx_cb : p54u_tx_dummy_cb, context: skb); |
367 | data_urb->transfer_flags |= URB_ZERO_PACKET; |
368 | |
369 | usb_anchor_urb(urb: int_urb, anchor: &priv->submitted); |
370 | err = usb_submit_urb(urb: int_urb, GFP_ATOMIC); |
371 | if (err) { |
372 | usb_unanchor_urb(urb: int_urb); |
373 | goto out; |
374 | } |
375 | |
376 | usb_anchor_urb(urb: data_urb, anchor: &priv->submitted); |
377 | err = usb_submit_urb(urb: data_urb, GFP_ATOMIC); |
378 | if (err) { |
379 | usb_unanchor_urb(urb: data_urb); |
380 | goto out; |
381 | } |
382 | out: |
383 | usb_free_urb(urb: int_urb); |
384 | usb_free_urb(urb: data_urb); |
385 | |
386 | if (err) { |
387 | kfree(objp: reg); |
388 | p54_free_skb(dev, skb); |
389 | } |
390 | } |
391 | |
392 | static int p54u_write(struct p54u_priv *priv, |
393 | struct net2280_reg_write *buf, |
394 | enum net2280_op_type type, |
395 | __le32 addr, __le32 val) |
396 | { |
397 | unsigned int ep; |
398 | int alen; |
399 | |
400 | if (type & 0x0800) |
401 | ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV); |
402 | else |
403 | ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG); |
404 | |
405 | buf->port = cpu_to_le16(type); |
406 | buf->addr = addr; |
407 | buf->val = val; |
408 | |
409 | return usb_bulk_msg(usb_dev: priv->udev, pipe: ep, data: buf, len: sizeof(*buf), actual_length: &alen, timeout: 1000); |
410 | } |
411 | |
412 | static int p54u_read(struct p54u_priv *priv, void *buf, |
413 | enum net2280_op_type type, |
414 | __le32 addr, __le32 *val) |
415 | { |
416 | struct net2280_reg_read *read = buf; |
417 | __le32 *reg = buf; |
418 | unsigned int ep; |
419 | int alen, err; |
420 | |
421 | if (type & 0x0800) |
422 | ep = P54U_PIPE_DEV; |
423 | else |
424 | ep = P54U_PIPE_BRG; |
425 | |
426 | read->port = cpu_to_le16(type); |
427 | read->addr = addr; |
428 | |
429 | err = usb_bulk_msg(usb_dev: priv->udev, usb_sndbulkpipe(priv->udev, ep), |
430 | data: read, len: sizeof(*read), actual_length: &alen, timeout: 1000); |
431 | if (err) |
432 | return err; |
433 | |
434 | err = usb_bulk_msg(usb_dev: priv->udev, usb_rcvbulkpipe(priv->udev, ep), |
435 | data: reg, len: sizeof(*reg), actual_length: &alen, timeout: 1000); |
436 | if (err) |
437 | return err; |
438 | |
439 | *val = *reg; |
440 | return 0; |
441 | } |
442 | |
443 | static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, |
444 | void *data, size_t len) |
445 | { |
446 | int alen; |
447 | return usb_bulk_msg(usb_dev: priv->udev, usb_sndbulkpipe(priv->udev, ep), |
448 | data, len, actual_length: &alen, timeout: 2000); |
449 | } |
450 | |
451 | static int p54u_device_reset(struct ieee80211_hw *dev) |
452 | { |
453 | struct p54u_priv *priv = dev->priv; |
454 | int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING); |
455 | |
456 | if (lock) { |
457 | ret = usb_lock_device_for_reset(udev: priv->udev, iface: priv->intf); |
458 | if (ret < 0) { |
459 | dev_err(&priv->udev->dev, "(p54usb) unable to lock " |
460 | "device for reset (%d)!\n" , ret); |
461 | return ret; |
462 | } |
463 | } |
464 | |
465 | ret = usb_reset_device(dev: priv->udev); |
466 | if (lock) |
467 | usb_unlock_device(priv->udev); |
468 | |
469 | if (ret) |
470 | dev_err(&priv->udev->dev, "(p54usb) unable to reset " |
471 | "device (%d)!\n" , ret); |
472 | |
473 | return ret; |
474 | } |
475 | |
476 | static const char p54u_romboot_3887[] = "~~~~" ; |
477 | static int p54u_firmware_reset_3887(struct ieee80211_hw *dev) |
478 | { |
479 | struct p54u_priv *priv = dev->priv; |
480 | u8 *buf; |
481 | int ret; |
482 | |
483 | buf = kmemdup(p: p54u_romboot_3887, size: 4, GFP_KERNEL); |
484 | if (!buf) |
485 | return -ENOMEM; |
486 | ret = p54u_bulk_msg(priv, ep: P54U_PIPE_DATA, |
487 | data: buf, len: 4); |
488 | kfree(objp: buf); |
489 | if (ret) |
490 | dev_err(&priv->udev->dev, "(p54usb) unable to jump to " |
491 | "boot ROM (%d)!\n" , ret); |
492 | |
493 | return ret; |
494 | } |
495 | |
496 | static const char p54u_firmware_upload_3887[] = "<\r" ; |
497 | static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) |
498 | { |
499 | struct p54u_priv *priv = dev->priv; |
500 | int err, alen; |
501 | u8 carry = 0; |
502 | u8 *buf, *tmp; |
503 | const u8 *data; |
504 | unsigned int left, remains, block_size; |
505 | struct x2_header *hdr; |
506 | unsigned long timeout; |
507 | |
508 | err = p54u_firmware_reset_3887(dev); |
509 | if (err) |
510 | return err; |
511 | |
512 | tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); |
513 | if (!buf) |
514 | return -ENOMEM; |
515 | |
516 | left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size); |
517 | strcpy(p: buf, q: p54u_firmware_upload_3887); |
518 | left -= strlen(p54u_firmware_upload_3887); |
519 | tmp += strlen(p54u_firmware_upload_3887); |
520 | |
521 | data = priv->fw->data; |
522 | remains = priv->fw->size; |
523 | |
524 | hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887)); |
525 | memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); |
526 | hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); |
527 | hdr->fw_length = cpu_to_le32(priv->fw->size); |
528 | hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, |
529 | sizeof(u32)*2)); |
530 | left -= sizeof(*hdr); |
531 | tmp += sizeof(*hdr); |
532 | |
533 | while (remains) { |
534 | while (left--) { |
535 | if (carry) { |
536 | *tmp++ = carry; |
537 | carry = 0; |
538 | remains--; |
539 | continue; |
540 | } |
541 | switch (*data) { |
542 | case '~': |
543 | *tmp++ = '}'; |
544 | carry = '^'; |
545 | break; |
546 | case '}': |
547 | *tmp++ = '}'; |
548 | carry = ']'; |
549 | break; |
550 | default: |
551 | *tmp++ = *data; |
552 | remains--; |
553 | break; |
554 | } |
555 | data++; |
556 | } |
557 | |
558 | err = p54u_bulk_msg(priv, ep: P54U_PIPE_DATA, data: buf, len: block_size); |
559 | if (err) { |
560 | dev_err(&priv->udev->dev, "(p54usb) firmware " |
561 | "upload failed!\n" ); |
562 | goto err_upload_failed; |
563 | } |
564 | |
565 | tmp = buf; |
566 | left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); |
567 | } |
568 | |
569 | *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data, |
570 | priv->fw->size)); |
571 | err = p54u_bulk_msg(priv, ep: P54U_PIPE_DATA, data: buf, len: sizeof(u32)); |
572 | if (err) { |
573 | dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n" ); |
574 | goto err_upload_failed; |
575 | } |
576 | timeout = jiffies + msecs_to_jiffies(m: 1000); |
577 | while (!(err = usb_bulk_msg(usb_dev: priv->udev, |
578 | usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), data: buf, len: 128, actual_length: &alen, timeout: 1000))) { |
579 | if (alen > 2 && !memcmp(p: buf, q: "OK" , size: 2)) |
580 | break; |
581 | |
582 | if (alen > 5 && !memcmp(p: buf, q: "ERROR" , size: 5)) { |
583 | err = -EINVAL; |
584 | break; |
585 | } |
586 | |
587 | if (time_after(jiffies, timeout)) { |
588 | dev_err(&priv->udev->dev, "(p54usb) firmware boot " |
589 | "timed out!\n" ); |
590 | err = -ETIMEDOUT; |
591 | break; |
592 | } |
593 | } |
594 | if (err) { |
595 | dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n" ); |
596 | goto err_upload_failed; |
597 | } |
598 | |
599 | buf[0] = 'g'; |
600 | buf[1] = '\r'; |
601 | err = p54u_bulk_msg(priv, ep: P54U_PIPE_DATA, data: buf, len: 2); |
602 | if (err) { |
603 | dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n" ); |
604 | goto err_upload_failed; |
605 | } |
606 | |
607 | timeout = jiffies + msecs_to_jiffies(m: 1000); |
608 | while (!(err = usb_bulk_msg(usb_dev: priv->udev, |
609 | usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), data: buf, len: 128, actual_length: &alen, timeout: 1000))) { |
610 | if (alen > 0 && buf[0] == 'g') |
611 | break; |
612 | |
613 | if (time_after(jiffies, timeout)) { |
614 | err = -ETIMEDOUT; |
615 | break; |
616 | } |
617 | } |
618 | if (err) |
619 | goto err_upload_failed; |
620 | |
621 | err_upload_failed: |
622 | kfree(objp: buf); |
623 | return err; |
624 | } |
625 | |
626 | static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) |
627 | { |
628 | struct p54u_priv *priv = dev->priv; |
629 | const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; |
630 | int err, alen; |
631 | void *buf; |
632 | __le32 reg; |
633 | unsigned int remains, offset; |
634 | const u8 *data; |
635 | |
636 | buf = kmalloc(size: 512, GFP_KERNEL); |
637 | if (!buf) |
638 | return -ENOMEM; |
639 | |
640 | #define P54U_WRITE(type, addr, data) \ |
641 | do {\ |
642 | err = p54u_write(priv, buf, type,\ |
643 | cpu_to_le32((u32)(unsigned long)addr), data);\ |
644 | if (err) \ |
645 | goto fail;\ |
646 | } while (0) |
647 | |
648 | #define P54U_READ(type, addr) \ |
649 | do {\ |
650 | err = p54u_read(priv, buf, type,\ |
651 | cpu_to_le32((u32)(unsigned long)addr), ®);\ |
652 | if (err)\ |
653 | goto fail;\ |
654 | } while (0) |
655 | |
656 | /* power down net2280 bridge */ |
657 | P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL); |
658 | reg |= cpu_to_le32(P54U_BRG_POWER_DOWN); |
659 | reg &= cpu_to_le32(~P54U_BRG_POWER_UP); |
660 | P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); |
661 | |
662 | mdelay(100); |
663 | |
664 | /* power up bridge */ |
665 | reg |= cpu_to_le32(P54U_BRG_POWER_UP); |
666 | reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN); |
667 | P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); |
668 | |
669 | mdelay(100); |
670 | |
671 | P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT, |
672 | cpu_to_le32(NET2280_CLK_30Mhz | |
673 | NET2280_PCI_ENABLE | |
674 | NET2280_PCI_SOFT_RESET)); |
675 | |
676 | mdelay(20); |
677 | |
678 | P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND, |
679 | cpu_to_le32(PCI_COMMAND_MEMORY | |
680 | PCI_COMMAND_MASTER)); |
681 | |
682 | P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0, |
683 | cpu_to_le32(NET2280_BASE)); |
684 | |
685 | P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS); |
686 | reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT); |
687 | P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg); |
688 | |
689 | // TODO: we really need this? |
690 | P54U_READ(NET2280_BRG_U32, NET2280_RELNUM); |
691 | |
692 | P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP, |
693 | cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); |
694 | P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP, |
695 | cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); |
696 | |
697 | P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2, |
698 | cpu_to_le32(NET2280_BASE2)); |
699 | |
700 | /* finally done setting up the bridge */ |
701 | |
702 | P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND, |
703 | cpu_to_le32(PCI_COMMAND_MEMORY | |
704 | PCI_COMMAND_MASTER)); |
705 | |
706 | P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0); |
707 | P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0, |
708 | cpu_to_le32(P54U_DEV_BASE)); |
709 | |
710 | P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); |
711 | P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, |
712 | cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); |
713 | |
714 | /* do romboot */ |
715 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0); |
716 | |
717 | P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); |
718 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
719 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); |
720 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); |
721 | P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
722 | |
723 | mdelay(20); |
724 | |
725 | reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); |
726 | P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
727 | |
728 | mdelay(20); |
729 | |
730 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
731 | P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
732 | |
733 | mdelay(100); |
734 | |
735 | P54U_READ(NET2280_DEV_U32, &devreg->int_ident); |
736 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
737 | |
738 | /* finally, we can upload firmware now! */ |
739 | remains = priv->fw->size; |
740 | data = priv->fw->data; |
741 | offset = ISL38XX_DEV_FIRMWARE_ADDR; |
742 | |
743 | while (remains) { |
744 | unsigned int block_len = min(remains, (unsigned int)512); |
745 | memcpy(buf, data, block_len); |
746 | |
747 | err = p54u_bulk_msg(priv, ep: P54U_PIPE_DATA, data: buf, len: block_len); |
748 | if (err) { |
749 | dev_err(&priv->udev->dev, "(p54usb) firmware block " |
750 | "upload failed\n" ); |
751 | goto fail; |
752 | } |
753 | |
754 | P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base, |
755 | cpu_to_le32(0xc0000f00)); |
756 | |
757 | P54U_WRITE(NET2280_DEV_U32, |
758 | 0x0020 | (unsigned long)&devreg->direct_mem_win, 0); |
759 | P54U_WRITE(NET2280_DEV_U32, |
760 | 0x0020 | (unsigned long)&devreg->direct_mem_win, |
761 | cpu_to_le32(1)); |
762 | |
763 | P54U_WRITE(NET2280_DEV_U32, |
764 | 0x0024 | (unsigned long)&devreg->direct_mem_win, |
765 | cpu_to_le32(block_len)); |
766 | P54U_WRITE(NET2280_DEV_U32, |
767 | 0x0028 | (unsigned long)&devreg->direct_mem_win, |
768 | cpu_to_le32(offset)); |
769 | |
770 | P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr, |
771 | cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR)); |
772 | P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len, |
773 | cpu_to_le32(block_len >> 2)); |
774 | P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl, |
775 | cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER)); |
776 | |
777 | mdelay(10); |
778 | |
779 | P54U_READ(NET2280_DEV_U32, |
780 | 0x002C | (unsigned long)&devreg->direct_mem_win); |
781 | if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || |
782 | !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { |
783 | dev_err(&priv->udev->dev, "(p54usb) firmware DMA " |
784 | "transfer failed\n" ); |
785 | goto fail; |
786 | } |
787 | |
788 | P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT, |
789 | cpu_to_le32(NET2280_FIFO_FLUSH)); |
790 | |
791 | remains -= block_len; |
792 | data += block_len; |
793 | offset += block_len; |
794 | } |
795 | |
796 | /* do ramboot */ |
797 | P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); |
798 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
799 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); |
800 | reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); |
801 | P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
802 | |
803 | mdelay(20); |
804 | |
805 | reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); |
806 | P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
807 | |
808 | reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
809 | P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
810 | |
811 | mdelay(100); |
812 | |
813 | P54U_READ(NET2280_DEV_U32, &devreg->int_ident); |
814 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
815 | |
816 | /* start up the firmware */ |
817 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, |
818 | cpu_to_le32(ISL38XX_INT_IDENT_INIT)); |
819 | |
820 | P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, |
821 | cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); |
822 | |
823 | P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, |
824 | cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE | |
825 | NET2280_USB_INTERRUPT_ENABLE)); |
826 | |
827 | P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int, |
828 | cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
829 | |
830 | err = usb_interrupt_msg(usb_dev: priv->udev, |
831 | usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT), |
832 | data: buf, len: sizeof(__le32), actual_length: &alen, timeout: 1000); |
833 | if (err || alen != sizeof(__le32)) |
834 | goto fail; |
835 | |
836 | P54U_READ(NET2280_DEV_U32, &devreg->int_ident); |
837 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
838 | |
839 | if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))) |
840 | err = -EINVAL; |
841 | |
842 | P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); |
843 | P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, |
844 | cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); |
845 | |
846 | #undef P54U_WRITE |
847 | #undef P54U_READ |
848 | |
849 | fail: |
850 | kfree(objp: buf); |
851 | return err; |
852 | } |
853 | |
854 | static int p54_find_type(struct p54u_priv *priv) |
855 | { |
856 | int i; |
857 | |
858 | for (i = 0; i < __NUM_P54U_HWTYPES; i++) |
859 | if (p54u_fwlist[i].type == priv->hw_type) |
860 | break; |
861 | if (i == __NUM_P54U_HWTYPES) |
862 | return -EOPNOTSUPP; |
863 | |
864 | return i; |
865 | } |
866 | |
867 | static int p54u_start_ops(struct p54u_priv *priv) |
868 | { |
869 | struct ieee80211_hw *dev = priv->common.hw; |
870 | int ret; |
871 | |
872 | ret = p54_parse_firmware(dev, fw: priv->fw); |
873 | if (ret) |
874 | goto err_out; |
875 | |
876 | ret = p54_find_type(priv); |
877 | if (ret < 0) |
878 | goto err_out; |
879 | |
880 | if (priv->common.fw_interface != p54u_fwlist[ret].intf) { |
881 | dev_err(&priv->udev->dev, "wrong firmware, please get " |
882 | "a firmware for \"%s\" and try again.\n" , |
883 | p54u_fwlist[ret].hw); |
884 | ret = -ENODEV; |
885 | goto err_out; |
886 | } |
887 | |
888 | ret = priv->upload_fw(dev); |
889 | if (ret) |
890 | goto err_out; |
891 | |
892 | ret = p54u_open(dev); |
893 | if (ret) |
894 | goto err_out; |
895 | |
896 | ret = p54_read_eeprom(dev); |
897 | if (ret) |
898 | goto err_stop; |
899 | |
900 | p54u_stop(dev); |
901 | |
902 | ret = p54_register_common(dev, pdev: &priv->udev->dev); |
903 | if (ret) |
904 | goto err_stop; |
905 | |
906 | return 0; |
907 | |
908 | err_stop: |
909 | p54u_stop(dev); |
910 | |
911 | err_out: |
912 | /* |
913 | * p54u_disconnect will do the rest of the |
914 | * cleanup |
915 | */ |
916 | return ret; |
917 | } |
918 | |
919 | static void p54u_load_firmware_cb(const struct firmware *firmware, |
920 | void *context) |
921 | { |
922 | struct p54u_priv *priv = context; |
923 | struct usb_device *udev = priv->udev; |
924 | struct usb_interface *intf = priv->intf; |
925 | int err; |
926 | |
927 | if (firmware) { |
928 | priv->fw = firmware; |
929 | err = p54u_start_ops(priv); |
930 | } else { |
931 | err = -ENOENT; |
932 | dev_err(&udev->dev, "Firmware not found.\n" ); |
933 | } |
934 | |
935 | complete(&priv->fw_wait_load); |
936 | /* |
937 | * At this point p54u_disconnect may have already freed |
938 | * the "priv" context. Do not use it anymore! |
939 | */ |
940 | priv = NULL; |
941 | |
942 | if (err) { |
943 | dev_err(&intf->dev, "failed to initialize device (%d)\n" , err); |
944 | |
945 | usb_lock_device(udev); |
946 | usb_driver_release_interface(driver: &p54u_driver, iface: intf); |
947 | usb_unlock_device(udev); |
948 | } |
949 | |
950 | usb_put_intf(intf); |
951 | } |
952 | |
953 | static int p54u_load_firmware(struct ieee80211_hw *dev, |
954 | struct usb_interface *intf) |
955 | { |
956 | struct usb_device *udev = interface_to_usbdev(intf); |
957 | struct p54u_priv *priv = dev->priv; |
958 | struct device *device = &udev->dev; |
959 | int err, i; |
960 | |
961 | BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); |
962 | |
963 | init_completion(x: &priv->fw_wait_load); |
964 | i = p54_find_type(priv); |
965 | if (i < 0) |
966 | return i; |
967 | |
968 | dev_info(&priv->udev->dev, "Loading firmware file %s\n" , |
969 | p54u_fwlist[i].fw); |
970 | |
971 | usb_get_intf(intf); |
972 | err = request_firmware_nowait(THIS_MODULE, uevent: 1, name: p54u_fwlist[i].fw, |
973 | device, GFP_KERNEL, context: priv, |
974 | cont: p54u_load_firmware_cb); |
975 | if (err) { |
976 | dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " |
977 | "(%d)!\n" , p54u_fwlist[i].fw, err); |
978 | usb_put_intf(intf); |
979 | } |
980 | |
981 | return err; |
982 | } |
983 | |
984 | static int p54u_probe(struct usb_interface *intf, |
985 | const struct usb_device_id *id) |
986 | { |
987 | struct usb_device *udev = interface_to_usbdev(intf); |
988 | struct ieee80211_hw *dev; |
989 | struct p54u_priv *priv; |
990 | int err; |
991 | unsigned int i, recognized_pipes; |
992 | |
993 | dev = p54_init_common(priv_data_len: sizeof(*priv)); |
994 | |
995 | if (!dev) { |
996 | dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n" ); |
997 | return -ENOMEM; |
998 | } |
999 | |
1000 | priv = dev->priv; |
1001 | priv->hw_type = P54U_INVALID_HW; |
1002 | |
1003 | SET_IEEE80211_DEV(hw: dev, dev: &intf->dev); |
1004 | usb_set_intfdata(intf, data: dev); |
1005 | priv->udev = udev; |
1006 | priv->intf = intf; |
1007 | skb_queue_head_init(list: &priv->rx_queue); |
1008 | init_usb_anchor(anchor: &priv->submitted); |
1009 | |
1010 | /* really lazy and simple way of figuring out if we're a 3887 */ |
1011 | /* TODO: should just stick the identification in the device table */ |
1012 | i = intf->altsetting->desc.bNumEndpoints; |
1013 | recognized_pipes = 0; |
1014 | while (i--) { |
1015 | switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) { |
1016 | case P54U_PIPE_DATA: |
1017 | case P54U_PIPE_MGMT: |
1018 | case P54U_PIPE_BRG: |
1019 | case P54U_PIPE_DEV: |
1020 | case P54U_PIPE_DATA | USB_DIR_IN: |
1021 | case P54U_PIPE_MGMT | USB_DIR_IN: |
1022 | case P54U_PIPE_BRG | USB_DIR_IN: |
1023 | case P54U_PIPE_DEV | USB_DIR_IN: |
1024 | case P54U_PIPE_INT | USB_DIR_IN: |
1025 | recognized_pipes++; |
1026 | } |
1027 | } |
1028 | priv->common.open = p54u_open; |
1029 | priv->common.stop = p54u_stop; |
1030 | if (recognized_pipes < P54U_PIPE_NUMBER) { |
1031 | #ifdef CONFIG_PM |
1032 | /* ISL3887 needs a full reset on resume */ |
1033 | udev->reset_resume = 1; |
1034 | #endif /* CONFIG_PM */ |
1035 | err = p54u_device_reset(dev); |
1036 | |
1037 | priv->hw_type = P54U_3887; |
1038 | dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); |
1039 | priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); |
1040 | priv->common.tx = p54u_tx_lm87; |
1041 | priv->upload_fw = p54u_upload_firmware_3887; |
1042 | } else { |
1043 | priv->hw_type = P54U_NET2280; |
1044 | dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); |
1045 | priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); |
1046 | priv->common.tx = p54u_tx_net2280; |
1047 | priv->upload_fw = p54u_upload_firmware_net2280; |
1048 | } |
1049 | err = p54u_load_firmware(dev, intf); |
1050 | if (err) |
1051 | p54_free_common(dev); |
1052 | return err; |
1053 | } |
1054 | |
1055 | static void p54u_disconnect(struct usb_interface *intf) |
1056 | { |
1057 | struct ieee80211_hw *dev = usb_get_intfdata(intf); |
1058 | struct p54u_priv *priv; |
1059 | |
1060 | if (!dev) |
1061 | return; |
1062 | |
1063 | priv = dev->priv; |
1064 | wait_for_completion(&priv->fw_wait_load); |
1065 | p54_unregister_common(dev); |
1066 | |
1067 | release_firmware(fw: priv->fw); |
1068 | p54_free_common(dev); |
1069 | } |
1070 | |
1071 | static int p54u_pre_reset(struct usb_interface *intf) |
1072 | { |
1073 | struct ieee80211_hw *dev = usb_get_intfdata(intf); |
1074 | |
1075 | if (!dev) |
1076 | return -ENODEV; |
1077 | |
1078 | p54u_stop(dev); |
1079 | return 0; |
1080 | } |
1081 | |
1082 | static int p54u_resume(struct usb_interface *intf) |
1083 | { |
1084 | struct ieee80211_hw *dev = usb_get_intfdata(intf); |
1085 | struct p54u_priv *priv; |
1086 | |
1087 | if (!dev) |
1088 | return -ENODEV; |
1089 | |
1090 | priv = dev->priv; |
1091 | if (unlikely(!(priv->upload_fw && priv->fw))) |
1092 | return 0; |
1093 | |
1094 | return priv->upload_fw(dev); |
1095 | } |
1096 | |
1097 | static int p54u_post_reset(struct usb_interface *intf) |
1098 | { |
1099 | struct ieee80211_hw *dev = usb_get_intfdata(intf); |
1100 | struct p54u_priv *priv; |
1101 | int err; |
1102 | |
1103 | err = p54u_resume(intf); |
1104 | if (err) |
1105 | return err; |
1106 | |
1107 | /* reinitialize old device state */ |
1108 | priv = dev->priv; |
1109 | if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) |
1110 | ieee80211_restart_hw(hw: dev); |
1111 | |
1112 | return 0; |
1113 | } |
1114 | |
1115 | #ifdef CONFIG_PM |
1116 | |
1117 | static int p54u_suspend(struct usb_interface *intf, pm_message_t message) |
1118 | { |
1119 | return p54u_pre_reset(intf); |
1120 | } |
1121 | |
1122 | #endif /* CONFIG_PM */ |
1123 | |
1124 | static struct usb_driver p54u_driver = { |
1125 | .name = "p54usb" , |
1126 | .id_table = p54u_table, |
1127 | .probe = p54u_probe, |
1128 | .disconnect = p54u_disconnect, |
1129 | .pre_reset = p54u_pre_reset, |
1130 | .post_reset = p54u_post_reset, |
1131 | #ifdef CONFIG_PM |
1132 | .suspend = p54u_suspend, |
1133 | .resume = p54u_resume, |
1134 | .reset_resume = p54u_resume, |
1135 | #endif /* CONFIG_PM */ |
1136 | .soft_unbind = 1, |
1137 | .disable_hub_initiated_lpm = 1, |
1138 | }; |
1139 | |
1140 | module_usb_driver(p54u_driver); |
1141 | |