blob: c44a200059d21c4ce0aae4a6f66b2e61af73984e [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;
Christian Lamparter61107812008-12-17 12:04:43 +0100304 __le32 addr = ((struct p54_hdr *) skb->data)->req_id;
305 __le16 len = cpu_to_le16(skb->len);
Michael Wueff1a592007-09-25 18:11:01 -0700306
307 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
308 if (!reg)
309 return;
310
311 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
312 if (!int_urb) {
313 kfree(reg);
314 return;
315 }
316
317 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
318 if (!data_urb) {
319 kfree(reg);
320 usb_free_urb(int_urb);
321 return;
322 }
323
324 reg->port = cpu_to_le16(NET2280_DEV_U32);
325 reg->addr = cpu_to_le32(P54U_DEV_BASE);
326 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
327
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200328 hdr = (void *)skb_push(skb, sizeof(*hdr));
Michael Wueff1a592007-09-25 18:11:01 -0700329 memset(hdr, 0, sizeof(*hdr));
Christian Lamparter61107812008-12-17 12:04:43 +0100330 hdr->len = len;
331 hdr->device_addr = addr;
Michael Wueff1a592007-09-25 18:11:01 -0700332
333 usb_fill_bulk_urb(int_urb, priv->udev,
334 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100335 p54u_tx_dummy_cb, dev);
336
337 /*
338 * This flag triggers a code path in the USB subsystem that will
339 * free what's inside the transfer_buffer after the callback routine
340 * has completed.
341 */
342 int_urb->transfer_flags |= URB_FREE_BUFFER;
Michael Wueff1a592007-09-25 18:11:01 -0700343
344 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200345 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100346 skb->data, skb->len, p54u_tx_cb, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100347
348 usb_anchor_urb(int_urb, &priv->submitted);
349 err = usb_submit_urb(int_urb, GFP_ATOMIC);
350 if (err) {
351 usb_unanchor_urb(int_urb);
352 goto out;
353 }
354
355 usb_anchor_urb(data_urb, &priv->submitted);
356 err = usb_submit_urb(data_urb, GFP_ATOMIC);
357 if (err) {
358 usb_unanchor_urb(data_urb);
359 goto out;
360 }
361 out:
362 usb_free_urb(int_urb);
363 usb_free_urb(data_urb);
364
365 if (err) {
366 skb_pull(skb, sizeof(*hdr));
367 p54_free_skb(dev, skb);
368 }
Michael Wueff1a592007-09-25 18:11:01 -0700369}
370
371static int p54u_write(struct p54u_priv *priv,
372 struct net2280_reg_write *buf,
373 enum net2280_op_type type,
374 __le32 addr, __le32 val)
375{
376 unsigned int ep;
377 int alen;
378
379 if (type & 0x0800)
380 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
381 else
382 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
383
384 buf->port = cpu_to_le16(type);
385 buf->addr = addr;
386 buf->val = val;
387
388 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
389}
390
391static int p54u_read(struct p54u_priv *priv, void *buf,
392 enum net2280_op_type type,
393 __le32 addr, __le32 *val)
394{
395 struct net2280_reg_read *read = buf;
396 __le32 *reg = buf;
397 unsigned int ep;
398 int alen, err;
399
400 if (type & 0x0800)
401 ep = P54U_PIPE_DEV;
402 else
403 ep = P54U_PIPE_BRG;
404
405 read->port = cpu_to_le16(type);
406 read->addr = addr;
407
408 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
409 read, sizeof(*read), &alen, 1000);
410 if (err)
411 return err;
412
413 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
414 reg, sizeof(*reg), &alen, 1000);
415 if (err)
416 return err;
417
418 *val = *reg;
419 return 0;
420}
421
422static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
423 void *data, size_t len)
424{
425 int alen;
426 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
427 data, len, &alen, 2000);
428}
429
Michael Wueff1a592007-09-25 18:11:01 -0700430static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
431{
432 static char start_string[] = "~~~~<\r";
433 struct p54u_priv *priv = dev->priv;
434 const struct firmware *fw_entry = NULL;
435 int err, alen;
436 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100437 u8 *buf, *tmp;
438 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700439 unsigned int left, remains, block_size;
440 struct x2_header *hdr;
441 unsigned long timeout;
442
443 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
444 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100445 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
446 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700447 err = -ENOMEM;
448 goto err_bufalloc;
449 }
450
451 memcpy(buf, start_string, 4);
452 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
453 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100454 dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
Michael Wueff1a592007-09-25 18:11:01 -0700455 goto err_reset;
456 }
457
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200458 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700459 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100460 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
461 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200462 err = request_firmware(&fw_entry, "isl3887usb_bare",
463 &priv->udev->dev);
464 if (err)
465 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700466 }
467
Christian Lamparter4e416a62008-09-01 22:48:41 +0200468 err = p54_parse_firmware(dev, fw_entry);
469 if (err)
470 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700471
472 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
473 strcpy(buf, start_string);
474 left -= strlen(start_string);
475 tmp += strlen(start_string);
476
477 data = fw_entry->data;
478 remains = fw_entry->size;
479
480 hdr = (struct x2_header *)(buf + strlen(start_string));
481 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
482 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
483 hdr->fw_length = cpu_to_le32(fw_entry->size);
484 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
485 sizeof(u32)*2));
486 left -= sizeof(*hdr);
487 tmp += sizeof(*hdr);
488
489 while (remains) {
490 while (left--) {
491 if (carry) {
492 *tmp++ = carry;
493 carry = 0;
494 remains--;
495 continue;
496 }
497 switch (*data) {
498 case '~':
499 *tmp++ = '}';
500 carry = '^';
501 break;
502 case '}':
503 *tmp++ = '}';
504 carry = ']';
505 break;
506 default:
507 *tmp++ = *data;
508 remains--;
509 break;
510 }
511 data++;
512 }
513
514 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
515 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100516 dev_err(&priv->udev->dev, "(p54usb) firmware "
517 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700518 goto err_upload_failed;
519 }
520
521 tmp = buf;
522 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
523 }
524
525 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
526 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
527 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100528 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700529 goto err_upload_failed;
530 }
Michael Wueff1a592007-09-25 18:11:01 -0700531 timeout = jiffies + msecs_to_jiffies(1000);
532 while (!(err = usb_bulk_msg(priv->udev,
533 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
534 if (alen > 2 && !memcmp(buf, "OK", 2))
535 break;
536
537 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700538 err = -EINVAL;
539 break;
540 }
541
542 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100543 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
544 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700545 err = -ETIMEDOUT;
546 break;
547 }
548 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100549 if (err) {
550 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700551 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100552 }
Michael Wueff1a592007-09-25 18:11:01 -0700553
554 buf[0] = 'g';
555 buf[1] = '\r';
556 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
557 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100558 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700559 goto err_upload_failed;
560 }
561
562 timeout = jiffies + msecs_to_jiffies(1000);
563 while (!(err = usb_bulk_msg(priv->udev,
564 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
565 if (alen > 0 && buf[0] == 'g')
566 break;
567
568 if (time_after(jiffies, timeout)) {
569 err = -ETIMEDOUT;
570 break;
571 }
572 }
573 if (err)
574 goto err_upload_failed;
575
576 err_upload_failed:
577 release_firmware(fw_entry);
578 err_req_fw_failed:
579 err_reset:
580 kfree(buf);
581 err_bufalloc:
582 return err;
583}
584
585static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
586{
587 struct p54u_priv *priv = dev->priv;
588 const struct firmware *fw_entry = NULL;
589 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
590 int err, alen;
591 void *buf;
592 __le32 reg;
593 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100594 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700595
596 buf = kmalloc(512, GFP_KERNEL);
597 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100598 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
599 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700600 return -ENOMEM;
601 }
602
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200603 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700604 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100605 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
606 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200607 err = request_firmware(&fw_entry, "isl3890usb",
608 &priv->udev->dev);
609 if (err) {
610 kfree(buf);
611 return err;
612 }
Michael Wueff1a592007-09-25 18:11:01 -0700613 }
614
Christian Lamparter4e416a62008-09-01 22:48:41 +0200615 err = p54_parse_firmware(dev, fw_entry);
616 if (err) {
617 kfree(buf);
618 release_firmware(fw_entry);
619 return err;
620 }
Michael Wueff1a592007-09-25 18:11:01 -0700621
622#define P54U_WRITE(type, addr, data) \
623 do {\
624 err = p54u_write(priv, buf, type,\
625 cpu_to_le32((u32)(unsigned long)addr), data);\
626 if (err) \
627 goto fail;\
628 } while (0)
629
630#define P54U_READ(type, addr) \
631 do {\
632 err = p54u_read(priv, buf, type,\
633 cpu_to_le32((u32)(unsigned long)addr), &reg);\
634 if (err)\
635 goto fail;\
636 } while (0)
637
638 /* power down net2280 bridge */
639 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
640 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
641 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
642 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
643
644 mdelay(100);
645
646 /* power up bridge */
647 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
648 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
649 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
650
651 mdelay(100);
652
653 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
654 cpu_to_le32(NET2280_CLK_30Mhz |
655 NET2280_PCI_ENABLE |
656 NET2280_PCI_SOFT_RESET));
657
658 mdelay(20);
659
660 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
661 cpu_to_le32(PCI_COMMAND_MEMORY |
662 PCI_COMMAND_MASTER));
663
664 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
665 cpu_to_le32(NET2280_BASE));
666
667 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
668 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
669 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
670
671 // TODO: we really need this?
672 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
673
674 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
675 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
676 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
677 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
678
679 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
680 cpu_to_le32(NET2280_BASE2));
681
682 /* finally done setting up the bridge */
683
684 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
685 cpu_to_le32(PCI_COMMAND_MEMORY |
686 PCI_COMMAND_MASTER));
687
688 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
689 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
690 cpu_to_le32(P54U_DEV_BASE));
691
692 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
693 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
694 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
695
696 /* do romboot */
697 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
698
699 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
700 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
701 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
702 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
703 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
704
705 mdelay(20);
706
707 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
708 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
709
710 mdelay(20);
711
712 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
713 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
714
715 mdelay(100);
716
717 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
718 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
719
720 /* finally, we can upload firmware now! */
721 remains = fw_entry->size;
722 data = fw_entry->data;
723 offset = ISL38XX_DEV_FIRMWARE_ADDR;
724
725 while (remains) {
726 unsigned int block_len = min(remains, (unsigned int)512);
727 memcpy(buf, data, block_len);
728
729 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
730 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100731 dev_err(&priv->udev->dev, "(p54usb) firmware block "
732 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700733 goto fail;
734 }
735
736 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
737 cpu_to_le32(0xc0000f00));
738
739 P54U_WRITE(NET2280_DEV_U32,
740 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
741 P54U_WRITE(NET2280_DEV_U32,
742 0x0020 | (unsigned long)&devreg->direct_mem_win,
743 cpu_to_le32(1));
744
745 P54U_WRITE(NET2280_DEV_U32,
746 0x0024 | (unsigned long)&devreg->direct_mem_win,
747 cpu_to_le32(block_len));
748 P54U_WRITE(NET2280_DEV_U32,
749 0x0028 | (unsigned long)&devreg->direct_mem_win,
750 cpu_to_le32(offset));
751
752 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
753 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
754 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
755 cpu_to_le32(block_len >> 2));
756 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
757 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
758
759 mdelay(10);
760
761 P54U_READ(NET2280_DEV_U32,
762 0x002C | (unsigned long)&devreg->direct_mem_win);
763 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
764 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100765 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
766 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700767 goto fail;
768 }
769
770 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
771 cpu_to_le32(NET2280_FIFO_FLUSH));
772
773 remains -= block_len;
774 data += block_len;
775 offset += block_len;
776 }
777
778 /* do ramboot */
779 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
780 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
781 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
782 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
783 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
784
785 mdelay(20);
786
787 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
788 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
789
790 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
791 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
792
793 mdelay(100);
794
795 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
796 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
797
798 /* start up the firmware */
799 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
800 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
801
802 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
803 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
804
805 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
806 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
807 NET2280_USB_INTERRUPT_ENABLE));
808
809 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
810 cpu_to_le32(ISL38XX_DEV_INT_RESET));
811
812 err = usb_interrupt_msg(priv->udev,
813 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
814 buf, sizeof(__le32), &alen, 1000);
815 if (err || alen != sizeof(__le32))
816 goto fail;
817
818 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
819 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
820
821 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
822 err = -EINVAL;
823
824 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
825 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
826 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
827
828#undef P54U_WRITE
829#undef P54U_READ
830
831 fail:
832 release_firmware(fw_entry);
833 kfree(buf);
834 return err;
835}
836
837static int p54u_open(struct ieee80211_hw *dev)
838{
839 struct p54u_priv *priv = dev->priv;
840 int err;
841
842 err = p54u_init_urbs(dev);
843 if (err) {
844 return err;
845 }
846
847 priv->common.open = p54u_init_urbs;
848
849 return 0;
850}
851
852static void p54u_stop(struct ieee80211_hw *dev)
853{
854 /* TODO: figure out how to reliably stop the 3887 and net2280 so
855 the hardware is still usable next time we want to start it.
856 until then, we just stop listening to the hardware.. */
857 p54u_free_urbs(dev);
858 return;
859}
860
861static int __devinit p54u_probe(struct usb_interface *intf,
862 const struct usb_device_id *id)
863{
864 struct usb_device *udev = interface_to_usbdev(intf);
865 struct ieee80211_hw *dev;
866 struct p54u_priv *priv;
867 int err;
868 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700869
870 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100871
Michael Wueff1a592007-09-25 18:11:01 -0700872 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100873 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700874 return -ENOMEM;
875 }
876
877 priv = dev->priv;
878
879 SET_IEEE80211_DEV(dev, &intf->dev);
880 usb_set_intfdata(intf, dev);
881 priv->udev = udev;
882
883 usb_get_dev(udev);
884
885 /* really lazy and simple way of figuring out if we're a 3887 */
886 /* TODO: should just stick the identification in the device table */
887 i = intf->altsetting->desc.bNumEndpoints;
888 recognized_pipes = 0;
889 while (i--) {
890 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
891 case P54U_PIPE_DATA:
892 case P54U_PIPE_MGMT:
893 case P54U_PIPE_BRG:
894 case P54U_PIPE_DEV:
895 case P54U_PIPE_DATA | USB_DIR_IN:
896 case P54U_PIPE_MGMT | USB_DIR_IN:
897 case P54U_PIPE_BRG | USB_DIR_IN:
898 case P54U_PIPE_DEV | USB_DIR_IN:
899 case P54U_PIPE_INT | USB_DIR_IN:
900 recognized_pipes++;
901 }
902 }
903 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200904 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700905 if (recognized_pipes < P54U_PIPE_NUMBER) {
906 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200907 err = p54u_upload_firmware_3887(dev);
908 if (priv->common.fw_interface == FW_LM87) {
909 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
910 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
911 priv->common.tx = p54u_tx_lm87;
912 } else
913 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700914 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200915 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700916 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
917 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
918 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700919 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200920 }
Michael Wueff1a592007-09-25 18:11:01 -0700921 if (err)
922 goto err_free_dev;
923
Christian Lamparter7cb77072008-09-01 22:48:51 +0200924 skb_queue_head_init(&priv->rx_queue);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100925 init_usb_anchor(&priv->submitted);
Christian Lamparter7cb77072008-09-01 22:48:51 +0200926
927 p54u_open(dev);
928 err = p54_read_eeprom(dev);
929 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700930 if (err)
931 goto err_free_dev;
932
Michael Wueff1a592007-09-25 18:11:01 -0700933 err = ieee80211_register_hw(dev);
934 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100935 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700936 goto err_free_dev;
937 }
938
Michael Wueff1a592007-09-25 18:11:01 -0700939 return 0;
940
941 err_free_dev:
942 ieee80211_free_hw(dev);
943 usb_set_intfdata(intf, NULL);
944 usb_put_dev(udev);
945 return err;
946}
947
948static void __devexit p54u_disconnect(struct usb_interface *intf)
949{
950 struct ieee80211_hw *dev = usb_get_intfdata(intf);
951 struct p54u_priv *priv;
952
953 if (!dev)
954 return;
955
956 ieee80211_unregister_hw(dev);
957
958 priv = dev->priv;
959 usb_put_dev(interface_to_usbdev(intf));
960 p54_free_common(dev);
961 ieee80211_free_hw(dev);
962}
963
964static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200965 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700966 .id_table = p54u_table,
967 .probe = p54u_probe,
968 .disconnect = p54u_disconnect,
969};
970
971static int __init p54u_init(void)
972{
973 return usb_register(&p54u_driver);
974}
975
976static void __exit p54u_exit(void)
977{
978 usb_deregister(&p54u_driver);
979}
980
981module_init(p54u_init);
982module_exit(p54u_exit);