blob: 3b5e54e6793d580fa949500fef44c5a98c0648a2 [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;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100433 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100434 u8 buf[4];
435
Christian Lamparterc88a7682009-01-16 20:24:31 +0100436 if (lock) {
437 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
438 if (ret < 0) {
439 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
440 " device for reset: %d\n", ret);
441 return ret;
442 }
Christian Lamparter69828692008-12-26 19:08:31 +0100443 }
444
445 ret = usb_reset_device(priv->udev);
446 if (lock)
447 usb_unlock_device(priv->udev);
448
449 if (ret) {
450 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
451 "device: %d\n", ret);
452 return ret;
453 }
454
455 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
456 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
457 buf, sizeof(buf));
458 if (ret)
459 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
460 "boot ROM: %d\n", ret);
461
462 return ret;
463}
464
Michael Wueff1a592007-09-25 18:11:01 -0700465static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
466{
Michael Wueff1a592007-09-25 18:11:01 -0700467 struct p54u_priv *priv = dev->priv;
468 const struct firmware *fw_entry = NULL;
469 int err, alen;
470 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100471 u8 *buf, *tmp;
472 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700473 unsigned int left, remains, block_size;
474 struct x2_header *hdr;
475 unsigned long timeout;
476
477 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
478 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100479 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
480 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700481 err = -ENOMEM;
482 goto err_bufalloc;
483 }
484
Christian Lamparter69828692008-12-26 19:08:31 +0100485 err = p54u_device_reset_3887(dev);
486 if (err)
Michael Wueff1a592007-09-25 18:11:01 -0700487 goto err_reset;
Michael Wueff1a592007-09-25 18:11:01 -0700488
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200489 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700490 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100491 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
492 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200493 err = request_firmware(&fw_entry, "isl3887usb_bare",
494 &priv->udev->dev);
495 if (err)
496 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700497 }
498
Christian Lamparter4e416a62008-09-01 22:48:41 +0200499 err = p54_parse_firmware(dev, fw_entry);
500 if (err)
501 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700502
Christian Lampartere365f162008-12-26 19:09:34 +0100503 if (priv->common.fw_interface != FW_LM87) {
504 dev_err(&priv->udev->dev, "wrong firmware, "
505 "please get a LM87 firmware and try again.\n");
506 err = -EINVAL;
507 goto err_upload_failed;
508 }
509
Michael Wueff1a592007-09-25 18:11:01 -0700510 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100511 strcpy(buf, p54u_firmware_upload_3887);
512 left -= strlen(p54u_firmware_upload_3887);
513 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700514
515 data = fw_entry->data;
516 remains = fw_entry->size;
517
Christian Lamparter69828692008-12-26 19:08:31 +0100518 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700519 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
520 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
521 hdr->fw_length = cpu_to_le32(fw_entry->size);
522 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
523 sizeof(u32)*2));
524 left -= sizeof(*hdr);
525 tmp += sizeof(*hdr);
526
527 while (remains) {
528 while (left--) {
529 if (carry) {
530 *tmp++ = carry;
531 carry = 0;
532 remains--;
533 continue;
534 }
535 switch (*data) {
536 case '~':
537 *tmp++ = '}';
538 carry = '^';
539 break;
540 case '}':
541 *tmp++ = '}';
542 carry = ']';
543 break;
544 default:
545 *tmp++ = *data;
546 remains--;
547 break;
548 }
549 data++;
550 }
551
552 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
553 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100554 dev_err(&priv->udev->dev, "(p54usb) firmware "
555 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700556 goto err_upload_failed;
557 }
558
559 tmp = buf;
560 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
561 }
562
563 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
564 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
565 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100566 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700567 goto err_upload_failed;
568 }
Michael Wueff1a592007-09-25 18:11:01 -0700569 timeout = jiffies + msecs_to_jiffies(1000);
570 while (!(err = usb_bulk_msg(priv->udev,
571 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
572 if (alen > 2 && !memcmp(buf, "OK", 2))
573 break;
574
575 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700576 err = -EINVAL;
577 break;
578 }
579
580 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100581 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
582 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700583 err = -ETIMEDOUT;
584 break;
585 }
586 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100587 if (err) {
588 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700589 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100590 }
Michael Wueff1a592007-09-25 18:11:01 -0700591
592 buf[0] = 'g';
593 buf[1] = '\r';
594 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
595 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100596 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700597 goto err_upload_failed;
598 }
599
600 timeout = jiffies + msecs_to_jiffies(1000);
601 while (!(err = usb_bulk_msg(priv->udev,
602 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
603 if (alen > 0 && buf[0] == 'g')
604 break;
605
606 if (time_after(jiffies, timeout)) {
607 err = -ETIMEDOUT;
608 break;
609 }
610 }
611 if (err)
612 goto err_upload_failed;
613
614 err_upload_failed:
615 release_firmware(fw_entry);
616 err_req_fw_failed:
617 err_reset:
618 kfree(buf);
619 err_bufalloc:
620 return err;
621}
622
623static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
624{
625 struct p54u_priv *priv = dev->priv;
626 const struct firmware *fw_entry = NULL;
627 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
628 int err, alen;
629 void *buf;
630 __le32 reg;
631 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100632 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700633
634 buf = kmalloc(512, GFP_KERNEL);
635 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100636 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
637 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700638 return -ENOMEM;
639 }
640
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200641 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700642 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100643 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
644 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200645 err = request_firmware(&fw_entry, "isl3890usb",
646 &priv->udev->dev);
647 if (err) {
648 kfree(buf);
649 return err;
650 }
Michael Wueff1a592007-09-25 18:11:01 -0700651 }
652
Christian Lamparter4e416a62008-09-01 22:48:41 +0200653 err = p54_parse_firmware(dev, fw_entry);
654 if (err) {
655 kfree(buf);
656 release_firmware(fw_entry);
657 return err;
658 }
Michael Wueff1a592007-09-25 18:11:01 -0700659
Christian Lampartere365f162008-12-26 19:09:34 +0100660 if (priv->common.fw_interface != FW_LM86) {
661 dev_err(&priv->udev->dev, "wrong firmware, "
662 "please get a LM86(USB) firmware and try again.\n");
663 kfree(buf);
664 release_firmware(fw_entry);
665 return -EINVAL;
666 }
667
Michael Wueff1a592007-09-25 18:11:01 -0700668#define P54U_WRITE(type, addr, data) \
669 do {\
670 err = p54u_write(priv, buf, type,\
671 cpu_to_le32((u32)(unsigned long)addr), data);\
672 if (err) \
673 goto fail;\
674 } while (0)
675
676#define P54U_READ(type, addr) \
677 do {\
678 err = p54u_read(priv, buf, type,\
679 cpu_to_le32((u32)(unsigned long)addr), &reg);\
680 if (err)\
681 goto fail;\
682 } while (0)
683
684 /* power down net2280 bridge */
685 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
686 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
687 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
688 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
689
690 mdelay(100);
691
692 /* power up bridge */
693 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
694 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
695 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
696
697 mdelay(100);
698
699 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
700 cpu_to_le32(NET2280_CLK_30Mhz |
701 NET2280_PCI_ENABLE |
702 NET2280_PCI_SOFT_RESET));
703
704 mdelay(20);
705
706 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
707 cpu_to_le32(PCI_COMMAND_MEMORY |
708 PCI_COMMAND_MASTER));
709
710 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
711 cpu_to_le32(NET2280_BASE));
712
713 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
714 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
715 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
716
717 // TODO: we really need this?
718 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
719
720 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
721 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
722 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
723 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
724
725 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
726 cpu_to_le32(NET2280_BASE2));
727
728 /* finally done setting up the bridge */
729
730 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
731 cpu_to_le32(PCI_COMMAND_MEMORY |
732 PCI_COMMAND_MASTER));
733
734 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
735 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
736 cpu_to_le32(P54U_DEV_BASE));
737
738 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
739 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
740 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
741
742 /* do romboot */
743 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
744
745 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
746 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
747 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
748 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
749 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
750
751 mdelay(20);
752
753 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
754 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
755
756 mdelay(20);
757
758 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
759 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
760
761 mdelay(100);
762
763 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
764 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
765
766 /* finally, we can upload firmware now! */
767 remains = fw_entry->size;
768 data = fw_entry->data;
769 offset = ISL38XX_DEV_FIRMWARE_ADDR;
770
771 while (remains) {
772 unsigned int block_len = min(remains, (unsigned int)512);
773 memcpy(buf, data, block_len);
774
775 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
776 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100777 dev_err(&priv->udev->dev, "(p54usb) firmware block "
778 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700779 goto fail;
780 }
781
782 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
783 cpu_to_le32(0xc0000f00));
784
785 P54U_WRITE(NET2280_DEV_U32,
786 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
787 P54U_WRITE(NET2280_DEV_U32,
788 0x0020 | (unsigned long)&devreg->direct_mem_win,
789 cpu_to_le32(1));
790
791 P54U_WRITE(NET2280_DEV_U32,
792 0x0024 | (unsigned long)&devreg->direct_mem_win,
793 cpu_to_le32(block_len));
794 P54U_WRITE(NET2280_DEV_U32,
795 0x0028 | (unsigned long)&devreg->direct_mem_win,
796 cpu_to_le32(offset));
797
798 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
799 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
800 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
801 cpu_to_le32(block_len >> 2));
802 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
803 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
804
805 mdelay(10);
806
807 P54U_READ(NET2280_DEV_U32,
808 0x002C | (unsigned long)&devreg->direct_mem_win);
809 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
810 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100811 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
812 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700813 goto fail;
814 }
815
816 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
817 cpu_to_le32(NET2280_FIFO_FLUSH));
818
819 remains -= block_len;
820 data += block_len;
821 offset += block_len;
822 }
823
824 /* do ramboot */
825 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
826 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
827 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
828 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
829 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
830
831 mdelay(20);
832
833 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
834 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
835
836 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
837 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
838
839 mdelay(100);
840
841 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
842 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
843
844 /* start up the firmware */
845 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
846 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
847
848 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
849 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
850
851 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
852 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
853 NET2280_USB_INTERRUPT_ENABLE));
854
855 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
856 cpu_to_le32(ISL38XX_DEV_INT_RESET));
857
858 err = usb_interrupt_msg(priv->udev,
859 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
860 buf, sizeof(__le32), &alen, 1000);
861 if (err || alen != sizeof(__le32))
862 goto fail;
863
864 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
865 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
866
867 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
868 err = -EINVAL;
869
870 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
871 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
872 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
873
874#undef P54U_WRITE
875#undef P54U_READ
876
877 fail:
878 release_firmware(fw_entry);
879 kfree(buf);
880 return err;
881}
882
883static int p54u_open(struct ieee80211_hw *dev)
884{
885 struct p54u_priv *priv = dev->priv;
886 int err;
887
888 err = p54u_init_urbs(dev);
889 if (err) {
890 return err;
891 }
892
893 priv->common.open = p54u_init_urbs;
894
895 return 0;
896}
897
898static void p54u_stop(struct ieee80211_hw *dev)
899{
900 /* TODO: figure out how to reliably stop the 3887 and net2280 so
901 the hardware is still usable next time we want to start it.
902 until then, we just stop listening to the hardware.. */
903 p54u_free_urbs(dev);
904 return;
905}
906
907static int __devinit p54u_probe(struct usb_interface *intf,
908 const struct usb_device_id *id)
909{
910 struct usb_device *udev = interface_to_usbdev(intf);
911 struct ieee80211_hw *dev;
912 struct p54u_priv *priv;
913 int err;
914 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700915
916 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100917
Michael Wueff1a592007-09-25 18:11:01 -0700918 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100919 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700920 return -ENOMEM;
921 }
922
923 priv = dev->priv;
924
925 SET_IEEE80211_DEV(dev, &intf->dev);
926 usb_set_intfdata(intf, dev);
927 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100928 priv->intf = intf;
929 skb_queue_head_init(&priv->rx_queue);
930 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700931
932 usb_get_dev(udev);
933
934 /* really lazy and simple way of figuring out if we're a 3887 */
935 /* TODO: should just stick the identification in the device table */
936 i = intf->altsetting->desc.bNumEndpoints;
937 recognized_pipes = 0;
938 while (i--) {
939 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
940 case P54U_PIPE_DATA:
941 case P54U_PIPE_MGMT:
942 case P54U_PIPE_BRG:
943 case P54U_PIPE_DEV:
944 case P54U_PIPE_DATA | USB_DIR_IN:
945 case P54U_PIPE_MGMT | USB_DIR_IN:
946 case P54U_PIPE_BRG | USB_DIR_IN:
947 case P54U_PIPE_DEV | USB_DIR_IN:
948 case P54U_PIPE_INT | USB_DIR_IN:
949 recognized_pipes++;
950 }
951 }
952 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200953 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700954 if (recognized_pipes < P54U_PIPE_NUMBER) {
955 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200956 err = p54u_upload_firmware_3887(dev);
957 if (priv->common.fw_interface == FW_LM87) {
958 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
959 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
960 priv->common.tx = p54u_tx_lm87;
961 } else
962 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700963 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200964 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700965 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
966 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
967 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700968 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200969 }
Michael Wueff1a592007-09-25 18:11:01 -0700970 if (err)
971 goto err_free_dev;
972
Christian Lamparter7cb77072008-09-01 22:48:51 +0200973 p54u_open(dev);
974 err = p54_read_eeprom(dev);
975 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700976 if (err)
977 goto err_free_dev;
978
Michael Wueff1a592007-09-25 18:11:01 -0700979 err = ieee80211_register_hw(dev);
980 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100981 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700982 goto err_free_dev;
983 }
984
Michael Wueff1a592007-09-25 18:11:01 -0700985 return 0;
986
987 err_free_dev:
988 ieee80211_free_hw(dev);
989 usb_set_intfdata(intf, NULL);
990 usb_put_dev(udev);
991 return err;
992}
993
994static void __devexit p54u_disconnect(struct usb_interface *intf)
995{
996 struct ieee80211_hw *dev = usb_get_intfdata(intf);
997 struct p54u_priv *priv;
998
999 if (!dev)
1000 return;
1001
1002 ieee80211_unregister_hw(dev);
1003
1004 priv = dev->priv;
1005 usb_put_dev(interface_to_usbdev(intf));
1006 p54_free_common(dev);
1007 ieee80211_free_hw(dev);
1008}
1009
Christian Lamparter69828692008-12-26 19:08:31 +01001010static int p54u_pre_reset(struct usb_interface *intf)
1011{
1012 return 0;
1013}
1014
1015static int p54u_post_reset(struct usb_interface *intf)
1016{
1017 return 0;
1018}
1019
Michael Wueff1a592007-09-25 18:11:01 -07001020static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001021 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001022 .id_table = p54u_table,
1023 .probe = p54u_probe,
1024 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001025 .pre_reset = p54u_pre_reset,
1026 .post_reset = p54u_post_reset,
Christian Lamparterfbf95292009-03-05 21:29:51 +01001027 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001028};
1029
1030static int __init p54u_init(void)
1031{
1032 return usb_register(&p54u_driver);
1033}
1034
1035static void __exit p54u_exit(void)
1036{
1037 usb_deregister(&p54u_driver);
1038}
1039
1040module_init(p54u_init);
1041module_exit(p54u_exit);