blob: 461d88f5ceb74fcf708f5ef549bf0be4d86d0cf5 [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"
Christian Lamparterd8c92102009-06-23 10:39:45 -050025#include "lmac.h"
Michael Wueff1a592007-09-25 18:11:01 -070026#include "p54usb.h"
27
28MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
29MODULE_DESCRIPTION("Prism54 USB wireless driver");
30MODULE_LICENSE("GPL");
31MODULE_ALIAS("prism54usb");
Christian Lamparter9a8675d2008-10-18 23:04:15 +020032MODULE_FIRMWARE("isl3886usb");
33MODULE_FIRMWARE("isl3887usb");
Michael Wueff1a592007-09-25 18:11:01 -070034
35static struct usb_device_id p54u_table[] __devinitdata = {
36 /* Version 1 devices (pci chip + net2280) */
37 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
38 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
39 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
40 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050041 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070042 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
43 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
44 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020045 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070046 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
47 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
48 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
49 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
50 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
51 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
52 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
53 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
54
55 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070056 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070057 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
58 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
59 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060060 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070061 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
62 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
63 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
64 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
65 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
66 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
67 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
68 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
69 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
70 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070071 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020072 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050073 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040074 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020075 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070076 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
77 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
78 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
79 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
80 {}
81};
82
83MODULE_DEVICE_TABLE(usb, p54u_table);
84
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020085static const struct {
86 u32 intf;
87 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020088 const char *fw;
89 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020090 char hw[20];
91} p54u_fwlist[__NUM_P54U_HWTYPES] = {
92 {
93 .type = P54U_NET2280,
94 .intf = FW_LM86,
95 .fw = "isl3886usb",
96 .fw_legacy = "isl3890usb",
97 .hw = "ISL3886 + net2280",
98 },
99 {
100 .type = P54U_3887,
101 .intf = FW_LM87,
102 .fw = "isl3887usb",
103 .fw_legacy = "isl3887usb_bare",
104 .hw = "ISL3887",
105 },
106};
107
Michael Wueff1a592007-09-25 18:11:01 -0700108static void p54u_rx_cb(struct urb *urb)
109{
110 struct sk_buff *skb = (struct sk_buff *) urb->context;
111 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
112 struct ieee80211_hw *dev = info->dev;
113 struct p54u_priv *priv = dev->priv;
114
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100115 skb_unlink(skb, &priv->rx_queue);
116
Michael Wueff1a592007-09-25 18:11:01 -0700117 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100118 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700119 return;
120 }
121
Michael Wueff1a592007-09-25 18:11:01 -0700122 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200123
124 if (priv->hw_type == P54U_NET2280)
125 skb_pull(skb, priv->common.tx_hdr_len);
126 if (priv->common.fw_interface == FW_LM87) {
127 skb_pull(skb, 4);
128 skb_put(skb, 4);
129 }
Michael Wueff1a592007-09-25 18:11:01 -0700130
131 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200132 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700133 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700134 /* TODO check rx queue length and refill *somewhere* */
135 return;
136 }
137
138 info = (struct p54u_rx_info *) skb->cb;
139 info->urb = urb;
140 info->dev = dev;
141 urb->transfer_buffer = skb_tail_pointer(skb);
142 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700143 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200144 if (priv->hw_type == P54U_NET2280)
145 skb_push(skb, priv->common.tx_hdr_len);
146 if (priv->common.fw_interface == FW_LM87) {
147 skb_push(skb, 4);
148 skb_put(skb, 4);
149 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200150 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700151 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200152 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700153 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100154 skb_queue_tail(&priv->rx_queue, skb);
155 usb_anchor_urb(urb, &priv->submitted);
156 if (usb_submit_urb(urb, GFP_ATOMIC)) {
157 skb_unlink(skb, &priv->rx_queue);
158 usb_unanchor_urb(urb);
159 dev_kfree_skb_irq(skb);
160 }
Michael Wueff1a592007-09-25 18:11:01 -0700161}
162
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100163static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200164{
165 struct sk_buff *skb = urb->context;
166 struct ieee80211_hw *dev = (struct ieee80211_hw *)
167 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
168
Christian Lampartere2fe1542009-01-20 00:27:57 +0100169 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100170}
171
172static void p54u_tx_dummy_cb(struct urb *urb) { }
173
174static void p54u_free_urbs(struct ieee80211_hw *dev)
175{
176 struct p54u_priv *priv = dev->priv;
177 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200178}
179
Michael Wueff1a592007-09-25 18:11:01 -0700180static int p54u_init_urbs(struct ieee80211_hw *dev)
181{
182 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100183 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700184 struct sk_buff *skb;
185 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100186 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700187
188 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200189 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100190 if (!skb) {
191 ret = -ENOMEM;
192 goto err;
193 }
Michael Wueff1a592007-09-25 18:11:01 -0700194 entry = usb_alloc_urb(0, GFP_KERNEL);
195 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100196 ret = -ENOMEM;
197 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700198 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100199
Christian Lamparter4e416a62008-09-01 22:48:41 +0200200 usb_fill_bulk_urb(entry, priv->udev,
201 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
202 skb_tail_pointer(skb),
203 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700204 info = (struct p54u_rx_info *) skb->cb;
205 info->urb = entry;
206 info->dev = dev;
207 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100208
209 usb_anchor_urb(entry, &priv->submitted);
210 ret = usb_submit_urb(entry, GFP_KERNEL);
211 if (ret) {
212 skb_unlink(skb, &priv->rx_queue);
213 usb_unanchor_urb(entry);
214 goto err;
215 }
216 usb_free_urb(entry);
217 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700218 }
219
220 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700221
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100222 err:
223 usb_free_urb(entry);
224 kfree_skb(skb);
225 p54u_free_urbs(dev);
226 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700227}
228
Johannes Bergc9127652008-12-01 18:19:36 +0100229static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200230{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500231 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200232
233 length >>= 2;
234 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100235 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200236 chk = (chk >> 5) ^ (chk << 3);
237 }
238
Larry Finger1f1c0e32008-09-25 14:54:28 -0500239 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200240}
241
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100242static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200243{
244 struct p54u_priv *priv = dev->priv;
245 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100246 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200247
248 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
249 if (!data_urb)
250 return;
251
Christian Lampartere2fe1542009-01-20 00:27:57 +0100252 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
253 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200254
255 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200256 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100257 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
258 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100259 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200260
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100261 usb_anchor_urb(data_urb, &priv->submitted);
262 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
263 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100264 p54_free_skb(dev, skb);
265 }
266 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200267}
268
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100269static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700270{
271 struct p54u_priv *priv = dev->priv;
272 struct urb *int_urb, *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100273 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Michael Wueff1a592007-09-25 18:11:01 -0700274 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100275 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700276
277 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
278 if (!reg)
279 return;
280
281 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
282 if (!int_urb) {
283 kfree(reg);
284 return;
285 }
286
287 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
288 if (!data_urb) {
289 kfree(reg);
290 usb_free_urb(int_urb);
291 return;
292 }
293
294 reg->port = cpu_to_le16(NET2280_DEV_U32);
295 reg->addr = cpu_to_le32(P54U_DEV_BASE);
296 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
297
Michael Wueff1a592007-09-25 18:11:01 -0700298 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100299 hdr->len = cpu_to_le16(skb->len);
300 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700301
302 usb_fill_bulk_urb(int_urb, priv->udev,
303 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100304 p54u_tx_dummy_cb, dev);
305
306 /*
307 * This flag triggers a code path in the USB subsystem that will
308 * free what's inside the transfer_buffer after the callback routine
309 * has completed.
310 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100311 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Michael Wueff1a592007-09-25 18:11:01 -0700312
313 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200314 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100315 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
316 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100317 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100318
319 usb_anchor_urb(int_urb, &priv->submitted);
320 err = usb_submit_urb(int_urb, GFP_ATOMIC);
321 if (err) {
322 usb_unanchor_urb(int_urb);
323 goto out;
324 }
325
326 usb_anchor_urb(data_urb, &priv->submitted);
327 err = usb_submit_urb(data_urb, GFP_ATOMIC);
328 if (err) {
329 usb_unanchor_urb(data_urb);
330 goto out;
331 }
332 out:
333 usb_free_urb(int_urb);
334 usb_free_urb(data_urb);
335
336 if (err) {
337 skb_pull(skb, sizeof(*hdr));
338 p54_free_skb(dev, skb);
339 }
Michael Wueff1a592007-09-25 18:11:01 -0700340}
341
342static int p54u_write(struct p54u_priv *priv,
343 struct net2280_reg_write *buf,
344 enum net2280_op_type type,
345 __le32 addr, __le32 val)
346{
347 unsigned int ep;
348 int alen;
349
350 if (type & 0x0800)
351 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
352 else
353 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
354
355 buf->port = cpu_to_le16(type);
356 buf->addr = addr;
357 buf->val = val;
358
359 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
360}
361
362static int p54u_read(struct p54u_priv *priv, void *buf,
363 enum net2280_op_type type,
364 __le32 addr, __le32 *val)
365{
366 struct net2280_reg_read *read = buf;
367 __le32 *reg = buf;
368 unsigned int ep;
369 int alen, err;
370
371 if (type & 0x0800)
372 ep = P54U_PIPE_DEV;
373 else
374 ep = P54U_PIPE_BRG;
375
376 read->port = cpu_to_le16(type);
377 read->addr = addr;
378
379 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
380 read, sizeof(*read), &alen, 1000);
381 if (err)
382 return err;
383
384 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
385 reg, sizeof(*reg), &alen, 1000);
386 if (err)
387 return err;
388
389 *val = *reg;
390 return 0;
391}
392
393static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
394 void *data, size_t len)
395{
396 int alen;
397 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
398 data, len, &alen, 2000);
399}
400
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200401static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100402{
403 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100404 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100405
Christian Lamparterc88a7682009-01-16 20:24:31 +0100406 if (lock) {
407 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
408 if (ret < 0) {
409 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200410 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100411 return ret;
412 }
Christian Lamparter69828692008-12-26 19:08:31 +0100413 }
414
415 ret = usb_reset_device(priv->udev);
416 if (lock)
417 usb_unlock_device(priv->udev);
418
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200419 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100420 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200421 "device (%d)!\n", ret);
422
423 return ret;
424}
425
426static const char p54u_romboot_3887[] = "~~~~";
427static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
428{
429 struct p54u_priv *priv = dev->priv;
430 u8 buf[4];
431 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100432
433 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
434 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
435 buf, sizeof(buf));
436 if (ret)
437 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200438 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100439
440 return ret;
441}
442
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200443static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700444static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
445{
Michael Wueff1a592007-09-25 18:11:01 -0700446 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700447 int err, alen;
448 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100449 u8 *buf, *tmp;
450 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700451 unsigned int left, remains, block_size;
452 struct x2_header *hdr;
453 unsigned long timeout;
454
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200455 err = p54u_firmware_reset_3887(dev);
456 if (err)
457 return err;
458
Michael Wueff1a592007-09-25 18:11:01 -0700459 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
460 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100461 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
462 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200463 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700464 }
465
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200466 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100467 strcpy(buf, p54u_firmware_upload_3887);
468 left -= strlen(p54u_firmware_upload_3887);
469 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700470
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200471 data = priv->fw->data;
472 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700473
Christian Lamparter69828692008-12-26 19:08:31 +0100474 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700475 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
476 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200477 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700478 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
479 sizeof(u32)*2));
480 left -= sizeof(*hdr);
481 tmp += sizeof(*hdr);
482
483 while (remains) {
484 while (left--) {
485 if (carry) {
486 *tmp++ = carry;
487 carry = 0;
488 remains--;
489 continue;
490 }
491 switch (*data) {
492 case '~':
493 *tmp++ = '}';
494 carry = '^';
495 break;
496 case '}':
497 *tmp++ = '}';
498 carry = ']';
499 break;
500 default:
501 *tmp++ = *data;
502 remains--;
503 break;
504 }
505 data++;
506 }
507
508 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
509 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100510 dev_err(&priv->udev->dev, "(p54usb) firmware "
511 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700512 goto err_upload_failed;
513 }
514
515 tmp = buf;
516 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
517 }
518
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200519 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
520 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700521 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
522 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100523 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700524 goto err_upload_failed;
525 }
Michael Wueff1a592007-09-25 18:11:01 -0700526 timeout = jiffies + msecs_to_jiffies(1000);
527 while (!(err = usb_bulk_msg(priv->udev,
528 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
529 if (alen > 2 && !memcmp(buf, "OK", 2))
530 break;
531
532 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700533 err = -EINVAL;
534 break;
535 }
536
537 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100538 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
539 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700540 err = -ETIMEDOUT;
541 break;
542 }
543 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100544 if (err) {
545 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700546 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100547 }
Michael Wueff1a592007-09-25 18:11:01 -0700548
549 buf[0] = 'g';
550 buf[1] = '\r';
551 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
552 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100553 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700554 goto err_upload_failed;
555 }
556
557 timeout = jiffies + msecs_to_jiffies(1000);
558 while (!(err = usb_bulk_msg(priv->udev,
559 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
560 if (alen > 0 && buf[0] == 'g')
561 break;
562
563 if (time_after(jiffies, timeout)) {
564 err = -ETIMEDOUT;
565 break;
566 }
567 }
568 if (err)
569 goto err_upload_failed;
570
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200571err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700572 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700573 return err;
574}
575
576static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
577{
578 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700579 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
580 int err, alen;
581 void *buf;
582 __le32 reg;
583 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100584 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700585
586 buf = kmalloc(512, GFP_KERNEL);
587 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100588 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
589 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700590 return -ENOMEM;
591 }
592
Michael Wueff1a592007-09-25 18:11:01 -0700593#define P54U_WRITE(type, addr, data) \
594 do {\
595 err = p54u_write(priv, buf, type,\
596 cpu_to_le32((u32)(unsigned long)addr), data);\
597 if (err) \
598 goto fail;\
599 } while (0)
600
601#define P54U_READ(type, addr) \
602 do {\
603 err = p54u_read(priv, buf, type,\
604 cpu_to_le32((u32)(unsigned long)addr), &reg);\
605 if (err)\
606 goto fail;\
607 } while (0)
608
609 /* power down net2280 bridge */
610 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
611 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
612 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
613 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
614
615 mdelay(100);
616
617 /* power up bridge */
618 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
619 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
620 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
621
622 mdelay(100);
623
624 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
625 cpu_to_le32(NET2280_CLK_30Mhz |
626 NET2280_PCI_ENABLE |
627 NET2280_PCI_SOFT_RESET));
628
629 mdelay(20);
630
631 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
632 cpu_to_le32(PCI_COMMAND_MEMORY |
633 PCI_COMMAND_MASTER));
634
635 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
636 cpu_to_le32(NET2280_BASE));
637
638 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
639 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
640 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
641
642 // TODO: we really need this?
643 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
644
645 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
646 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
647 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
648 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
649
650 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
651 cpu_to_le32(NET2280_BASE2));
652
653 /* finally done setting up the bridge */
654
655 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
656 cpu_to_le32(PCI_COMMAND_MEMORY |
657 PCI_COMMAND_MASTER));
658
659 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
660 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
661 cpu_to_le32(P54U_DEV_BASE));
662
663 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
664 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
665 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
666
667 /* do romboot */
668 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
669
670 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
671 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
672 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
673 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
674 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
675
676 mdelay(20);
677
678 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
679 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
680
681 mdelay(20);
682
683 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
684 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
685
686 mdelay(100);
687
688 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
689 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
690
691 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200692 remains = priv->fw->size;
693 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700694 offset = ISL38XX_DEV_FIRMWARE_ADDR;
695
696 while (remains) {
697 unsigned int block_len = min(remains, (unsigned int)512);
698 memcpy(buf, data, block_len);
699
700 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
701 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100702 dev_err(&priv->udev->dev, "(p54usb) firmware block "
703 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700704 goto fail;
705 }
706
707 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
708 cpu_to_le32(0xc0000f00));
709
710 P54U_WRITE(NET2280_DEV_U32,
711 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
712 P54U_WRITE(NET2280_DEV_U32,
713 0x0020 | (unsigned long)&devreg->direct_mem_win,
714 cpu_to_le32(1));
715
716 P54U_WRITE(NET2280_DEV_U32,
717 0x0024 | (unsigned long)&devreg->direct_mem_win,
718 cpu_to_le32(block_len));
719 P54U_WRITE(NET2280_DEV_U32,
720 0x0028 | (unsigned long)&devreg->direct_mem_win,
721 cpu_to_le32(offset));
722
723 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
724 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
725 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
726 cpu_to_le32(block_len >> 2));
727 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
728 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
729
730 mdelay(10);
731
732 P54U_READ(NET2280_DEV_U32,
733 0x002C | (unsigned long)&devreg->direct_mem_win);
734 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
735 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100736 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
737 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700738 goto fail;
739 }
740
741 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
742 cpu_to_le32(NET2280_FIFO_FLUSH));
743
744 remains -= block_len;
745 data += block_len;
746 offset += block_len;
747 }
748
749 /* do ramboot */
750 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
751 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
752 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
753 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
754 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
755
756 mdelay(20);
757
758 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
759 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
760
761 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
762 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
763
764 mdelay(100);
765
766 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
767 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
768
769 /* start up the firmware */
770 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
771 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
772
773 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
774 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
775
776 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
777 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
778 NET2280_USB_INTERRUPT_ENABLE));
779
780 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
781 cpu_to_le32(ISL38XX_DEV_INT_RESET));
782
783 err = usb_interrupt_msg(priv->udev,
784 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
785 buf, sizeof(__le32), &alen, 1000);
786 if (err || alen != sizeof(__le32))
787 goto fail;
788
789 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
790 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
791
792 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
793 err = -EINVAL;
794
795 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
796 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
797 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
798
799#undef P54U_WRITE
800#undef P54U_READ
801
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200802fail:
Michael Wueff1a592007-09-25 18:11:01 -0700803 kfree(buf);
804 return err;
805}
806
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200807static int p54u_load_firmware(struct ieee80211_hw *dev)
808{
809 struct p54u_priv *priv = dev->priv;
810 int err, i;
811
812 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
813
814 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
815 if (p54u_fwlist[i].type == priv->hw_type)
816 break;
817
818 if (i == __NUM_P54U_HWTYPES)
819 return -EOPNOTSUPP;
820
821 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
822 if (err) {
823 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
824 "(%d)!\n", p54u_fwlist[i].fw, err);
825
826 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
827 &priv->udev->dev);
828 if (err)
829 return err;
830 }
831
832 err = p54_parse_firmware(dev, priv->fw);
833 if (err)
834 goto out;
835
836 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
837 dev_err(&priv->udev->dev, "wrong firmware, please get "
838 "a firmware for \"%s\" and try again.\n",
839 p54u_fwlist[i].hw);
840 err = -EINVAL;
841 }
842
843out:
844 if (err)
845 release_firmware(priv->fw);
846
847 return err;
848}
849
Michael Wueff1a592007-09-25 18:11:01 -0700850static int p54u_open(struct ieee80211_hw *dev)
851{
852 struct p54u_priv *priv = dev->priv;
853 int err;
854
855 err = p54u_init_urbs(dev);
856 if (err) {
857 return err;
858 }
859
860 priv->common.open = p54u_init_urbs;
861
862 return 0;
863}
864
865static void p54u_stop(struct ieee80211_hw *dev)
866{
867 /* TODO: figure out how to reliably stop the 3887 and net2280 so
868 the hardware is still usable next time we want to start it.
869 until then, we just stop listening to the hardware.. */
870 p54u_free_urbs(dev);
871 return;
872}
873
874static int __devinit p54u_probe(struct usb_interface *intf,
875 const struct usb_device_id *id)
876{
877 struct usb_device *udev = interface_to_usbdev(intf);
878 struct ieee80211_hw *dev;
879 struct p54u_priv *priv;
880 int err;
881 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700882
883 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100884
Michael Wueff1a592007-09-25 18:11:01 -0700885 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100886 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700887 return -ENOMEM;
888 }
889
890 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200891 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700892
893 SET_IEEE80211_DEV(dev, &intf->dev);
894 usb_set_intfdata(intf, dev);
895 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100896 priv->intf = intf;
897 skb_queue_head_init(&priv->rx_queue);
898 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700899
900 usb_get_dev(udev);
901
902 /* really lazy and simple way of figuring out if we're a 3887 */
903 /* TODO: should just stick the identification in the device table */
904 i = intf->altsetting->desc.bNumEndpoints;
905 recognized_pipes = 0;
906 while (i--) {
907 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
908 case P54U_PIPE_DATA:
909 case P54U_PIPE_MGMT:
910 case P54U_PIPE_BRG:
911 case P54U_PIPE_DEV:
912 case P54U_PIPE_DATA | USB_DIR_IN:
913 case P54U_PIPE_MGMT | USB_DIR_IN:
914 case P54U_PIPE_BRG | USB_DIR_IN:
915 case P54U_PIPE_DEV | USB_DIR_IN:
916 case P54U_PIPE_INT | USB_DIR_IN:
917 recognized_pipes++;
918 }
919 }
920 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200921 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700922 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200923#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200924 /* ISL3887 needs a full reset on resume */
925 udev->reset_resume = 1;
926 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200927#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200928
Michael Wueff1a592007-09-25 18:11:01 -0700929 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200930 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
931 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
932 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200933 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700934 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200935 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700936 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
937 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
938 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200939 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200940 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200941 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700942 if (err)
943 goto err_free_dev;
944
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200945 err = priv->upload_fw(dev);
946 if (err)
947 goto err_free_fw;
948
Christian Lamparter7cb77072008-09-01 22:48:51 +0200949 p54u_open(dev);
950 err = p54_read_eeprom(dev);
951 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700952 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200953 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700954
Christian Lamparter2ac71072009-03-05 21:30:10 +0100955 err = p54_register_common(dev, &udev->dev);
956 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200957 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700958
Michael Wueff1a592007-09-25 18:11:01 -0700959 return 0;
960
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200961err_free_fw:
962 release_firmware(priv->fw);
963
964err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500965 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700966 usb_set_intfdata(intf, NULL);
967 usb_put_dev(udev);
968 return err;
969}
970
971static void __devexit p54u_disconnect(struct usb_interface *intf)
972{
973 struct ieee80211_hw *dev = usb_get_intfdata(intf);
974 struct p54u_priv *priv;
975
976 if (!dev)
977 return;
978
Christian Lamparterd8c92102009-06-23 10:39:45 -0500979 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700980
981 priv = dev->priv;
982 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200983 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700984 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700985}
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);