blob: 8f5c063b854b42bd0da1851854adebdd1df99163 [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));
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100147 struct p54u_priv *priv = dev->priv;
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200148
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100149 skb_pull(skb, priv->common.tx_hdr_len);
150 if (FREE_AFTER_TX(skb))
151 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100152}
153
154static void p54u_tx_dummy_cb(struct urb *urb) { }
155
156static void p54u_free_urbs(struct ieee80211_hw *dev)
157{
158 struct p54u_priv *priv = dev->priv;
159 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200160}
161
Michael Wueff1a592007-09-25 18:11:01 -0700162static int p54u_init_urbs(struct ieee80211_hw *dev)
163{
164 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100165 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700166 struct sk_buff *skb;
167 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100168 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700169
170 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200171 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100172 if (!skb) {
173 ret = -ENOMEM;
174 goto err;
175 }
Michael Wueff1a592007-09-25 18:11:01 -0700176 entry = usb_alloc_urb(0, GFP_KERNEL);
177 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100178 ret = -ENOMEM;
179 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700180 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100181
Christian Lamparter4e416a62008-09-01 22:48:41 +0200182 usb_fill_bulk_urb(entry, priv->udev,
183 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
184 skb_tail_pointer(skb),
185 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700186 info = (struct p54u_rx_info *) skb->cb;
187 info->urb = entry;
188 info->dev = dev;
189 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100190
191 usb_anchor_urb(entry, &priv->submitted);
192 ret = usb_submit_urb(entry, GFP_KERNEL);
193 if (ret) {
194 skb_unlink(skb, &priv->rx_queue);
195 usb_unanchor_urb(entry);
196 goto err;
197 }
198 usb_free_urb(entry);
199 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700200 }
201
202 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700203
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100204 err:
205 usb_free_urb(entry);
206 kfree_skb(skb);
207 p54u_free_urbs(dev);
208 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700209}
210
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100211static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700212{
213 struct p54u_priv *priv = dev->priv;
214 struct urb *addr_urb, *data_urb;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100215 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700216
217 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
218 if (!addr_urb)
219 return;
220
221 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
222 if (!data_urb) {
223 usb_free_urb(addr_urb);
224 return;
225 }
226
227 usb_fill_bulk_urb(addr_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200228 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
John W. Linville27df6052008-10-22 16:41:55 -0400229 &((struct p54_hdr *)skb->data)->req_id, 4,
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100230 p54u_tx_dummy_cb, dev);
Michael Wueff1a592007-09-25 18:11:01 -0700231 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200232 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100233 skb->data, skb->len, p54u_tx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700234
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100235 usb_anchor_urb(addr_urb, &priv->submitted);
236 err = usb_submit_urb(addr_urb, GFP_ATOMIC);
237 if (err) {
238 usb_unanchor_urb(addr_urb);
239 goto out;
240 }
241
242 usb_anchor_urb(addr_urb, &priv->submitted);
243 err = usb_submit_urb(data_urb, GFP_ATOMIC);
244 if (err)
245 usb_unanchor_urb(data_urb);
246
247 out:
248 usb_free_urb(addr_urb);
249 usb_free_urb(data_urb);
250
251 if (err)
252 p54_free_skb(dev, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700253}
254
Johannes Bergc9127652008-12-01 18:19:36 +0100255static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200256{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500257 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200258
259 length >>= 2;
260 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100261 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200262 chk = (chk >> 5) ^ (chk << 3);
263 }
264
Larry Finger1f1c0e32008-09-25 14:54:28 -0500265 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200266}
267
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100268static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200269{
270 struct p54u_priv *priv = dev->priv;
271 struct urb *data_urb;
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200272 struct lm87_tx_hdr *hdr;
273 __le32 checksum;
John W. Linville27df6052008-10-22 16:41:55 -0400274 __le32 addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200275
276 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
277 if (!data_urb)
278 return;
279
Johannes Bergc9127652008-12-01 18:19:36 +0100280 checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200281 hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr));
282 hdr->chksum = checksum;
283 hdr->device_addr = addr;
Christian Lamparter2b808482008-09-04 12:29:38 +0200284
285 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200286 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100287 skb->data, skb->len, p54u_tx_cb, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200288
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100289 usb_anchor_urb(data_urb, &priv->submitted);
290 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
291 usb_unanchor_urb(data_urb);
292 skb_pull(skb, sizeof(*hdr));
293 p54_free_skb(dev, skb);
294 }
295 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200296}
297
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100298static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700299{
300 struct p54u_priv *priv = dev->priv;
301 struct urb *int_urb, *data_urb;
302 struct net2280_tx_hdr *hdr;
303 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100304 int err = 0;
Christian Lamparter61107812008-12-17 12:04:43 +0100305 __le32 addr = ((struct p54_hdr *) skb->data)->req_id;
306 __le16 len = cpu_to_le16(skb->len);
Michael Wueff1a592007-09-25 18:11:01 -0700307
308 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
309 if (!reg)
310 return;
311
312 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
313 if (!int_urb) {
314 kfree(reg);
315 return;
316 }
317
318 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
319 if (!data_urb) {
320 kfree(reg);
321 usb_free_urb(int_urb);
322 return;
323 }
324
325 reg->port = cpu_to_le16(NET2280_DEV_U32);
326 reg->addr = cpu_to_le32(P54U_DEV_BASE);
327 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
328
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200329 hdr = (void *)skb_push(skb, sizeof(*hdr));
Michael Wueff1a592007-09-25 18:11:01 -0700330 memset(hdr, 0, sizeof(*hdr));
Christian Lamparter61107812008-12-17 12:04:43 +0100331 hdr->len = len;
332 hdr->device_addr = addr;
Michael Wueff1a592007-09-25 18:11:01 -0700333
334 usb_fill_bulk_urb(int_urb, priv->udev,
335 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100336 p54u_tx_dummy_cb, dev);
337
338 /*
339 * This flag triggers a code path in the USB subsystem that will
340 * free what's inside the transfer_buffer after the callback routine
341 * has completed.
342 */
343 int_urb->transfer_flags |= URB_FREE_BUFFER;
Michael Wueff1a592007-09-25 18:11:01 -0700344
345 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200346 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100347 skb->data, skb->len, p54u_tx_cb, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100348
349 usb_anchor_urb(int_urb, &priv->submitted);
350 err = usb_submit_urb(int_urb, GFP_ATOMIC);
351 if (err) {
352 usb_unanchor_urb(int_urb);
353 goto out;
354 }
355
356 usb_anchor_urb(data_urb, &priv->submitted);
357 err = usb_submit_urb(data_urb, GFP_ATOMIC);
358 if (err) {
359 usb_unanchor_urb(data_urb);
360 goto out;
361 }
362 out:
363 usb_free_urb(int_urb);
364 usb_free_urb(data_urb);
365
366 if (err) {
367 skb_pull(skb, sizeof(*hdr));
368 p54_free_skb(dev, skb);
369 }
Michael Wueff1a592007-09-25 18:11:01 -0700370}
371
372static int p54u_write(struct p54u_priv *priv,
373 struct net2280_reg_write *buf,
374 enum net2280_op_type type,
375 __le32 addr, __le32 val)
376{
377 unsigned int ep;
378 int alen;
379
380 if (type & 0x0800)
381 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
382 else
383 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
384
385 buf->port = cpu_to_le16(type);
386 buf->addr = addr;
387 buf->val = val;
388
389 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
390}
391
392static int p54u_read(struct p54u_priv *priv, void *buf,
393 enum net2280_op_type type,
394 __le32 addr, __le32 *val)
395{
396 struct net2280_reg_read *read = buf;
397 __le32 *reg = buf;
398 unsigned int ep;
399 int alen, err;
400
401 if (type & 0x0800)
402 ep = P54U_PIPE_DEV;
403 else
404 ep = P54U_PIPE_BRG;
405
406 read->port = cpu_to_le16(type);
407 read->addr = addr;
408
409 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
410 read, sizeof(*read), &alen, 1000);
411 if (err)
412 return err;
413
414 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
415 reg, sizeof(*reg), &alen, 1000);
416 if (err)
417 return err;
418
419 *val = *reg;
420 return 0;
421}
422
423static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
424 void *data, size_t len)
425{
426 int alen;
427 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
428 data, len, &alen, 2000);
429}
430
Michael Wueff1a592007-09-25 18:11:01 -0700431static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
432{
433 static char start_string[] = "~~~~<\r";
434 struct p54u_priv *priv = dev->priv;
435 const struct firmware *fw_entry = NULL;
436 int err, alen;
437 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100438 u8 *buf, *tmp;
439 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700440 unsigned int left, remains, block_size;
441 struct x2_header *hdr;
442 unsigned long timeout;
443
444 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
445 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100446 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
447 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700448 err = -ENOMEM;
449 goto err_bufalloc;
450 }
451
452 memcpy(buf, start_string, 4);
453 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
454 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100455 dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
Michael Wueff1a592007-09-25 18:11:01 -0700456 goto err_reset;
457 }
458
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200459 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700460 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100461 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
462 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200463 err = request_firmware(&fw_entry, "isl3887usb_bare",
464 &priv->udev->dev);
465 if (err)
466 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700467 }
468
Christian Lamparter4e416a62008-09-01 22:48:41 +0200469 err = p54_parse_firmware(dev, fw_entry);
470 if (err)
471 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700472
473 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
474 strcpy(buf, start_string);
475 left -= strlen(start_string);
476 tmp += strlen(start_string);
477
478 data = fw_entry->data;
479 remains = fw_entry->size;
480
481 hdr = (struct x2_header *)(buf + strlen(start_string));
482 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
483 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
484 hdr->fw_length = cpu_to_le32(fw_entry->size);
485 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
486 sizeof(u32)*2));
487 left -= sizeof(*hdr);
488 tmp += sizeof(*hdr);
489
490 while (remains) {
491 while (left--) {
492 if (carry) {
493 *tmp++ = carry;
494 carry = 0;
495 remains--;
496 continue;
497 }
498 switch (*data) {
499 case '~':
500 *tmp++ = '}';
501 carry = '^';
502 break;
503 case '}':
504 *tmp++ = '}';
505 carry = ']';
506 break;
507 default:
508 *tmp++ = *data;
509 remains--;
510 break;
511 }
512 data++;
513 }
514
515 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
516 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100517 dev_err(&priv->udev->dev, "(p54usb) firmware "
518 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700519 goto err_upload_failed;
520 }
521
522 tmp = buf;
523 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
524 }
525
526 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
527 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
528 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100529 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700530 goto err_upload_failed;
531 }
Michael Wueff1a592007-09-25 18:11:01 -0700532 timeout = jiffies + msecs_to_jiffies(1000);
533 while (!(err = usb_bulk_msg(priv->udev,
534 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
535 if (alen > 2 && !memcmp(buf, "OK", 2))
536 break;
537
538 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700539 err = -EINVAL;
540 break;
541 }
542
543 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100544 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
545 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700546 err = -ETIMEDOUT;
547 break;
548 }
549 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100550 if (err) {
551 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700552 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100553 }
Michael Wueff1a592007-09-25 18:11:01 -0700554
555 buf[0] = 'g';
556 buf[1] = '\r';
557 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
558 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100559 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700560 goto err_upload_failed;
561 }
562
563 timeout = jiffies + msecs_to_jiffies(1000);
564 while (!(err = usb_bulk_msg(priv->udev,
565 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
566 if (alen > 0 && buf[0] == 'g')
567 break;
568
569 if (time_after(jiffies, timeout)) {
570 err = -ETIMEDOUT;
571 break;
572 }
573 }
574 if (err)
575 goto err_upload_failed;
576
577 err_upload_failed:
578 release_firmware(fw_entry);
579 err_req_fw_failed:
580 err_reset:
581 kfree(buf);
582 err_bufalloc:
583 return err;
584}
585
586static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
587{
588 struct p54u_priv *priv = dev->priv;
589 const struct firmware *fw_entry = NULL;
590 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
591 int err, alen;
592 void *buf;
593 __le32 reg;
594 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100595 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700596
597 buf = kmalloc(512, GFP_KERNEL);
598 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100599 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
600 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700601 return -ENOMEM;
602 }
603
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200604 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700605 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100606 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
607 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200608 err = request_firmware(&fw_entry, "isl3890usb",
609 &priv->udev->dev);
610 if (err) {
611 kfree(buf);
612 return err;
613 }
Michael Wueff1a592007-09-25 18:11:01 -0700614 }
615
Christian Lamparter4e416a62008-09-01 22:48:41 +0200616 err = p54_parse_firmware(dev, fw_entry);
617 if (err) {
618 kfree(buf);
619 release_firmware(fw_entry);
620 return err;
621 }
Michael Wueff1a592007-09-25 18:11:01 -0700622
623#define P54U_WRITE(type, addr, data) \
624 do {\
625 err = p54u_write(priv, buf, type,\
626 cpu_to_le32((u32)(unsigned long)addr), data);\
627 if (err) \
628 goto fail;\
629 } while (0)
630
631#define P54U_READ(type, addr) \
632 do {\
633 err = p54u_read(priv, buf, type,\
634 cpu_to_le32((u32)(unsigned long)addr), &reg);\
635 if (err)\
636 goto fail;\
637 } while (0)
638
639 /* power down net2280 bridge */
640 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
641 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
642 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
643 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
644
645 mdelay(100);
646
647 /* power up bridge */
648 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
649 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
650 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
651
652 mdelay(100);
653
654 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
655 cpu_to_le32(NET2280_CLK_30Mhz |
656 NET2280_PCI_ENABLE |
657 NET2280_PCI_SOFT_RESET));
658
659 mdelay(20);
660
661 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
662 cpu_to_le32(PCI_COMMAND_MEMORY |
663 PCI_COMMAND_MASTER));
664
665 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
666 cpu_to_le32(NET2280_BASE));
667
668 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
669 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
670 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
671
672 // TODO: we really need this?
673 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
674
675 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
676 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
677 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
678 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
679
680 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
681 cpu_to_le32(NET2280_BASE2));
682
683 /* finally done setting up the bridge */
684
685 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
686 cpu_to_le32(PCI_COMMAND_MEMORY |
687 PCI_COMMAND_MASTER));
688
689 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
690 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
691 cpu_to_le32(P54U_DEV_BASE));
692
693 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
694 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
695 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
696
697 /* do romboot */
698 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
699
700 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
701 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
702 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
703 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
704 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
705
706 mdelay(20);
707
708 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
709 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
710
711 mdelay(20);
712
713 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
714 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
715
716 mdelay(100);
717
718 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
719 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
720
721 /* finally, we can upload firmware now! */
722 remains = fw_entry->size;
723 data = fw_entry->data;
724 offset = ISL38XX_DEV_FIRMWARE_ADDR;
725
726 while (remains) {
727 unsigned int block_len = min(remains, (unsigned int)512);
728 memcpy(buf, data, block_len);
729
730 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
731 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100732 dev_err(&priv->udev->dev, "(p54usb) firmware block "
733 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700734 goto fail;
735 }
736
737 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
738 cpu_to_le32(0xc0000f00));
739
740 P54U_WRITE(NET2280_DEV_U32,
741 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
742 P54U_WRITE(NET2280_DEV_U32,
743 0x0020 | (unsigned long)&devreg->direct_mem_win,
744 cpu_to_le32(1));
745
746 P54U_WRITE(NET2280_DEV_U32,
747 0x0024 | (unsigned long)&devreg->direct_mem_win,
748 cpu_to_le32(block_len));
749 P54U_WRITE(NET2280_DEV_U32,
750 0x0028 | (unsigned long)&devreg->direct_mem_win,
751 cpu_to_le32(offset));
752
753 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
754 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
755 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
756 cpu_to_le32(block_len >> 2));
757 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
758 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
759
760 mdelay(10);
761
762 P54U_READ(NET2280_DEV_U32,
763 0x002C | (unsigned long)&devreg->direct_mem_win);
764 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
765 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100766 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
767 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700768 goto fail;
769 }
770
771 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
772 cpu_to_le32(NET2280_FIFO_FLUSH));
773
774 remains -= block_len;
775 data += block_len;
776 offset += block_len;
777 }
778
779 /* do ramboot */
780 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
781 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
782 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
783 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
784 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
785
786 mdelay(20);
787
788 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
789 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
790
791 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
792 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
793
794 mdelay(100);
795
796 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
797 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
798
799 /* start up the firmware */
800 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
801 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
802
803 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
804 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
805
806 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
807 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
808 NET2280_USB_INTERRUPT_ENABLE));
809
810 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
811 cpu_to_le32(ISL38XX_DEV_INT_RESET));
812
813 err = usb_interrupt_msg(priv->udev,
814 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
815 buf, sizeof(__le32), &alen, 1000);
816 if (err || alen != sizeof(__le32))
817 goto fail;
818
819 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
820 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
821
822 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
823 err = -EINVAL;
824
825 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
826 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
827 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
828
829#undef P54U_WRITE
830#undef P54U_READ
831
832 fail:
833 release_firmware(fw_entry);
834 kfree(buf);
835 return err;
836}
837
838static int p54u_open(struct ieee80211_hw *dev)
839{
840 struct p54u_priv *priv = dev->priv;
841 int err;
842
843 err = p54u_init_urbs(dev);
844 if (err) {
845 return err;
846 }
847
848 priv->common.open = p54u_init_urbs;
849
850 return 0;
851}
852
853static void p54u_stop(struct ieee80211_hw *dev)
854{
855 /* TODO: figure out how to reliably stop the 3887 and net2280 so
856 the hardware is still usable next time we want to start it.
857 until then, we just stop listening to the hardware.. */
858 p54u_free_urbs(dev);
859 return;
860}
861
862static int __devinit p54u_probe(struct usb_interface *intf,
863 const struct usb_device_id *id)
864{
865 struct usb_device *udev = interface_to_usbdev(intf);
866 struct ieee80211_hw *dev;
867 struct p54u_priv *priv;
868 int err;
869 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700870
871 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100872
Michael Wueff1a592007-09-25 18:11:01 -0700873 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100874 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700875 return -ENOMEM;
876 }
877
878 priv = dev->priv;
879
880 SET_IEEE80211_DEV(dev, &intf->dev);
881 usb_set_intfdata(intf, dev);
882 priv->udev = udev;
883
884 usb_get_dev(udev);
885
886 /* really lazy and simple way of figuring out if we're a 3887 */
887 /* TODO: should just stick the identification in the device table */
888 i = intf->altsetting->desc.bNumEndpoints;
889 recognized_pipes = 0;
890 while (i--) {
891 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
892 case P54U_PIPE_DATA:
893 case P54U_PIPE_MGMT:
894 case P54U_PIPE_BRG:
895 case P54U_PIPE_DEV:
896 case P54U_PIPE_DATA | USB_DIR_IN:
897 case P54U_PIPE_MGMT | USB_DIR_IN:
898 case P54U_PIPE_BRG | USB_DIR_IN:
899 case P54U_PIPE_DEV | USB_DIR_IN:
900 case P54U_PIPE_INT | USB_DIR_IN:
901 recognized_pipes++;
902 }
903 }
904 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200905 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700906 if (recognized_pipes < P54U_PIPE_NUMBER) {
907 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200908 err = p54u_upload_firmware_3887(dev);
909 if (priv->common.fw_interface == FW_LM87) {
910 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
911 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
912 priv->common.tx = p54u_tx_lm87;
913 } else
914 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700915 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200916 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700917 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
918 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
919 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700920 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200921 }
Michael Wueff1a592007-09-25 18:11:01 -0700922 if (err)
923 goto err_free_dev;
924
Christian Lamparter7cb77072008-09-01 22:48:51 +0200925 skb_queue_head_init(&priv->rx_queue);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100926 init_usb_anchor(&priv->submitted);
Christian Lamparter7cb77072008-09-01 22:48:51 +0200927
928 p54u_open(dev);
929 err = p54_read_eeprom(dev);
930 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700931 if (err)
932 goto err_free_dev;
933
Michael Wueff1a592007-09-25 18:11:01 -0700934 err = ieee80211_register_hw(dev);
935 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100936 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700937 goto err_free_dev;
938 }
939
Michael Wueff1a592007-09-25 18:11:01 -0700940 return 0;
941
942 err_free_dev:
943 ieee80211_free_hw(dev);
944 usb_set_intfdata(intf, NULL);
945 usb_put_dev(udev);
946 return err;
947}
948
949static void __devexit p54u_disconnect(struct usb_interface *intf)
950{
951 struct ieee80211_hw *dev = usb_get_intfdata(intf);
952 struct p54u_priv *priv;
953
954 if (!dev)
955 return;
956
957 ieee80211_unregister_hw(dev);
958
959 priv = dev->priv;
960 usb_put_dev(interface_to_usbdev(intf));
961 p54_free_common(dev);
962 ieee80211_free_hw(dev);
963}
964
965static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200966 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700967 .id_table = p54u_table,
968 .probe = p54u_probe,
969 .disconnect = p54u_disconnect,
970};
971
972static int __init p54u_init(void)
973{
974 return usb_register(&p54u_driver);
975}
976
977static void __exit p54u_exit(void)
978{
979 usb_deregister(&p54u_driver);
980}
981
982module_init(p54u_init);
983module_exit(p54u_exit);