blob: af30777ce31f264edec78c9e2b55bb6e9d37a739 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Michael Wueff1a592007-09-25 18:11:01 -070019#include <linux/firmware.h>
20#include <linux/etherdevice.h>
21#include <linux/delay.h>
22#include <linux/crc32.h>
Paul Gortmaker9d9779e2011-07-03 15:21:01 -040023#include <linux/module.h>
Michael Wueff1a592007-09-25 18:11:01 -070024#include <net/mac80211.h>
25
26#include "p54.h"
Christian Lamparterd8c92102009-06-23 10:39:45 -050027#include "lmac.h"
Michael Wueff1a592007-09-25 18:11:01 -070028#include "p54usb.h"
29
30MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
31MODULE_DESCRIPTION("Prism54 USB wireless driver");
32MODULE_LICENSE("GPL");
33MODULE_ALIAS("prism54usb");
Christian Lamparter9a8675d2008-10-18 23:04:15 +020034MODULE_FIRMWARE("isl3886usb");
35MODULE_FIRMWARE("isl3887usb");
Michael Wueff1a592007-09-25 18:11:01 -070036
Christian Lamparter1a927952010-10-01 22:01:24 +020037/*
38 * Note:
39 *
40 * Always update our wiki's device list (located at:
41 * http://wireless.kernel.org/en/users/Drivers/p54/devices ),
42 * whenever you add a new device.
43 */
44
Greg Kroah-Hartman37037e12012-08-17 17:48:28 -070045static struct usb_device_id p54u_table[] = {
Michael Wueff1a592007-09-25 18:11:01 -070046 /* Version 1 devices (pci chip + net2280) */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010047 {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */
Christian Lamparter1a927952010-10-01 22:01:24 +020048 {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
Michael Wueff1a592007-09-25 18:11:01 -070049 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
Christian Lamparter44c818b2012-12-27 15:18:20 +010050 {USB_DEVICE(0x0675, 0x0530)}, /* DrayTek Vigor 530 */
Hans de Goede05a9a162010-03-17 14:37:16 +010051 {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
Michael Wueff1a592007-09-25 18:11:01 -070052 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090053 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070054 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
55 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050056 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070057 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
58 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
59 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020060 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Christian Lamparter22010762011-04-02 11:31:29 +020061 {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */
Michael Wueff1a592007-09-25 18:11:01 -070062 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010063 {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
Christian Lamparter1a927952010-10-01 22:01:24 +020064 {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
Michael Wueff1a592007-09-25 18:11:01 -070065 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010066 {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
Eduardo Costa56e64172010-12-14 14:37:59 -060067 {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
Christian Lamparter1a927952010-10-01 22:01:24 +020068 {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010069 {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
Michael Wueff1a592007-09-25 18:11:01 -070070 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
71 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
72 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
73 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
Christian Lamparter22010762011-04-02 11:31:29 +020074 {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */
Michael Wueff1a592007-09-25 18:11:01 -070075 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
76 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
77
78 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070079 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070080 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
81 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
82 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Christian Lamparter1a927952010-10-01 22:01:24 +020083 {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
Michiel878e6a42009-01-04 17:22:28 -060084 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070085 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
Christian Lamparter44c818b2012-12-27 15:18:20 +010086 {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */
Michael Wueff1a592007-09-25 18:11:01 -070087 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Tomasz Guszkowskia8fb02f2013-02-05 22:10:31 +010088 {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */
Christian Lamparter9368a9a2011-05-13 21:47:23 +020089 {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060090 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070091 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
92 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
93 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
94 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
95 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070096 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
97 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070098 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020099 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -0700100 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -0700101 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +0200102 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -0500103 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -0400104 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +0200105 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700106 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter44c818b2012-12-27 15:18:20 +0100107 /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */
Christian Lamparter1a927952010-10-01 22:01:24 +0200108 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Christian Lamparter2b799a62011-02-26 12:58:06 +0100109 {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */
Michael Wueff1a592007-09-25 18:11:01 -0700110 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +0100111 {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
Jason Dravet0f666a02010-06-05 15:08:29 -0500112 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700113 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
114 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
115 {}
116};
117
118MODULE_DEVICE_TABLE(usb, p54u_table);
119
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200120static const struct {
121 u32 intf;
122 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200123 const char *fw;
124 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200125 char hw[20];
126} p54u_fwlist[__NUM_P54U_HWTYPES] = {
127 {
128 .type = P54U_NET2280,
129 .intf = FW_LM86,
130 .fw = "isl3886usb",
131 .fw_legacy = "isl3890usb",
132 .hw = "ISL3886 + net2280",
133 },
134 {
135 .type = P54U_3887,
136 .intf = FW_LM87,
137 .fw = "isl3887usb",
138 .fw_legacy = "isl3887usb_bare",
139 .hw = "ISL3887",
140 },
141};
142
Michael Wueff1a592007-09-25 18:11:01 -0700143static void p54u_rx_cb(struct urb *urb)
144{
145 struct sk_buff *skb = (struct sk_buff *) urb->context;
146 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
147 struct ieee80211_hw *dev = info->dev;
148 struct p54u_priv *priv = dev->priv;
149
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100150 skb_unlink(skb, &priv->rx_queue);
151
Michael Wueff1a592007-09-25 18:11:01 -0700152 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100153 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700154 return;
155 }
156
Michael Wueff1a592007-09-25 18:11:01 -0700157 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200158
159 if (priv->hw_type == P54U_NET2280)
160 skb_pull(skb, priv->common.tx_hdr_len);
161 if (priv->common.fw_interface == FW_LM87) {
162 skb_pull(skb, 4);
163 skb_put(skb, 4);
164 }
Michael Wueff1a592007-09-25 18:11:01 -0700165
166 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200167 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700168 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700169 /* TODO check rx queue length and refill *somewhere* */
170 return;
171 }
172
173 info = (struct p54u_rx_info *) skb->cb;
174 info->urb = urb;
175 info->dev = dev;
176 urb->transfer_buffer = skb_tail_pointer(skb);
177 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700178 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200179 if (priv->hw_type == P54U_NET2280)
180 skb_push(skb, priv->common.tx_hdr_len);
181 if (priv->common.fw_interface == FW_LM87) {
182 skb_push(skb, 4);
183 skb_put(skb, 4);
184 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200185 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700186 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200187 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700188 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100189 skb_queue_tail(&priv->rx_queue, skb);
190 usb_anchor_urb(urb, &priv->submitted);
191 if (usb_submit_urb(urb, GFP_ATOMIC)) {
192 skb_unlink(skb, &priv->rx_queue);
193 usb_unanchor_urb(urb);
194 dev_kfree_skb_irq(skb);
195 }
Michael Wueff1a592007-09-25 18:11:01 -0700196}
197
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100198static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200199{
200 struct sk_buff *skb = urb->context;
Joe Perchesb2767362010-11-30 13:42:08 -0800201 struct ieee80211_hw *dev =
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200202 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
203
Christian Lampartere2fe1542009-01-20 00:27:57 +0100204 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100205}
206
207static void p54u_tx_dummy_cb(struct urb *urb) { }
208
209static void p54u_free_urbs(struct ieee80211_hw *dev)
210{
211 struct p54u_priv *priv = dev->priv;
212 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200213}
214
Michael Wueff1a592007-09-25 18:11:01 -0700215static int p54u_init_urbs(struct ieee80211_hw *dev)
216{
217 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100218 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700219 struct sk_buff *skb;
220 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100221 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700222
223 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200224 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100225 if (!skb) {
226 ret = -ENOMEM;
227 goto err;
228 }
Michael Wueff1a592007-09-25 18:11:01 -0700229 entry = usb_alloc_urb(0, GFP_KERNEL);
230 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100231 ret = -ENOMEM;
232 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700233 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100234
Christian Lamparter4e416a62008-09-01 22:48:41 +0200235 usb_fill_bulk_urb(entry, priv->udev,
236 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
237 skb_tail_pointer(skb),
238 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700239 info = (struct p54u_rx_info *) skb->cb;
240 info->urb = entry;
241 info->dev = dev;
242 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100243
244 usb_anchor_urb(entry, &priv->submitted);
245 ret = usb_submit_urb(entry, GFP_KERNEL);
246 if (ret) {
247 skb_unlink(skb, &priv->rx_queue);
248 usb_unanchor_urb(entry);
249 goto err;
250 }
251 usb_free_urb(entry);
252 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700253 }
254
255 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700256
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100257 err:
258 usb_free_urb(entry);
259 kfree_skb(skb);
260 p54u_free_urbs(dev);
261 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700262}
263
Johannes Bergc9127652008-12-01 18:19:36 +0100264static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200265{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500266 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200267
268 length >>= 2;
269 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100270 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200271 chk = (chk >> 5) ^ (chk << 3);
272 }
273
Larry Finger1f1c0e32008-09-25 14:54:28 -0500274 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200275}
276
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100277static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200278{
279 struct p54u_priv *priv = dev->priv;
280 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100281 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200282
283 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200284 if (!data_urb) {
285 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200286 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200287 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200288
Christian Lampartere2fe1542009-01-20 00:27:57 +0100289 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
290 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200291
292 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200293 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100294 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
295 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100296 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200297
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100298 usb_anchor_urb(data_urb, &priv->submitted);
299 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
300 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100301 p54_free_skb(dev, skb);
302 }
303 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200304}
305
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100306static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700307{
308 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200309 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100310 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200311 struct net2280_reg_write *reg = NULL;
312 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700313
314 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
315 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200316 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700317
318 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200319 if (!int_urb)
320 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700321
322 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200323 if (!data_urb)
324 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700325
326 reg->port = cpu_to_le16(NET2280_DEV_U32);
327 reg->addr = cpu_to_le32(P54U_DEV_BASE);
328 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
329
Michael Wueff1a592007-09-25 18:11:01 -0700330 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100331 hdr->len = cpu_to_le16(skb->len);
332 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700333
334 usb_fill_bulk_urb(int_urb, priv->udev,
335 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100336 p54u_tx_dummy_cb, dev);
337
338 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200339 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
340 * free what is inside the transfer_buffer after the last reference to
341 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100342 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100343 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200344 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700345
346 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200347 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100348 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
349 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100350 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100351
352 usb_anchor_urb(int_urb, &priv->submitted);
353 err = usb_submit_urb(int_urb, GFP_ATOMIC);
354 if (err) {
355 usb_unanchor_urb(int_urb);
356 goto out;
357 }
358
359 usb_anchor_urb(data_urb, &priv->submitted);
360 err = usb_submit_urb(data_urb, GFP_ATOMIC);
361 if (err) {
362 usb_unanchor_urb(data_urb);
363 goto out;
364 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200365out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100366 usb_free_urb(int_urb);
367 usb_free_urb(data_urb);
368
369 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200370 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100371 p54_free_skb(dev, skb);
372 }
Michael Wueff1a592007-09-25 18:11:01 -0700373}
374
375static int p54u_write(struct p54u_priv *priv,
376 struct net2280_reg_write *buf,
377 enum net2280_op_type type,
378 __le32 addr, __le32 val)
379{
380 unsigned int ep;
381 int alen;
382
383 if (type & 0x0800)
384 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
385 else
386 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
387
388 buf->port = cpu_to_le16(type);
389 buf->addr = addr;
390 buf->val = val;
391
392 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
393}
394
395static int p54u_read(struct p54u_priv *priv, void *buf,
396 enum net2280_op_type type,
397 __le32 addr, __le32 *val)
398{
399 struct net2280_reg_read *read = buf;
400 __le32 *reg = buf;
401 unsigned int ep;
402 int alen, err;
403
404 if (type & 0x0800)
405 ep = P54U_PIPE_DEV;
406 else
407 ep = P54U_PIPE_BRG;
408
409 read->port = cpu_to_le16(type);
410 read->addr = addr;
411
412 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
413 read, sizeof(*read), &alen, 1000);
414 if (err)
415 return err;
416
417 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
418 reg, sizeof(*reg), &alen, 1000);
419 if (err)
420 return err;
421
422 *val = *reg;
423 return 0;
424}
425
426static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
427 void *data, size_t len)
428{
429 int alen;
430 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
431 data, len, &alen, 2000);
432}
433
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200434static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100435{
436 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100437 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100438
Christian Lamparterc88a7682009-01-16 20:24:31 +0100439 if (lock) {
440 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
441 if (ret < 0) {
442 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200443 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100444 return ret;
445 }
Christian Lamparter69828692008-12-26 19:08:31 +0100446 }
447
448 ret = usb_reset_device(priv->udev);
449 if (lock)
450 usb_unlock_device(priv->udev);
451
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200452 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100453 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200454 "device (%d)!\n", ret);
455
456 return ret;
457}
458
459static const char p54u_romboot_3887[] = "~~~~";
460static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
461{
462 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600463 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200464 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100465
Julia Lawall27b81bb2010-05-15 23:22:55 +0200466 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600467 if (!buf)
468 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100469 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600470 buf, 4);
471 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100472 if (ret)
473 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200474 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100475
476 return ret;
477}
478
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200479static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700480static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
481{
Michael Wueff1a592007-09-25 18:11:01 -0700482 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700483 int err, alen;
484 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100485 u8 *buf, *tmp;
486 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700487 unsigned int left, remains, block_size;
488 struct x2_header *hdr;
489 unsigned long timeout;
490
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200491 err = p54u_firmware_reset_3887(dev);
492 if (err)
493 return err;
494
Michael Wueff1a592007-09-25 18:11:01 -0700495 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
496 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100497 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
498 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200499 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700500 }
501
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200502 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100503 strcpy(buf, p54u_firmware_upload_3887);
504 left -= strlen(p54u_firmware_upload_3887);
505 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700506
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200507 data = priv->fw->data;
508 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700509
Christian Lamparter69828692008-12-26 19:08:31 +0100510 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700511 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
512 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200513 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700514 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
515 sizeof(u32)*2));
516 left -= sizeof(*hdr);
517 tmp += sizeof(*hdr);
518
519 while (remains) {
520 while (left--) {
521 if (carry) {
522 *tmp++ = carry;
523 carry = 0;
524 remains--;
525 continue;
526 }
527 switch (*data) {
528 case '~':
529 *tmp++ = '}';
530 carry = '^';
531 break;
532 case '}':
533 *tmp++ = '}';
534 carry = ']';
535 break;
536 default:
537 *tmp++ = *data;
538 remains--;
539 break;
540 }
541 data++;
542 }
543
544 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
545 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100546 dev_err(&priv->udev->dev, "(p54usb) firmware "
547 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700548 goto err_upload_failed;
549 }
550
551 tmp = buf;
552 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
553 }
554
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200555 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
556 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700557 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
558 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100559 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700560 goto err_upload_failed;
561 }
Michael Wueff1a592007-09-25 18:11:01 -0700562 timeout = jiffies + msecs_to_jiffies(1000);
563 while (!(err = usb_bulk_msg(priv->udev,
564 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
565 if (alen > 2 && !memcmp(buf, "OK", 2))
566 break;
567
568 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700569 err = -EINVAL;
570 break;
571 }
572
573 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100574 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
575 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700576 err = -ETIMEDOUT;
577 break;
578 }
579 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100580 if (err) {
581 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700582 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100583 }
Michael Wueff1a592007-09-25 18:11:01 -0700584
585 buf[0] = 'g';
586 buf[1] = '\r';
587 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
588 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100589 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700590 goto err_upload_failed;
591 }
592
593 timeout = jiffies + msecs_to_jiffies(1000);
594 while (!(err = usb_bulk_msg(priv->udev,
595 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
596 if (alen > 0 && buf[0] == 'g')
597 break;
598
599 if (time_after(jiffies, timeout)) {
600 err = -ETIMEDOUT;
601 break;
602 }
603 }
604 if (err)
605 goto err_upload_failed;
606
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200607err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700608 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700609 return err;
610}
611
612static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
613{
614 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700615 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
616 int err, alen;
617 void *buf;
618 __le32 reg;
619 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100620 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700621
622 buf = kmalloc(512, GFP_KERNEL);
623 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100624 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
625 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700626 return -ENOMEM;
627 }
628
Michael Wueff1a592007-09-25 18:11:01 -0700629#define P54U_WRITE(type, addr, data) \
630 do {\
631 err = p54u_write(priv, buf, type,\
632 cpu_to_le32((u32)(unsigned long)addr), data);\
633 if (err) \
634 goto fail;\
635 } while (0)
636
637#define P54U_READ(type, addr) \
638 do {\
639 err = p54u_read(priv, buf, type,\
640 cpu_to_le32((u32)(unsigned long)addr), &reg);\
641 if (err)\
642 goto fail;\
643 } while (0)
644
645 /* power down net2280 bridge */
646 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
647 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
648 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
649 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
650
651 mdelay(100);
652
653 /* power up bridge */
654 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
655 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
656 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
657
658 mdelay(100);
659
660 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
661 cpu_to_le32(NET2280_CLK_30Mhz |
662 NET2280_PCI_ENABLE |
663 NET2280_PCI_SOFT_RESET));
664
665 mdelay(20);
666
667 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
668 cpu_to_le32(PCI_COMMAND_MEMORY |
669 PCI_COMMAND_MASTER));
670
671 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
672 cpu_to_le32(NET2280_BASE));
673
674 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
675 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
676 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
677
678 // TODO: we really need this?
679 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
680
681 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
682 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
683 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
684 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
685
686 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
687 cpu_to_le32(NET2280_BASE2));
688
689 /* finally done setting up the bridge */
690
691 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
692 cpu_to_le32(PCI_COMMAND_MEMORY |
693 PCI_COMMAND_MASTER));
694
695 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
696 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
697 cpu_to_le32(P54U_DEV_BASE));
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 /* do romboot */
704 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
705
706 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
707 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
708 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
709 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
710 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
711
712 mdelay(20);
713
714 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
715 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
716
717 mdelay(20);
718
719 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
720 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
721
722 mdelay(100);
723
724 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
725 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
726
727 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200728 remains = priv->fw->size;
729 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700730 offset = ISL38XX_DEV_FIRMWARE_ADDR;
731
732 while (remains) {
733 unsigned int block_len = min(remains, (unsigned int)512);
734 memcpy(buf, data, block_len);
735
736 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
737 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100738 dev_err(&priv->udev->dev, "(p54usb) firmware block "
739 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700740 goto fail;
741 }
742
743 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
744 cpu_to_le32(0xc0000f00));
745
746 P54U_WRITE(NET2280_DEV_U32,
747 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
748 P54U_WRITE(NET2280_DEV_U32,
749 0x0020 | (unsigned long)&devreg->direct_mem_win,
750 cpu_to_le32(1));
751
752 P54U_WRITE(NET2280_DEV_U32,
753 0x0024 | (unsigned long)&devreg->direct_mem_win,
754 cpu_to_le32(block_len));
755 P54U_WRITE(NET2280_DEV_U32,
756 0x0028 | (unsigned long)&devreg->direct_mem_win,
757 cpu_to_le32(offset));
758
759 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
760 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
761 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
762 cpu_to_le32(block_len >> 2));
763 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
764 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
765
766 mdelay(10);
767
768 P54U_READ(NET2280_DEV_U32,
769 0x002C | (unsigned long)&devreg->direct_mem_win);
770 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
771 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100772 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
773 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700774 goto fail;
775 }
776
777 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
778 cpu_to_le32(NET2280_FIFO_FLUSH));
779
780 remains -= block_len;
781 data += block_len;
782 offset += block_len;
783 }
784
785 /* do ramboot */
786 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
787 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
788 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
789 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
790 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
791
792 mdelay(20);
793
794 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
795 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
796
797 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
798 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
799
800 mdelay(100);
801
802 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
803 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
804
805 /* start up the firmware */
806 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
807 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
808
809 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
810 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
811
812 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
813 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
814 NET2280_USB_INTERRUPT_ENABLE));
815
816 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
817 cpu_to_le32(ISL38XX_DEV_INT_RESET));
818
819 err = usb_interrupt_msg(priv->udev,
820 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
821 buf, sizeof(__le32), &alen, 1000);
822 if (err || alen != sizeof(__le32))
823 goto fail;
824
825 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
826 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
827
828 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
829 err = -EINVAL;
830
831 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
832 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
833 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
834
835#undef P54U_WRITE
836#undef P54U_READ
837
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200838fail:
Michael Wueff1a592007-09-25 18:11:01 -0700839 kfree(buf);
840 return err;
841}
842
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200843static int p54u_load_firmware(struct ieee80211_hw *dev)
844{
845 struct p54u_priv *priv = dev->priv;
846 int err, i;
847
848 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
849
850 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
851 if (p54u_fwlist[i].type == priv->hw_type)
852 break;
853
854 if (i == __NUM_P54U_HWTYPES)
855 return -EOPNOTSUPP;
856
857 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
858 if (err) {
859 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
860 "(%d)!\n", p54u_fwlist[i].fw, err);
861
862 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
863 &priv->udev->dev);
864 if (err)
865 return err;
866 }
867
868 err = p54_parse_firmware(dev, priv->fw);
869 if (err)
870 goto out;
871
872 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
873 dev_err(&priv->udev->dev, "wrong firmware, please get "
874 "a firmware for \"%s\" and try again.\n",
875 p54u_fwlist[i].hw);
876 err = -EINVAL;
877 }
878
879out:
880 if (err)
881 release_firmware(priv->fw);
882
883 return err;
884}
885
Michael Wueff1a592007-09-25 18:11:01 -0700886static int p54u_open(struct ieee80211_hw *dev)
887{
888 struct p54u_priv *priv = dev->priv;
889 int err;
890
891 err = p54u_init_urbs(dev);
892 if (err) {
893 return err;
894 }
895
896 priv->common.open = p54u_init_urbs;
897
898 return 0;
899}
900
901static void p54u_stop(struct ieee80211_hw *dev)
902{
903 /* TODO: figure out how to reliably stop the 3887 and net2280 so
904 the hardware is still usable next time we want to start it.
905 until then, we just stop listening to the hardware.. */
906 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700907}
908
909static int __devinit p54u_probe(struct usb_interface *intf,
910 const struct usb_device_id *id)
911{
912 struct usb_device *udev = interface_to_usbdev(intf);
913 struct ieee80211_hw *dev;
914 struct p54u_priv *priv;
915 int err;
916 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700917
918 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100919
Michael Wueff1a592007-09-25 18:11:01 -0700920 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100921 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700922 return -ENOMEM;
923 }
924
925 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200926 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700927
928 SET_IEEE80211_DEV(dev, &intf->dev);
929 usb_set_intfdata(intf, dev);
930 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100931 priv->intf = intf;
932 skb_queue_head_init(&priv->rx_queue);
933 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700934
935 usb_get_dev(udev);
936
937 /* really lazy and simple way of figuring out if we're a 3887 */
938 /* TODO: should just stick the identification in the device table */
939 i = intf->altsetting->desc.bNumEndpoints;
940 recognized_pipes = 0;
941 while (i--) {
942 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
943 case P54U_PIPE_DATA:
944 case P54U_PIPE_MGMT:
945 case P54U_PIPE_BRG:
946 case P54U_PIPE_DEV:
947 case P54U_PIPE_DATA | USB_DIR_IN:
948 case P54U_PIPE_MGMT | USB_DIR_IN:
949 case P54U_PIPE_BRG | USB_DIR_IN:
950 case P54U_PIPE_DEV | USB_DIR_IN:
951 case P54U_PIPE_INT | USB_DIR_IN:
952 recognized_pipes++;
953 }
954 }
955 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200956 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700957 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200958#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200959 /* ISL3887 needs a full reset on resume */
960 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200961#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200962 err = p54u_device_reset(dev);
963
Michael Wueff1a592007-09-25 18:11:01 -0700964 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200965 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
966 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
967 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200968 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700969 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200970 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700971 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
972 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
973 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200974 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200975 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200976 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700977 if (err)
978 goto err_free_dev;
979
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200980 err = priv->upload_fw(dev);
981 if (err)
982 goto err_free_fw;
983
Christian Lamparter7cb77072008-09-01 22:48:51 +0200984 p54u_open(dev);
985 err = p54_read_eeprom(dev);
986 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700987 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200988 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700989
Christian Lamparter2ac71072009-03-05 21:30:10 +0100990 err = p54_register_common(dev, &udev->dev);
991 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200992 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700993
Michael Wueff1a592007-09-25 18:11:01 -0700994 return 0;
995
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200996err_free_fw:
997 release_firmware(priv->fw);
998
999err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -05001000 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001001 usb_set_intfdata(intf, NULL);
1002 usb_put_dev(udev);
1003 return err;
1004}
1005
1006static void __devexit p54u_disconnect(struct usb_interface *intf)
1007{
1008 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1009 struct p54u_priv *priv;
1010
1011 if (!dev)
1012 return;
1013
Christian Lamparterd8c92102009-06-23 10:39:45 -05001014 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001015
1016 priv = dev->priv;
1017 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001018 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001019 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001020}
1021
Christian Lamparter69828692008-12-26 19:08:31 +01001022static int p54u_pre_reset(struct usb_interface *intf)
1023{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001024 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1025
1026 if (!dev)
1027 return -ENODEV;
1028
1029 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001030 return 0;
1031}
1032
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001033static int p54u_resume(struct usb_interface *intf)
1034{
1035 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1036 struct p54u_priv *priv;
1037
1038 if (!dev)
1039 return -ENODEV;
1040
1041 priv = dev->priv;
1042 if (unlikely(!(priv->upload_fw && priv->fw)))
1043 return 0;
1044
1045 return priv->upload_fw(dev);
1046}
1047
Christian Lamparter69828692008-12-26 19:08:31 +01001048static int p54u_post_reset(struct usb_interface *intf)
1049{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001050 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1051 struct p54u_priv *priv;
1052 int err;
1053
1054 err = p54u_resume(intf);
1055 if (err)
1056 return err;
1057
1058 /* reinitialize old device state */
1059 priv = dev->priv;
1060 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1061 ieee80211_restart_hw(dev);
1062
Christian Lamparter69828692008-12-26 19:08:31 +01001063 return 0;
1064}
1065
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001066#ifdef CONFIG_PM
1067
1068static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1069{
1070 return p54u_pre_reset(intf);
1071}
1072
1073#endif /* CONFIG_PM */
1074
Michael Wueff1a592007-09-25 18:11:01 -07001075static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001076 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001077 .id_table = p54u_table,
1078 .probe = p54u_probe,
1079 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001080 .pre_reset = p54u_pre_reset,
1081 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001082#ifdef CONFIG_PM
1083 .suspend = p54u_suspend,
1084 .resume = p54u_resume,
1085 .reset_resume = p54u_resume,
1086#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001087 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001088};
1089
Greg Kroah-Hartmand632eb12011-11-18 09:44:20 -08001090module_usb_driver(p54u_driver);