blob: 17f89c7eb098c38c2902e1353c55110520d5a79f [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 */
59 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
60 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
61 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
62 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
63 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
64 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
65 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
66 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
67 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
68 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070069 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020070 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050071 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040072 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Michael Wueff1a592007-09-25 18:11:01 -070073 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
74 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
75 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
76 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
77 {}
78};
79
80MODULE_DEVICE_TABLE(usb, p54u_table);
81
82static void p54u_rx_cb(struct urb *urb)
83{
84 struct sk_buff *skb = (struct sk_buff *) urb->context;
85 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
86 struct ieee80211_hw *dev = info->dev;
87 struct p54u_priv *priv = dev->priv;
88
Christian Lamparterdd397dc2008-12-09 15:14:37 +010089 skb_unlink(skb, &priv->rx_queue);
90
Michael Wueff1a592007-09-25 18:11:01 -070091 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +010092 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -070093 return;
94 }
95
Michael Wueff1a592007-09-25 18:11:01 -070096 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +020097
98 if (priv->hw_type == P54U_NET2280)
99 skb_pull(skb, priv->common.tx_hdr_len);
100 if (priv->common.fw_interface == FW_LM87) {
101 skb_pull(skb, 4);
102 skb_put(skb, 4);
103 }
Michael Wueff1a592007-09-25 18:11:01 -0700104
105 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200106 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700107 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700108 /* TODO check rx queue length and refill *somewhere* */
109 return;
110 }
111
112 info = (struct p54u_rx_info *) skb->cb;
113 info->urb = urb;
114 info->dev = dev;
115 urb->transfer_buffer = skb_tail_pointer(skb);
116 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700117 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200118 if (priv->hw_type == P54U_NET2280)
119 skb_push(skb, priv->common.tx_hdr_len);
120 if (priv->common.fw_interface == FW_LM87) {
121 skb_push(skb, 4);
122 skb_put(skb, 4);
123 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200124 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700125 skb_trim(skb, 0);
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200126 if (urb->transfer_buffer != skb_tail_pointer(skb)) {
127 /* this should not happen */
128 WARN_ON(1);
129 urb->transfer_buffer = skb_tail_pointer(skb);
130 }
Michael Wueff1a592007-09-25 18:11:01 -0700131 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100132 skb_queue_tail(&priv->rx_queue, skb);
133 usb_anchor_urb(urb, &priv->submitted);
134 if (usb_submit_urb(urb, GFP_ATOMIC)) {
135 skb_unlink(skb, &priv->rx_queue);
136 usb_unanchor_urb(urb);
137 dev_kfree_skb_irq(skb);
138 }
Michael Wueff1a592007-09-25 18:11:01 -0700139}
140
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100141static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200142{
143 struct sk_buff *skb = urb->context;
144 struct ieee80211_hw *dev = (struct ieee80211_hw *)
145 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100146 struct p54u_priv *priv = dev->priv;
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200147
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100148 skb_pull(skb, priv->common.tx_hdr_len);
149 if (FREE_AFTER_TX(skb))
150 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100151}
152
153static void p54u_tx_dummy_cb(struct urb *urb) { }
154
155static void p54u_free_urbs(struct ieee80211_hw *dev)
156{
157 struct p54u_priv *priv = dev->priv;
158 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200159}
160
Michael Wueff1a592007-09-25 18:11:01 -0700161static int p54u_init_urbs(struct ieee80211_hw *dev)
162{
163 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100164 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700165 struct sk_buff *skb;
166 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100167 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700168
169 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200170 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100171 if (!skb) {
172 ret = -ENOMEM;
173 goto err;
174 }
Michael Wueff1a592007-09-25 18:11:01 -0700175 entry = usb_alloc_urb(0, GFP_KERNEL);
176 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100177 ret = -ENOMEM;
178 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700179 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100180
Christian Lamparter4e416a62008-09-01 22:48:41 +0200181 usb_fill_bulk_urb(entry, priv->udev,
182 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
183 skb_tail_pointer(skb),
184 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700185 info = (struct p54u_rx_info *) skb->cb;
186 info->urb = entry;
187 info->dev = dev;
188 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100189
190 usb_anchor_urb(entry, &priv->submitted);
191 ret = usb_submit_urb(entry, GFP_KERNEL);
192 if (ret) {
193 skb_unlink(skb, &priv->rx_queue);
194 usb_unanchor_urb(entry);
195 goto err;
196 }
197 usb_free_urb(entry);
198 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700199 }
200
201 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700202
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100203 err:
204 usb_free_urb(entry);
205 kfree_skb(skb);
206 p54u_free_urbs(dev);
207 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700208}
209
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100210static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700211{
212 struct p54u_priv *priv = dev->priv;
213 struct urb *addr_urb, *data_urb;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100214 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700215
216 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
217 if (!addr_urb)
218 return;
219
220 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
221 if (!data_urb) {
222 usb_free_urb(addr_urb);
223 return;
224 }
225
226 usb_fill_bulk_urb(addr_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200227 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
John W. Linville27df6052008-10-22 16:41:55 -0400228 &((struct p54_hdr *)skb->data)->req_id, 4,
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100229 p54u_tx_dummy_cb, dev);
Michael Wueff1a592007-09-25 18:11:01 -0700230 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200231 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100232 skb->data, skb->len, p54u_tx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700233
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100234 usb_anchor_urb(addr_urb, &priv->submitted);
235 err = usb_submit_urb(addr_urb, GFP_ATOMIC);
236 if (err) {
237 usb_unanchor_urb(addr_urb);
238 goto out;
239 }
240
241 usb_anchor_urb(addr_urb, &priv->submitted);
242 err = usb_submit_urb(data_urb, GFP_ATOMIC);
243 if (err)
244 usb_unanchor_urb(data_urb);
245
246 out:
247 usb_free_urb(addr_urb);
248 usb_free_urb(data_urb);
249
250 if (err)
251 p54_free_skb(dev, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700252}
253
Johannes Bergc9127652008-12-01 18:19:36 +0100254static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200255{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500256 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200257
258 length >>= 2;
259 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100260 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200261 chk = (chk >> 5) ^ (chk << 3);
262 }
263
Larry Finger1f1c0e32008-09-25 14:54:28 -0500264 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200265}
266
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100267static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200268{
269 struct p54u_priv *priv = dev->priv;
270 struct urb *data_urb;
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200271 struct lm87_tx_hdr *hdr;
272 __le32 checksum;
John W. Linville27df6052008-10-22 16:41:55 -0400273 __le32 addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200274
275 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
276 if (!data_urb)
277 return;
278
Johannes Bergc9127652008-12-01 18:19:36 +0100279 checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200280 hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr));
281 hdr->chksum = checksum;
282 hdr->device_addr = addr;
Christian Lamparter2b808482008-09-04 12:29:38 +0200283
284 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200285 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100286 skb->data, skb->len, p54u_tx_cb, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200287
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100288 usb_anchor_urb(data_urb, &priv->submitted);
289 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
290 usb_unanchor_urb(data_urb);
291 skb_pull(skb, sizeof(*hdr));
292 p54_free_skb(dev, skb);
293 }
294 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200295}
296
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100297static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700298{
299 struct p54u_priv *priv = dev->priv;
300 struct urb *int_urb, *data_urb;
301 struct net2280_tx_hdr *hdr;
302 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100303 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700304
305 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
306 if (!reg)
307 return;
308
309 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
310 if (!int_urb) {
311 kfree(reg);
312 return;
313 }
314
315 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
316 if (!data_urb) {
317 kfree(reg);
318 usb_free_urb(int_urb);
319 return;
320 }
321
322 reg->port = cpu_to_le16(NET2280_DEV_U32);
323 reg->addr = cpu_to_le32(P54U_DEV_BASE);
324 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
325
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200326 hdr = (void *)skb_push(skb, sizeof(*hdr));
Michael Wueff1a592007-09-25 18:11:01 -0700327 memset(hdr, 0, sizeof(*hdr));
John W. Linville27df6052008-10-22 16:41:55 -0400328 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
329 hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr));
Michael Wueff1a592007-09-25 18:11:01 -0700330
331 usb_fill_bulk_urb(int_urb, priv->udev,
332 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100333 p54u_tx_dummy_cb, dev);
334
335 /*
336 * This flag triggers a code path in the USB subsystem that will
337 * free what's inside the transfer_buffer after the callback routine
338 * has completed.
339 */
340 int_urb->transfer_flags |= URB_FREE_BUFFER;
Michael Wueff1a592007-09-25 18:11:01 -0700341
342 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200343 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100344 skb->data, skb->len, p54u_tx_cb, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100345
346 usb_anchor_urb(int_urb, &priv->submitted);
347 err = usb_submit_urb(int_urb, GFP_ATOMIC);
348 if (err) {
349 usb_unanchor_urb(int_urb);
350 goto out;
351 }
352
353 usb_anchor_urb(data_urb, &priv->submitted);
354 err = usb_submit_urb(data_urb, GFP_ATOMIC);
355 if (err) {
356 usb_unanchor_urb(data_urb);
357 goto out;
358 }
359 out:
360 usb_free_urb(int_urb);
361 usb_free_urb(data_urb);
362
363 if (err) {
364 skb_pull(skb, sizeof(*hdr));
365 p54_free_skb(dev, skb);
366 }
Michael Wueff1a592007-09-25 18:11:01 -0700367}
368
369static int p54u_write(struct p54u_priv *priv,
370 struct net2280_reg_write *buf,
371 enum net2280_op_type type,
372 __le32 addr, __le32 val)
373{
374 unsigned int ep;
375 int alen;
376
377 if (type & 0x0800)
378 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
379 else
380 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
381
382 buf->port = cpu_to_le16(type);
383 buf->addr = addr;
384 buf->val = val;
385
386 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
387}
388
389static int p54u_read(struct p54u_priv *priv, void *buf,
390 enum net2280_op_type type,
391 __le32 addr, __le32 *val)
392{
393 struct net2280_reg_read *read = buf;
394 __le32 *reg = buf;
395 unsigned int ep;
396 int alen, err;
397
398 if (type & 0x0800)
399 ep = P54U_PIPE_DEV;
400 else
401 ep = P54U_PIPE_BRG;
402
403 read->port = cpu_to_le16(type);
404 read->addr = addr;
405
406 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
407 read, sizeof(*read), &alen, 1000);
408 if (err)
409 return err;
410
411 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
412 reg, sizeof(*reg), &alen, 1000);
413 if (err)
414 return err;
415
416 *val = *reg;
417 return 0;
418}
419
420static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
421 void *data, size_t len)
422{
423 int alen;
424 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
425 data, len, &alen, 2000);
426}
427
Michael Wueff1a592007-09-25 18:11:01 -0700428static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
429{
430 static char start_string[] = "~~~~<\r";
431 struct p54u_priv *priv = dev->priv;
432 const struct firmware *fw_entry = NULL;
433 int err, alen;
434 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100435 u8 *buf, *tmp;
436 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700437 unsigned int left, remains, block_size;
438 struct x2_header *hdr;
439 unsigned long timeout;
440
441 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
442 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100443 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
444 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700445 err = -ENOMEM;
446 goto err_bufalloc;
447 }
448
449 memcpy(buf, start_string, 4);
450 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
451 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100452 dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
Michael Wueff1a592007-09-25 18:11:01 -0700453 goto err_reset;
454 }
455
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200456 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700457 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100458 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
459 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200460 err = request_firmware(&fw_entry, "isl3887usb_bare",
461 &priv->udev->dev);
462 if (err)
463 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700464 }
465
Christian Lamparter4e416a62008-09-01 22:48:41 +0200466 err = p54_parse_firmware(dev, fw_entry);
467 if (err)
468 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700469
470 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
471 strcpy(buf, start_string);
472 left -= strlen(start_string);
473 tmp += strlen(start_string);
474
475 data = fw_entry->data;
476 remains = fw_entry->size;
477
478 hdr = (struct x2_header *)(buf + strlen(start_string));
479 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
480 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
481 hdr->fw_length = cpu_to_le32(fw_entry->size);
482 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
483 sizeof(u32)*2));
484 left -= sizeof(*hdr);
485 tmp += sizeof(*hdr);
486
487 while (remains) {
488 while (left--) {
489 if (carry) {
490 *tmp++ = carry;
491 carry = 0;
492 remains--;
493 continue;
494 }
495 switch (*data) {
496 case '~':
497 *tmp++ = '}';
498 carry = '^';
499 break;
500 case '}':
501 *tmp++ = '}';
502 carry = ']';
503 break;
504 default:
505 *tmp++ = *data;
506 remains--;
507 break;
508 }
509 data++;
510 }
511
512 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
513 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100514 dev_err(&priv->udev->dev, "(p54usb) firmware "
515 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700516 goto err_upload_failed;
517 }
518
519 tmp = buf;
520 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
521 }
522
523 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
524 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
525 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100526 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700527 goto err_upload_failed;
528 }
Michael Wueff1a592007-09-25 18:11:01 -0700529 timeout = jiffies + msecs_to_jiffies(1000);
530 while (!(err = usb_bulk_msg(priv->udev,
531 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
532 if (alen > 2 && !memcmp(buf, "OK", 2))
533 break;
534
535 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700536 err = -EINVAL;
537 break;
538 }
539
540 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100541 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
542 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700543 err = -ETIMEDOUT;
544 break;
545 }
546 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100547 if (err) {
548 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700549 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100550 }
Michael Wueff1a592007-09-25 18:11:01 -0700551
552 buf[0] = 'g';
553 buf[1] = '\r';
554 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
555 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100556 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700557 goto err_upload_failed;
558 }
559
560 timeout = jiffies + msecs_to_jiffies(1000);
561 while (!(err = usb_bulk_msg(priv->udev,
562 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
563 if (alen > 0 && buf[0] == 'g')
564 break;
565
566 if (time_after(jiffies, timeout)) {
567 err = -ETIMEDOUT;
568 break;
569 }
570 }
571 if (err)
572 goto err_upload_failed;
573
574 err_upload_failed:
575 release_firmware(fw_entry);
576 err_req_fw_failed:
577 err_reset:
578 kfree(buf);
579 err_bufalloc:
580 return err;
581}
582
583static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
584{
585 struct p54u_priv *priv = dev->priv;
586 const struct firmware *fw_entry = NULL;
587 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
588 int err, alen;
589 void *buf;
590 __le32 reg;
591 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100592 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700593
594 buf = kmalloc(512, GFP_KERNEL);
595 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100596 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
597 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700598 return -ENOMEM;
599 }
600
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200601 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700602 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100603 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
604 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200605 err = request_firmware(&fw_entry, "isl3890usb",
606 &priv->udev->dev);
607 if (err) {
608 kfree(buf);
609 return err;
610 }
Michael Wueff1a592007-09-25 18:11:01 -0700611 }
612
Christian Lamparter4e416a62008-09-01 22:48:41 +0200613 err = p54_parse_firmware(dev, fw_entry);
614 if (err) {
615 kfree(buf);
616 release_firmware(fw_entry);
617 return err;
618 }
Michael Wueff1a592007-09-25 18:11:01 -0700619
620#define P54U_WRITE(type, addr, data) \
621 do {\
622 err = p54u_write(priv, buf, type,\
623 cpu_to_le32((u32)(unsigned long)addr), data);\
624 if (err) \
625 goto fail;\
626 } while (0)
627
628#define P54U_READ(type, addr) \
629 do {\
630 err = p54u_read(priv, buf, type,\
631 cpu_to_le32((u32)(unsigned long)addr), &reg);\
632 if (err)\
633 goto fail;\
634 } while (0)
635
636 /* power down net2280 bridge */
637 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
638 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
639 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
640 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
641
642 mdelay(100);
643
644 /* power up bridge */
645 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
646 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
647 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
648
649 mdelay(100);
650
651 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
652 cpu_to_le32(NET2280_CLK_30Mhz |
653 NET2280_PCI_ENABLE |
654 NET2280_PCI_SOFT_RESET));
655
656 mdelay(20);
657
658 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
659 cpu_to_le32(PCI_COMMAND_MEMORY |
660 PCI_COMMAND_MASTER));
661
662 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
663 cpu_to_le32(NET2280_BASE));
664
665 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
666 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
667 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
668
669 // TODO: we really need this?
670 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
671
672 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
673 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
674 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
675 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
676
677 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
678 cpu_to_le32(NET2280_BASE2));
679
680 /* finally done setting up the bridge */
681
682 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
683 cpu_to_le32(PCI_COMMAND_MEMORY |
684 PCI_COMMAND_MASTER));
685
686 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
687 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
688 cpu_to_le32(P54U_DEV_BASE));
689
690 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
691 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
692 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
693
694 /* do romboot */
695 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
696
697 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
698 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
699 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
700 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
701 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
702
703 mdelay(20);
704
705 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
706 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
707
708 mdelay(20);
709
710 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
711 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
712
713 mdelay(100);
714
715 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
716 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
717
718 /* finally, we can upload firmware now! */
719 remains = fw_entry->size;
720 data = fw_entry->data;
721 offset = ISL38XX_DEV_FIRMWARE_ADDR;
722
723 while (remains) {
724 unsigned int block_len = min(remains, (unsigned int)512);
725 memcpy(buf, data, block_len);
726
727 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
728 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100729 dev_err(&priv->udev->dev, "(p54usb) firmware block "
730 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700731 goto fail;
732 }
733
734 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
735 cpu_to_le32(0xc0000f00));
736
737 P54U_WRITE(NET2280_DEV_U32,
738 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
739 P54U_WRITE(NET2280_DEV_U32,
740 0x0020 | (unsigned long)&devreg->direct_mem_win,
741 cpu_to_le32(1));
742
743 P54U_WRITE(NET2280_DEV_U32,
744 0x0024 | (unsigned long)&devreg->direct_mem_win,
745 cpu_to_le32(block_len));
746 P54U_WRITE(NET2280_DEV_U32,
747 0x0028 | (unsigned long)&devreg->direct_mem_win,
748 cpu_to_le32(offset));
749
750 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
751 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
752 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
753 cpu_to_le32(block_len >> 2));
754 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
755 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
756
757 mdelay(10);
758
759 P54U_READ(NET2280_DEV_U32,
760 0x002C | (unsigned long)&devreg->direct_mem_win);
761 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
762 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100763 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
764 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700765 goto fail;
766 }
767
768 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
769 cpu_to_le32(NET2280_FIFO_FLUSH));
770
771 remains -= block_len;
772 data += block_len;
773 offset += block_len;
774 }
775
776 /* do ramboot */
777 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
778 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
779 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
780 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
781 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
782
783 mdelay(20);
784
785 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
786 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
787
788 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
789 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
790
791 mdelay(100);
792
793 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
794 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
795
796 /* start up the firmware */
797 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
798 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
799
800 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
801 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
802
803 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
804 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
805 NET2280_USB_INTERRUPT_ENABLE));
806
807 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
808 cpu_to_le32(ISL38XX_DEV_INT_RESET));
809
810 err = usb_interrupt_msg(priv->udev,
811 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
812 buf, sizeof(__le32), &alen, 1000);
813 if (err || alen != sizeof(__le32))
814 goto fail;
815
816 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
817 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
818
819 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
820 err = -EINVAL;
821
822 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
823 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
824 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
825
826#undef P54U_WRITE
827#undef P54U_READ
828
829 fail:
830 release_firmware(fw_entry);
831 kfree(buf);
832 return err;
833}
834
835static int p54u_open(struct ieee80211_hw *dev)
836{
837 struct p54u_priv *priv = dev->priv;
838 int err;
839
840 err = p54u_init_urbs(dev);
841 if (err) {
842 return err;
843 }
844
845 priv->common.open = p54u_init_urbs;
846
847 return 0;
848}
849
850static void p54u_stop(struct ieee80211_hw *dev)
851{
852 /* TODO: figure out how to reliably stop the 3887 and net2280 so
853 the hardware is still usable next time we want to start it.
854 until then, we just stop listening to the hardware.. */
855 p54u_free_urbs(dev);
856 return;
857}
858
859static int __devinit p54u_probe(struct usb_interface *intf,
860 const struct usb_device_id *id)
861{
862 struct usb_device *udev = interface_to_usbdev(intf);
863 struct ieee80211_hw *dev;
864 struct p54u_priv *priv;
865 int err;
866 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700867
868 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100869
Michael Wueff1a592007-09-25 18:11:01 -0700870 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100871 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700872 return -ENOMEM;
873 }
874
875 priv = dev->priv;
876
877 SET_IEEE80211_DEV(dev, &intf->dev);
878 usb_set_intfdata(intf, dev);
879 priv->udev = udev;
880
881 usb_get_dev(udev);
882
883 /* really lazy and simple way of figuring out if we're a 3887 */
884 /* TODO: should just stick the identification in the device table */
885 i = intf->altsetting->desc.bNumEndpoints;
886 recognized_pipes = 0;
887 while (i--) {
888 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
889 case P54U_PIPE_DATA:
890 case P54U_PIPE_MGMT:
891 case P54U_PIPE_BRG:
892 case P54U_PIPE_DEV:
893 case P54U_PIPE_DATA | USB_DIR_IN:
894 case P54U_PIPE_MGMT | USB_DIR_IN:
895 case P54U_PIPE_BRG | USB_DIR_IN:
896 case P54U_PIPE_DEV | USB_DIR_IN:
897 case P54U_PIPE_INT | USB_DIR_IN:
898 recognized_pipes++;
899 }
900 }
901 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200902 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700903 if (recognized_pipes < P54U_PIPE_NUMBER) {
904 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200905 err = p54u_upload_firmware_3887(dev);
906 if (priv->common.fw_interface == FW_LM87) {
907 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
908 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
909 priv->common.tx = p54u_tx_lm87;
910 } else
911 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700912 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200913 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700914 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
915 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
916 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700917 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200918 }
Michael Wueff1a592007-09-25 18:11:01 -0700919 if (err)
920 goto err_free_dev;
921
Christian Lamparter7cb77072008-09-01 22:48:51 +0200922 skb_queue_head_init(&priv->rx_queue);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100923 init_usb_anchor(&priv->submitted);
Christian Lamparter7cb77072008-09-01 22:48:51 +0200924
925 p54u_open(dev);
926 err = p54_read_eeprom(dev);
927 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700928 if (err)
929 goto err_free_dev;
930
Michael Wueff1a592007-09-25 18:11:01 -0700931 err = ieee80211_register_hw(dev);
932 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100933 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700934 goto err_free_dev;
935 }
936
Michael Wueff1a592007-09-25 18:11:01 -0700937 return 0;
938
939 err_free_dev:
940 ieee80211_free_hw(dev);
941 usb_set_intfdata(intf, NULL);
942 usb_put_dev(udev);
943 return err;
944}
945
946static void __devexit p54u_disconnect(struct usb_interface *intf)
947{
948 struct ieee80211_hw *dev = usb_get_intfdata(intf);
949 struct p54u_priv *priv;
950
951 if (!dev)
952 return;
953
954 ieee80211_unregister_hw(dev);
955
956 priv = dev->priv;
957 usb_put_dev(interface_to_usbdev(intf));
958 p54_free_common(dev);
959 ieee80211_free_hw(dev);
960}
961
962static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200963 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700964 .id_table = p54u_table,
965 .probe = p54u_probe,
966 .disconnect = p54u_disconnect,
967};
968
969static int __init p54u_init(void)
970{
971 return usb_register(&p54u_driver);
972}
973
974static void __exit p54u_exit(void)
975{
976 usb_deregister(&p54u_driver);
977}
978
979module_init(p54u_init);
980module_exit(p54u_exit);