blob: 4487cc5c928b3037c7c2088f5e8d5c8ff37c9221 [file] [log] [blame]
Michael Wueff1a592007-09-25 18:11:01 -07001
2/*
3 * Linux device driver for USB based Prism54
4 *
5 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
6 *
7 * Based on the islsm (softmac prism54) driver, which is:
8 * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/init.h>
16#include <linux/usb.h>
17#include <linux/pci.h>
18#include <linux/firmware.h>
19#include <linux/etherdevice.h>
20#include <linux/delay.h>
21#include <linux/crc32.h>
22#include <net/mac80211.h>
23
24#include "p54.h"
25#include "p54usb.h"
26
27MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
28MODULE_DESCRIPTION("Prism54 USB wireless driver");
29MODULE_LICENSE("GPL");
30MODULE_ALIAS("prism54usb");
Christian Lamparter9a8675d2008-10-18 23:04:15 +020031MODULE_FIRMWARE("isl3886usb");
32MODULE_FIRMWARE("isl3887usb");
Michael Wueff1a592007-09-25 18:11:01 -070033
34static struct usb_device_id p54u_table[] __devinitdata = {
35 /* Version 1 devices (pci chip + net2280) */
36 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
37 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
38 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
39 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050040 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070041 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
42 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
43 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020044 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070045 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
46 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
47 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
48 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
49 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
50 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
51 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
52 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
53
54 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070055 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070056 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
57 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
58 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060059 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070060 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
61 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
62 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
63 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
64 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
65 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
66 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
67 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
68 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
69 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070070 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020071 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050072 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040073 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Michael Wueff1a592007-09-25 18:11:01 -070074 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
75 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
76 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
77 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
78 {}
79};
80
81MODULE_DEVICE_TABLE(usb, p54u_table);
82
83static void p54u_rx_cb(struct urb *urb)
84{
85 struct sk_buff *skb = (struct sk_buff *) urb->context;
86 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
87 struct ieee80211_hw *dev = info->dev;
88 struct p54u_priv *priv = dev->priv;
89
Christian Lamparterdd397dc2008-12-09 15:14:37 +010090 skb_unlink(skb, &priv->rx_queue);
91
Michael Wueff1a592007-09-25 18:11:01 -070092 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +010093 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -070094 return;
95 }
96
Michael Wueff1a592007-09-25 18:11:01 -070097 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +020098
99 if (priv->hw_type == P54U_NET2280)
100 skb_pull(skb, priv->common.tx_hdr_len);
101 if (priv->common.fw_interface == FW_LM87) {
102 skb_pull(skb, 4);
103 skb_put(skb, 4);
104 }
Michael Wueff1a592007-09-25 18:11:01 -0700105
106 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200107 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700108 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700109 /* TODO check rx queue length and refill *somewhere* */
110 return;
111 }
112
113 info = (struct p54u_rx_info *) skb->cb;
114 info->urb = urb;
115 info->dev = dev;
116 urb->transfer_buffer = skb_tail_pointer(skb);
117 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700118 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200119 if (priv->hw_type == P54U_NET2280)
120 skb_push(skb, priv->common.tx_hdr_len);
121 if (priv->common.fw_interface == FW_LM87) {
122 skb_push(skb, 4);
123 skb_put(skb, 4);
124 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200125 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700126 skb_trim(skb, 0);
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200127 if (urb->transfer_buffer != skb_tail_pointer(skb)) {
128 /* this should not happen */
129 WARN_ON(1);
130 urb->transfer_buffer = skb_tail_pointer(skb);
131 }
Michael Wueff1a592007-09-25 18:11:01 -0700132 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100133 skb_queue_tail(&priv->rx_queue, skb);
134 usb_anchor_urb(urb, &priv->submitted);
135 if (usb_submit_urb(urb, GFP_ATOMIC)) {
136 skb_unlink(skb, &priv->rx_queue);
137 usb_unanchor_urb(urb);
138 dev_kfree_skb_irq(skb);
139 }
Michael Wueff1a592007-09-25 18:11:01 -0700140}
141
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100142static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200143{
144 struct sk_buff *skb = urb->context;
145 struct ieee80211_hw *dev = (struct ieee80211_hw *)
146 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
147
Christian Lampartere2fe1542009-01-20 00:27:57 +0100148 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100149}
150
151static void p54u_tx_dummy_cb(struct urb *urb) { }
152
153static void p54u_free_urbs(struct ieee80211_hw *dev)
154{
155 struct p54u_priv *priv = dev->priv;
156 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200157}
158
Michael Wueff1a592007-09-25 18:11:01 -0700159static int p54u_init_urbs(struct ieee80211_hw *dev)
160{
161 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100162 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700163 struct sk_buff *skb;
164 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100165 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700166
167 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200168 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100169 if (!skb) {
170 ret = -ENOMEM;
171 goto err;
172 }
Michael Wueff1a592007-09-25 18:11:01 -0700173 entry = usb_alloc_urb(0, GFP_KERNEL);
174 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100175 ret = -ENOMEM;
176 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700177 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100178
Christian Lamparter4e416a62008-09-01 22:48:41 +0200179 usb_fill_bulk_urb(entry, priv->udev,
180 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
181 skb_tail_pointer(skb),
182 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700183 info = (struct p54u_rx_info *) skb->cb;
184 info->urb = entry;
185 info->dev = dev;
186 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100187
188 usb_anchor_urb(entry, &priv->submitted);
189 ret = usb_submit_urb(entry, GFP_KERNEL);
190 if (ret) {
191 skb_unlink(skb, &priv->rx_queue);
192 usb_unanchor_urb(entry);
193 goto err;
194 }
195 usb_free_urb(entry);
196 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700197 }
198
199 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700200
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100201 err:
202 usb_free_urb(entry);
203 kfree_skb(skb);
204 p54u_free_urbs(dev);
205 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700206}
207
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100208static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700209{
210 struct p54u_priv *priv = dev->priv;
211 struct urb *addr_urb, *data_urb;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100212 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700213
214 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
215 if (!addr_urb)
216 return;
217
218 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
219 if (!data_urb) {
220 usb_free_urb(addr_urb);
221 return;
222 }
223
224 usb_fill_bulk_urb(addr_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200225 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
John W. Linville27df6052008-10-22 16:41:55 -0400226 &((struct p54_hdr *)skb->data)->req_id, 4,
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100227 p54u_tx_dummy_cb, dev);
Michael Wueff1a592007-09-25 18:11:01 -0700228 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200229 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100230 skb->data, skb->len, FREE_AFTER_TX(skb) ?
231 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700232
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100233 usb_anchor_urb(addr_urb, &priv->submitted);
234 err = usb_submit_urb(addr_urb, GFP_ATOMIC);
235 if (err) {
236 usb_unanchor_urb(addr_urb);
237 goto out;
238 }
239
240 usb_anchor_urb(addr_urb, &priv->submitted);
241 err = usb_submit_urb(data_urb, GFP_ATOMIC);
242 if (err)
243 usb_unanchor_urb(data_urb);
244
245 out:
246 usb_free_urb(addr_urb);
247 usb_free_urb(data_urb);
248
249 if (err)
250 p54_free_skb(dev, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700251}
252
Johannes Bergc9127652008-12-01 18:19:36 +0100253static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200254{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500255 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200256
257 length >>= 2;
258 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100259 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200260 chk = (chk >> 5) ^ (chk << 3);
261 }
262
Larry Finger1f1c0e32008-09-25 14:54:28 -0500263 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200264}
265
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100266static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200267{
268 struct p54u_priv *priv = dev->priv;
269 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100270 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200271
272 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
273 if (!data_urb)
274 return;
275
Christian Lampartere2fe1542009-01-20 00:27:57 +0100276 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
277 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200278
279 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200280 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100281 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
282 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100283 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200284
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100285 usb_anchor_urb(data_urb, &priv->submitted);
286 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
287 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100288 p54_free_skb(dev, skb);
289 }
290 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200291}
292
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100293static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700294{
295 struct p54u_priv *priv = dev->priv;
296 struct urb *int_urb, *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100297 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Michael Wueff1a592007-09-25 18:11:01 -0700298 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100299 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700300
301 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
302 if (!reg)
303 return;
304
305 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
306 if (!int_urb) {
307 kfree(reg);
308 return;
309 }
310
311 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
312 if (!data_urb) {
313 kfree(reg);
314 usb_free_urb(int_urb);
315 return;
316 }
317
318 reg->port = cpu_to_le16(NET2280_DEV_U32);
319 reg->addr = cpu_to_le32(P54U_DEV_BASE);
320 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
321
Michael Wueff1a592007-09-25 18:11:01 -0700322 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100323 hdr->len = cpu_to_le16(skb->len);
324 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700325
326 usb_fill_bulk_urb(int_urb, priv->udev,
327 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100328 p54u_tx_dummy_cb, dev);
329
330 /*
331 * This flag triggers a code path in the USB subsystem that will
332 * free what's inside the transfer_buffer after the callback routine
333 * has completed.
334 */
335 int_urb->transfer_flags |= URB_FREE_BUFFER;
Michael Wueff1a592007-09-25 18:11:01 -0700336
337 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200338 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100339 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
340 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100341
342 usb_anchor_urb(int_urb, &priv->submitted);
343 err = usb_submit_urb(int_urb, GFP_ATOMIC);
344 if (err) {
345 usb_unanchor_urb(int_urb);
346 goto out;
347 }
348
349 usb_anchor_urb(data_urb, &priv->submitted);
350 err = usb_submit_urb(data_urb, GFP_ATOMIC);
351 if (err) {
352 usb_unanchor_urb(data_urb);
353 goto out;
354 }
355 out:
356 usb_free_urb(int_urb);
357 usb_free_urb(data_urb);
358
359 if (err) {
360 skb_pull(skb, sizeof(*hdr));
361 p54_free_skb(dev, skb);
362 }
Michael Wueff1a592007-09-25 18:11:01 -0700363}
364
365static int p54u_write(struct p54u_priv *priv,
366 struct net2280_reg_write *buf,
367 enum net2280_op_type type,
368 __le32 addr, __le32 val)
369{
370 unsigned int ep;
371 int alen;
372
373 if (type & 0x0800)
374 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
375 else
376 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
377
378 buf->port = cpu_to_le16(type);
379 buf->addr = addr;
380 buf->val = val;
381
382 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
383}
384
385static int p54u_read(struct p54u_priv *priv, void *buf,
386 enum net2280_op_type type,
387 __le32 addr, __le32 *val)
388{
389 struct net2280_reg_read *read = buf;
390 __le32 *reg = buf;
391 unsigned int ep;
392 int alen, err;
393
394 if (type & 0x0800)
395 ep = P54U_PIPE_DEV;
396 else
397 ep = P54U_PIPE_BRG;
398
399 read->port = cpu_to_le16(type);
400 read->addr = addr;
401
402 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
403 read, sizeof(*read), &alen, 1000);
404 if (err)
405 return err;
406
407 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
408 reg, sizeof(*reg), &alen, 1000);
409 if (err)
410 return err;
411
412 *val = *reg;
413 return 0;
414}
415
416static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
417 void *data, size_t len)
418{
419 int alen;
420 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
421 data, len, &alen, 2000);
422}
423
Michael Wueff1a592007-09-25 18:11:01 -0700424static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
425{
426 static char start_string[] = "~~~~<\r";
427 struct p54u_priv *priv = dev->priv;
428 const struct firmware *fw_entry = NULL;
429 int err, alen;
430 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100431 u8 *buf, *tmp;
432 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700433 unsigned int left, remains, block_size;
434 struct x2_header *hdr;
435 unsigned long timeout;
436
437 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
438 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100439 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
440 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700441 err = -ENOMEM;
442 goto err_bufalloc;
443 }
444
445 memcpy(buf, start_string, 4);
446 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
447 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100448 dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
Michael Wueff1a592007-09-25 18:11:01 -0700449 goto err_reset;
450 }
451
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200452 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700453 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100454 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
455 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200456 err = request_firmware(&fw_entry, "isl3887usb_bare",
457 &priv->udev->dev);
458 if (err)
459 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700460 }
461
Christian Lamparter4e416a62008-09-01 22:48:41 +0200462 err = p54_parse_firmware(dev, fw_entry);
463 if (err)
464 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700465
466 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
467 strcpy(buf, start_string);
468 left -= strlen(start_string);
469 tmp += strlen(start_string);
470
471 data = fw_entry->data;
472 remains = fw_entry->size;
473
474 hdr = (struct x2_header *)(buf + strlen(start_string));
475 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
476 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
477 hdr->fw_length = cpu_to_le32(fw_entry->size);
478 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
519 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
520 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
521 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100522 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700523 goto err_upload_failed;
524 }
Michael Wueff1a592007-09-25 18:11:01 -0700525 timeout = jiffies + msecs_to_jiffies(1000);
526 while (!(err = usb_bulk_msg(priv->udev,
527 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
528 if (alen > 2 && !memcmp(buf, "OK", 2))
529 break;
530
531 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700532 err = -EINVAL;
533 break;
534 }
535
536 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100537 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
538 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700539 err = -ETIMEDOUT;
540 break;
541 }
542 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100543 if (err) {
544 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700545 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100546 }
Michael Wueff1a592007-09-25 18:11:01 -0700547
548 buf[0] = 'g';
549 buf[1] = '\r';
550 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
551 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100552 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700553 goto err_upload_failed;
554 }
555
556 timeout = jiffies + msecs_to_jiffies(1000);
557 while (!(err = usb_bulk_msg(priv->udev,
558 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
559 if (alen > 0 && buf[0] == 'g')
560 break;
561
562 if (time_after(jiffies, timeout)) {
563 err = -ETIMEDOUT;
564 break;
565 }
566 }
567 if (err)
568 goto err_upload_failed;
569
570 err_upload_failed:
571 release_firmware(fw_entry);
572 err_req_fw_failed:
573 err_reset:
574 kfree(buf);
575 err_bufalloc:
576 return err;
577}
578
579static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
580{
581 struct p54u_priv *priv = dev->priv;
582 const struct firmware *fw_entry = NULL;
583 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
584 int err, alen;
585 void *buf;
586 __le32 reg;
587 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100588 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700589
590 buf = kmalloc(512, GFP_KERNEL);
591 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100592 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
593 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700594 return -ENOMEM;
595 }
596
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200597 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700598 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100599 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
600 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200601 err = request_firmware(&fw_entry, "isl3890usb",
602 &priv->udev->dev);
603 if (err) {
604 kfree(buf);
605 return err;
606 }
Michael Wueff1a592007-09-25 18:11:01 -0700607 }
608
Christian Lamparter4e416a62008-09-01 22:48:41 +0200609 err = p54_parse_firmware(dev, fw_entry);
610 if (err) {
611 kfree(buf);
612 release_firmware(fw_entry);
613 return err;
614 }
Michael Wueff1a592007-09-25 18:11:01 -0700615
616#define P54U_WRITE(type, addr, data) \
617 do {\
618 err = p54u_write(priv, buf, type,\
619 cpu_to_le32((u32)(unsigned long)addr), data);\
620 if (err) \
621 goto fail;\
622 } while (0)
623
624#define P54U_READ(type, addr) \
625 do {\
626 err = p54u_read(priv, buf, type,\
627 cpu_to_le32((u32)(unsigned long)addr), &reg);\
628 if (err)\
629 goto fail;\
630 } while (0)
631
632 /* power down net2280 bridge */
633 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
634 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
635 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
636 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
637
638 mdelay(100);
639
640 /* power up bridge */
641 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
642 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
643 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
644
645 mdelay(100);
646
647 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
648 cpu_to_le32(NET2280_CLK_30Mhz |
649 NET2280_PCI_ENABLE |
650 NET2280_PCI_SOFT_RESET));
651
652 mdelay(20);
653
654 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
655 cpu_to_le32(PCI_COMMAND_MEMORY |
656 PCI_COMMAND_MASTER));
657
658 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
659 cpu_to_le32(NET2280_BASE));
660
661 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
662 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
663 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
664
665 // TODO: we really need this?
666 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
667
668 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
669 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
670 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
671 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
672
673 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
674 cpu_to_le32(NET2280_BASE2));
675
676 /* finally done setting up the bridge */
677
678 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
679 cpu_to_le32(PCI_COMMAND_MEMORY |
680 PCI_COMMAND_MASTER));
681
682 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
683 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
684 cpu_to_le32(P54U_DEV_BASE));
685
686 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
687 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
688 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
689
690 /* do romboot */
691 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
692
693 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
694 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
695 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
696 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
697 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
698
699 mdelay(20);
700
701 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
702 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
703
704 mdelay(20);
705
706 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
707 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
708
709 mdelay(100);
710
711 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
712 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
713
714 /* finally, we can upload firmware now! */
715 remains = fw_entry->size;
716 data = fw_entry->data;
717 offset = ISL38XX_DEV_FIRMWARE_ADDR;
718
719 while (remains) {
720 unsigned int block_len = min(remains, (unsigned int)512);
721 memcpy(buf, data, block_len);
722
723 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
724 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100725 dev_err(&priv->udev->dev, "(p54usb) firmware block "
726 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700727 goto fail;
728 }
729
730 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
731 cpu_to_le32(0xc0000f00));
732
733 P54U_WRITE(NET2280_DEV_U32,
734 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
735 P54U_WRITE(NET2280_DEV_U32,
736 0x0020 | (unsigned long)&devreg->direct_mem_win,
737 cpu_to_le32(1));
738
739 P54U_WRITE(NET2280_DEV_U32,
740 0x0024 | (unsigned long)&devreg->direct_mem_win,
741 cpu_to_le32(block_len));
742 P54U_WRITE(NET2280_DEV_U32,
743 0x0028 | (unsigned long)&devreg->direct_mem_win,
744 cpu_to_le32(offset));
745
746 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
747 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
748 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
749 cpu_to_le32(block_len >> 2));
750 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
751 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
752
753 mdelay(10);
754
755 P54U_READ(NET2280_DEV_U32,
756 0x002C | (unsigned long)&devreg->direct_mem_win);
757 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
758 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100759 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
760 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700761 goto fail;
762 }
763
764 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
765 cpu_to_le32(NET2280_FIFO_FLUSH));
766
767 remains -= block_len;
768 data += block_len;
769 offset += block_len;
770 }
771
772 /* do ramboot */
773 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
774 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
775 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
776 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
777 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
778
779 mdelay(20);
780
781 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
782 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
783
784 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
785 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
786
787 mdelay(100);
788
789 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
790 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
791
792 /* start up the firmware */
793 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
794 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
795
796 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
797 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
798
799 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
800 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
801 NET2280_USB_INTERRUPT_ENABLE));
802
803 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
804 cpu_to_le32(ISL38XX_DEV_INT_RESET));
805
806 err = usb_interrupt_msg(priv->udev,
807 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
808 buf, sizeof(__le32), &alen, 1000);
809 if (err || alen != sizeof(__le32))
810 goto fail;
811
812 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
813 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
814
815 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
816 err = -EINVAL;
817
818 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
819 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
820 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
821
822#undef P54U_WRITE
823#undef P54U_READ
824
825 fail:
826 release_firmware(fw_entry);
827 kfree(buf);
828 return err;
829}
830
831static int p54u_open(struct ieee80211_hw *dev)
832{
833 struct p54u_priv *priv = dev->priv;
834 int err;
835
836 err = p54u_init_urbs(dev);
837 if (err) {
838 return err;
839 }
840
841 priv->common.open = p54u_init_urbs;
842
843 return 0;
844}
845
846static void p54u_stop(struct ieee80211_hw *dev)
847{
848 /* TODO: figure out how to reliably stop the 3887 and net2280 so
849 the hardware is still usable next time we want to start it.
850 until then, we just stop listening to the hardware.. */
851 p54u_free_urbs(dev);
852 return;
853}
854
855static int __devinit p54u_probe(struct usb_interface *intf,
856 const struct usb_device_id *id)
857{
858 struct usb_device *udev = interface_to_usbdev(intf);
859 struct ieee80211_hw *dev;
860 struct p54u_priv *priv;
861 int err;
862 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700863
864 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100865
Michael Wueff1a592007-09-25 18:11:01 -0700866 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100867 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700868 return -ENOMEM;
869 }
870
871 priv = dev->priv;
872
873 SET_IEEE80211_DEV(dev, &intf->dev);
874 usb_set_intfdata(intf, dev);
875 priv->udev = udev;
876
877 usb_get_dev(udev);
878
879 /* really lazy and simple way of figuring out if we're a 3887 */
880 /* TODO: should just stick the identification in the device table */
881 i = intf->altsetting->desc.bNumEndpoints;
882 recognized_pipes = 0;
883 while (i--) {
884 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
885 case P54U_PIPE_DATA:
886 case P54U_PIPE_MGMT:
887 case P54U_PIPE_BRG:
888 case P54U_PIPE_DEV:
889 case P54U_PIPE_DATA | USB_DIR_IN:
890 case P54U_PIPE_MGMT | USB_DIR_IN:
891 case P54U_PIPE_BRG | USB_DIR_IN:
892 case P54U_PIPE_DEV | USB_DIR_IN:
893 case P54U_PIPE_INT | USB_DIR_IN:
894 recognized_pipes++;
895 }
896 }
897 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200898 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700899 if (recognized_pipes < P54U_PIPE_NUMBER) {
900 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200901 err = p54u_upload_firmware_3887(dev);
902 if (priv->common.fw_interface == FW_LM87) {
903 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
904 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
905 priv->common.tx = p54u_tx_lm87;
906 } else
907 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700908 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200909 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700910 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
911 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
912 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700913 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200914 }
Michael Wueff1a592007-09-25 18:11:01 -0700915 if (err)
916 goto err_free_dev;
917
Christian Lamparter7cb77072008-09-01 22:48:51 +0200918 skb_queue_head_init(&priv->rx_queue);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100919 init_usb_anchor(&priv->submitted);
Christian Lamparter7cb77072008-09-01 22:48:51 +0200920
921 p54u_open(dev);
922 err = p54_read_eeprom(dev);
923 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700924 if (err)
925 goto err_free_dev;
926
Michael Wueff1a592007-09-25 18:11:01 -0700927 err = ieee80211_register_hw(dev);
928 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100929 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700930 goto err_free_dev;
931 }
932
Michael Wueff1a592007-09-25 18:11:01 -0700933 return 0;
934
935 err_free_dev:
936 ieee80211_free_hw(dev);
937 usb_set_intfdata(intf, NULL);
938 usb_put_dev(udev);
939 return err;
940}
941
942static void __devexit p54u_disconnect(struct usb_interface *intf)
943{
944 struct ieee80211_hw *dev = usb_get_intfdata(intf);
945 struct p54u_priv *priv;
946
947 if (!dev)
948 return;
949
950 ieee80211_unregister_hw(dev);
951
952 priv = dev->priv;
953 usb_put_dev(interface_to_usbdev(intf));
954 p54_free_common(dev);
955 ieee80211_free_hw(dev);
956}
957
958static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200959 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700960 .id_table = p54u_table,
961 .probe = p54u_probe,
962 .disconnect = p54u_disconnect,
963};
964
965static int __init p54u_init(void)
966{
967 return usb_register(&p54u_driver);
968}
969
970static void __exit p54u_exit(void)
971{
972 usb_deregister(&p54u_driver);
973}
974
975module_init(p54u_init);
976module_exit(p54u_exit);