blob: 21ba526a45bf9435a96e92baf6276bc5137cae41 [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 */
59 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
60 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
61 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
62 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
63 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
64 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
65 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
66 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
67 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
68 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070069 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020070 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050071 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040072 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Michael Wueff1a592007-09-25 18:11:01 -070073 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
74 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
75 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
76 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
77 {}
78};
79
80MODULE_DEVICE_TABLE(usb, p54u_table);
81
82static void p54u_rx_cb(struct urb *urb)
83{
84 struct sk_buff *skb = (struct sk_buff *) urb->context;
85 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
86 struct ieee80211_hw *dev = info->dev;
87 struct p54u_priv *priv = dev->priv;
88
89 if (unlikely(urb->status)) {
90 info->urb = NULL;
91 usb_free_urb(urb);
92 return;
93 }
94
95 skb_unlink(skb, &priv->rx_queue);
96 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +020097
98 if (priv->hw_type == P54U_NET2280)
99 skb_pull(skb, priv->common.tx_hdr_len);
100 if (priv->common.fw_interface == FW_LM87) {
101 skb_pull(skb, 4);
102 skb_put(skb, 4);
103 }
Michael Wueff1a592007-09-25 18:11:01 -0700104
105 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200106 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700107 if (unlikely(!skb)) {
108 usb_free_urb(urb);
109 /* 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;
118 skb_queue_tail(&priv->rx_queue, skb);
119 } 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 }
133
Michael Wueff1a592007-09-25 18:11:01 -0700134 skb_queue_tail(&priv->rx_queue, skb);
135 }
136
137 usb_submit_urb(urb, GFP_ATOMIC);
138}
139
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200140static void p54u_tx_reuse_skb_cb(struct urb *urb)
141{
142 struct sk_buff *skb = urb->context;
143 struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *)
144 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv;
145
146 skb_pull(skb, priv->common.tx_hdr_len);
147 usb_free_urb(urb);
148}
149
Michael Wueff1a592007-09-25 18:11:01 -0700150static void p54u_tx_cb(struct urb *urb)
151{
152 usb_free_urb(urb);
153}
154
155static void p54u_tx_free_cb(struct urb *urb)
156{
157 kfree(urb->transfer_buffer);
158 usb_free_urb(urb);
159}
160
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200161static void p54u_tx_free_skb_cb(struct urb *urb)
162{
163 struct sk_buff *skb = urb->context;
164 struct ieee80211_hw *dev = (struct ieee80211_hw *)
165 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
166
167 p54_free_skb(dev, skb);
168 usb_free_urb(urb);
169}
170
Michael Wueff1a592007-09-25 18:11:01 -0700171static int p54u_init_urbs(struct ieee80211_hw *dev)
172{
173 struct p54u_priv *priv = dev->priv;
174 struct urb *entry;
175 struct sk_buff *skb;
176 struct p54u_rx_info *info;
177
178 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200179 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Michael Wueff1a592007-09-25 18:11:01 -0700180 if (!skb)
181 break;
182 entry = usb_alloc_urb(0, GFP_KERNEL);
183 if (!entry) {
184 kfree_skb(skb);
185 break;
186 }
Christian Lamparter4e416a62008-09-01 22:48:41 +0200187 usb_fill_bulk_urb(entry, priv->udev,
188 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
189 skb_tail_pointer(skb),
190 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700191 info = (struct p54u_rx_info *) skb->cb;
192 info->urb = entry;
193 info->dev = dev;
194 skb_queue_tail(&priv->rx_queue, skb);
195 usb_submit_urb(entry, GFP_KERNEL);
196 }
197
198 return 0;
199}
200
201static void p54u_free_urbs(struct ieee80211_hw *dev)
202{
203 struct p54u_priv *priv = dev->priv;
204 struct p54u_rx_info *info;
205 struct sk_buff *skb;
206
207 while ((skb = skb_dequeue(&priv->rx_queue))) {
208 info = (struct p54u_rx_info *) skb->cb;
209 if (!info->urb)
210 continue;
211
212 usb_kill_urb(info->urb);
213 kfree_skb(skb);
214 }
215}
216
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200217static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb,
218 int free_on_tx)
Michael Wueff1a592007-09-25 18:11:01 -0700219{
220 struct p54u_priv *priv = dev->priv;
221 struct urb *addr_urb, *data_urb;
222
223 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
224 if (!addr_urb)
225 return;
226
227 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
228 if (!data_urb) {
229 usb_free_urb(addr_urb);
230 return;
231 }
232
233 usb_fill_bulk_urb(addr_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200234 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
John W. Linville27df6052008-10-22 16:41:55 -0400235 &((struct p54_hdr *)skb->data)->req_id, 4,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200236 p54u_tx_cb, dev);
Michael Wueff1a592007-09-25 18:11:01 -0700237 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200238 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
239 skb->data, skb->len,
240 free_on_tx ? p54u_tx_free_skb_cb :
241 p54u_tx_reuse_skb_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700242
243 usb_submit_urb(addr_urb, GFP_ATOMIC);
244 usb_submit_urb(data_urb, GFP_ATOMIC);
245}
246
Larry Finger1f1c0e32008-09-25 14:54:28 -0500247static __le32 p54u_lm87_chksum(const u32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200248{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500249 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200250
251 length >>= 2;
252 while (length--) {
Larry Finger1f1c0e32008-09-25 14:54:28 -0500253 chk ^= *data++;
Christian Lamparter2b808482008-09-04 12:29:38 +0200254 chk = (chk >> 5) ^ (chk << 3);
255 }
256
Larry Finger1f1c0e32008-09-25 14:54:28 -0500257 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200258}
259
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200260static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
261 int free_on_tx)
Christian Lamparter2b808482008-09-04 12:29:38 +0200262{
263 struct p54u_priv *priv = dev->priv;
264 struct urb *data_urb;
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200265 struct lm87_tx_hdr *hdr;
266 __le32 checksum;
John W. Linville27df6052008-10-22 16:41:55 -0400267 __le32 addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200268
269 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
270 if (!data_urb)
271 return;
272
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200273 checksum = p54u_lm87_chksum((u32 *)skb->data, skb->len);
274 hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr));
275 hdr->chksum = checksum;
276 hdr->device_addr = addr;
Christian Lamparter2b808482008-09-04 12:29:38 +0200277
278 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200279 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
280 skb->data, skb->len,
281 free_on_tx ? p54u_tx_free_skb_cb :
282 p54u_tx_reuse_skb_cb, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200283
284 usb_submit_urb(data_urb, GFP_ATOMIC);
285}
286
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200287static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
288 int free_on_tx)
Michael Wueff1a592007-09-25 18:11:01 -0700289{
290 struct p54u_priv *priv = dev->priv;
291 struct urb *int_urb, *data_urb;
292 struct net2280_tx_hdr *hdr;
293 struct net2280_reg_write *reg;
294
295 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
296 if (!reg)
297 return;
298
299 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
300 if (!int_urb) {
301 kfree(reg);
302 return;
303 }
304
305 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
306 if (!data_urb) {
307 kfree(reg);
308 usb_free_urb(int_urb);
309 return;
310 }
311
312 reg->port = cpu_to_le16(NET2280_DEV_U32);
313 reg->addr = cpu_to_le32(P54U_DEV_BASE);
314 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
315
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200316 hdr = (void *)skb_push(skb, sizeof(*hdr));
Michael Wueff1a592007-09-25 18:11:01 -0700317 memset(hdr, 0, sizeof(*hdr));
John W. Linville27df6052008-10-22 16:41:55 -0400318 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
319 hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr));
Michael Wueff1a592007-09-25 18:11:01 -0700320
321 usb_fill_bulk_urb(int_urb, priv->udev,
322 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
323 p54u_tx_free_cb, dev);
324 usb_submit_urb(int_urb, GFP_ATOMIC);
325
326 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200327 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
328 skb->data, skb->len,
329 free_on_tx ? p54u_tx_free_skb_cb :
330 p54u_tx_reuse_skb_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700331 usb_submit_urb(data_urb, GFP_ATOMIC);
332}
333
334static int p54u_write(struct p54u_priv *priv,
335 struct net2280_reg_write *buf,
336 enum net2280_op_type type,
337 __le32 addr, __le32 val)
338{
339 unsigned int ep;
340 int alen;
341
342 if (type & 0x0800)
343 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
344 else
345 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
346
347 buf->port = cpu_to_le16(type);
348 buf->addr = addr;
349 buf->val = val;
350
351 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
352}
353
354static int p54u_read(struct p54u_priv *priv, void *buf,
355 enum net2280_op_type type,
356 __le32 addr, __le32 *val)
357{
358 struct net2280_reg_read *read = buf;
359 __le32 *reg = buf;
360 unsigned int ep;
361 int alen, err;
362
363 if (type & 0x0800)
364 ep = P54U_PIPE_DEV;
365 else
366 ep = P54U_PIPE_BRG;
367
368 read->port = cpu_to_le16(type);
369 read->addr = addr;
370
371 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
372 read, sizeof(*read), &alen, 1000);
373 if (err)
374 return err;
375
376 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
377 reg, sizeof(*reg), &alen, 1000);
378 if (err)
379 return err;
380
381 *val = *reg;
382 return 0;
383}
384
385static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
386 void *data, size_t len)
387{
388 int alen;
389 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
390 data, len, &alen, 2000);
391}
392
Michael Wueff1a592007-09-25 18:11:01 -0700393static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
394{
395 static char start_string[] = "~~~~<\r";
396 struct p54u_priv *priv = dev->priv;
397 const struct firmware *fw_entry = NULL;
398 int err, alen;
399 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100400 u8 *buf, *tmp;
401 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700402 unsigned int left, remains, block_size;
403 struct x2_header *hdr;
404 unsigned long timeout;
405
406 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
407 if (!buf) {
408 printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
409 err = -ENOMEM;
410 goto err_bufalloc;
411 }
412
413 memcpy(buf, start_string, 4);
414 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
415 if (err) {
416 printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
417 goto err_reset;
418 }
419
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200420 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700421 if (err) {
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200422 printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n");
423 err = request_firmware(&fw_entry, "isl3887usb_bare",
424 &priv->udev->dev);
425 if (err)
426 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700427 }
428
Christian Lamparter4e416a62008-09-01 22:48:41 +0200429 err = p54_parse_firmware(dev, fw_entry);
430 if (err)
431 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700432
433 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
434 strcpy(buf, start_string);
435 left -= strlen(start_string);
436 tmp += strlen(start_string);
437
438 data = fw_entry->data;
439 remains = fw_entry->size;
440
441 hdr = (struct x2_header *)(buf + strlen(start_string));
442 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
443 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
444 hdr->fw_length = cpu_to_le32(fw_entry->size);
445 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
446 sizeof(u32)*2));
447 left -= sizeof(*hdr);
448 tmp += sizeof(*hdr);
449
450 while (remains) {
451 while (left--) {
452 if (carry) {
453 *tmp++ = carry;
454 carry = 0;
455 remains--;
456 continue;
457 }
458 switch (*data) {
459 case '~':
460 *tmp++ = '}';
461 carry = '^';
462 break;
463 case '}':
464 *tmp++ = '}';
465 carry = ']';
466 break;
467 default:
468 *tmp++ = *data;
469 remains--;
470 break;
471 }
472 data++;
473 }
474
475 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
476 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200477 printk(KERN_ERR "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700478 goto err_upload_failed;
479 }
480
481 tmp = buf;
482 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
483 }
484
485 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
486 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
487 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200488 printk(KERN_ERR "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700489 goto err_upload_failed;
490 }
491
492 timeout = jiffies + msecs_to_jiffies(1000);
493 while (!(err = usb_bulk_msg(priv->udev,
494 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
495 if (alen > 2 && !memcmp(buf, "OK", 2))
496 break;
497
498 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200499 printk(KERN_INFO "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700500 err = -EINVAL;
501 break;
502 }
503
504 if (time_after(jiffies, timeout)) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200505 printk(KERN_ERR "p54usb: firmware boot timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700506 err = -ETIMEDOUT;
507 break;
508 }
509 }
510 if (err)
511 goto err_upload_failed;
512
513 buf[0] = 'g';
514 buf[1] = '\r';
515 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
516 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200517 printk(KERN_ERR "p54usb: firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700518 goto err_upload_failed;
519 }
520
521 timeout = jiffies + msecs_to_jiffies(1000);
522 while (!(err = usb_bulk_msg(priv->udev,
523 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
524 if (alen > 0 && buf[0] == 'g')
525 break;
526
527 if (time_after(jiffies, timeout)) {
528 err = -ETIMEDOUT;
529 break;
530 }
531 }
532 if (err)
533 goto err_upload_failed;
534
535 err_upload_failed:
536 release_firmware(fw_entry);
537 err_req_fw_failed:
538 err_reset:
539 kfree(buf);
540 err_bufalloc:
541 return err;
542}
543
544static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
545{
546 struct p54u_priv *priv = dev->priv;
547 const struct firmware *fw_entry = NULL;
548 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
549 int err, alen;
550 void *buf;
551 __le32 reg;
552 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100553 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700554
555 buf = kmalloc(512, GFP_KERNEL);
556 if (!buf) {
557 printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
558 return -ENOMEM;
559 }
560
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200561 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700562 if (err) {
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200563 printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n");
564 err = request_firmware(&fw_entry, "isl3890usb",
565 &priv->udev->dev);
566 if (err) {
567 kfree(buf);
568 return err;
569 }
Michael Wueff1a592007-09-25 18:11:01 -0700570 }
571
Christian Lamparter4e416a62008-09-01 22:48:41 +0200572 err = p54_parse_firmware(dev, fw_entry);
573 if (err) {
574 kfree(buf);
575 release_firmware(fw_entry);
576 return err;
577 }
Michael Wueff1a592007-09-25 18:11:01 -0700578
579#define P54U_WRITE(type, addr, data) \
580 do {\
581 err = p54u_write(priv, buf, type,\
582 cpu_to_le32((u32)(unsigned long)addr), data);\
583 if (err) \
584 goto fail;\
585 } while (0)
586
587#define P54U_READ(type, addr) \
588 do {\
589 err = p54u_read(priv, buf, type,\
590 cpu_to_le32((u32)(unsigned long)addr), &reg);\
591 if (err)\
592 goto fail;\
593 } while (0)
594
595 /* power down net2280 bridge */
596 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
597 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
598 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
599 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
600
601 mdelay(100);
602
603 /* power up bridge */
604 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
605 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
606 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
607
608 mdelay(100);
609
610 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
611 cpu_to_le32(NET2280_CLK_30Mhz |
612 NET2280_PCI_ENABLE |
613 NET2280_PCI_SOFT_RESET));
614
615 mdelay(20);
616
617 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
618 cpu_to_le32(PCI_COMMAND_MEMORY |
619 PCI_COMMAND_MASTER));
620
621 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
622 cpu_to_le32(NET2280_BASE));
623
624 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
625 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
626 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
627
628 // TODO: we really need this?
629 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
630
631 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
632 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
633 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
634 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
635
636 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
637 cpu_to_le32(NET2280_BASE2));
638
639 /* finally done setting up the bridge */
640
641 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
642 cpu_to_le32(PCI_COMMAND_MEMORY |
643 PCI_COMMAND_MASTER));
644
645 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
646 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
647 cpu_to_le32(P54U_DEV_BASE));
648
649 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
650 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
651 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
652
653 /* do romboot */
654 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
655
656 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
657 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
658 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
659 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
660 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
661
662 mdelay(20);
663
664 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
665 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
666
667 mdelay(20);
668
669 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
670 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
671
672 mdelay(100);
673
674 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
675 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
676
677 /* finally, we can upload firmware now! */
678 remains = fw_entry->size;
679 data = fw_entry->data;
680 offset = ISL38XX_DEV_FIRMWARE_ADDR;
681
682 while (remains) {
683 unsigned int block_len = min(remains, (unsigned int)512);
684 memcpy(buf, data, block_len);
685
686 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
687 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200688 printk(KERN_ERR "p54usb: firmware block upload "
Michael Wueff1a592007-09-25 18:11:01 -0700689 "failed\n");
690 goto fail;
691 }
692
693 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
694 cpu_to_le32(0xc0000f00));
695
696 P54U_WRITE(NET2280_DEV_U32,
697 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
698 P54U_WRITE(NET2280_DEV_U32,
699 0x0020 | (unsigned long)&devreg->direct_mem_win,
700 cpu_to_le32(1));
701
702 P54U_WRITE(NET2280_DEV_U32,
703 0x0024 | (unsigned long)&devreg->direct_mem_win,
704 cpu_to_le32(block_len));
705 P54U_WRITE(NET2280_DEV_U32,
706 0x0028 | (unsigned long)&devreg->direct_mem_win,
707 cpu_to_le32(offset));
708
709 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
710 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
711 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
712 cpu_to_le32(block_len >> 2));
713 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
714 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
715
716 mdelay(10);
717
718 P54U_READ(NET2280_DEV_U32,
719 0x002C | (unsigned long)&devreg->direct_mem_win);
720 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
721 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200722 printk(KERN_ERR "p54usb: firmware DMA transfer "
Michael Wueff1a592007-09-25 18:11:01 -0700723 "failed\n");
724 goto fail;
725 }
726
727 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
728 cpu_to_le32(NET2280_FIFO_FLUSH));
729
730 remains -= block_len;
731 data += block_len;
732 offset += block_len;
733 }
734
735 /* do ramboot */
736 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
737 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
738 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
739 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
740 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
741
742 mdelay(20);
743
744 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
745 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
746
747 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
748 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
749
750 mdelay(100);
751
752 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
753 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
754
755 /* start up the firmware */
756 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
757 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
758
759 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
760 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
761
762 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
763 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
764 NET2280_USB_INTERRUPT_ENABLE));
765
766 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
767 cpu_to_le32(ISL38XX_DEV_INT_RESET));
768
769 err = usb_interrupt_msg(priv->udev,
770 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
771 buf, sizeof(__le32), &alen, 1000);
772 if (err || alen != sizeof(__le32))
773 goto fail;
774
775 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
776 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
777
778 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
779 err = -EINVAL;
780
781 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
782 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
783 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
784
785#undef P54U_WRITE
786#undef P54U_READ
787
788 fail:
789 release_firmware(fw_entry);
790 kfree(buf);
791 return err;
792}
793
794static int p54u_open(struct ieee80211_hw *dev)
795{
796 struct p54u_priv *priv = dev->priv;
797 int err;
798
799 err = p54u_init_urbs(dev);
800 if (err) {
801 return err;
802 }
803
804 priv->common.open = p54u_init_urbs;
805
806 return 0;
807}
808
809static void p54u_stop(struct ieee80211_hw *dev)
810{
811 /* TODO: figure out how to reliably stop the 3887 and net2280 so
812 the hardware is still usable next time we want to start it.
813 until then, we just stop listening to the hardware.. */
814 p54u_free_urbs(dev);
815 return;
816}
817
818static int __devinit p54u_probe(struct usb_interface *intf,
819 const struct usb_device_id *id)
820{
821 struct usb_device *udev = interface_to_usbdev(intf);
822 struct ieee80211_hw *dev;
823 struct p54u_priv *priv;
824 int err;
825 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700826
827 dev = p54_init_common(sizeof(*priv));
828 if (!dev) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200829 printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700830 return -ENOMEM;
831 }
832
833 priv = dev->priv;
834
835 SET_IEEE80211_DEV(dev, &intf->dev);
836 usb_set_intfdata(intf, dev);
837 priv->udev = udev;
838
839 usb_get_dev(udev);
840
841 /* really lazy and simple way of figuring out if we're a 3887 */
842 /* TODO: should just stick the identification in the device table */
843 i = intf->altsetting->desc.bNumEndpoints;
844 recognized_pipes = 0;
845 while (i--) {
846 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
847 case P54U_PIPE_DATA:
848 case P54U_PIPE_MGMT:
849 case P54U_PIPE_BRG:
850 case P54U_PIPE_DEV:
851 case P54U_PIPE_DATA | USB_DIR_IN:
852 case P54U_PIPE_MGMT | USB_DIR_IN:
853 case P54U_PIPE_BRG | USB_DIR_IN:
854 case P54U_PIPE_DEV | USB_DIR_IN:
855 case P54U_PIPE_INT | USB_DIR_IN:
856 recognized_pipes++;
857 }
858 }
859 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200860 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700861 if (recognized_pipes < P54U_PIPE_NUMBER) {
862 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200863 err = p54u_upload_firmware_3887(dev);
864 if (priv->common.fw_interface == FW_LM87) {
865 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
866 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
867 priv->common.tx = p54u_tx_lm87;
868 } else
869 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700870 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200871 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700872 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
873 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
874 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700875 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200876 }
Michael Wueff1a592007-09-25 18:11:01 -0700877 if (err)
878 goto err_free_dev;
879
Christian Lamparter7cb77072008-09-01 22:48:51 +0200880 skb_queue_head_init(&priv->rx_queue);
881
882 p54u_open(dev);
883 err = p54_read_eeprom(dev);
884 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700885 if (err)
886 goto err_free_dev;
887
Michael Wueff1a592007-09-25 18:11:01 -0700888 err = ieee80211_register_hw(dev);
889 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200890 printk(KERN_ERR "p54usb: Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700891 goto err_free_dev;
892 }
893
Michael Wueff1a592007-09-25 18:11:01 -0700894 return 0;
895
896 err_free_dev:
897 ieee80211_free_hw(dev);
898 usb_set_intfdata(intf, NULL);
899 usb_put_dev(udev);
900 return err;
901}
902
903static void __devexit p54u_disconnect(struct usb_interface *intf)
904{
905 struct ieee80211_hw *dev = usb_get_intfdata(intf);
906 struct p54u_priv *priv;
907
908 if (!dev)
909 return;
910
911 ieee80211_unregister_hw(dev);
912
913 priv = dev->priv;
914 usb_put_dev(interface_to_usbdev(intf));
915 p54_free_common(dev);
916 ieee80211_free_hw(dev);
917}
918
919static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200920 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700921 .id_table = p54u_table,
922 .probe = p54u_probe,
923 .disconnect = p54u_disconnect,
924};
925
926static int __init p54u_init(void)
927{
928 return usb_register(&p54u_driver);
929}
930
931static void __exit p54u_exit(void)
932{
933 usb_deregister(&p54u_driver);
934}
935
936module_init(p54u_init);
937module_exit(p54u_exit);