blob: e9630b949256a890fa130948eb5b6edecda8e289 [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) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100408 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
409 "upload buffer!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700410 err = -ENOMEM;
411 goto err_bufalloc;
412 }
413
414 memcpy(buf, start_string, 4);
415 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
416 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100417 dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
Michael Wueff1a592007-09-25 18:11:01 -0700418 goto err_reset;
419 }
420
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200421 err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700422 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100423 dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
424 "(isl3887usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200425 err = request_firmware(&fw_entry, "isl3887usb_bare",
426 &priv->udev->dev);
427 if (err)
428 goto err_req_fw_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700429 }
430
Christian Lamparter4e416a62008-09-01 22:48:41 +0200431 err = p54_parse_firmware(dev, fw_entry);
432 if (err)
433 goto err_upload_failed;
Michael Wueff1a592007-09-25 18:11:01 -0700434
435 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
436 strcpy(buf, start_string);
437 left -= strlen(start_string);
438 tmp += strlen(start_string);
439
440 data = fw_entry->data;
441 remains = fw_entry->size;
442
443 hdr = (struct x2_header *)(buf + strlen(start_string));
444 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
445 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
446 hdr->fw_length = cpu_to_le32(fw_entry->size);
447 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
448 sizeof(u32)*2));
449 left -= sizeof(*hdr);
450 tmp += sizeof(*hdr);
451
452 while (remains) {
453 while (left--) {
454 if (carry) {
455 *tmp++ = carry;
456 carry = 0;
457 remains--;
458 continue;
459 }
460 switch (*data) {
461 case '~':
462 *tmp++ = '}';
463 carry = '^';
464 break;
465 case '}':
466 *tmp++ = '}';
467 carry = ']';
468 break;
469 default:
470 *tmp++ = *data;
471 remains--;
472 break;
473 }
474 data++;
475 }
476
477 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
478 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100479 dev_err(&priv->udev->dev, "(p54usb) firmware "
480 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700481 goto err_upload_failed;
482 }
483
484 tmp = buf;
485 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
486 }
487
488 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
489 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
490 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100491 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700492 goto err_upload_failed;
493 }
Michael Wueff1a592007-09-25 18:11:01 -0700494 timeout = jiffies + msecs_to_jiffies(1000);
495 while (!(err = usb_bulk_msg(priv->udev,
496 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
497 if (alen > 2 && !memcmp(buf, "OK", 2))
498 break;
499
500 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700501 err = -EINVAL;
502 break;
503 }
504
505 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100506 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
507 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700508 err = -ETIMEDOUT;
509 break;
510 }
511 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100512 if (err) {
513 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700514 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100515 }
Michael Wueff1a592007-09-25 18:11:01 -0700516
517 buf[0] = 'g';
518 buf[1] = '\r';
519 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
520 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100521 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700522 goto err_upload_failed;
523 }
524
525 timeout = jiffies + msecs_to_jiffies(1000);
526 while (!(err = usb_bulk_msg(priv->udev,
527 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
528 if (alen > 0 && buf[0] == 'g')
529 break;
530
531 if (time_after(jiffies, timeout)) {
532 err = -ETIMEDOUT;
533 break;
534 }
535 }
536 if (err)
537 goto err_upload_failed;
538
539 err_upload_failed:
540 release_firmware(fw_entry);
541 err_req_fw_failed:
542 err_reset:
543 kfree(buf);
544 err_bufalloc:
545 return err;
546}
547
548static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
549{
550 struct p54u_priv *priv = dev->priv;
551 const struct firmware *fw_entry = NULL;
552 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
553 int err, alen;
554 void *buf;
555 __le32 reg;
556 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100557 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700558
559 buf = kmalloc(512, GFP_KERNEL);
560 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100561 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
562 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700563 return -ENOMEM;
564 }
565
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200566 err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
Michael Wueff1a592007-09-25 18:11:01 -0700567 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100568 dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
569 "(isl3886usb)\n");
Christian Lamparter9a8675d2008-10-18 23:04:15 +0200570 err = request_firmware(&fw_entry, "isl3890usb",
571 &priv->udev->dev);
572 if (err) {
573 kfree(buf);
574 return err;
575 }
Michael Wueff1a592007-09-25 18:11:01 -0700576 }
577
Christian Lamparter4e416a62008-09-01 22:48:41 +0200578 err = p54_parse_firmware(dev, fw_entry);
579 if (err) {
580 kfree(buf);
581 release_firmware(fw_entry);
582 return err;
583 }
Michael Wueff1a592007-09-25 18:11:01 -0700584
585#define P54U_WRITE(type, addr, data) \
586 do {\
587 err = p54u_write(priv, buf, type,\
588 cpu_to_le32((u32)(unsigned long)addr), data);\
589 if (err) \
590 goto fail;\
591 } while (0)
592
593#define P54U_READ(type, addr) \
594 do {\
595 err = p54u_read(priv, buf, type,\
596 cpu_to_le32((u32)(unsigned long)addr), &reg);\
597 if (err)\
598 goto fail;\
599 } while (0)
600
601 /* power down net2280 bridge */
602 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
603 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
604 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
605 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
606
607 mdelay(100);
608
609 /* power up bridge */
610 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
611 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
612 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
613
614 mdelay(100);
615
616 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
617 cpu_to_le32(NET2280_CLK_30Mhz |
618 NET2280_PCI_ENABLE |
619 NET2280_PCI_SOFT_RESET));
620
621 mdelay(20);
622
623 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
624 cpu_to_le32(PCI_COMMAND_MEMORY |
625 PCI_COMMAND_MASTER));
626
627 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
628 cpu_to_le32(NET2280_BASE));
629
630 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
631 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
632 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
633
634 // TODO: we really need this?
635 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
636
637 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
638 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
639 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
640 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
641
642 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
643 cpu_to_le32(NET2280_BASE2));
644
645 /* finally done setting up the bridge */
646
647 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
648 cpu_to_le32(PCI_COMMAND_MEMORY |
649 PCI_COMMAND_MASTER));
650
651 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
652 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
653 cpu_to_le32(P54U_DEV_BASE));
654
655 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
656 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
657 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
658
659 /* do romboot */
660 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
661
662 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
663 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
664 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
665 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
666 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
667
668 mdelay(20);
669
670 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
671 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
672
673 mdelay(20);
674
675 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
676 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
677
678 mdelay(100);
679
680 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
681 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
682
683 /* finally, we can upload firmware now! */
684 remains = fw_entry->size;
685 data = fw_entry->data;
686 offset = ISL38XX_DEV_FIRMWARE_ADDR;
687
688 while (remains) {
689 unsigned int block_len = min(remains, (unsigned int)512);
690 memcpy(buf, data, block_len);
691
692 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
693 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100694 dev_err(&priv->udev->dev, "(p54usb) firmware block "
695 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700696 goto fail;
697 }
698
699 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
700 cpu_to_le32(0xc0000f00));
701
702 P54U_WRITE(NET2280_DEV_U32,
703 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
704 P54U_WRITE(NET2280_DEV_U32,
705 0x0020 | (unsigned long)&devreg->direct_mem_win,
706 cpu_to_le32(1));
707
708 P54U_WRITE(NET2280_DEV_U32,
709 0x0024 | (unsigned long)&devreg->direct_mem_win,
710 cpu_to_le32(block_len));
711 P54U_WRITE(NET2280_DEV_U32,
712 0x0028 | (unsigned long)&devreg->direct_mem_win,
713 cpu_to_le32(offset));
714
715 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
716 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
717 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
718 cpu_to_le32(block_len >> 2));
719 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
720 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
721
722 mdelay(10);
723
724 P54U_READ(NET2280_DEV_U32,
725 0x002C | (unsigned long)&devreg->direct_mem_win);
726 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
727 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100728 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
729 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700730 goto fail;
731 }
732
733 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
734 cpu_to_le32(NET2280_FIFO_FLUSH));
735
736 remains -= block_len;
737 data += block_len;
738 offset += block_len;
739 }
740
741 /* do ramboot */
742 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
743 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
744 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
745 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
746 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
747
748 mdelay(20);
749
750 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
751 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
752
753 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
754 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
755
756 mdelay(100);
757
758 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
759 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
760
761 /* start up the firmware */
762 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
763 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
764
765 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
766 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
767
768 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
769 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
770 NET2280_USB_INTERRUPT_ENABLE));
771
772 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
773 cpu_to_le32(ISL38XX_DEV_INT_RESET));
774
775 err = usb_interrupt_msg(priv->udev,
776 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
777 buf, sizeof(__le32), &alen, 1000);
778 if (err || alen != sizeof(__le32))
779 goto fail;
780
781 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
782 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
783
784 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
785 err = -EINVAL;
786
787 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
788 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
789 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
790
791#undef P54U_WRITE
792#undef P54U_READ
793
794 fail:
795 release_firmware(fw_entry);
796 kfree(buf);
797 return err;
798}
799
800static int p54u_open(struct ieee80211_hw *dev)
801{
802 struct p54u_priv *priv = dev->priv;
803 int err;
804
805 err = p54u_init_urbs(dev);
806 if (err) {
807 return err;
808 }
809
810 priv->common.open = p54u_init_urbs;
811
812 return 0;
813}
814
815static void p54u_stop(struct ieee80211_hw *dev)
816{
817 /* TODO: figure out how to reliably stop the 3887 and net2280 so
818 the hardware is still usable next time we want to start it.
819 until then, we just stop listening to the hardware.. */
820 p54u_free_urbs(dev);
821 return;
822}
823
824static int __devinit p54u_probe(struct usb_interface *intf,
825 const struct usb_device_id *id)
826{
827 struct usb_device *udev = interface_to_usbdev(intf);
828 struct ieee80211_hw *dev;
829 struct p54u_priv *priv;
830 int err;
831 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700832
833 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100834
Michael Wueff1a592007-09-25 18:11:01 -0700835 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100836 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700837 return -ENOMEM;
838 }
839
840 priv = dev->priv;
841
842 SET_IEEE80211_DEV(dev, &intf->dev);
843 usb_set_intfdata(intf, dev);
844 priv->udev = udev;
845
846 usb_get_dev(udev);
847
848 /* really lazy and simple way of figuring out if we're a 3887 */
849 /* TODO: should just stick the identification in the device table */
850 i = intf->altsetting->desc.bNumEndpoints;
851 recognized_pipes = 0;
852 while (i--) {
853 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
854 case P54U_PIPE_DATA:
855 case P54U_PIPE_MGMT:
856 case P54U_PIPE_BRG:
857 case P54U_PIPE_DEV:
858 case P54U_PIPE_DATA | USB_DIR_IN:
859 case P54U_PIPE_MGMT | USB_DIR_IN:
860 case P54U_PIPE_BRG | USB_DIR_IN:
861 case P54U_PIPE_DEV | USB_DIR_IN:
862 case P54U_PIPE_INT | USB_DIR_IN:
863 recognized_pipes++;
864 }
865 }
866 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200867 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700868 if (recognized_pipes < P54U_PIPE_NUMBER) {
869 priv->hw_type = P54U_3887;
Christian Lamparter2b808482008-09-04 12:29:38 +0200870 err = p54u_upload_firmware_3887(dev);
871 if (priv->common.fw_interface == FW_LM87) {
872 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
873 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
874 priv->common.tx = p54u_tx_lm87;
875 } else
876 priv->common.tx = p54u_tx_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700877 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200878 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700879 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
880 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
881 priv->common.tx = p54u_tx_net2280;
Michael Wueff1a592007-09-25 18:11:01 -0700882 err = p54u_upload_firmware_net2280(dev);
Christian Lamparter2b808482008-09-04 12:29:38 +0200883 }
Michael Wueff1a592007-09-25 18:11:01 -0700884 if (err)
885 goto err_free_dev;
886
Christian Lamparter7cb77072008-09-01 22:48:51 +0200887 skb_queue_head_init(&priv->rx_queue);
888
889 p54u_open(dev);
890 err = p54_read_eeprom(dev);
891 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700892 if (err)
893 goto err_free_dev;
894
Michael Wueff1a592007-09-25 18:11:01 -0700895 err = ieee80211_register_hw(dev);
896 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100897 dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
Michael Wueff1a592007-09-25 18:11:01 -0700898 goto err_free_dev;
899 }
900
Michael Wueff1a592007-09-25 18:11:01 -0700901 return 0;
902
903 err_free_dev:
904 ieee80211_free_hw(dev);
905 usb_set_intfdata(intf, NULL);
906 usb_put_dev(udev);
907 return err;
908}
909
910static void __devexit p54u_disconnect(struct usb_interface *intf)
911{
912 struct ieee80211_hw *dev = usb_get_intfdata(intf);
913 struct p54u_priv *priv;
914
915 if (!dev)
916 return;
917
918 ieee80211_unregister_hw(dev);
919
920 priv = dev->priv;
921 usb_put_dev(interface_to_usbdev(intf));
922 p54_free_common(dev);
923 ieee80211_free_hw(dev);
924}
925
926static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +0200927 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -0700928 .id_table = p54u_table,
929 .probe = p54u_probe,
930 .disconnect = p54u_disconnect,
931};
932
933static int __init p54u_init(void)
934{
935 return usb_register(&p54u_driver);
936}
937
938static void __exit p54u_exit(void)
939{
940 usb_deregister(&p54u_driver);
941}
942
943module_init(p54u_init);
944module_exit(p54u_exit);