blob: f40c0f468b279acc41cc9f26063e1ace235e2bc8 [file] [log] [blame]
Michael Wueff1a592007-09-25 18:11:01 -07001
2/*
3 * Linux device driver for USB based Prism54
4 *
5 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
6 *
7 * Based on the islsm (softmac prism54) driver, which is:
8 * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/init.h>
16#include <linux/usb.h>
17#include <linux/pci.h>
18#include <linux/firmware.h>
19#include <linux/etherdevice.h>
20#include <linux/delay.h>
21#include <linux/crc32.h>
22#include <net/mac80211.h>
23
24#include "p54.h"
25#include "p54usb.h"
26
27MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
28MODULE_DESCRIPTION("Prism54 USB wireless driver");
29MODULE_LICENSE("GPL");
30MODULE_ALIAS("prism54usb");
Christian Lamparter9a8675d2008-10-18 23:04:15 +020031MODULE_FIRMWARE("isl3886usb");
32MODULE_FIRMWARE("isl3887usb");
Michael Wueff1a592007-09-25 18:11:01 -070033
34static struct usb_device_id p54u_table[] __devinitdata = {
35 /* Version 1 devices (pci chip + net2280) */
36 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
37 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
38 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
39 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050040 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070041 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
42 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
43 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020044 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070045 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
46 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
47 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
48 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
49 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
50 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
51 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
52 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
53
54 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070055 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070056 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
57 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
58 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060059 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070060 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
61 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
62 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
63 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
64 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
65 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
66 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
67 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
68 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
69 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070070 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020071 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050072 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040073 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020074 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070075 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
76 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
77 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
78 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
79 {}
80};
81
82MODULE_DEVICE_TABLE(usb, p54u_table);
83
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020084static const struct {
85 u32 intf;
86 enum p54u_hw_type type;
87 char fw[FIRMWARE_NAME_MAX];
88 char fw_legacy[FIRMWARE_NAME_MAX];
89 char hw[20];
90} p54u_fwlist[__NUM_P54U_HWTYPES] = {
91 {
92 .type = P54U_NET2280,
93 .intf = FW_LM86,
94 .fw = "isl3886usb",
95 .fw_legacy = "isl3890usb",
96 .hw = "ISL3886 + net2280",
97 },
98 {
99 .type = P54U_3887,
100 .intf = FW_LM87,
101 .fw = "isl3887usb",
102 .fw_legacy = "isl3887usb_bare",
103 .hw = "ISL3887",
104 },
105};
106
Michael Wueff1a592007-09-25 18:11:01 -0700107static void p54u_rx_cb(struct urb *urb)
108{
109 struct sk_buff *skb = (struct sk_buff *) urb->context;
110 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
111 struct ieee80211_hw *dev = info->dev;
112 struct p54u_priv *priv = dev->priv;
113
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100114 skb_unlink(skb, &priv->rx_queue);
115
Michael Wueff1a592007-09-25 18:11:01 -0700116 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100117 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700118 return;
119 }
120
Michael Wueff1a592007-09-25 18:11:01 -0700121 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200122
123 if (priv->hw_type == P54U_NET2280)
124 skb_pull(skb, priv->common.tx_hdr_len);
125 if (priv->common.fw_interface == FW_LM87) {
126 skb_pull(skb, 4);
127 skb_put(skb, 4);
128 }
Michael Wueff1a592007-09-25 18:11:01 -0700129
130 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200131 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700132 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700133 /* TODO check rx queue length and refill *somewhere* */
134 return;
135 }
136
137 info = (struct p54u_rx_info *) skb->cb;
138 info->urb = urb;
139 info->dev = dev;
140 urb->transfer_buffer = skb_tail_pointer(skb);
141 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700142 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200143 if (priv->hw_type == P54U_NET2280)
144 skb_push(skb, priv->common.tx_hdr_len);
145 if (priv->common.fw_interface == FW_LM87) {
146 skb_push(skb, 4);
147 skb_put(skb, 4);
148 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200149 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700150 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200151 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700152 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100153 skb_queue_tail(&priv->rx_queue, skb);
154 usb_anchor_urb(urb, &priv->submitted);
155 if (usb_submit_urb(urb, GFP_ATOMIC)) {
156 skb_unlink(skb, &priv->rx_queue);
157 usb_unanchor_urb(urb);
158 dev_kfree_skb_irq(skb);
159 }
Michael Wueff1a592007-09-25 18:11:01 -0700160}
161
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100162static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200163{
164 struct sk_buff *skb = urb->context;
165 struct ieee80211_hw *dev = (struct ieee80211_hw *)
166 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
167
Christian Lampartere2fe1542009-01-20 00:27:57 +0100168 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100169}
170
171static void p54u_tx_dummy_cb(struct urb *urb) { }
172
173static void p54u_free_urbs(struct ieee80211_hw *dev)
174{
175 struct p54u_priv *priv = dev->priv;
176 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200177}
178
Michael Wueff1a592007-09-25 18:11:01 -0700179static int p54u_init_urbs(struct ieee80211_hw *dev)
180{
181 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100182 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700183 struct sk_buff *skb;
184 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100185 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700186
187 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200188 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100189 if (!skb) {
190 ret = -ENOMEM;
191 goto err;
192 }
Michael Wueff1a592007-09-25 18:11:01 -0700193 entry = usb_alloc_urb(0, GFP_KERNEL);
194 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100195 ret = -ENOMEM;
196 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700197 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100198
Christian Lamparter4e416a62008-09-01 22:48:41 +0200199 usb_fill_bulk_urb(entry, priv->udev,
200 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
201 skb_tail_pointer(skb),
202 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700203 info = (struct p54u_rx_info *) skb->cb;
204 info->urb = entry;
205 info->dev = dev;
206 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100207
208 usb_anchor_urb(entry, &priv->submitted);
209 ret = usb_submit_urb(entry, GFP_KERNEL);
210 if (ret) {
211 skb_unlink(skb, &priv->rx_queue);
212 usb_unanchor_urb(entry);
213 goto err;
214 }
215 usb_free_urb(entry);
216 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700217 }
218
219 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700220
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100221 err:
222 usb_free_urb(entry);
223 kfree_skb(skb);
224 p54u_free_urbs(dev);
225 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700226}
227
Johannes Bergc9127652008-12-01 18:19:36 +0100228static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200229{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500230 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200231
232 length >>= 2;
233 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100234 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200235 chk = (chk >> 5) ^ (chk << 3);
236 }
237
Larry Finger1f1c0e32008-09-25 14:54:28 -0500238 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200239}
240
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100241static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200242{
243 struct p54u_priv *priv = dev->priv;
244 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100245 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200246
247 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
248 if (!data_urb)
249 return;
250
Christian Lampartere2fe1542009-01-20 00:27:57 +0100251 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
252 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200253
254 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200255 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100256 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
257 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100258 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200259
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100260 usb_anchor_urb(data_urb, &priv->submitted);
261 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
262 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100263 p54_free_skb(dev, skb);
264 }
265 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200266}
267
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100268static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700269{
270 struct p54u_priv *priv = dev->priv;
271 struct urb *int_urb, *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100272 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Michael Wueff1a592007-09-25 18:11:01 -0700273 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100274 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700275
276 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
277 if (!reg)
278 return;
279
280 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
281 if (!int_urb) {
282 kfree(reg);
283 return;
284 }
285
286 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
287 if (!data_urb) {
288 kfree(reg);
289 usb_free_urb(int_urb);
290 return;
291 }
292
293 reg->port = cpu_to_le16(NET2280_DEV_U32);
294 reg->addr = cpu_to_le32(P54U_DEV_BASE);
295 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
296
Michael Wueff1a592007-09-25 18:11:01 -0700297 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100298 hdr->len = cpu_to_le16(skb->len);
299 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700300
301 usb_fill_bulk_urb(int_urb, priv->udev,
302 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100303 p54u_tx_dummy_cb, dev);
304
305 /*
306 * This flag triggers a code path in the USB subsystem that will
307 * free what's inside the transfer_buffer after the callback routine
308 * has completed.
309 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100310 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Michael Wueff1a592007-09-25 18:11:01 -0700311
312 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200313 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100314 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
315 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100316 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100317
318 usb_anchor_urb(int_urb, &priv->submitted);
319 err = usb_submit_urb(int_urb, GFP_ATOMIC);
320 if (err) {
321 usb_unanchor_urb(int_urb);
322 goto out;
323 }
324
325 usb_anchor_urb(data_urb, &priv->submitted);
326 err = usb_submit_urb(data_urb, GFP_ATOMIC);
327 if (err) {
328 usb_unanchor_urb(data_urb);
329 goto out;
330 }
331 out:
332 usb_free_urb(int_urb);
333 usb_free_urb(data_urb);
334
335 if (err) {
336 skb_pull(skb, sizeof(*hdr));
337 p54_free_skb(dev, skb);
338 }
Michael Wueff1a592007-09-25 18:11:01 -0700339}
340
341static int p54u_write(struct p54u_priv *priv,
342 struct net2280_reg_write *buf,
343 enum net2280_op_type type,
344 __le32 addr, __le32 val)
345{
346 unsigned int ep;
347 int alen;
348
349 if (type & 0x0800)
350 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
351 else
352 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
353
354 buf->port = cpu_to_le16(type);
355 buf->addr = addr;
356 buf->val = val;
357
358 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
359}
360
361static int p54u_read(struct p54u_priv *priv, void *buf,
362 enum net2280_op_type type,
363 __le32 addr, __le32 *val)
364{
365 struct net2280_reg_read *read = buf;
366 __le32 *reg = buf;
367 unsigned int ep;
368 int alen, err;
369
370 if (type & 0x0800)
371 ep = P54U_PIPE_DEV;
372 else
373 ep = P54U_PIPE_BRG;
374
375 read->port = cpu_to_le16(type);
376 read->addr = addr;
377
378 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
379 read, sizeof(*read), &alen, 1000);
380 if (err)
381 return err;
382
383 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
384 reg, sizeof(*reg), &alen, 1000);
385 if (err)
386 return err;
387
388 *val = *reg;
389 return 0;
390}
391
392static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
393 void *data, size_t len)
394{
395 int alen;
396 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
397 data, len, &alen, 2000);
398}
399
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200400static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100401{
402 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100403 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100404
Christian Lamparterc88a7682009-01-16 20:24:31 +0100405 if (lock) {
406 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
407 if (ret < 0) {
408 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200409 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100410 return ret;
411 }
Christian Lamparter69828692008-12-26 19:08:31 +0100412 }
413
414 ret = usb_reset_device(priv->udev);
415 if (lock)
416 usb_unlock_device(priv->udev);
417
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200418 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100419 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200420 "device (%d)!\n", ret);
421
422 return ret;
423}
424
425static const char p54u_romboot_3887[] = "~~~~";
426static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
427{
428 struct p54u_priv *priv = dev->priv;
429 u8 buf[4];
430 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100431
432 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
433 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
434 buf, sizeof(buf));
435 if (ret)
436 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200437 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100438
439 return ret;
440}
441
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200442static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700443static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
444{
Michael Wueff1a592007-09-25 18:11:01 -0700445 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700446 int err, alen;
447 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100448 u8 *buf, *tmp;
449 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700450 unsigned int left, remains, block_size;
451 struct x2_header *hdr;
452 unsigned long timeout;
453
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200454 err = p54u_firmware_reset_3887(dev);
455 if (err)
456 return err;
457
Michael Wueff1a592007-09-25 18:11:01 -0700458 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
459 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100460 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
461 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200462 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700463 }
464
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200465 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100466 strcpy(buf, p54u_firmware_upload_3887);
467 left -= strlen(p54u_firmware_upload_3887);
468 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700469
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200470 data = priv->fw->data;
471 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700472
Christian Lamparter69828692008-12-26 19:08:31 +0100473 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700474 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
475 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200476 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700477 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
478 sizeof(u32)*2));
479 left -= sizeof(*hdr);
480 tmp += sizeof(*hdr);
481
482 while (remains) {
483 while (left--) {
484 if (carry) {
485 *tmp++ = carry;
486 carry = 0;
487 remains--;
488 continue;
489 }
490 switch (*data) {
491 case '~':
492 *tmp++ = '}';
493 carry = '^';
494 break;
495 case '}':
496 *tmp++ = '}';
497 carry = ']';
498 break;
499 default:
500 *tmp++ = *data;
501 remains--;
502 break;
503 }
504 data++;
505 }
506
507 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
508 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100509 dev_err(&priv->udev->dev, "(p54usb) firmware "
510 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700511 goto err_upload_failed;
512 }
513
514 tmp = buf;
515 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
516 }
517
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200518 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
519 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700520 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
521 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100522 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700523 goto err_upload_failed;
524 }
Michael Wueff1a592007-09-25 18:11:01 -0700525 timeout = jiffies + msecs_to_jiffies(1000);
526 while (!(err = usb_bulk_msg(priv->udev,
527 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
528 if (alen > 2 && !memcmp(buf, "OK", 2))
529 break;
530
531 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700532 err = -EINVAL;
533 break;
534 }
535
536 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100537 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
538 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700539 err = -ETIMEDOUT;
540 break;
541 }
542 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100543 if (err) {
544 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700545 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100546 }
Michael Wueff1a592007-09-25 18:11:01 -0700547
548 buf[0] = 'g';
549 buf[1] = '\r';
550 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
551 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100552 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700553 goto err_upload_failed;
554 }
555
556 timeout = jiffies + msecs_to_jiffies(1000);
557 while (!(err = usb_bulk_msg(priv->udev,
558 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
559 if (alen > 0 && buf[0] == 'g')
560 break;
561
562 if (time_after(jiffies, timeout)) {
563 err = -ETIMEDOUT;
564 break;
565 }
566 }
567 if (err)
568 goto err_upload_failed;
569
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200570err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700571 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700572 return err;
573}
574
575static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
576{
577 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700578 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
579 int err, alen;
580 void *buf;
581 __le32 reg;
582 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100583 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700584
585 buf = kmalloc(512, GFP_KERNEL);
586 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100587 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
588 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700589 return -ENOMEM;
590 }
591
Michael Wueff1a592007-09-25 18:11:01 -0700592#define P54U_WRITE(type, addr, data) \
593 do {\
594 err = p54u_write(priv, buf, type,\
595 cpu_to_le32((u32)(unsigned long)addr), data);\
596 if (err) \
597 goto fail;\
598 } while (0)
599
600#define P54U_READ(type, addr) \
601 do {\
602 err = p54u_read(priv, buf, type,\
603 cpu_to_le32((u32)(unsigned long)addr), &reg);\
604 if (err)\
605 goto fail;\
606 } while (0)
607
608 /* power down net2280 bridge */
609 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
610 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
611 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
612 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
613
614 mdelay(100);
615
616 /* power up bridge */
617 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
618 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
619 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
620
621 mdelay(100);
622
623 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
624 cpu_to_le32(NET2280_CLK_30Mhz |
625 NET2280_PCI_ENABLE |
626 NET2280_PCI_SOFT_RESET));
627
628 mdelay(20);
629
630 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
631 cpu_to_le32(PCI_COMMAND_MEMORY |
632 PCI_COMMAND_MASTER));
633
634 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
635 cpu_to_le32(NET2280_BASE));
636
637 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
638 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
639 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
640
641 // TODO: we really need this?
642 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
643
644 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
645 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
646 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
647 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
648
649 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
650 cpu_to_le32(NET2280_BASE2));
651
652 /* finally done setting up the bridge */
653
654 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
655 cpu_to_le32(PCI_COMMAND_MEMORY |
656 PCI_COMMAND_MASTER));
657
658 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
659 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
660 cpu_to_le32(P54U_DEV_BASE));
661
662 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
663 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
664 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
665
666 /* do romboot */
667 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
668
669 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
670 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
671 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
672 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
673 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
674
675 mdelay(20);
676
677 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
678 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
679
680 mdelay(20);
681
682 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
683 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
684
685 mdelay(100);
686
687 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
688 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
689
690 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200691 remains = priv->fw->size;
692 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700693 offset = ISL38XX_DEV_FIRMWARE_ADDR;
694
695 while (remains) {
696 unsigned int block_len = min(remains, (unsigned int)512);
697 memcpy(buf, data, block_len);
698
699 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
700 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100701 dev_err(&priv->udev->dev, "(p54usb) firmware block "
702 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700703 goto fail;
704 }
705
706 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
707 cpu_to_le32(0xc0000f00));
708
709 P54U_WRITE(NET2280_DEV_U32,
710 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
711 P54U_WRITE(NET2280_DEV_U32,
712 0x0020 | (unsigned long)&devreg->direct_mem_win,
713 cpu_to_le32(1));
714
715 P54U_WRITE(NET2280_DEV_U32,
716 0x0024 | (unsigned long)&devreg->direct_mem_win,
717 cpu_to_le32(block_len));
718 P54U_WRITE(NET2280_DEV_U32,
719 0x0028 | (unsigned long)&devreg->direct_mem_win,
720 cpu_to_le32(offset));
721
722 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
723 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
724 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
725 cpu_to_le32(block_len >> 2));
726 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
727 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
728
729 mdelay(10);
730
731 P54U_READ(NET2280_DEV_U32,
732 0x002C | (unsigned long)&devreg->direct_mem_win);
733 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
734 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100735 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
736 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700737 goto fail;
738 }
739
740 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
741 cpu_to_le32(NET2280_FIFO_FLUSH));
742
743 remains -= block_len;
744 data += block_len;
745 offset += block_len;
746 }
747
748 /* do ramboot */
749 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
750 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
751 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
752 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
753 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
754
755 mdelay(20);
756
757 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
758 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
759
760 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
761 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
762
763 mdelay(100);
764
765 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
766 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
767
768 /* start up the firmware */
769 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
770 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
771
772 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
773 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
774
775 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
776 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
777 NET2280_USB_INTERRUPT_ENABLE));
778
779 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
780 cpu_to_le32(ISL38XX_DEV_INT_RESET));
781
782 err = usb_interrupt_msg(priv->udev,
783 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
784 buf, sizeof(__le32), &alen, 1000);
785 if (err || alen != sizeof(__le32))
786 goto fail;
787
788 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
789 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
790
791 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
792 err = -EINVAL;
793
794 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
795 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
796 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
797
798#undef P54U_WRITE
799#undef P54U_READ
800
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200801fail:
Michael Wueff1a592007-09-25 18:11:01 -0700802 kfree(buf);
803 return err;
804}
805
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200806static int p54u_load_firmware(struct ieee80211_hw *dev)
807{
808 struct p54u_priv *priv = dev->priv;
809 int err, i;
810
811 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
812
813 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
814 if (p54u_fwlist[i].type == priv->hw_type)
815 break;
816
817 if (i == __NUM_P54U_HWTYPES)
818 return -EOPNOTSUPP;
819
820 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
821 if (err) {
822 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
823 "(%d)!\n", p54u_fwlist[i].fw, err);
824
825 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
826 &priv->udev->dev);
827 if (err)
828 return err;
829 }
830
831 err = p54_parse_firmware(dev, priv->fw);
832 if (err)
833 goto out;
834
835 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
836 dev_err(&priv->udev->dev, "wrong firmware, please get "
837 "a firmware for \"%s\" and try again.\n",
838 p54u_fwlist[i].hw);
839 err = -EINVAL;
840 }
841
842out:
843 if (err)
844 release_firmware(priv->fw);
845
846 return err;
847}
848
Michael Wueff1a592007-09-25 18:11:01 -0700849static int p54u_open(struct ieee80211_hw *dev)
850{
851 struct p54u_priv *priv = dev->priv;
852 int err;
853
854 err = p54u_init_urbs(dev);
855 if (err) {
856 return err;
857 }
858
859 priv->common.open = p54u_init_urbs;
860
861 return 0;
862}
863
864static void p54u_stop(struct ieee80211_hw *dev)
865{
866 /* TODO: figure out how to reliably stop the 3887 and net2280 so
867 the hardware is still usable next time we want to start it.
868 until then, we just stop listening to the hardware.. */
869 p54u_free_urbs(dev);
870 return;
871}
872
873static int __devinit p54u_probe(struct usb_interface *intf,
874 const struct usb_device_id *id)
875{
876 struct usb_device *udev = interface_to_usbdev(intf);
877 struct ieee80211_hw *dev;
878 struct p54u_priv *priv;
879 int err;
880 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700881
882 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100883
Michael Wueff1a592007-09-25 18:11:01 -0700884 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100885 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700886 return -ENOMEM;
887 }
888
889 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200890 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700891
892 SET_IEEE80211_DEV(dev, &intf->dev);
893 usb_set_intfdata(intf, dev);
894 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100895 priv->intf = intf;
896 skb_queue_head_init(&priv->rx_queue);
897 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700898
899 usb_get_dev(udev);
900
901 /* really lazy and simple way of figuring out if we're a 3887 */
902 /* TODO: should just stick the identification in the device table */
903 i = intf->altsetting->desc.bNumEndpoints;
904 recognized_pipes = 0;
905 while (i--) {
906 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
907 case P54U_PIPE_DATA:
908 case P54U_PIPE_MGMT:
909 case P54U_PIPE_BRG:
910 case P54U_PIPE_DEV:
911 case P54U_PIPE_DATA | USB_DIR_IN:
912 case P54U_PIPE_MGMT | USB_DIR_IN:
913 case P54U_PIPE_BRG | USB_DIR_IN:
914 case P54U_PIPE_DEV | USB_DIR_IN:
915 case P54U_PIPE_INT | USB_DIR_IN:
916 recognized_pipes++;
917 }
918 }
919 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200920 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700921 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200922#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200923 /* ISL3887 needs a full reset on resume */
924 udev->reset_resume = 1;
925 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200926#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200927
Michael Wueff1a592007-09-25 18:11:01 -0700928 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200929 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
930 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
931 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200932 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700933 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200934 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700935 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
936 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
937 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200938 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200939 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200940 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700941 if (err)
942 goto err_free_dev;
943
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200944 err = priv->upload_fw(dev);
945 if (err)
946 goto err_free_fw;
947
Christian Lamparter7cb77072008-09-01 22:48:51 +0200948 p54u_open(dev);
949 err = p54_read_eeprom(dev);
950 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700951 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200952 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700953
Christian Lamparter2ac71072009-03-05 21:30:10 +0100954 err = p54_register_common(dev, &udev->dev);
955 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200956 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700957
Michael Wueff1a592007-09-25 18:11:01 -0700958 return 0;
959
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200960err_free_fw:
961 release_firmware(priv->fw);
962
963err_free_dev:
Michael Wueff1a592007-09-25 18:11:01 -0700964 ieee80211_free_hw(dev);
965 usb_set_intfdata(intf, NULL);
966 usb_put_dev(udev);
967 return err;
968}
969
970static void __devexit p54u_disconnect(struct usb_interface *intf)
971{
972 struct ieee80211_hw *dev = usb_get_intfdata(intf);
973 struct p54u_priv *priv;
974
975 if (!dev)
976 return;
977
978 ieee80211_unregister_hw(dev);
979
980 priv = dev->priv;
981 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200982 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700983 p54_free_common(dev);
984 ieee80211_free_hw(dev);
985}
986
Christian Lamparter69828692008-12-26 19:08:31 +0100987static int p54u_pre_reset(struct usb_interface *intf)
988{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200989 struct ieee80211_hw *dev = usb_get_intfdata(intf);
990
991 if (!dev)
992 return -ENODEV;
993
994 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +0100995 return 0;
996}
997
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200998static int p54u_resume(struct usb_interface *intf)
999{
1000 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1001 struct p54u_priv *priv;
1002
1003 if (!dev)
1004 return -ENODEV;
1005
1006 priv = dev->priv;
1007 if (unlikely(!(priv->upload_fw && priv->fw)))
1008 return 0;
1009
1010 return priv->upload_fw(dev);
1011}
1012
Christian Lamparter69828692008-12-26 19:08:31 +01001013static int p54u_post_reset(struct usb_interface *intf)
1014{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001015 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1016 struct p54u_priv *priv;
1017 int err;
1018
1019 err = p54u_resume(intf);
1020 if (err)
1021 return err;
1022
1023 /* reinitialize old device state */
1024 priv = dev->priv;
1025 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1026 ieee80211_restart_hw(dev);
1027
Christian Lamparter69828692008-12-26 19:08:31 +01001028 return 0;
1029}
1030
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001031#ifdef CONFIG_PM
1032
1033static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1034{
1035 return p54u_pre_reset(intf);
1036}
1037
1038#endif /* CONFIG_PM */
1039
Michael Wueff1a592007-09-25 18:11:01 -07001040static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001041 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001042 .id_table = p54u_table,
1043 .probe = p54u_probe,
1044 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001045 .pre_reset = p54u_pre_reset,
1046 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001047#ifdef CONFIG_PM
1048 .suspend = p54u_suspend,
1049 .resume = p54u_resume,
1050 .reset_resume = p54u_resume,
1051#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001052 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001053};
1054
1055static int __init p54u_init(void)
1056{
1057 return usb_register(&p54u_driver);
1058}
1059
1060static void __exit p54u_exit(void)
1061{
1062 usb_deregister(&p54u_driver);
1063}
1064
1065module_init(p54u_init);
1066module_exit(p54u_exit);