blob: 44ab3ccac91018f8de26cc2814a53e381e577867 [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 */
Christian Lampartere3062402009-03-29 22:50:28 +020074 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070075 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
76 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
77 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
78 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
79 {}
80};
81
82MODULE_DEVICE_TABLE(usb, p54u_table);
83
84static void p54u_rx_cb(struct urb *urb)
85{
86 struct sk_buff *skb = (struct sk_buff *) urb->context;
87 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
88 struct ieee80211_hw *dev = info->dev;
89 struct p54u_priv *priv = dev->priv;
90
Christian Lamparterdd397dc2008-12-09 15:14:37 +010091 skb_unlink(skb, &priv->rx_queue);
92
Michael Wueff1a592007-09-25 18:11:01 -070093 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +010094 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -070095 return;
96 }
97
Michael Wueff1a592007-09-25 18:11:01 -070098 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +020099
100 if (priv->hw_type == P54U_NET2280)
101 skb_pull(skb, priv->common.tx_hdr_len);
102 if (priv->common.fw_interface == FW_LM87) {
103 skb_pull(skb, 4);
104 skb_put(skb, 4);
105 }
Michael Wueff1a592007-09-25 18:11:01 -0700106
107 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200108 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700109 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700110 /* TODO check rx queue length and refill *somewhere* */
111 return;
112 }
113
114 info = (struct p54u_rx_info *) skb->cb;
115 info->urb = urb;
116 info->dev = dev;
117 urb->transfer_buffer = skb_tail_pointer(skb);
118 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700119 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200120 if (priv->hw_type == P54U_NET2280)
121 skb_push(skb, priv->common.tx_hdr_len);
122 if (priv->common.fw_interface == FW_LM87) {
123 skb_push(skb, 4);
124 skb_put(skb, 4);
125 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200126 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700127 skb_trim(skb, 0);
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200128 if (urb->transfer_buffer != skb_tail_pointer(skb)) {
129 /* this should not happen */
130 WARN_ON(1);
131 urb->transfer_buffer = skb_tail_pointer(skb);
132 }
Michael Wueff1a592007-09-25 18:11:01 -0700133 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100134 skb_queue_tail(&priv->rx_queue, skb);
135 usb_anchor_urb(urb, &priv->submitted);
136 if (usb_submit_urb(urb, GFP_ATOMIC)) {
137 skb_unlink(skb, &priv->rx_queue);
138 usb_unanchor_urb(urb);
139 dev_kfree_skb_irq(skb);
140 }
Michael Wueff1a592007-09-25 18:11:01 -0700141}
142
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100143static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200144{
145 struct sk_buff *skb = urb->context;
146 struct ieee80211_hw *dev = (struct ieee80211_hw *)
147 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
148
Christian Lampartere2fe1542009-01-20 00:27:57 +0100149 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100150}
151
152static void p54u_tx_dummy_cb(struct urb *urb) { }
153
154static void p54u_free_urbs(struct ieee80211_hw *dev)
155{
156 struct p54u_priv *priv = dev->priv;
157 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200158}
159
Michael Wueff1a592007-09-25 18:11:01 -0700160static int p54u_init_urbs(struct ieee80211_hw *dev)
161{
162 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100163 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700164 struct sk_buff *skb;
165 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100166 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700167
168 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200169 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100170 if (!skb) {
171 ret = -ENOMEM;
172 goto err;
173 }
Michael Wueff1a592007-09-25 18:11:01 -0700174 entry = usb_alloc_urb(0, GFP_KERNEL);
175 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100176 ret = -ENOMEM;
177 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700178 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100179
Christian Lamparter4e416a62008-09-01 22:48:41 +0200180 usb_fill_bulk_urb(entry, priv->udev,
181 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
182 skb_tail_pointer(skb),
183 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700184 info = (struct p54u_rx_info *) skb->cb;
185 info->urb = entry;
186 info->dev = dev;
187 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100188
189 usb_anchor_urb(entry, &priv->submitted);
190 ret = usb_submit_urb(entry, GFP_KERNEL);
191 if (ret) {
192 skb_unlink(skb, &priv->rx_queue);
193 usb_unanchor_urb(entry);
194 goto err;
195 }
196 usb_free_urb(entry);
197 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700198 }
199
200 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700201
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100202 err:
203 usb_free_urb(entry);
204 kfree_skb(skb);
205 p54u_free_urbs(dev);
206 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700207}
208
Johannes Bergc9127652008-12-01 18:19:36 +0100209static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200210{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500211 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200212
213 length >>= 2;
214 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100215 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200216 chk = (chk >> 5) ^ (chk << 3);
217 }
218
Larry Finger1f1c0e32008-09-25 14:54:28 -0500219 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200220}
221
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100222static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200223{
224 struct p54u_priv *priv = dev->priv;
225 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100226 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200227
228 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
229 if (!data_urb)
230 return;
231
Christian Lampartere2fe1542009-01-20 00:27:57 +0100232 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
233 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200234
235 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200236 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100237 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
238 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100239 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200240
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100241 usb_anchor_urb(data_urb, &priv->submitted);
242 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
243 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100244 p54_free_skb(dev, skb);
245 }
246 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200247}
248
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100249static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700250{
251 struct p54u_priv *priv = dev->priv;
252 struct urb *int_urb, *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100253 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Michael Wueff1a592007-09-25 18:11:01 -0700254 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100255 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700256
257 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
258 if (!reg)
259 return;
260
261 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
262 if (!int_urb) {
263 kfree(reg);
264 return;
265 }
266
267 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
268 if (!data_urb) {
269 kfree(reg);
270 usb_free_urb(int_urb);
271 return;
272 }
273
274 reg->port = cpu_to_le16(NET2280_DEV_U32);
275 reg->addr = cpu_to_le32(P54U_DEV_BASE);
276 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
277
Michael Wueff1a592007-09-25 18:11:01 -0700278 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100279 hdr->len = cpu_to_le16(skb->len);
280 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700281
282 usb_fill_bulk_urb(int_urb, priv->udev,
283 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100284 p54u_tx_dummy_cb, dev);
285
286 /*
287 * This flag triggers a code path in the USB subsystem that will
288 * free what's inside the transfer_buffer after the callback routine
289 * has completed.
290 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100291 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Michael Wueff1a592007-09-25 18:11:01 -0700292
293 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200294 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100295 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
296 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100297 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100298
299 usb_anchor_urb(int_urb, &priv->submitted);
300 err = usb_submit_urb(int_urb, GFP_ATOMIC);
301 if (err) {
302 usb_unanchor_urb(int_urb);
303 goto out;
304 }
305
306 usb_anchor_urb(data_urb, &priv->submitted);
307 err = usb_submit_urb(data_urb, GFP_ATOMIC);
308 if (err) {
309 usb_unanchor_urb(data_urb);
310 goto out;
311 }
312 out:
313 usb_free_urb(int_urb);
314 usb_free_urb(data_urb);
315
316 if (err) {
317 skb_pull(skb, sizeof(*hdr));
318 p54_free_skb(dev, skb);
319 }
Michael Wueff1a592007-09-25 18:11:01 -0700320}
321
322static int p54u_write(struct p54u_priv *priv,
323 struct net2280_reg_write *buf,
324 enum net2280_op_type type,
325 __le32 addr, __le32 val)
326{
327 unsigned int ep;
328 int alen;
329
330 if (type & 0x0800)
331 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
332 else
333 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
334
335 buf->port = cpu_to_le16(type);
336 buf->addr = addr;
337 buf->val = val;
338
339 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
340}
341
342static int p54u_read(struct p54u_priv *priv, void *buf,
343 enum net2280_op_type type,
344 __le32 addr, __le32 *val)
345{
346 struct net2280_reg_read *read = buf;
347 __le32 *reg = buf;
348 unsigned int ep;
349 int alen, err;
350
351 if (type & 0x0800)
352 ep = P54U_PIPE_DEV;
353 else
354 ep = P54U_PIPE_BRG;
355
356 read->port = cpu_to_le16(type);
357 read->addr = addr;
358
359 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
360 read, sizeof(*read), &alen, 1000);
361 if (err)
362 return err;
363
364 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
365 reg, sizeof(*reg), &alen, 1000);
366 if (err)
367 return err;
368
369 *val = *reg;
370 return 0;
371}
372
373static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
374 void *data, size_t len)
375{
376 int alen;
377 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
378 data, len, &alen, 2000);
379}
380
Christian Lamparter69828692008-12-26 19:08:31 +0100381static const char p54u_romboot_3887[] = "~~~~";
382static const char p54u_firmware_upload_3887[] = "<\r";
383
384static int p54u_device_reset_3887(struct ieee80211_hw *dev)
385{
386 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100387 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100388 u8 buf[4];
389
Christian Lamparterc88a7682009-01-16 20:24:31 +0100390 if (lock) {
391 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
392 if (ret < 0) {
393 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
394 " device for reset: %d\n", ret);
395 return ret;
396 }
Christian Lamparter69828692008-12-26 19:08:31 +0100397 }
398
399 ret = usb_reset_device(priv->udev);
400 if (lock)
401 usb_unlock_device(priv->udev);
402
403 if (ret) {
404 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
405 "device: %d\n", ret);
406 return ret;
407 }
408
409 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
410 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
411 buf, sizeof(buf));
412 if (ret)
413 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
414 "boot ROM: %d\n", ret);
415
416 return ret;
417}
418
Michael Wueff1a592007-09-25 18:11:01 -0700419static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
420{
Michael Wueff1a592007-09-25 18:11:01 -0700421 struct p54u_priv *priv = dev->priv;
422 const struct firmware *fw_entry = NULL;
423 int err, alen;
424 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100425 u8 *buf, *tmp;
426 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700427 unsigned int left, remains, block_size;
428 struct x2_header *hdr;
429 unsigned long timeout;
430
431 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
432 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100433 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
434 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700435 err = -ENOMEM;
436 goto err_bufalloc;
437 }
438
Christian Lamparter69828692008-12-26 19:08:31 +0100439 err = p54u_device_reset_3887(dev);
440 if (err)
Michael Wueff1a592007-09-25 18:11:01 -0700441 goto err_reset;
Michael Wueff1a592007-09-25 18:11:01 -0700442
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200443 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700444 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100445 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
446 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200447 err = request_firmware(&fw_entry, "isl3887usb_bare",
448 &priv->udev->dev);
449 if (err)
450 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700451 }
452
Christian Lamparter4e416a62008-09-01 22:48:41 +0200453 err = p54_parse_firmware(dev, fw_entry);
454 if (err)
455 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700456
Christian Lampartere365f162008-12-26 19:09:34 +0100457 if (priv->common.fw_interface != FW_LM87) {
458 dev_err(&priv->udev->dev, "wrong firmware, "
459 "please get a LM87 firmware and try again.\n");
460 err = -EINVAL;
461 goto err_upload_failed;
462 }
463
Michael Wueff1a592007-09-25 18:11:01 -0700464 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100465 strcpy(buf, p54u_firmware_upload_3887);
466 left -= strlen(p54u_firmware_upload_3887);
467 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700468
469 data = fw_entry->data;
470 remains = fw_entry->size;
471
Christian Lamparter69828692008-12-26 19:08:31 +0100472 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700473 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
474 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
475 hdr->fw_length = cpu_to_le32(fw_entry->size);
476 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
477 sizeof(u32)*2));
478 left -= sizeof(*hdr);
479 tmp += sizeof(*hdr);
480
481 while (remains) {
482 while (left--) {
483 if (carry) {
484 *tmp++ = carry;
485 carry = 0;
486 remains--;
487 continue;
488 }
489 switch (*data) {
490 case '~':
491 *tmp++ = '}';
492 carry = '^';
493 break;
494 case '}':
495 *tmp++ = '}';
496 carry = ']';
497 break;
498 default:
499 *tmp++ = *data;
500 remains--;
501 break;
502 }
503 data++;
504 }
505
506 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
507 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100508 dev_err(&priv->udev->dev, "(p54usb) firmware "
509 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700510 goto err_upload_failed;
511 }
512
513 tmp = buf;
514 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
515 }
516
517 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
518 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
519 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100520 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700521 goto err_upload_failed;
522 }
Michael Wueff1a592007-09-25 18:11:01 -0700523 timeout = jiffies + msecs_to_jiffies(1000);
524 while (!(err = usb_bulk_msg(priv->udev,
525 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
526 if (alen > 2 && !memcmp(buf, "OK", 2))
527 break;
528
529 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700530 err = -EINVAL;
531 break;
532 }
533
534 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100535 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
536 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700537 err = -ETIMEDOUT;
538 break;
539 }
540 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100541 if (err) {
542 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700543 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100544 }
Michael Wueff1a592007-09-25 18:11:01 -0700545
546 buf[0] = 'g';
547 buf[1] = '\r';
548 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
549 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100550 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700551 goto err_upload_failed;
552 }
553
554 timeout = jiffies + msecs_to_jiffies(1000);
555 while (!(err = usb_bulk_msg(priv->udev,
556 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
557 if (alen > 0 && buf[0] == 'g')
558 break;
559
560 if (time_after(jiffies, timeout)) {
561 err = -ETIMEDOUT;
562 break;
563 }
564 }
565 if (err)
566 goto err_upload_failed;
567
568 err_upload_failed:
569 release_firmware(fw_entry);
570 err_req_fw_failed:
571 err_reset:
572 kfree(buf);
573 err_bufalloc:
574 return err;
575}
576
577static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
578{
579 struct p54u_priv *priv = dev->priv;
580 const struct firmware *fw_entry = NULL;
581 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
582 int err, alen;
583 void *buf;
584 __le32 reg;
585 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100586 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700587
588 buf = kmalloc(512, GFP_KERNEL);
589 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100590 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
591 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700592 return -ENOMEM;
593 }
594
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200595 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700596 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100597 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
598 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200599 err = request_firmware(&fw_entry, "isl3890usb",
600 &priv->udev->dev);
601 if (err) {
602 kfree(buf);
603 return err;
604 }
Michael Wueff1a592007-09-25 18:11:01 -0700605 }
606
Christian Lamparter4e416a62008-09-01 22:48:41 +0200607 err = p54_parse_firmware(dev, fw_entry);
608 if (err) {
609 kfree(buf);
610 release_firmware(fw_entry);
611 return err;
612 }
Michael Wueff1a592007-09-25 18:11:01 -0700613
Christian Lampartere365f162008-12-26 19:09:34 +0100614 if (priv->common.fw_interface != FW_LM86) {
615 dev_err(&priv->udev->dev, "wrong firmware, "
616 "please get a LM86(USB) firmware and try again.\n");
617 kfree(buf);
618 release_firmware(fw_entry);
619 return -EINVAL;
620 }
621
Michael Wueff1a592007-09-25 18:11:01 -0700622#define P54U_WRITE(type, addr, data) \
623 do {\
624 err = p54u_write(priv, buf, type,\
625 cpu_to_le32((u32)(unsigned long)addr), data);\
626 if (err) \
627 goto fail;\
628 } while (0)
629
630#define P54U_READ(type, addr) \
631 do {\
632 err = p54u_read(priv, buf, type,\
633 cpu_to_le32((u32)(unsigned long)addr), &reg);\
634 if (err)\
635 goto fail;\
636 } while (0)
637
638 /* power down net2280 bridge */
639 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
640 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
641 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
642 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
643
644 mdelay(100);
645
646 /* power up bridge */
647 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
648 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
649 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
650
651 mdelay(100);
652
653 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
654 cpu_to_le32(NET2280_CLK_30Mhz |
655 NET2280_PCI_ENABLE |
656 NET2280_PCI_SOFT_RESET));
657
658 mdelay(20);
659
660 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
661 cpu_to_le32(PCI_COMMAND_MEMORY |
662 PCI_COMMAND_MASTER));
663
664 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
665 cpu_to_le32(NET2280_BASE));
666
667 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
668 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
669 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
670
671 // TODO: we really need this?
672 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
673
674 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
675 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
676 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
677 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
678
679 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
680 cpu_to_le32(NET2280_BASE2));
681
682 /* finally done setting up the bridge */
683
684 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
685 cpu_to_le32(PCI_COMMAND_MEMORY |
686 PCI_COMMAND_MASTER));
687
688 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
689 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
690 cpu_to_le32(P54U_DEV_BASE));
691
692 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
693 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
694 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
695
696 /* do romboot */
697 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
698
699 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
700 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
701 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
702 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
703 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
704
705 mdelay(20);
706
707 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
708 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
709
710 mdelay(20);
711
712 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
713 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
714
715 mdelay(100);
716
717 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
718 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
719
720 /* finally, we can upload firmware now! */
721 remains = fw_entry->size;
722 data = fw_entry->data;
723 offset = ISL38XX_DEV_FIRMWARE_ADDR;
724
725 while (remains) {
726 unsigned int block_len = min(remains, (unsigned int)512);
727 memcpy(buf, data, block_len);
728
729 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
730 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100731 dev_err(&priv->udev->dev, "(p54usb) firmware block "
732 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700733 goto fail;
734 }
735
736 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
737 cpu_to_le32(0xc0000f00));
738
739 P54U_WRITE(NET2280_DEV_U32,
740 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
741 P54U_WRITE(NET2280_DEV_U32,
742 0x0020 | (unsigned long)&devreg->direct_mem_win,
743 cpu_to_le32(1));
744
745 P54U_WRITE(NET2280_DEV_U32,
746 0x0024 | (unsigned long)&devreg->direct_mem_win,
747 cpu_to_le32(block_len));
748 P54U_WRITE(NET2280_DEV_U32,
749 0x0028 | (unsigned long)&devreg->direct_mem_win,
750 cpu_to_le32(offset));
751
752 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
753 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
754 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
755 cpu_to_le32(block_len >> 2));
756 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
757 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
758
759 mdelay(10);
760
761 P54U_READ(NET2280_DEV_U32,
762 0x002C | (unsigned long)&devreg->direct_mem_win);
763 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
764 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100765 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
766 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700767 goto fail;
768 }
769
770 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
771 cpu_to_le32(NET2280_FIFO_FLUSH));
772
773 remains -= block_len;
774 data += block_len;
775 offset += block_len;
776 }
777
778 /* do ramboot */
779 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
780 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
781 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
782 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
783 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
784
785 mdelay(20);
786
787 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
788 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
789
790 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
791 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
792
793 mdelay(100);
794
795 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
796 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
797
798 /* start up the firmware */
799 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
800 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
801
802 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
803 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
804
805 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
806 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
807 NET2280_USB_INTERRUPT_ENABLE));
808
809 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
810 cpu_to_le32(ISL38XX_DEV_INT_RESET));
811
812 err = usb_interrupt_msg(priv->udev,
813 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
814 buf, sizeof(__le32), &alen, 1000);
815 if (err || alen != sizeof(__le32))
816 goto fail;
817
818 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
819 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
820
821 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
822 err = -EINVAL;
823
824 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
825 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
826 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
827
828#undef P54U_WRITE
829#undef P54U_READ
830
831 fail:
832 release_firmware(fw_entry);
833 kfree(buf);
834 return err;
835}
836
837static int p54u_open(struct ieee80211_hw *dev)
838{
839 struct p54u_priv *priv = dev->priv;
840 int err;
841
842 err = p54u_init_urbs(dev);
843 if (err) {
844 return err;
845 }
846
847 priv->common.open = p54u_init_urbs;
848
849 return 0;
850}
851
852static void p54u_stop(struct ieee80211_hw *dev)
853{
854 /* TODO: figure out how to reliably stop the 3887 and net2280 so
855 the hardware is still usable next time we want to start it.
856 until then, we just stop listening to the hardware.. */
857 p54u_free_urbs(dev);
858 return;
859}
860
861static int __devinit p54u_probe(struct usb_interface *intf,
862 const struct usb_device_id *id)
863{
864 struct usb_device *udev = interface_to_usbdev(intf);
865 struct ieee80211_hw *dev;
866 struct p54u_priv *priv;
867 int err;
868 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700869
870 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100871
Michael Wueff1a592007-09-25 18:11:01 -0700872 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100873 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700874 return -ENOMEM;
875 }
876
877 priv = dev->priv;
878
879 SET_IEEE80211_DEV(dev, &intf->dev);
880 usb_set_intfdata(intf, dev);
881 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100882 priv->intf = intf;
883 skb_queue_head_init(&priv->rx_queue);
884 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700885
886 usb_get_dev(udev);
887
888 /* really lazy and simple way of figuring out if we're a 3887 */
889 /* TODO: should just stick the identification in the device table */
890 i = intf->altsetting->desc.bNumEndpoints;
891 recognized_pipes = 0;
892 while (i--) {
893 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
894 case P54U_PIPE_DATA:
895 case P54U_PIPE_MGMT:
896 case P54U_PIPE_BRG:
897 case P54U_PIPE_DEV:
898 case P54U_PIPE_DATA | USB_DIR_IN:
899 case P54U_PIPE_MGMT | USB_DIR_IN:
900 case P54U_PIPE_BRG | USB_DIR_IN:
901 case P54U_PIPE_DEV | USB_DIR_IN:
902 case P54U_PIPE_INT | USB_DIR_IN:
903 recognized_pipes++;
904 }
905 }
906 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200907 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700908 if (recognized_pipes < P54U_PIPE_NUMBER) {
909 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200910 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;
Christian Lamparter2b808482008-09-04 12:29:38 +0200913 err = p54u_upload_firmware_3887(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700914 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200915 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700916 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
917 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
918 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700919 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200920 }
Michael Wueff1a592007-09-25 18:11:01 -0700921 if (err)
922 goto err_free_dev;
923
Christian Lamparter7cb77072008-09-01 22:48:51 +0200924 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
Christian Lamparter2ac71072009-03-05 21:30:10 +0100930 err = p54_register_common(dev, &udev->dev);
931 if (err)
Michael Wueff1a592007-09-25 18:11:01 -0700932 goto err_free_dev;
Michael Wueff1a592007-09-25 18:11:01 -0700933
Michael Wueff1a592007-09-25 18:11:01 -0700934 return 0;
935
936 err_free_dev:
937 ieee80211_free_hw(dev);
938 usb_set_intfdata(intf, NULL);
939 usb_put_dev(udev);
940 return err;
941}
942
943static void __devexit p54u_disconnect(struct usb_interface *intf)
944{
945 struct ieee80211_hw *dev = usb_get_intfdata(intf);
946 struct p54u_priv *priv;
947
948 if (!dev)
949 return;
950
951 ieee80211_unregister_hw(dev);
952
953 priv = dev->priv;
954 usb_put_dev(interface_to_usbdev(intf));
955 p54_free_common(dev);
956 ieee80211_free_hw(dev);
957}
958
Christian Lamparter69828692008-12-26 19:08:31 +0100959static int p54u_pre_reset(struct usb_interface *intf)
960{
961 return 0;
962}
963
964static int p54u_post_reset(struct usb_interface *intf)
965{
966 return 0;
967}
968
Michael Wueff1a592007-09-25 18:11:01 -0700969static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200970 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700971 .id_table = p54u_table,
972 .probe = p54u_probe,
973 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +0100974 .pre_reset = p54u_pre_reset,
975 .post_reset = p54u_post_reset,
Christian Lamparterfbf95292009-03-05 21:29:51 +0100976 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -0700977};
978
979static int __init p54u_init(void)
980{
981 return usb_register(&p54u_driver);
982}
983
984static void __exit p54u_exit(void)
985{
986 usb_deregister(&p54u_driver);
987}
988
989module_init(p54u_init);
990module_exit(p54u_exit);