blob: 3c31c15267b51475319bd7aa3eb519556ba124e2 [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
Christian Lamparter69828692008-12-26 19:08:31 +0100427static const char p54u_romboot_3887[] = "~~~~";
428static const char p54u_firmware_upload_3887[] = "<\r";
429
430static int p54u_device_reset_3887(struct ieee80211_hw *dev)
431{
432 struct p54u_priv *priv = dev->priv;
433 int ret, lock;
434 u8 buf[4];
435
436 ret = lock = usb_lock_device_for_reset(priv->udev, priv->intf);
437 if (ret < 0) {
438 dev_err(&priv->udev->dev, "(p54usb) unable to lock device for "
439 "reset: %d\n", ret);
440 return ret;
441 }
442
443 ret = usb_reset_device(priv->udev);
444 if (lock)
445 usb_unlock_device(priv->udev);
446
447 if (ret) {
448 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
449 "device: %d\n", ret);
450 return ret;
451 }
452
453 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
454 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
455 buf, sizeof(buf));
456 if (ret)
457 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
458 "boot ROM: %d\n", ret);
459
460 return ret;
461}
462
Michael Wueff1a592007-09-25 18:11:01 -0700463static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
464{
Michael Wueff1a592007-09-25 18:11:01 -0700465 struct p54u_priv *priv = dev->priv;
466 const struct firmware *fw_entry = NULL;
467 int err, alen;
468 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100469 u8 *buf, *tmp;
470 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700471 unsigned int left, remains, block_size;
472 struct x2_header *hdr;
473 unsigned long timeout;
474
475 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
476 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100477 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
478 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700479 err = -ENOMEM;
480 goto err_bufalloc;
481 }
482
Christian Lamparter69828692008-12-26 19:08:31 +0100483 err = p54u_device_reset_3887(dev);
484 if (err)
Michael Wueff1a592007-09-25 18:11:01 -0700485 goto err_reset;
Michael Wueff1a592007-09-25 18:11:01 -0700486
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200487 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700488 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100489 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
490 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200491 err = request_firmware(&fw_entry, "isl3887usb_bare",
492 &priv->udev->dev);
493 if (err)
494 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700495 }
496
Christian Lamparter4e416a62008-09-01 22:48:41 +0200497 err = p54_parse_firmware(dev, fw_entry);
498 if (err)
499 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700500
501 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100502 strcpy(buf, p54u_firmware_upload_3887);
503 left -= strlen(p54u_firmware_upload_3887);
504 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700505
506 data = fw_entry->data;
507 remains = fw_entry->size;
508
Christian Lamparter69828692008-12-26 19:08:31 +0100509 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700510 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
511 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
512 hdr->fw_length = cpu_to_le32(fw_entry->size);
513 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
514 sizeof(u32)*2));
515 left -= sizeof(*hdr);
516 tmp += sizeof(*hdr);
517
518 while (remains) {
519 while (left--) {
520 if (carry) {
521 *tmp++ = carry;
522 carry = 0;
523 remains--;
524 continue;
525 }
526 switch (*data) {
527 case '~':
528 *tmp++ = '}';
529 carry = '^';
530 break;
531 case '}':
532 *tmp++ = '}';
533 carry = ']';
534 break;
535 default:
536 *tmp++ = *data;
537 remains--;
538 break;
539 }
540 data++;
541 }
542
543 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
544 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100545 dev_err(&priv->udev->dev, "(p54usb) firmware "
546 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700547 goto err_upload_failed;
548 }
549
550 tmp = buf;
551 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
552 }
553
554 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
555 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
556 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100557 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700558 goto err_upload_failed;
559 }
Michael Wueff1a592007-09-25 18:11:01 -0700560 timeout = jiffies + msecs_to_jiffies(1000);
561 while (!(err = usb_bulk_msg(priv->udev,
562 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
563 if (alen > 2 && !memcmp(buf, "OK", 2))
564 break;
565
566 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700567 err = -EINVAL;
568 break;
569 }
570
571 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100572 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
573 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700574 err = -ETIMEDOUT;
575 break;
576 }
577 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100578 if (err) {
579 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700580 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100581 }
Michael Wueff1a592007-09-25 18:11:01 -0700582
583 buf[0] = 'g';
584 buf[1] = '\r';
585 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
586 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100587 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700588 goto err_upload_failed;
589 }
590
591 timeout = jiffies + msecs_to_jiffies(1000);
592 while (!(err = usb_bulk_msg(priv->udev,
593 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
594 if (alen > 0 && buf[0] == 'g')
595 break;
596
597 if (time_after(jiffies, timeout)) {
598 err = -ETIMEDOUT;
599 break;
600 }
601 }
602 if (err)
603 goto err_upload_failed;
604
605 err_upload_failed:
606 release_firmware(fw_entry);
607 err_req_fw_failed:
608 err_reset:
609 kfree(buf);
610 err_bufalloc:
611 return err;
612}
613
614static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
615{
616 struct p54u_priv *priv = dev->priv;
617 const struct firmware *fw_entry = NULL;
618 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
619 int err, alen;
620 void *buf;
621 __le32 reg;
622 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100623 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700624
625 buf = kmalloc(512, GFP_KERNEL);
626 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100627 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
628 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700629 return -ENOMEM;
630 }
631
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200632 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700633 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100634 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
635 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200636 err = request_firmware(&fw_entry, "isl3890usb",
637 &priv->udev->dev);
638 if (err) {
639 kfree(buf);
640 return err;
641 }
Michael Wueff1a592007-09-25 18:11:01 -0700642 }
643
Christian Lamparter4e416a62008-09-01 22:48:41 +0200644 err = p54_parse_firmware(dev, fw_entry);
645 if (err) {
646 kfree(buf);
647 release_firmware(fw_entry);
648 return err;
649 }
Michael Wueff1a592007-09-25 18:11:01 -0700650
651#define P54U_WRITE(type, addr, data) \
652 do {\
653 err = p54u_write(priv, buf, type,\
654 cpu_to_le32((u32)(unsigned long)addr), data);\
655 if (err) \
656 goto fail;\
657 } while (0)
658
659#define P54U_READ(type, addr) \
660 do {\
661 err = p54u_read(priv, buf, type,\
662 cpu_to_le32((u32)(unsigned long)addr), &reg);\
663 if (err)\
664 goto fail;\
665 } while (0)
666
667 /* power down net2280 bridge */
668 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
669 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
670 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
671 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
672
673 mdelay(100);
674
675 /* power up bridge */
676 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
677 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
678 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
679
680 mdelay(100);
681
682 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
683 cpu_to_le32(NET2280_CLK_30Mhz |
684 NET2280_PCI_ENABLE |
685 NET2280_PCI_SOFT_RESET));
686
687 mdelay(20);
688
689 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
690 cpu_to_le32(PCI_COMMAND_MEMORY |
691 PCI_COMMAND_MASTER));
692
693 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
694 cpu_to_le32(NET2280_BASE));
695
696 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
697 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
698 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
699
700 // TODO: we really need this?
701 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
702
703 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
704 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
705 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
706 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
707
708 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
709 cpu_to_le32(NET2280_BASE2));
710
711 /* finally done setting up the bridge */
712
713 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
714 cpu_to_le32(PCI_COMMAND_MEMORY |
715 PCI_COMMAND_MASTER));
716
717 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
718 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
719 cpu_to_le32(P54U_DEV_BASE));
720
721 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
722 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
723 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
724
725 /* do romboot */
726 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
727
728 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
729 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
730 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
731 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
732 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
733
734 mdelay(20);
735
736 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
737 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
738
739 mdelay(20);
740
741 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
742 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
743
744 mdelay(100);
745
746 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
747 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
748
749 /* finally, we can upload firmware now! */
750 remains = fw_entry->size;
751 data = fw_entry->data;
752 offset = ISL38XX_DEV_FIRMWARE_ADDR;
753
754 while (remains) {
755 unsigned int block_len = min(remains, (unsigned int)512);
756 memcpy(buf, data, block_len);
757
758 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
759 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100760 dev_err(&priv->udev->dev, "(p54usb) firmware block "
761 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700762 goto fail;
763 }
764
765 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
766 cpu_to_le32(0xc0000f00));
767
768 P54U_WRITE(NET2280_DEV_U32,
769 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
770 P54U_WRITE(NET2280_DEV_U32,
771 0x0020 | (unsigned long)&devreg->direct_mem_win,
772 cpu_to_le32(1));
773
774 P54U_WRITE(NET2280_DEV_U32,
775 0x0024 | (unsigned long)&devreg->direct_mem_win,
776 cpu_to_le32(block_len));
777 P54U_WRITE(NET2280_DEV_U32,
778 0x0028 | (unsigned long)&devreg->direct_mem_win,
779 cpu_to_le32(offset));
780
781 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
782 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
783 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
784 cpu_to_le32(block_len >> 2));
785 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
786 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
787
788 mdelay(10);
789
790 P54U_READ(NET2280_DEV_U32,
791 0x002C | (unsigned long)&devreg->direct_mem_win);
792 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
793 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100794 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
795 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700796 goto fail;
797 }
798
799 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
800 cpu_to_le32(NET2280_FIFO_FLUSH));
801
802 remains -= block_len;
803 data += block_len;
804 offset += block_len;
805 }
806
807 /* do ramboot */
808 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
809 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
810 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
811 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
812 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
813
814 mdelay(20);
815
816 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
817 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
818
819 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
820 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
821
822 mdelay(100);
823
824 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
825 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
826
827 /* start up the firmware */
828 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
829 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
830
831 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
832 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
833
834 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
835 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
836 NET2280_USB_INTERRUPT_ENABLE));
837
838 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
839 cpu_to_le32(ISL38XX_DEV_INT_RESET));
840
841 err = usb_interrupt_msg(priv->udev,
842 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
843 buf, sizeof(__le32), &alen, 1000);
844 if (err || alen != sizeof(__le32))
845 goto fail;
846
847 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
848 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
849
850 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
851 err = -EINVAL;
852
853 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
854 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
855 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
856
857#undef P54U_WRITE
858#undef P54U_READ
859
860 fail:
861 release_firmware(fw_entry);
862 kfree(buf);
863 return err;
864}
865
866static int p54u_open(struct ieee80211_hw *dev)
867{
868 struct p54u_priv *priv = dev->priv;
869 int err;
870
871 err = p54u_init_urbs(dev);
872 if (err) {
873 return err;
874 }
875
876 priv->common.open = p54u_init_urbs;
877
878 return 0;
879}
880
881static void p54u_stop(struct ieee80211_hw *dev)
882{
883 /* TODO: figure out how to reliably stop the 3887 and net2280 so
884 the hardware is still usable next time we want to start it.
885 until then, we just stop listening to the hardware.. */
886 p54u_free_urbs(dev);
887 return;
888}
889
890static int __devinit p54u_probe(struct usb_interface *intf,
891 const struct usb_device_id *id)
892{
893 struct usb_device *udev = interface_to_usbdev(intf);
894 struct ieee80211_hw *dev;
895 struct p54u_priv *priv;
896 int err;
897 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700898
899 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100900
Michael Wueff1a592007-09-25 18:11:01 -0700901 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100902 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700903 return -ENOMEM;
904 }
905
906 priv = dev->priv;
907
908 SET_IEEE80211_DEV(dev, &intf->dev);
909 usb_set_intfdata(intf, dev);
910 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100911 priv->intf = intf;
912 skb_queue_head_init(&priv->rx_queue);
913 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700914
915 usb_get_dev(udev);
916
917 /* really lazy and simple way of figuring out if we're a 3887 */
918 /* TODO: should just stick the identification in the device table */
919 i = intf->altsetting->desc.bNumEndpoints;
920 recognized_pipes = 0;
921 while (i--) {
922 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
923 case P54U_PIPE_DATA:
924 case P54U_PIPE_MGMT:
925 case P54U_PIPE_BRG:
926 case P54U_PIPE_DEV:
927 case P54U_PIPE_DATA | USB_DIR_IN:
928 case P54U_PIPE_MGMT | USB_DIR_IN:
929 case P54U_PIPE_BRG | USB_DIR_IN:
930 case P54U_PIPE_DEV | USB_DIR_IN:
931 case P54U_PIPE_INT | USB_DIR_IN:
932 recognized_pipes++;
933 }
934 }
935 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200936 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700937 if (recognized_pipes < P54U_PIPE_NUMBER) {
938 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200939 err = p54u_upload_firmware_3887(dev);
940 if (priv->common.fw_interface == FW_LM87) {
941 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
942 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
943 priv->common.tx = p54u_tx_lm87;
944 } else
945 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700946 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200947 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700948 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
949 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
950 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700951 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200952 }
Michael Wueff1a592007-09-25 18:11:01 -0700953 if (err)
954 goto err_free_dev;
955
Christian Lamparter7cb77072008-09-01 22:48:51 +0200956 p54u_open(dev);
957 err = p54_read_eeprom(dev);
958 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700959 if (err)
960 goto err_free_dev;
961
Michael Wueff1a592007-09-25 18:11:01 -0700962 err = ieee80211_register_hw(dev);
963 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100964 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700965 goto err_free_dev;
966 }
967
Michael Wueff1a592007-09-25 18:11:01 -0700968 return 0;
969
970 err_free_dev:
971 ieee80211_free_hw(dev);
972 usb_set_intfdata(intf, NULL);
973 usb_put_dev(udev);
974 return err;
975}
976
977static void __devexit p54u_disconnect(struct usb_interface *intf)
978{
979 struct ieee80211_hw *dev = usb_get_intfdata(intf);
980 struct p54u_priv *priv;
981
982 if (!dev)
983 return;
984
985 ieee80211_unregister_hw(dev);
986
987 priv = dev->priv;
988 usb_put_dev(interface_to_usbdev(intf));
989 p54_free_common(dev);
990 ieee80211_free_hw(dev);
991}
992
Christian Lamparter69828692008-12-26 19:08:31 +0100993static int p54u_pre_reset(struct usb_interface *intf)
994{
995 return 0;
996}
997
998static int p54u_post_reset(struct usb_interface *intf)
999{
1000 return 0;
1001}
1002
Michael Wueff1a592007-09-25 18:11:01 -07001003static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001004 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001005 .id_table = p54u_table,
1006 .probe = p54u_probe,
1007 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001008 .pre_reset = p54u_pre_reset,
1009 .post_reset = p54u_post_reset,
Michael Wueff1a592007-09-25 18:11:01 -07001010};
1011
1012static int __init p54u_init(void)
1013{
1014 return usb_register(&p54u_driver);
1015}
1016
1017static void __exit p54u_exit(void)
1018{
1019 usb_deregister(&p54u_driver);
1020}
1021
1022module_init(p54u_init);
1023module_exit(p54u_exit);