blob: 6cc6cbc9234fb52439a8dd8c044516e4d50f5585 [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
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100209static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700210{
211 struct p54u_priv *priv = dev->priv;
212 struct urb *addr_urb, *data_urb;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100213 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700214
215 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
216 if (!addr_urb)
217 return;
218
219 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
220 if (!data_urb) {
221 usb_free_urb(addr_urb);
222 return;
223 }
224
225 usb_fill_bulk_urb(addr_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200226 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
John W. Linville27df6052008-10-22 16:41:55 -0400227 &((struct p54_hdr *)skb->data)->req_id, 4,
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100228 p54u_tx_dummy_cb, dev);
Michael Wueff1a592007-09-25 18:11:01 -0700229 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200230 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100231 skb->data, skb->len, FREE_AFTER_TX(skb) ?
232 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100233 addr_urb->transfer_flags |= URB_ZERO_PACKET;
234 data_urb->transfer_flags |= URB_ZERO_PACKET;
Michael Wueff1a592007-09-25 18:11:01 -0700235
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100236 usb_anchor_urb(addr_urb, &priv->submitted);
237 err = usb_submit_urb(addr_urb, GFP_ATOMIC);
238 if (err) {
239 usb_unanchor_urb(addr_urb);
240 goto out;
241 }
242
Christian Lamparterb4068a82009-01-20 23:11:21 +0100243 usb_anchor_urb(data_urb, &priv->submitted);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100244 err = usb_submit_urb(data_urb, GFP_ATOMIC);
245 if (err)
246 usb_unanchor_urb(data_urb);
247
248 out:
249 usb_free_urb(addr_urb);
250 usb_free_urb(data_urb);
251
252 if (err)
253 p54_free_skb(dev, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700254}
255
Johannes Bergc9127652008-12-01 18:19:36 +0100256static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200257{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500258 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200259
260 length >>= 2;
261 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100262 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200263 chk = (chk >> 5) ^ (chk << 3);
264 }
265
Larry Finger1f1c0e32008-09-25 14:54:28 -0500266 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200267}
268
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100269static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200270{
271 struct p54u_priv *priv = dev->priv;
272 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100273 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200274
275 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
276 if (!data_urb)
277 return;
278
Christian Lampartere2fe1542009-01-20 00:27:57 +0100279 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
280 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200281
282 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200283 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100284 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
285 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100286 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200287
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100288 usb_anchor_urb(data_urb, &priv->submitted);
289 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
290 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100291 p54_free_skb(dev, skb);
292 }
293 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200294}
295
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100296static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700297{
298 struct p54u_priv *priv = dev->priv;
299 struct urb *int_urb, *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100300 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Michael Wueff1a592007-09-25 18:11:01 -0700301 struct net2280_reg_write *reg;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100302 int err = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700303
304 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
305 if (!reg)
306 return;
307
308 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
309 if (!int_urb) {
310 kfree(reg);
311 return;
312 }
313
314 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
315 if (!data_urb) {
316 kfree(reg);
317 usb_free_urb(int_urb);
318 return;
319 }
320
321 reg->port = cpu_to_le16(NET2280_DEV_U32);
322 reg->addr = cpu_to_le32(P54U_DEV_BASE);
323 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
324
Michael Wueff1a592007-09-25 18:11:01 -0700325 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100326 hdr->len = cpu_to_le16(skb->len);
327 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700328
329 usb_fill_bulk_urb(int_urb, priv->udev,
330 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100331 p54u_tx_dummy_cb, dev);
332
333 /*
334 * This flag triggers a code path in the USB subsystem that will
335 * free what's inside the transfer_buffer after the callback routine
336 * has completed.
337 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100338 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Michael Wueff1a592007-09-25 18:11:01 -0700339
340 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200341 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100342 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
343 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100344 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100345
346 usb_anchor_urb(int_urb, &priv->submitted);
347 err = usb_submit_urb(int_urb, GFP_ATOMIC);
348 if (err) {
349 usb_unanchor_urb(int_urb);
350 goto out;
351 }
352
353 usb_anchor_urb(data_urb, &priv->submitted);
354 err = usb_submit_urb(data_urb, GFP_ATOMIC);
355 if (err) {
356 usb_unanchor_urb(data_urb);
357 goto out;
358 }
359 out:
360 usb_free_urb(int_urb);
361 usb_free_urb(data_urb);
362
363 if (err) {
364 skb_pull(skb, sizeof(*hdr));
365 p54_free_skb(dev, skb);
366 }
Michael Wueff1a592007-09-25 18:11:01 -0700367}
368
369static int p54u_write(struct p54u_priv *priv,
370 struct net2280_reg_write *buf,
371 enum net2280_op_type type,
372 __le32 addr, __le32 val)
373{
374 unsigned int ep;
375 int alen;
376
377 if (type & 0x0800)
378 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
379 else
380 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
381
382 buf->port = cpu_to_le16(type);
383 buf->addr = addr;
384 buf->val = val;
385
386 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
387}
388
389static int p54u_read(struct p54u_priv *priv, void *buf,
390 enum net2280_op_type type,
391 __le32 addr, __le32 *val)
392{
393 struct net2280_reg_read *read = buf;
394 __le32 *reg = buf;
395 unsigned int ep;
396 int alen, err;
397
398 if (type & 0x0800)
399 ep = P54U_PIPE_DEV;
400 else
401 ep = P54U_PIPE_BRG;
402
403 read->port = cpu_to_le16(type);
404 read->addr = addr;
405
406 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
407 read, sizeof(*read), &alen, 1000);
408 if (err)
409 return err;
410
411 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
412 reg, sizeof(*reg), &alen, 1000);
413 if (err)
414 return err;
415
416 *val = *reg;
417 return 0;
418}
419
420static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
421 void *data, size_t len)
422{
423 int alen;
424 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
425 data, len, &alen, 2000);
426}
427
Christian Lamparter69828692008-12-26 19:08:31 +0100428static const char p54u_romboot_3887[] = "~~~~";
429static const char p54u_firmware_upload_3887[] = "<\r";
430
431static int p54u_device_reset_3887(struct ieee80211_hw *dev)
432{
433 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100434 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100435 u8 buf[4];
436
Christian Lamparterc88a7682009-01-16 20:24:31 +0100437 if (lock) {
438 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
439 if (ret < 0) {
440 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
441 " device for reset: %d\n", ret);
442 return ret;
443 }
Christian Lamparter69828692008-12-26 19:08:31 +0100444 }
445
446 ret = usb_reset_device(priv->udev);
447 if (lock)
448 usb_unlock_device(priv->udev);
449
450 if (ret) {
451 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
452 "device: %d\n", ret);
453 return ret;
454 }
455
456 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
457 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
458 buf, sizeof(buf));
459 if (ret)
460 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
461 "boot ROM: %d\n", ret);
462
463 return ret;
464}
465
Michael Wueff1a592007-09-25 18:11:01 -0700466static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
467{
Michael Wueff1a592007-09-25 18:11:01 -0700468 struct p54u_priv *priv = dev->priv;
469 const struct firmware *fw_entry = NULL;
470 int err, alen;
471 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100472 u8 *buf, *tmp;
473 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700474 unsigned int left, remains, block_size;
475 struct x2_header *hdr;
476 unsigned long timeout;
477
478 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
479 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100480 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
481 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700482 err = -ENOMEM;
483 goto err_bufalloc;
484 }
485
Christian Lamparter69828692008-12-26 19:08:31 +0100486 err = p54u_device_reset_3887(dev);
487 if (err)
Michael Wueff1a592007-09-25 18:11:01 -0700488 goto err_reset;
Michael Wueff1a592007-09-25 18:11:01 -0700489
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200490 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700491 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100492 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
493 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200494 err = request_firmware(&fw_entry, "isl3887usb_bare",
495 &priv->udev->dev);
496 if (err)
497 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700498 }
499
Christian Lamparter4e416a62008-09-01 22:48:41 +0200500 err = p54_parse_firmware(dev, fw_entry);
501 if (err)
502 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700503
Christian Lampartere365f162008-12-26 19:09:34 +0100504 if (priv->common.fw_interface != FW_LM87) {
505 dev_err(&priv->udev->dev, "wrong firmware, "
506 "please get a LM87 firmware and try again.\n");
507 err = -EINVAL;
508 goto err_upload_failed;
509 }
510
Michael Wueff1a592007-09-25 18:11:01 -0700511 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100512 strcpy(buf, p54u_firmware_upload_3887);
513 left -= strlen(p54u_firmware_upload_3887);
514 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700515
516 data = fw_entry->data;
517 remains = fw_entry->size;
518
Christian Lamparter69828692008-12-26 19:08:31 +0100519 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700520 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
521 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
522 hdr->fw_length = cpu_to_le32(fw_entry->size);
523 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
524 sizeof(u32)*2));
525 left -= sizeof(*hdr);
526 tmp += sizeof(*hdr);
527
528 while (remains) {
529 while (left--) {
530 if (carry) {
531 *tmp++ = carry;
532 carry = 0;
533 remains--;
534 continue;
535 }
536 switch (*data) {
537 case '~':
538 *tmp++ = '}';
539 carry = '^';
540 break;
541 case '}':
542 *tmp++ = '}';
543 carry = ']';
544 break;
545 default:
546 *tmp++ = *data;
547 remains--;
548 break;
549 }
550 data++;
551 }
552
553 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
554 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100555 dev_err(&priv->udev->dev, "(p54usb) firmware "
556 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700557 goto err_upload_failed;
558 }
559
560 tmp = buf;
561 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
562 }
563
564 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
565 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
566 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100567 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700568 goto err_upload_failed;
569 }
Michael Wueff1a592007-09-25 18:11:01 -0700570 timeout = jiffies + msecs_to_jiffies(1000);
571 while (!(err = usb_bulk_msg(priv->udev,
572 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
573 if (alen > 2 && !memcmp(buf, "OK", 2))
574 break;
575
576 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700577 err = -EINVAL;
578 break;
579 }
580
581 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100582 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
583 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700584 err = -ETIMEDOUT;
585 break;
586 }
587 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100588 if (err) {
589 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700590 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100591 }
Michael Wueff1a592007-09-25 18:11:01 -0700592
593 buf[0] = 'g';
594 buf[1] = '\r';
595 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
596 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100597 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700598 goto err_upload_failed;
599 }
600
601 timeout = jiffies + msecs_to_jiffies(1000);
602 while (!(err = usb_bulk_msg(priv->udev,
603 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
604 if (alen > 0 && buf[0] == 'g')
605 break;
606
607 if (time_after(jiffies, timeout)) {
608 err = -ETIMEDOUT;
609 break;
610 }
611 }
612 if (err)
613 goto err_upload_failed;
614
615 err_upload_failed:
616 release_firmware(fw_entry);
617 err_req_fw_failed:
618 err_reset:
619 kfree(buf);
620 err_bufalloc:
621 return err;
622}
623
624static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
625{
626 struct p54u_priv *priv = dev->priv;
627 const struct firmware *fw_entry = NULL;
628 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
629 int err, alen;
630 void *buf;
631 __le32 reg;
632 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100633 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700634
635 buf = kmalloc(512, GFP_KERNEL);
636 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100637 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
638 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700639 return -ENOMEM;
640 }
641
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200642 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700643 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100644 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
645 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200646 err = request_firmware(&fw_entry, "isl3890usb",
647 &priv->udev->dev);
648 if (err) {
649 kfree(buf);
650 return err;
651 }
Michael Wueff1a592007-09-25 18:11:01 -0700652 }
653
Christian Lamparter4e416a62008-09-01 22:48:41 +0200654 err = p54_parse_firmware(dev, fw_entry);
655 if (err) {
656 kfree(buf);
657 release_firmware(fw_entry);
658 return err;
659 }
Michael Wueff1a592007-09-25 18:11:01 -0700660
Christian Lampartere365f162008-12-26 19:09:34 +0100661 if (priv->common.fw_interface != FW_LM86) {
662 dev_err(&priv->udev->dev, "wrong firmware, "
663 "please get a LM86(USB) firmware and try again.\n");
664 kfree(buf);
665 release_firmware(fw_entry);
666 return -EINVAL;
667 }
668
Michael Wueff1a592007-09-25 18:11:01 -0700669#define P54U_WRITE(type, addr, data) \
670 do {\
671 err = p54u_write(priv, buf, type,\
672 cpu_to_le32((u32)(unsigned long)addr), data);\
673 if (err) \
674 goto fail;\
675 } while (0)
676
677#define P54U_READ(type, addr) \
678 do {\
679 err = p54u_read(priv, buf, type,\
680 cpu_to_le32((u32)(unsigned long)addr), &reg);\
681 if (err)\
682 goto fail;\
683 } while (0)
684
685 /* power down net2280 bridge */
686 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
687 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
688 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
689 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
690
691 mdelay(100);
692
693 /* power up bridge */
694 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
695 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
696 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
697
698 mdelay(100);
699
700 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
701 cpu_to_le32(NET2280_CLK_30Mhz |
702 NET2280_PCI_ENABLE |
703 NET2280_PCI_SOFT_RESET));
704
705 mdelay(20);
706
707 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
708 cpu_to_le32(PCI_COMMAND_MEMORY |
709 PCI_COMMAND_MASTER));
710
711 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
712 cpu_to_le32(NET2280_BASE));
713
714 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
715 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
716 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
717
718 // TODO: we really need this?
719 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
720
721 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
722 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
723 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
724 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
725
726 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
727 cpu_to_le32(NET2280_BASE2));
728
729 /* finally done setting up the bridge */
730
731 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
732 cpu_to_le32(PCI_COMMAND_MEMORY |
733 PCI_COMMAND_MASTER));
734
735 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
736 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
737 cpu_to_le32(P54U_DEV_BASE));
738
739 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
740 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
741 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
742
743 /* do romboot */
744 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
745
746 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
747 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
748 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
749 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
750 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
751
752 mdelay(20);
753
754 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
755 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
756
757 mdelay(20);
758
759 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
760 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
761
762 mdelay(100);
763
764 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
765 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
766
767 /* finally, we can upload firmware now! */
768 remains = fw_entry->size;
769 data = fw_entry->data;
770 offset = ISL38XX_DEV_FIRMWARE_ADDR;
771
772 while (remains) {
773 unsigned int block_len = min(remains, (unsigned int)512);
774 memcpy(buf, data, block_len);
775
776 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
777 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100778 dev_err(&priv->udev->dev, "(p54usb) firmware block "
779 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700780 goto fail;
781 }
782
783 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
784 cpu_to_le32(0xc0000f00));
785
786 P54U_WRITE(NET2280_DEV_U32,
787 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
788 P54U_WRITE(NET2280_DEV_U32,
789 0x0020 | (unsigned long)&devreg->direct_mem_win,
790 cpu_to_le32(1));
791
792 P54U_WRITE(NET2280_DEV_U32,
793 0x0024 | (unsigned long)&devreg->direct_mem_win,
794 cpu_to_le32(block_len));
795 P54U_WRITE(NET2280_DEV_U32,
796 0x0028 | (unsigned long)&devreg->direct_mem_win,
797 cpu_to_le32(offset));
798
799 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
800 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
801 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
802 cpu_to_le32(block_len >> 2));
803 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
804 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
805
806 mdelay(10);
807
808 P54U_READ(NET2280_DEV_U32,
809 0x002C | (unsigned long)&devreg->direct_mem_win);
810 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
811 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100812 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
813 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700814 goto fail;
815 }
816
817 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
818 cpu_to_le32(NET2280_FIFO_FLUSH));
819
820 remains -= block_len;
821 data += block_len;
822 offset += block_len;
823 }
824
825 /* do ramboot */
826 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
827 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
828 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
829 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
830 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
831
832 mdelay(20);
833
834 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
835 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
836
837 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
838 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
839
840 mdelay(100);
841
842 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
843 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
844
845 /* start up the firmware */
846 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
847 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
848
849 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
850 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
851
852 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
853 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
854 NET2280_USB_INTERRUPT_ENABLE));
855
856 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
857 cpu_to_le32(ISL38XX_DEV_INT_RESET));
858
859 err = usb_interrupt_msg(priv->udev,
860 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
861 buf, sizeof(__le32), &alen, 1000);
862 if (err || alen != sizeof(__le32))
863 goto fail;
864
865 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
866 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
867
868 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
869 err = -EINVAL;
870
871 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
872 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
873 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
874
875#undef P54U_WRITE
876#undef P54U_READ
877
878 fail:
879 release_firmware(fw_entry);
880 kfree(buf);
881 return err;
882}
883
884static int p54u_open(struct ieee80211_hw *dev)
885{
886 struct p54u_priv *priv = dev->priv;
887 int err;
888
889 err = p54u_init_urbs(dev);
890 if (err) {
891 return err;
892 }
893
894 priv->common.open = p54u_init_urbs;
895
896 return 0;
897}
898
899static void p54u_stop(struct ieee80211_hw *dev)
900{
901 /* TODO: figure out how to reliably stop the 3887 and net2280 so
902 the hardware is still usable next time we want to start it.
903 until then, we just stop listening to the hardware.. */
904 p54u_free_urbs(dev);
905 return;
906}
907
908static int __devinit p54u_probe(struct usb_interface *intf,
909 const struct usb_device_id *id)
910{
911 struct usb_device *udev = interface_to_usbdev(intf);
912 struct ieee80211_hw *dev;
913 struct p54u_priv *priv;
914 int err;
915 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700916
917 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100918
Michael Wueff1a592007-09-25 18:11:01 -0700919 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100920 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700921 return -ENOMEM;
922 }
923
924 priv = dev->priv;
925
926 SET_IEEE80211_DEV(dev, &intf->dev);
927 usb_set_intfdata(intf, dev);
928 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100929 priv->intf = intf;
930 skb_queue_head_init(&priv->rx_queue);
931 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700932
933 usb_get_dev(udev);
934
935 /* really lazy and simple way of figuring out if we're a 3887 */
936 /* TODO: should just stick the identification in the device table */
937 i = intf->altsetting->desc.bNumEndpoints;
938 recognized_pipes = 0;
939 while (i--) {
940 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
941 case P54U_PIPE_DATA:
942 case P54U_PIPE_MGMT:
943 case P54U_PIPE_BRG:
944 case P54U_PIPE_DEV:
945 case P54U_PIPE_DATA | USB_DIR_IN:
946 case P54U_PIPE_MGMT | USB_DIR_IN:
947 case P54U_PIPE_BRG | USB_DIR_IN:
948 case P54U_PIPE_DEV | USB_DIR_IN:
949 case P54U_PIPE_INT | USB_DIR_IN:
950 recognized_pipes++;
951 }
952 }
953 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200954 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700955 if (recognized_pipes < P54U_PIPE_NUMBER) {
956 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200957 err = p54u_upload_firmware_3887(dev);
958 if (priv->common.fw_interface == FW_LM87) {
959 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
960 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
961 priv->common.tx = p54u_tx_lm87;
962 } else
963 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700964 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200965 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700966 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
967 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
968 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700969 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200970 }
Michael Wueff1a592007-09-25 18:11:01 -0700971 if (err)
972 goto err_free_dev;
973
Christian Lamparter7cb77072008-09-01 22:48:51 +0200974 p54u_open(dev);
975 err = p54_read_eeprom(dev);
976 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700977 if (err)
978 goto err_free_dev;
979
Christian Lamparter2ac71072009-03-05 21:30:10 +0100980 err = p54_register_common(dev, &udev->dev);
981 if (err)
Michael Wueff1a592007-09-25 18:11:01 -0700982 goto err_free_dev;
Michael Wueff1a592007-09-25 18:11:01 -0700983
Michael Wueff1a592007-09-25 18:11:01 -0700984 return 0;
985
986 err_free_dev:
987 ieee80211_free_hw(dev);
988 usb_set_intfdata(intf, NULL);
989 usb_put_dev(udev);
990 return err;
991}
992
993static void __devexit p54u_disconnect(struct usb_interface *intf)
994{
995 struct ieee80211_hw *dev = usb_get_intfdata(intf);
996 struct p54u_priv *priv;
997
998 if (!dev)
999 return;
1000
1001 ieee80211_unregister_hw(dev);
1002
1003 priv = dev->priv;
1004 usb_put_dev(interface_to_usbdev(intf));
1005 p54_free_common(dev);
1006 ieee80211_free_hw(dev);
1007}
1008
Christian Lamparter69828692008-12-26 19:08:31 +01001009static int p54u_pre_reset(struct usb_interface *intf)
1010{
1011 return 0;
1012}
1013
1014static int p54u_post_reset(struct usb_interface *intf)
1015{
1016 return 0;
1017}
1018
Michael Wueff1a592007-09-25 18:11:01 -07001019static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001020 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001021 .id_table = p54u_table,
1022 .probe = p54u_probe,
1023 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001024 .pre_reset = p54u_pre_reset,
1025 .post_reset = p54u_post_reset,
Christian Lamparterfbf95292009-03-05 21:29:51 +01001026 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001027};
1028
1029static int __init p54u_init(void)
1030{
1031 return usb_register(&p54u_driver);
1032}
1033
1034static void __exit p54u_exit(void)
1035{
1036 usb_deregister(&p54u_driver);
1037}
1038
1039module_init(p54u_init);
1040module_exit(p54u_exit);