blob: 5de2ebfb28c7ef9b722c3a4028a2c6e5c7c25497 [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);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100232 addr_urb->transfer_flags |= URB_ZERO_PACKET;
233 data_urb->transfer_flags |= URB_ZERO_PACKET;
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
Christian Lamparterb4068a82009-01-20 23:11:21 +0100242 usb_anchor_urb(data_urb, &priv->submitted);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100243 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 Lampartere2fe1542009-01-20 00:27:57 +0100272 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200273
274 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
275 if (!data_urb)
276 return;
277
Christian Lampartere2fe1542009-01-20 00:27:57 +0100278 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
279 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200280
281 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200282 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100283 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
284 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100285 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200286
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100287 usb_anchor_urb(data_urb, &priv->submitted);
288 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
289 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100290 p54_free_skb(dev, skb);
291 }
292 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200293}
294
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100295static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700296{
297 struct p54u_priv *priv = dev->priv;
298 struct urb *int_urb, *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100299 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Michael Wueff1a592007-09-25 18:11:01 -0700300 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100301 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700302
303 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
304 if (!reg)
305 return;
306
307 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
308 if (!int_urb) {
309 kfree(reg);
310 return;
311 }
312
313 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
314 if (!data_urb) {
315 kfree(reg);
316 usb_free_urb(int_urb);
317 return;
318 }
319
320 reg->port = cpu_to_le16(NET2280_DEV_U32);
321 reg->addr = cpu_to_le32(P54U_DEV_BASE);
322 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
323
Michael Wueff1a592007-09-25 18:11:01 -0700324 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100325 hdr->len = cpu_to_le16(skb->len);
326 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700327
328 usb_fill_bulk_urb(int_urb, priv->udev,
329 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100330 p54u_tx_dummy_cb, dev);
331
332 /*
333 * This flag triggers a code path in the USB subsystem that will
334 * free what's inside the transfer_buffer after the callback routine
335 * has completed.
336 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100337 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Michael Wueff1a592007-09-25 18:11:01 -0700338
339 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200340 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100341 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
342 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100343 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100344
345 usb_anchor_urb(int_urb, &priv->submitted);
346 err = usb_submit_urb(int_urb, GFP_ATOMIC);
347 if (err) {
348 usb_unanchor_urb(int_urb);
349 goto out;
350 }
351
352 usb_anchor_urb(data_urb, &priv->submitted);
353 err = usb_submit_urb(data_urb, GFP_ATOMIC);
354 if (err) {
355 usb_unanchor_urb(data_urb);
356 goto out;
357 }
358 out:
359 usb_free_urb(int_urb);
360 usb_free_urb(data_urb);
361
362 if (err) {
363 skb_pull(skb, sizeof(*hdr));
364 p54_free_skb(dev, skb);
365 }
Michael Wueff1a592007-09-25 18:11:01 -0700366}
367
368static int p54u_write(struct p54u_priv *priv,
369 struct net2280_reg_write *buf,
370 enum net2280_op_type type,
371 __le32 addr, __le32 val)
372{
373 unsigned int ep;
374 int alen;
375
376 if (type & 0x0800)
377 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
378 else
379 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
380
381 buf->port = cpu_to_le16(type);
382 buf->addr = addr;
383 buf->val = val;
384
385 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
386}
387
388static int p54u_read(struct p54u_priv *priv, void *buf,
389 enum net2280_op_type type,
390 __le32 addr, __le32 *val)
391{
392 struct net2280_reg_read *read = buf;
393 __le32 *reg = buf;
394 unsigned int ep;
395 int alen, err;
396
397 if (type & 0x0800)
398 ep = P54U_PIPE_DEV;
399 else
400 ep = P54U_PIPE_BRG;
401
402 read->port = cpu_to_le16(type);
403 read->addr = addr;
404
405 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
406 read, sizeof(*read), &alen, 1000);
407 if (err)
408 return err;
409
410 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
411 reg, sizeof(*reg), &alen, 1000);
412 if (err)
413 return err;
414
415 *val = *reg;
416 return 0;
417}
418
419static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
420 void *data, size_t len)
421{
422 int alen;
423 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
424 data, len, &alen, 2000);
425}
426
Michael Wueff1a592007-09-25 18:11:01 -0700427static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
428{
429 static char start_string[] = "~~~~<\r";
430 struct p54u_priv *priv = dev->priv;
431 const struct firmware *fw_entry = NULL;
432 int err, alen;
433 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100434 u8 *buf, *tmp;
435 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700436 unsigned int left, remains, block_size;
437 struct x2_header *hdr;
438 unsigned long timeout;
439
440 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
441 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100442 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
443 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700444 err = -ENOMEM;
445 goto err_bufalloc;
446 }
447
448 memcpy(buf, start_string, 4);
449 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
450 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100451 dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
Michael Wueff1a592007-09-25 18:11:01 -0700452 goto err_reset;
453 }
454
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200455 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700456 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100457 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
458 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200459 err = request_firmware(&fw_entry, "isl3887usb_bare",
460 &priv->udev->dev);
461 if (err)
462 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700463 }
464
Christian Lamparter4e416a62008-09-01 22:48:41 +0200465 err = p54_parse_firmware(dev, fw_entry);
466 if (err)
467 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700468
469 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
470 strcpy(buf, start_string);
471 left -= strlen(start_string);
472 tmp += strlen(start_string);
473
474 data = fw_entry->data;
475 remains = fw_entry->size;
476
477 hdr = (struct x2_header *)(buf + strlen(start_string));
478 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
479 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
480 hdr->fw_length = cpu_to_le32(fw_entry->size);
481 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
482 sizeof(u32)*2));
483 left -= sizeof(*hdr);
484 tmp += sizeof(*hdr);
485
486 while (remains) {
487 while (left--) {
488 if (carry) {
489 *tmp++ = carry;
490 carry = 0;
491 remains--;
492 continue;
493 }
494 switch (*data) {
495 case '~':
496 *tmp++ = '}';
497 carry = '^';
498 break;
499 case '}':
500 *tmp++ = '}';
501 carry = ']';
502 break;
503 default:
504 *tmp++ = *data;
505 remains--;
506 break;
507 }
508 data++;
509 }
510
511 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
512 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100513 dev_err(&priv->udev->dev, "(p54usb) firmware "
514 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700515 goto err_upload_failed;
516 }
517
518 tmp = buf;
519 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
520 }
521
522 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
523 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
524 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100525 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700526 goto err_upload_failed;
527 }
Michael Wueff1a592007-09-25 18:11:01 -0700528 timeout = jiffies + msecs_to_jiffies(1000);
529 while (!(err = usb_bulk_msg(priv->udev,
530 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
531 if (alen > 2 && !memcmp(buf, "OK", 2))
532 break;
533
534 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700535 err = -EINVAL;
536 break;
537 }
538
539 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100540 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
541 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700542 err = -ETIMEDOUT;
543 break;
544 }
545 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100546 if (err) {
547 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700548 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100549 }
Michael Wueff1a592007-09-25 18:11:01 -0700550
551 buf[0] = 'g';
552 buf[1] = '\r';
553 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
554 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100555 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700556 goto err_upload_failed;
557 }
558
559 timeout = jiffies + msecs_to_jiffies(1000);
560 while (!(err = usb_bulk_msg(priv->udev,
561 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
562 if (alen > 0 && buf[0] == 'g')
563 break;
564
565 if (time_after(jiffies, timeout)) {
566 err = -ETIMEDOUT;
567 break;
568 }
569 }
570 if (err)
571 goto err_upload_failed;
572
573 err_upload_failed:
574 release_firmware(fw_entry);
575 err_req_fw_failed:
576 err_reset:
577 kfree(buf);
578 err_bufalloc:
579 return err;
580}
581
582static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
583{
584 struct p54u_priv *priv = dev->priv;
585 const struct firmware *fw_entry = NULL;
586 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
587 int err, alen;
588 void *buf;
589 __le32 reg;
590 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100591 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700592
593 buf = kmalloc(512, GFP_KERNEL);
594 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100595 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
596 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700597 return -ENOMEM;
598 }
599
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200600 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700601 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100602 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
603 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200604 err = request_firmware(&fw_entry, "isl3890usb",
605 &priv->udev->dev);
606 if (err) {
607 kfree(buf);
608 return err;
609 }
Michael Wueff1a592007-09-25 18:11:01 -0700610 }
611
Christian Lamparter4e416a62008-09-01 22:48:41 +0200612 err = p54_parse_firmware(dev, fw_entry);
613 if (err) {
614 kfree(buf);
615 release_firmware(fw_entry);
616 return err;
617 }
Michael Wueff1a592007-09-25 18:11:01 -0700618
619#define P54U_WRITE(type, addr, data) \
620 do {\
621 err = p54u_write(priv, buf, type,\
622 cpu_to_le32((u32)(unsigned long)addr), data);\
623 if (err) \
624 goto fail;\
625 } while (0)
626
627#define P54U_READ(type, addr) \
628 do {\
629 err = p54u_read(priv, buf, type,\
630 cpu_to_le32((u32)(unsigned long)addr), &reg);\
631 if (err)\
632 goto fail;\
633 } while (0)
634
635 /* power down net2280 bridge */
636 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
637 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
638 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
639 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
640
641 mdelay(100);
642
643 /* power up bridge */
644 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
645 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
646 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
647
648 mdelay(100);
649
650 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
651 cpu_to_le32(NET2280_CLK_30Mhz |
652 NET2280_PCI_ENABLE |
653 NET2280_PCI_SOFT_RESET));
654
655 mdelay(20);
656
657 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
658 cpu_to_le32(PCI_COMMAND_MEMORY |
659 PCI_COMMAND_MASTER));
660
661 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
662 cpu_to_le32(NET2280_BASE));
663
664 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
665 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
666 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
667
668 // TODO: we really need this?
669 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
670
671 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
672 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
673 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
674 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
675
676 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
677 cpu_to_le32(NET2280_BASE2));
678
679 /* finally done setting up the bridge */
680
681 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
682 cpu_to_le32(PCI_COMMAND_MEMORY |
683 PCI_COMMAND_MASTER));
684
685 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
686 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
687 cpu_to_le32(P54U_DEV_BASE));
688
689 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
690 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
691 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
692
693 /* do romboot */
694 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
695
696 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
697 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
698 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
699 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
700 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
701
702 mdelay(20);
703
704 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
705 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
706
707 mdelay(20);
708
709 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
710 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
711
712 mdelay(100);
713
714 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
715 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
716
717 /* finally, we can upload firmware now! */
718 remains = fw_entry->size;
719 data = fw_entry->data;
720 offset = ISL38XX_DEV_FIRMWARE_ADDR;
721
722 while (remains) {
723 unsigned int block_len = min(remains, (unsigned int)512);
724 memcpy(buf, data, block_len);
725
726 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
727 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100728 dev_err(&priv->udev->dev, "(p54usb) firmware block "
729 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700730 goto fail;
731 }
732
733 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
734 cpu_to_le32(0xc0000f00));
735
736 P54U_WRITE(NET2280_DEV_U32,
737 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
738 P54U_WRITE(NET2280_DEV_U32,
739 0x0020 | (unsigned long)&devreg->direct_mem_win,
740 cpu_to_le32(1));
741
742 P54U_WRITE(NET2280_DEV_U32,
743 0x0024 | (unsigned long)&devreg->direct_mem_win,
744 cpu_to_le32(block_len));
745 P54U_WRITE(NET2280_DEV_U32,
746 0x0028 | (unsigned long)&devreg->direct_mem_win,
747 cpu_to_le32(offset));
748
749 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
750 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
751 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
752 cpu_to_le32(block_len >> 2));
753 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
754 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
755
756 mdelay(10);
757
758 P54U_READ(NET2280_DEV_U32,
759 0x002C | (unsigned long)&devreg->direct_mem_win);
760 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
761 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100762 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
763 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700764 goto fail;
765 }
766
767 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
768 cpu_to_le32(NET2280_FIFO_FLUSH));
769
770 remains -= block_len;
771 data += block_len;
772 offset += block_len;
773 }
774
775 /* do ramboot */
776 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
777 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
778 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
779 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
780 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
781
782 mdelay(20);
783
784 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
785 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
786
787 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
788 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
789
790 mdelay(100);
791
792 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
793 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
794
795 /* start up the firmware */
796 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
797 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
798
799 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
800 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
801
802 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
803 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
804 NET2280_USB_INTERRUPT_ENABLE));
805
806 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
807 cpu_to_le32(ISL38XX_DEV_INT_RESET));
808
809 err = usb_interrupt_msg(priv->udev,
810 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
811 buf, sizeof(__le32), &alen, 1000);
812 if (err || alen != sizeof(__le32))
813 goto fail;
814
815 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
816 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
817
818 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
819 err = -EINVAL;
820
821 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
822 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
823 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
824
825#undef P54U_WRITE
826#undef P54U_READ
827
828 fail:
829 release_firmware(fw_entry);
830 kfree(buf);
831 return err;
832}
833
834static int p54u_open(struct ieee80211_hw *dev)
835{
836 struct p54u_priv *priv = dev->priv;
837 int err;
838
839 err = p54u_init_urbs(dev);
840 if (err) {
841 return err;
842 }
843
844 priv->common.open = p54u_init_urbs;
845
846 return 0;
847}
848
849static void p54u_stop(struct ieee80211_hw *dev)
850{
851 /* TODO: figure out how to reliably stop the 3887 and net2280 so
852 the hardware is still usable next time we want to start it.
853 until then, we just stop listening to the hardware.. */
854 p54u_free_urbs(dev);
855 return;
856}
857
858static int __devinit p54u_probe(struct usb_interface *intf,
859 const struct usb_device_id *id)
860{
861 struct usb_device *udev = interface_to_usbdev(intf);
862 struct ieee80211_hw *dev;
863 struct p54u_priv *priv;
864 int err;
865 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700866
867 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100868
Michael Wueff1a592007-09-25 18:11:01 -0700869 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100870 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700871 return -ENOMEM;
872 }
873
874 priv = dev->priv;
875
876 SET_IEEE80211_DEV(dev, &intf->dev);
877 usb_set_intfdata(intf, dev);
878 priv->udev = udev;
879
880 usb_get_dev(udev);
881
882 /* really lazy and simple way of figuring out if we're a 3887 */
883 /* TODO: should just stick the identification in the device table */
884 i = intf->altsetting->desc.bNumEndpoints;
885 recognized_pipes = 0;
886 while (i--) {
887 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
888 case P54U_PIPE_DATA:
889 case P54U_PIPE_MGMT:
890 case P54U_PIPE_BRG:
891 case P54U_PIPE_DEV:
892 case P54U_PIPE_DATA | USB_DIR_IN:
893 case P54U_PIPE_MGMT | USB_DIR_IN:
894 case P54U_PIPE_BRG | USB_DIR_IN:
895 case P54U_PIPE_DEV | USB_DIR_IN:
896 case P54U_PIPE_INT | USB_DIR_IN:
897 recognized_pipes++;
898 }
899 }
900 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200901 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700902 if (recognized_pipes < P54U_PIPE_NUMBER) {
903 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200904 err = p54u_upload_firmware_3887(dev);
905 if (priv->common.fw_interface == FW_LM87) {
906 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
907 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
908 priv->common.tx = p54u_tx_lm87;
909 } else
910 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700911 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200912 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700913 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
914 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
915 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700916 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200917 }
Michael Wueff1a592007-09-25 18:11:01 -0700918 if (err)
919 goto err_free_dev;
920
Christian Lamparter7cb77072008-09-01 22:48:51 +0200921 skb_queue_head_init(&priv->rx_queue);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100922 init_usb_anchor(&priv->submitted);
Christian Lamparter7cb77072008-09-01 22:48:51 +0200923
924 p54u_open(dev);
925 err = p54_read_eeprom(dev);
926 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700927 if (err)
928 goto err_free_dev;
929
Michael Wueff1a592007-09-25 18:11:01 -0700930 err = ieee80211_register_hw(dev);
931 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100932 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700933 goto err_free_dev;
934 }
935
Michael Wueff1a592007-09-25 18:11:01 -0700936 return 0;
937
938 err_free_dev:
939 ieee80211_free_hw(dev);
940 usb_set_intfdata(intf, NULL);
941 usb_put_dev(udev);
942 return err;
943}
944
945static void __devexit p54u_disconnect(struct usb_interface *intf)
946{
947 struct ieee80211_hw *dev = usb_get_intfdata(intf);
948 struct p54u_priv *priv;
949
950 if (!dev)
951 return;
952
953 ieee80211_unregister_hw(dev);
954
955 priv = dev->priv;
956 usb_put_dev(interface_to_usbdev(intf));
957 p54_free_common(dev);
958 ieee80211_free_hw(dev);
959}
960
961static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200962 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700963 .id_table = p54u_table,
964 .probe = p54u_probe,
965 .disconnect = p54u_disconnect,
966};
967
968static int __init p54u_init(void)
969{
970 return usb_register(&p54u_driver);
971}
972
973static void __exit p54u_exit(void)
974{
975 usb_deregister(&p54u_driver);
976}
977
978module_init(p54u_init);
979module_exit(p54u_exit);