blob: eca858c40b1f49d909a87ec0f4df0a0af24ed64d [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");
31
32static struct usb_device_id p54u_table[] __devinitdata = {
33 /* Version 1 devices (pci chip + net2280) */
34 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
35 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
36 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
37 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050038 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070039 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
40 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
41 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
42 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
43 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
44 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
45 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
46 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
47 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
48 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
49 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
50
51 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070052 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070053 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
54 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
55 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
56 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
57 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
58 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
59 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
60 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
61 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
62 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
63 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
64 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
65 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
66 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Jan Slupski43557e12008-03-10 22:41:18 -070067 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
John W. Linville387e1002008-02-20 15:06:02 -050068 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040069 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Michael Wueff1a592007-09-25 18:11:01 -070070 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
71 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
72 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
73 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
74 {}
75};
76
77MODULE_DEVICE_TABLE(usb, p54u_table);
78
79static void p54u_rx_cb(struct urb *urb)
80{
81 struct sk_buff *skb = (struct sk_buff *) urb->context;
82 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
83 struct ieee80211_hw *dev = info->dev;
84 struct p54u_priv *priv = dev->priv;
85
86 if (unlikely(urb->status)) {
87 info->urb = NULL;
88 usb_free_urb(urb);
89 return;
90 }
91
92 skb_unlink(skb, &priv->rx_queue);
93 skb_put(skb, urb->actual_length);
94 if (!priv->hw_type)
95 skb_pull(skb, sizeof(struct net2280_tx_hdr));
96
97 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +020098 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -070099 if (unlikely(!skb)) {
100 usb_free_urb(urb);
101 /* TODO check rx queue length and refill *somewhere* */
102 return;
103 }
104
105 info = (struct p54u_rx_info *) skb->cb;
106 info->urb = urb;
107 info->dev = dev;
108 urb->transfer_buffer = skb_tail_pointer(skb);
109 urb->context = skb;
110 skb_queue_tail(&priv->rx_queue, skb);
111 } else {
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200112 if (!priv->hw_type)
113 skb_push(skb, sizeof(struct net2280_tx_hdr));
114
115 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700116 skb_trim(skb, 0);
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200117 if (urb->transfer_buffer != skb_tail_pointer(skb)) {
118 /* this should not happen */
119 WARN_ON(1);
120 urb->transfer_buffer = skb_tail_pointer(skb);
121 }
122
Michael Wueff1a592007-09-25 18:11:01 -0700123 skb_queue_tail(&priv->rx_queue, skb);
124 }
125
126 usb_submit_urb(urb, GFP_ATOMIC);
127}
128
129static void p54u_tx_cb(struct urb *urb)
130{
131 usb_free_urb(urb);
132}
133
134static void p54u_tx_free_cb(struct urb *urb)
135{
136 kfree(urb->transfer_buffer);
137 usb_free_urb(urb);
138}
139
140static int p54u_init_urbs(struct ieee80211_hw *dev)
141{
142 struct p54u_priv *priv = dev->priv;
143 struct urb *entry;
144 struct sk_buff *skb;
145 struct p54u_rx_info *info;
146
147 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200148 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Michael Wueff1a592007-09-25 18:11:01 -0700149 if (!skb)
150 break;
151 entry = usb_alloc_urb(0, GFP_KERNEL);
152 if (!entry) {
153 kfree_skb(skb);
154 break;
155 }
Christian Lamparter4e416a62008-09-01 22:48:41 +0200156 usb_fill_bulk_urb(entry, priv->udev,
157 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
158 skb_tail_pointer(skb),
159 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700160 info = (struct p54u_rx_info *) skb->cb;
161 info->urb = entry;
162 info->dev = dev;
163 skb_queue_tail(&priv->rx_queue, skb);
164 usb_submit_urb(entry, GFP_KERNEL);
165 }
166
167 return 0;
168}
169
170static void p54u_free_urbs(struct ieee80211_hw *dev)
171{
172 struct p54u_priv *priv = dev->priv;
173 struct p54u_rx_info *info;
174 struct sk_buff *skb;
175
176 while ((skb = skb_dequeue(&priv->rx_queue))) {
177 info = (struct p54u_rx_info *) skb->cb;
178 if (!info->urb)
179 continue;
180
181 usb_kill_urb(info->urb);
182 kfree_skb(skb);
183 }
184}
185
186static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
187 size_t len, int free_on_tx)
188{
189 struct p54u_priv *priv = dev->priv;
190 struct urb *addr_urb, *data_urb;
191
192 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
193 if (!addr_urb)
194 return;
195
196 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
197 if (!data_urb) {
198 usb_free_urb(addr_urb);
199 return;
200 }
201
202 usb_fill_bulk_urb(addr_urb, priv->udev,
203 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
204 sizeof(data->req_id), p54u_tx_cb, dev);
205 usb_fill_bulk_urb(data_urb, priv->udev,
206 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
207 free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
208
209 usb_submit_urb(addr_urb, GFP_ATOMIC);
210 usb_submit_urb(data_urb, GFP_ATOMIC);
211}
212
213static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
214 size_t len, int free_on_tx)
215{
216 struct p54u_priv *priv = dev->priv;
217 struct urb *int_urb, *data_urb;
218 struct net2280_tx_hdr *hdr;
219 struct net2280_reg_write *reg;
220
221 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
222 if (!reg)
223 return;
224
225 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
226 if (!int_urb) {
227 kfree(reg);
228 return;
229 }
230
231 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
232 if (!data_urb) {
233 kfree(reg);
234 usb_free_urb(int_urb);
235 return;
236 }
237
238 reg->port = cpu_to_le16(NET2280_DEV_U32);
239 reg->addr = cpu_to_le32(P54U_DEV_BASE);
240 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
241
242 len += sizeof(*data);
243 hdr = (void *)data - sizeof(*hdr);
244 memset(hdr, 0, sizeof(*hdr));
245 hdr->device_addr = data->req_id;
246 hdr->len = cpu_to_le16(len);
247
248 usb_fill_bulk_urb(int_urb, priv->udev,
249 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
250 p54u_tx_free_cb, dev);
251 usb_submit_urb(int_urb, GFP_ATOMIC);
252
253 usb_fill_bulk_urb(data_urb, priv->udev,
254 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
255 free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
256 usb_submit_urb(data_urb, GFP_ATOMIC);
257}
258
259static int p54u_write(struct p54u_priv *priv,
260 struct net2280_reg_write *buf,
261 enum net2280_op_type type,
262 __le32 addr, __le32 val)
263{
264 unsigned int ep;
265 int alen;
266
267 if (type & 0x0800)
268 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
269 else
270 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
271
272 buf->port = cpu_to_le16(type);
273 buf->addr = addr;
274 buf->val = val;
275
276 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
277}
278
279static int p54u_read(struct p54u_priv *priv, void *buf,
280 enum net2280_op_type type,
281 __le32 addr, __le32 *val)
282{
283 struct net2280_reg_read *read = buf;
284 __le32 *reg = buf;
285 unsigned int ep;
286 int alen, err;
287
288 if (type & 0x0800)
289 ep = P54U_PIPE_DEV;
290 else
291 ep = P54U_PIPE_BRG;
292
293 read->port = cpu_to_le16(type);
294 read->addr = addr;
295
296 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
297 read, sizeof(*read), &alen, 1000);
298 if (err)
299 return err;
300
301 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
302 reg, sizeof(*reg), &alen, 1000);
303 if (err)
304 return err;
305
306 *val = *reg;
307 return 0;
308}
309
310static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
311 void *data, size_t len)
312{
313 int alen;
314 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
315 data, len, &alen, 2000);
316}
317
Michael Wueff1a592007-09-25 18:11:01 -0700318static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
319{
320 static char start_string[] = "~~~~<\r";
321 struct p54u_priv *priv = dev->priv;
322 const struct firmware *fw_entry = NULL;
323 int err, alen;
324 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100325 u8 *buf, *tmp;
326 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700327 unsigned int left, remains, block_size;
328 struct x2_header *hdr;
329 unsigned long timeout;
330
331 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
332 if (!buf) {
333 printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
334 err = -ENOMEM;
335 goto err_bufalloc;
336 }
337
338 memcpy(buf, start_string, 4);
339 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
340 if (err) {
341 printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
342 goto err_reset;
343 }
344
345 err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
346 if (err) {
347 printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
348 goto err_req_fw_failed;
349 }
350
Christian Lamparter4e416a62008-09-01 22:48:41 +0200351 err = p54_parse_firmware(dev, fw_entry);
352 if (err)
353 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700354
355 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
356 strcpy(buf, start_string);
357 left -= strlen(start_string);
358 tmp += strlen(start_string);
359
360 data = fw_entry->data;
361 remains = fw_entry->size;
362
363 hdr = (struct x2_header *)(buf + strlen(start_string));
364 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
365 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
366 hdr->fw_length = cpu_to_le32(fw_entry->size);
367 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
368 sizeof(u32)*2));
369 left -= sizeof(*hdr);
370 tmp += sizeof(*hdr);
371
372 while (remains) {
373 while (left--) {
374 if (carry) {
375 *tmp++ = carry;
376 carry = 0;
377 remains--;
378 continue;
379 }
380 switch (*data) {
381 case '~':
382 *tmp++ = '}';
383 carry = '^';
384 break;
385 case '}':
386 *tmp++ = '}';
387 carry = ']';
388 break;
389 default:
390 *tmp++ = *data;
391 remains--;
392 break;
393 }
394 data++;
395 }
396
397 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
398 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200399 printk(KERN_ERR "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700400 goto err_upload_failed;
401 }
402
403 tmp = buf;
404 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
405 }
406
407 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
408 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
409 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200410 printk(KERN_ERR "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700411 goto err_upload_failed;
412 }
413
414 timeout = jiffies + msecs_to_jiffies(1000);
415 while (!(err = usb_bulk_msg(priv->udev,
416 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
417 if (alen > 2 && !memcmp(buf, "OK", 2))
418 break;
419
420 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200421 printk(KERN_INFO "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700422 err = -EINVAL;
423 break;
424 }
425
426 if (time_after(jiffies, timeout)) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200427 printk(KERN_ERR "p54usb: firmware boot timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700428 err = -ETIMEDOUT;
429 break;
430 }
431 }
432 if (err)
433 goto err_upload_failed;
434
435 buf[0] = 'g';
436 buf[1] = '\r';
437 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
438 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200439 printk(KERN_ERR "p54usb: firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700440 goto err_upload_failed;
441 }
442
443 timeout = jiffies + msecs_to_jiffies(1000);
444 while (!(err = usb_bulk_msg(priv->udev,
445 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
446 if (alen > 0 && buf[0] == 'g')
447 break;
448
449 if (time_after(jiffies, timeout)) {
450 err = -ETIMEDOUT;
451 break;
452 }
453 }
454 if (err)
455 goto err_upload_failed;
456
457 err_upload_failed:
458 release_firmware(fw_entry);
459 err_req_fw_failed:
460 err_reset:
461 kfree(buf);
462 err_bufalloc:
463 return err;
464}
465
466static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
467{
468 struct p54u_priv *priv = dev->priv;
469 const struct firmware *fw_entry = NULL;
470 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
471 int err, alen;
472 void *buf;
473 __le32 reg;
474 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100475 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700476
477 buf = kmalloc(512, GFP_KERNEL);
478 if (!buf) {
479 printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
480 return -ENOMEM;
481 }
482
483 err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
484 if (err) {
485 printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
486 kfree(buf);
487 return err;
488 }
489
Christian Lamparter4e416a62008-09-01 22:48:41 +0200490 err = p54_parse_firmware(dev, fw_entry);
491 if (err) {
492 kfree(buf);
493 release_firmware(fw_entry);
494 return err;
495 }
Michael Wueff1a592007-09-25 18:11:01 -0700496
497#define P54U_WRITE(type, addr, data) \
498 do {\
499 err = p54u_write(priv, buf, type,\
500 cpu_to_le32((u32)(unsigned long)addr), data);\
501 if (err) \
502 goto fail;\
503 } while (0)
504
505#define P54U_READ(type, addr) \
506 do {\
507 err = p54u_read(priv, buf, type,\
508 cpu_to_le32((u32)(unsigned long)addr), &reg);\
509 if (err)\
510 goto fail;\
511 } while (0)
512
513 /* power down net2280 bridge */
514 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
515 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
516 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
517 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
518
519 mdelay(100);
520
521 /* power up bridge */
522 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
523 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
524 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
525
526 mdelay(100);
527
528 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
529 cpu_to_le32(NET2280_CLK_30Mhz |
530 NET2280_PCI_ENABLE |
531 NET2280_PCI_SOFT_RESET));
532
533 mdelay(20);
534
535 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
536 cpu_to_le32(PCI_COMMAND_MEMORY |
537 PCI_COMMAND_MASTER));
538
539 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
540 cpu_to_le32(NET2280_BASE));
541
542 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
543 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
544 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
545
546 // TODO: we really need this?
547 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
548
549 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
550 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
551 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
552 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
553
554 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
555 cpu_to_le32(NET2280_BASE2));
556
557 /* finally done setting up the bridge */
558
559 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
560 cpu_to_le32(PCI_COMMAND_MEMORY |
561 PCI_COMMAND_MASTER));
562
563 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
564 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
565 cpu_to_le32(P54U_DEV_BASE));
566
567 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
568 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
569 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
570
571 /* do romboot */
572 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
573
574 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
575 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
576 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
577 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
578 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
579
580 mdelay(20);
581
582 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
583 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
584
585 mdelay(20);
586
587 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
588 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
589
590 mdelay(100);
591
592 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
593 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
594
595 /* finally, we can upload firmware now! */
596 remains = fw_entry->size;
597 data = fw_entry->data;
598 offset = ISL38XX_DEV_FIRMWARE_ADDR;
599
600 while (remains) {
601 unsigned int block_len = min(remains, (unsigned int)512);
602 memcpy(buf, data, block_len);
603
604 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
605 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200606 printk(KERN_ERR "p54usb: firmware block upload "
Michael Wueff1a592007-09-25 18:11:01 -0700607 "failed\n");
608 goto fail;
609 }
610
611 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
612 cpu_to_le32(0xc0000f00));
613
614 P54U_WRITE(NET2280_DEV_U32,
615 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
616 P54U_WRITE(NET2280_DEV_U32,
617 0x0020 | (unsigned long)&devreg->direct_mem_win,
618 cpu_to_le32(1));
619
620 P54U_WRITE(NET2280_DEV_U32,
621 0x0024 | (unsigned long)&devreg->direct_mem_win,
622 cpu_to_le32(block_len));
623 P54U_WRITE(NET2280_DEV_U32,
624 0x0028 | (unsigned long)&devreg->direct_mem_win,
625 cpu_to_le32(offset));
626
627 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
628 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
629 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
630 cpu_to_le32(block_len >> 2));
631 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
632 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
633
634 mdelay(10);
635
636 P54U_READ(NET2280_DEV_U32,
637 0x002C | (unsigned long)&devreg->direct_mem_win);
638 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
639 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200640 printk(KERN_ERR "p54usb: firmware DMA transfer "
Michael Wueff1a592007-09-25 18:11:01 -0700641 "failed\n");
642 goto fail;
643 }
644
645 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
646 cpu_to_le32(NET2280_FIFO_FLUSH));
647
648 remains -= block_len;
649 data += block_len;
650 offset += block_len;
651 }
652
653 /* do ramboot */
654 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
655 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
656 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
657 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
658 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
659
660 mdelay(20);
661
662 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
663 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
664
665 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
666 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
667
668 mdelay(100);
669
670 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
671 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
672
673 /* start up the firmware */
674 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
675 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
676
677 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
678 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
679
680 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
681 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
682 NET2280_USB_INTERRUPT_ENABLE));
683
684 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
685 cpu_to_le32(ISL38XX_DEV_INT_RESET));
686
687 err = usb_interrupt_msg(priv->udev,
688 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
689 buf, sizeof(__le32), &alen, 1000);
690 if (err || alen != sizeof(__le32))
691 goto fail;
692
693 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
694 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
695
696 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
697 err = -EINVAL;
698
699 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
700 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
701 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
702
703#undef P54U_WRITE
704#undef P54U_READ
705
706 fail:
707 release_firmware(fw_entry);
708 kfree(buf);
709 return err;
710}
711
712static int p54u_open(struct ieee80211_hw *dev)
713{
714 struct p54u_priv *priv = dev->priv;
715 int err;
716
717 err = p54u_init_urbs(dev);
718 if (err) {
719 return err;
720 }
721
722 priv->common.open = p54u_init_urbs;
723
724 return 0;
725}
726
727static void p54u_stop(struct ieee80211_hw *dev)
728{
729 /* TODO: figure out how to reliably stop the 3887 and net2280 so
730 the hardware is still usable next time we want to start it.
731 until then, we just stop listening to the hardware.. */
732 p54u_free_urbs(dev);
733 return;
734}
735
736static int __devinit p54u_probe(struct usb_interface *intf,
737 const struct usb_device_id *id)
738{
739 struct usb_device *udev = interface_to_usbdev(intf);
740 struct ieee80211_hw *dev;
741 struct p54u_priv *priv;
742 int err;
743 unsigned int i, recognized_pipes;
744 DECLARE_MAC_BUF(mac);
745
746 dev = p54_init_common(sizeof(*priv));
747 if (!dev) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200748 printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700749 return -ENOMEM;
750 }
751
752 priv = dev->priv;
753
754 SET_IEEE80211_DEV(dev, &intf->dev);
755 usb_set_intfdata(intf, dev);
756 priv->udev = udev;
757
758 usb_get_dev(udev);
759
760 /* really lazy and simple way of figuring out if we're a 3887 */
761 /* TODO: should just stick the identification in the device table */
762 i = intf->altsetting->desc.bNumEndpoints;
763 recognized_pipes = 0;
764 while (i--) {
765 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
766 case P54U_PIPE_DATA:
767 case P54U_PIPE_MGMT:
768 case P54U_PIPE_BRG:
769 case P54U_PIPE_DEV:
770 case P54U_PIPE_DATA | USB_DIR_IN:
771 case P54U_PIPE_MGMT | USB_DIR_IN:
772 case P54U_PIPE_BRG | USB_DIR_IN:
773 case P54U_PIPE_DEV | USB_DIR_IN:
774 case P54U_PIPE_INT | USB_DIR_IN:
775 recognized_pipes++;
776 }
777 }
778 priv->common.open = p54u_open;
779
780 if (recognized_pipes < P54U_PIPE_NUMBER) {
781 priv->hw_type = P54U_3887;
782 priv->common.tx = p54u_tx_3887;
783 } else {
784 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
785 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
786 priv->common.tx = p54u_tx_net2280;
787 }
788 priv->common.stop = p54u_stop;
789
790 if (priv->hw_type)
791 err = p54u_upload_firmware_3887(dev);
792 else
793 err = p54u_upload_firmware_net2280(dev);
794 if (err)
795 goto err_free_dev;
796
Christian Lamparter7cb77072008-09-01 22:48:51 +0200797 skb_queue_head_init(&priv->rx_queue);
798
799 p54u_open(dev);
800 err = p54_read_eeprom(dev);
801 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700802 if (err)
803 goto err_free_dev;
804
Michael Wueff1a592007-09-25 18:11:01 -0700805 err = ieee80211_register_hw(dev);
806 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200807 printk(KERN_ERR "p54usb: Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700808 goto err_free_dev;
809 }
810
Michael Wueff1a592007-09-25 18:11:01 -0700811 return 0;
812
813 err_free_dev:
814 ieee80211_free_hw(dev);
815 usb_set_intfdata(intf, NULL);
816 usb_put_dev(udev);
817 return err;
818}
819
820static void __devexit p54u_disconnect(struct usb_interface *intf)
821{
822 struct ieee80211_hw *dev = usb_get_intfdata(intf);
823 struct p54u_priv *priv;
824
825 if (!dev)
826 return;
827
828 ieee80211_unregister_hw(dev);
829
830 priv = dev->priv;
831 usb_put_dev(interface_to_usbdev(intf));
832 p54_free_common(dev);
833 ieee80211_free_hw(dev);
834}
835
836static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200837 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700838 .id_table = p54u_table,
839 .probe = p54u_probe,
840 .disconnect = p54u_disconnect,
841};
842
843static int __init p54u_init(void)
844{
845 return usb_register(&p54u_driver);
846}
847
848static void __exit p54u_exit(void)
849{
850 usb_deregister(&p54u_driver);
851}
852
853module_init(p54u_init);
854module_exit(p54u_exit);