blob: 1912f5e9a0a98aff4d67e84180307060356ab349 [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);
Christian Lamparter2b808482008-09-04 12:29:38 +020094
95 if (priv->hw_type == P54U_NET2280)
96 skb_pull(skb, priv->common.tx_hdr_len);
97 if (priv->common.fw_interface == FW_LM87) {
98 skb_pull(skb, 4);
99 skb_put(skb, 4);
100 }
Michael Wueff1a592007-09-25 18:11:01 -0700101
102 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200103 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700104 if (unlikely(!skb)) {
105 usb_free_urb(urb);
106 /* TODO check rx queue length and refill *somewhere* */
107 return;
108 }
109
110 info = (struct p54u_rx_info *) skb->cb;
111 info->urb = urb;
112 info->dev = dev;
113 urb->transfer_buffer = skb_tail_pointer(skb);
114 urb->context = skb;
115 skb_queue_tail(&priv->rx_queue, skb);
116 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200117 if (priv->hw_type == P54U_NET2280)
118 skb_push(skb, priv->common.tx_hdr_len);
119 if (priv->common.fw_interface == FW_LM87) {
120 skb_push(skb, 4);
121 skb_put(skb, 4);
122 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200123 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700124 skb_trim(skb, 0);
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200125 if (urb->transfer_buffer != skb_tail_pointer(skb)) {
126 /* this should not happen */
127 WARN_ON(1);
128 urb->transfer_buffer = skb_tail_pointer(skb);
129 }
130
Michael Wueff1a592007-09-25 18:11:01 -0700131 skb_queue_tail(&priv->rx_queue, skb);
132 }
133
134 usb_submit_urb(urb, GFP_ATOMIC);
135}
136
137static void p54u_tx_cb(struct urb *urb)
138{
139 usb_free_urb(urb);
140}
141
142static void p54u_tx_free_cb(struct urb *urb)
143{
144 kfree(urb->transfer_buffer);
145 usb_free_urb(urb);
146}
147
148static int p54u_init_urbs(struct ieee80211_hw *dev)
149{
150 struct p54u_priv *priv = dev->priv;
151 struct urb *entry;
152 struct sk_buff *skb;
153 struct p54u_rx_info *info;
154
155 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200156 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Michael Wueff1a592007-09-25 18:11:01 -0700157 if (!skb)
158 break;
159 entry = usb_alloc_urb(0, GFP_KERNEL);
160 if (!entry) {
161 kfree_skb(skb);
162 break;
163 }
Christian Lamparter4e416a62008-09-01 22:48:41 +0200164 usb_fill_bulk_urb(entry, priv->udev,
165 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
166 skb_tail_pointer(skb),
167 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700168 info = (struct p54u_rx_info *) skb->cb;
169 info->urb = entry;
170 info->dev = dev;
171 skb_queue_tail(&priv->rx_queue, skb);
172 usb_submit_urb(entry, GFP_KERNEL);
173 }
174
175 return 0;
176}
177
178static void p54u_free_urbs(struct ieee80211_hw *dev)
179{
180 struct p54u_priv *priv = dev->priv;
181 struct p54u_rx_info *info;
182 struct sk_buff *skb;
183
184 while ((skb = skb_dequeue(&priv->rx_queue))) {
185 info = (struct p54u_rx_info *) skb->cb;
186 if (!info->urb)
187 continue;
188
189 usb_kill_urb(info->urb);
190 kfree_skb(skb);
191 }
192}
193
194static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
195 size_t len, int free_on_tx)
196{
197 struct p54u_priv *priv = dev->priv;
198 struct urb *addr_urb, *data_urb;
199
200 addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
201 if (!addr_urb)
202 return;
203
204 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
205 if (!data_urb) {
206 usb_free_urb(addr_urb);
207 return;
208 }
209
210 usb_fill_bulk_urb(addr_urb, priv->udev,
211 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
212 sizeof(data->req_id), p54u_tx_cb, dev);
213 usb_fill_bulk_urb(data_urb, priv->udev,
214 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
215 free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
216
217 usb_submit_urb(addr_urb, GFP_ATOMIC);
218 usb_submit_urb(data_urb, GFP_ATOMIC);
219}
220
Larry Finger1f1c0e32008-09-25 14:54:28 -0500221static __le32 p54u_lm87_chksum(const u32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200222{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500223 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200224
225 length >>= 2;
226 while (length--) {
Larry Finger1f1c0e32008-09-25 14:54:28 -0500227 chk ^= *data++;
Christian Lamparter2b808482008-09-04 12:29:38 +0200228 chk = (chk >> 5) ^ (chk << 3);
229 }
230
Larry Finger1f1c0e32008-09-25 14:54:28 -0500231 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200232}
233
234static void p54u_tx_lm87(struct ieee80211_hw *dev,
235 struct p54_control_hdr *data,
236 size_t len, int free_on_tx)
237{
238 struct p54u_priv *priv = dev->priv;
239 struct urb *data_urb;
240 struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
241
242 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
243 if (!data_urb)
244 return;
245
246 hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
247 hdr->device_addr = data->req_id;
248
249 usb_fill_bulk_urb(data_urb, priv->udev,
250 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
251 len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
252 dev);
253
254 usb_submit_urb(data_urb, GFP_ATOMIC);
255}
256
Michael Wueff1a592007-09-25 18:11:01 -0700257static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
258 size_t len, int free_on_tx)
259{
260 struct p54u_priv *priv = dev->priv;
261 struct urb *int_urb, *data_urb;
262 struct net2280_tx_hdr *hdr;
263 struct net2280_reg_write *reg;
264
265 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
266 if (!reg)
267 return;
268
269 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
270 if (!int_urb) {
271 kfree(reg);
272 return;
273 }
274
275 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
276 if (!data_urb) {
277 kfree(reg);
278 usb_free_urb(int_urb);
279 return;
280 }
281
282 reg->port = cpu_to_le16(NET2280_DEV_U32);
283 reg->addr = cpu_to_le32(P54U_DEV_BASE);
284 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
285
286 len += sizeof(*data);
287 hdr = (void *)data - sizeof(*hdr);
288 memset(hdr, 0, sizeof(*hdr));
289 hdr->device_addr = data->req_id;
290 hdr->len = cpu_to_le16(len);
291
292 usb_fill_bulk_urb(int_urb, priv->udev,
293 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
294 p54u_tx_free_cb, dev);
295 usb_submit_urb(int_urb, GFP_ATOMIC);
296
297 usb_fill_bulk_urb(data_urb, priv->udev,
298 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
299 free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
300 usb_submit_urb(data_urb, GFP_ATOMIC);
301}
302
303static int p54u_write(struct p54u_priv *priv,
304 struct net2280_reg_write *buf,
305 enum net2280_op_type type,
306 __le32 addr, __le32 val)
307{
308 unsigned int ep;
309 int alen;
310
311 if (type & 0x0800)
312 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
313 else
314 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
315
316 buf->port = cpu_to_le16(type);
317 buf->addr = addr;
318 buf->val = val;
319
320 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
321}
322
323static int p54u_read(struct p54u_priv *priv, void *buf,
324 enum net2280_op_type type,
325 __le32 addr, __le32 *val)
326{
327 struct net2280_reg_read *read = buf;
328 __le32 *reg = buf;
329 unsigned int ep;
330 int alen, err;
331
332 if (type & 0x0800)
333 ep = P54U_PIPE_DEV;
334 else
335 ep = P54U_PIPE_BRG;
336
337 read->port = cpu_to_le16(type);
338 read->addr = addr;
339
340 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
341 read, sizeof(*read), &alen, 1000);
342 if (err)
343 return err;
344
345 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
346 reg, sizeof(*reg), &alen, 1000);
347 if (err)
348 return err;
349
350 *val = *reg;
351 return 0;
352}
353
354static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
355 void *data, size_t len)
356{
357 int alen;
358 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
359 data, len, &alen, 2000);
360}
361
Michael Wueff1a592007-09-25 18:11:01 -0700362static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
363{
364 static char start_string[] = "~~~~<\r";
365 struct p54u_priv *priv = dev->priv;
366 const struct firmware *fw_entry = NULL;
367 int err, alen;
368 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100369 u8 *buf, *tmp;
370 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700371 unsigned int left, remains, block_size;
372 struct x2_header *hdr;
373 unsigned long timeout;
374
375 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
376 if (!buf) {
377 printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
378 err = -ENOMEM;
379 goto err_bufalloc;
380 }
381
382 memcpy(buf, start_string, 4);
383 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
384 if (err) {
385 printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
386 goto err_reset;
387 }
388
389 err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
390 if (err) {
391 printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
392 goto err_req_fw_failed;
393 }
394
Christian Lamparter4e416a62008-09-01 22:48:41 +0200395 err = p54_parse_firmware(dev, fw_entry);
396 if (err)
397 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700398
399 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
400 strcpy(buf, start_string);
401 left -= strlen(start_string);
402 tmp += strlen(start_string);
403
404 data = fw_entry->data;
405 remains = fw_entry->size;
406
407 hdr = (struct x2_header *)(buf + strlen(start_string));
408 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
409 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
410 hdr->fw_length = cpu_to_le32(fw_entry->size);
411 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
412 sizeof(u32)*2));
413 left -= sizeof(*hdr);
414 tmp += sizeof(*hdr);
415
416 while (remains) {
417 while (left--) {
418 if (carry) {
419 *tmp++ = carry;
420 carry = 0;
421 remains--;
422 continue;
423 }
424 switch (*data) {
425 case '~':
426 *tmp++ = '}';
427 carry = '^';
428 break;
429 case '}':
430 *tmp++ = '}';
431 carry = ']';
432 break;
433 default:
434 *tmp++ = *data;
435 remains--;
436 break;
437 }
438 data++;
439 }
440
441 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
442 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200443 printk(KERN_ERR "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700444 goto err_upload_failed;
445 }
446
447 tmp = buf;
448 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
449 }
450
451 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
452 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
453 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200454 printk(KERN_ERR "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700455 goto err_upload_failed;
456 }
457
458 timeout = jiffies + msecs_to_jiffies(1000);
459 while (!(err = usb_bulk_msg(priv->udev,
460 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
461 if (alen > 2 && !memcmp(buf, "OK", 2))
462 break;
463
464 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200465 printk(KERN_INFO "p54usb: firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700466 err = -EINVAL;
467 break;
468 }
469
470 if (time_after(jiffies, timeout)) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200471 printk(KERN_ERR "p54usb: firmware boot timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700472 err = -ETIMEDOUT;
473 break;
474 }
475 }
476 if (err)
477 goto err_upload_failed;
478
479 buf[0] = 'g';
480 buf[1] = '\r';
481 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
482 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200483 printk(KERN_ERR "p54usb: firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700484 goto err_upload_failed;
485 }
486
487 timeout = jiffies + msecs_to_jiffies(1000);
488 while (!(err = usb_bulk_msg(priv->udev,
489 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
490 if (alen > 0 && buf[0] == 'g')
491 break;
492
493 if (time_after(jiffies, timeout)) {
494 err = -ETIMEDOUT;
495 break;
496 }
497 }
498 if (err)
499 goto err_upload_failed;
500
501 err_upload_failed:
502 release_firmware(fw_entry);
503 err_req_fw_failed:
504 err_reset:
505 kfree(buf);
506 err_bufalloc:
507 return err;
508}
509
510static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
511{
512 struct p54u_priv *priv = dev->priv;
513 const struct firmware *fw_entry = NULL;
514 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
515 int err, alen;
516 void *buf;
517 __le32 reg;
518 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100519 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700520
521 buf = kmalloc(512, GFP_KERNEL);
522 if (!buf) {
523 printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
524 return -ENOMEM;
525 }
526
527 err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
528 if (err) {
529 printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
530 kfree(buf);
531 return err;
532 }
533
Christian Lamparter4e416a62008-09-01 22:48:41 +0200534 err = p54_parse_firmware(dev, fw_entry);
535 if (err) {
536 kfree(buf);
537 release_firmware(fw_entry);
538 return err;
539 }
Michael Wueff1a592007-09-25 18:11:01 -0700540
541#define P54U_WRITE(type, addr, data) \
542 do {\
543 err = p54u_write(priv, buf, type,\
544 cpu_to_le32((u32)(unsigned long)addr), data);\
545 if (err) \
546 goto fail;\
547 } while (0)
548
549#define P54U_READ(type, addr) \
550 do {\
551 err = p54u_read(priv, buf, type,\
552 cpu_to_le32((u32)(unsigned long)addr), &reg);\
553 if (err)\
554 goto fail;\
555 } while (0)
556
557 /* power down net2280 bridge */
558 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
559 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
560 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
561 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
562
563 mdelay(100);
564
565 /* power up bridge */
566 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
567 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
568 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
569
570 mdelay(100);
571
572 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
573 cpu_to_le32(NET2280_CLK_30Mhz |
574 NET2280_PCI_ENABLE |
575 NET2280_PCI_SOFT_RESET));
576
577 mdelay(20);
578
579 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
580 cpu_to_le32(PCI_COMMAND_MEMORY |
581 PCI_COMMAND_MASTER));
582
583 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
584 cpu_to_le32(NET2280_BASE));
585
586 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
587 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
588 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
589
590 // TODO: we really need this?
591 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
592
593 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
594 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
595 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
596 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
597
598 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
599 cpu_to_le32(NET2280_BASE2));
600
601 /* finally done setting up the bridge */
602
603 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
604 cpu_to_le32(PCI_COMMAND_MEMORY |
605 PCI_COMMAND_MASTER));
606
607 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
608 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
609 cpu_to_le32(P54U_DEV_BASE));
610
611 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
612 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
613 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
614
615 /* do romboot */
616 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
617
618 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
619 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
620 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
621 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
622 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
623
624 mdelay(20);
625
626 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
627 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
628
629 mdelay(20);
630
631 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
632 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
633
634 mdelay(100);
635
636 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
637 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
638
639 /* finally, we can upload firmware now! */
640 remains = fw_entry->size;
641 data = fw_entry->data;
642 offset = ISL38XX_DEV_FIRMWARE_ADDR;
643
644 while (remains) {
645 unsigned int block_len = min(remains, (unsigned int)512);
646 memcpy(buf, data, block_len);
647
648 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
649 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200650 printk(KERN_ERR "p54usb: firmware block upload "
Michael Wueff1a592007-09-25 18:11:01 -0700651 "failed\n");
652 goto fail;
653 }
654
655 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
656 cpu_to_le32(0xc0000f00));
657
658 P54U_WRITE(NET2280_DEV_U32,
659 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
660 P54U_WRITE(NET2280_DEV_U32,
661 0x0020 | (unsigned long)&devreg->direct_mem_win,
662 cpu_to_le32(1));
663
664 P54U_WRITE(NET2280_DEV_U32,
665 0x0024 | (unsigned long)&devreg->direct_mem_win,
666 cpu_to_le32(block_len));
667 P54U_WRITE(NET2280_DEV_U32,
668 0x0028 | (unsigned long)&devreg->direct_mem_win,
669 cpu_to_le32(offset));
670
671 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
672 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
673 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
674 cpu_to_le32(block_len >> 2));
675 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
676 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
677
678 mdelay(10);
679
680 P54U_READ(NET2280_DEV_U32,
681 0x002C | (unsigned long)&devreg->direct_mem_win);
682 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
683 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200684 printk(KERN_ERR "p54usb: firmware DMA transfer "
Michael Wueff1a592007-09-25 18:11:01 -0700685 "failed\n");
686 goto fail;
687 }
688
689 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
690 cpu_to_le32(NET2280_FIFO_FLUSH));
691
692 remains -= block_len;
693 data += block_len;
694 offset += block_len;
695 }
696
697 /* do ramboot */
698 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
699 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
700 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
701 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
702 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
703
704 mdelay(20);
705
706 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
707 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
708
709 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
710 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
711
712 mdelay(100);
713
714 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
715 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
716
717 /* start up the firmware */
718 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
719 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
720
721 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
722 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
723
724 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
725 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
726 NET2280_USB_INTERRUPT_ENABLE));
727
728 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
729 cpu_to_le32(ISL38XX_DEV_INT_RESET));
730
731 err = usb_interrupt_msg(priv->udev,
732 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
733 buf, sizeof(__le32), &alen, 1000);
734 if (err || alen != sizeof(__le32))
735 goto fail;
736
737 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
738 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
739
740 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
741 err = -EINVAL;
742
743 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
744 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
745 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
746
747#undef P54U_WRITE
748#undef P54U_READ
749
750 fail:
751 release_firmware(fw_entry);
752 kfree(buf);
753 return err;
754}
755
756static int p54u_open(struct ieee80211_hw *dev)
757{
758 struct p54u_priv *priv = dev->priv;
759 int err;
760
761 err = p54u_init_urbs(dev);
762 if (err) {
763 return err;
764 }
765
766 priv->common.open = p54u_init_urbs;
767
768 return 0;
769}
770
771static void p54u_stop(struct ieee80211_hw *dev)
772{
773 /* TODO: figure out how to reliably stop the 3887 and net2280 so
774 the hardware is still usable next time we want to start it.
775 until then, we just stop listening to the hardware.. */
776 p54u_free_urbs(dev);
777 return;
778}
779
780static int __devinit p54u_probe(struct usb_interface *intf,
781 const struct usb_device_id *id)
782{
783 struct usb_device *udev = interface_to_usbdev(intf);
784 struct ieee80211_hw *dev;
785 struct p54u_priv *priv;
786 int err;
787 unsigned int i, recognized_pipes;
788 DECLARE_MAC_BUF(mac);
789
790 dev = p54_init_common(sizeof(*priv));
791 if (!dev) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200792 printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700793 return -ENOMEM;
794 }
795
796 priv = dev->priv;
797
798 SET_IEEE80211_DEV(dev, &intf->dev);
799 usb_set_intfdata(intf, dev);
800 priv->udev = udev;
801
802 usb_get_dev(udev);
803
804 /* really lazy and simple way of figuring out if we're a 3887 */
805 /* TODO: should just stick the identification in the device table */
806 i = intf->altsetting->desc.bNumEndpoints;
807 recognized_pipes = 0;
808 while (i--) {
809 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
810 case P54U_PIPE_DATA:
811 case P54U_PIPE_MGMT:
812 case P54U_PIPE_BRG:
813 case P54U_PIPE_DEV:
814 case P54U_PIPE_DATA | USB_DIR_IN:
815 case P54U_PIPE_MGMT | USB_DIR_IN:
816 case P54U_PIPE_BRG | USB_DIR_IN:
817 case P54U_PIPE_DEV | USB_DIR_IN:
818 case P54U_PIPE_INT | USB_DIR_IN:
819 recognized_pipes++;
820 }
821 }
822 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200823 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700824 if (recognized_pipes < P54U_PIPE_NUMBER) {
825 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200826 err = p54u_upload_firmware_3887(dev);
827 if (priv->common.fw_interface == FW_LM87) {
828 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
829 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
830 priv->common.tx = p54u_tx_lm87;
831 } else
832 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700833 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200834 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700835 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
836 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
837 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700838 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200839 }
Michael Wueff1a592007-09-25 18:11:01 -0700840 if (err)
841 goto err_free_dev;
842
Christian Lamparter7cb77072008-09-01 22:48:51 +0200843 skb_queue_head_init(&priv->rx_queue);
844
845 p54u_open(dev);
846 err = p54_read_eeprom(dev);
847 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700848 if (err)
849 goto err_free_dev;
850
Michael Wueff1a592007-09-25 18:11:01 -0700851 err = ieee80211_register_hw(dev);
852 if (err) {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200853 printk(KERN_ERR "p54usb: Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700854 goto err_free_dev;
855 }
856
Michael Wueff1a592007-09-25 18:11:01 -0700857 return 0;
858
859 err_free_dev:
860 ieee80211_free_hw(dev);
861 usb_set_intfdata(intf, NULL);
862 usb_put_dev(udev);
863 return err;
864}
865
866static void __devexit p54u_disconnect(struct usb_interface *intf)
867{
868 struct ieee80211_hw *dev = usb_get_intfdata(intf);
869 struct p54u_priv *priv;
870
871 if (!dev)
872 return;
873
874 ieee80211_unregister_hw(dev);
875
876 priv = dev->priv;
877 usb_put_dev(interface_to_usbdev(intf));
878 p54_free_common(dev);
879 ieee80211_free_hw(dev);
880}
881
882static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200883 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700884 .id_table = p54u_table,
885 .probe = p54u_probe,
886 .disconnect = p54u_disconnect,
887};
888
889static int __init p54u_init(void)
890{
891 return usb_register(&p54u_driver);
892}
893
894static void __exit p54u_exit(void)
895{
896 usb_deregister(&p54u_driver);
897}
898
899module_init(p54u_init);
900module_exit(p54u_exit);