blob: c31ac08d647ce9ec479ff5c786c9361920e324ea [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 Lamparter30472682013-09-24 21:56:46 +020086 {USB_DEVICE(0x07aa, 0x0020)}, /* Corega WLUSB2GTST USB */
Christian Lamparter44c818b2012-12-27 15:18:20 +010087 {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */
Michael Wueff1a592007-09-25 18:11:01 -070088 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Tomasz Guszkowskia8fb02f2013-02-05 22:10:31 +010089 {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */
Christian Lamparter9368a9a2011-05-13 21:47:23 +020090 {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060091 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070092 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
93 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
94 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
95 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
96 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070097 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
98 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070099 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +0200100 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -0700101 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -0700102 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +0200103 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -0500104 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -0400105 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +0200106 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700107 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter44c818b2012-12-27 15:18:20 +0100108 /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */
Christian Lamparter1a927952010-10-01 22:01:24 +0200109 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Christian Lamparter2b799a62011-02-26 12:58:06 +0100110 {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */
Michael Wueff1a592007-09-25 18:11:01 -0700111 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +0100112 {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
Jason Dravet0f666a02010-06-05 15:08:29 -0500113 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700114 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
115 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
116 {}
117};
118
119MODULE_DEVICE_TABLE(usb, p54u_table);
120
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200121static const struct {
122 u32 intf;
123 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200124 const char *fw;
125 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200126 char hw[20];
127} p54u_fwlist[__NUM_P54U_HWTYPES] = {
128 {
129 .type = P54U_NET2280,
130 .intf = FW_LM86,
131 .fw = "isl3886usb",
132 .fw_legacy = "isl3890usb",
133 .hw = "ISL3886 + net2280",
134 },
135 {
136 .type = P54U_3887,
137 .intf = FW_LM87,
138 .fw = "isl3887usb",
139 .fw_legacy = "isl3887usb_bare",
140 .hw = "ISL3887",
141 },
142};
143
Michael Wueff1a592007-09-25 18:11:01 -0700144static void p54u_rx_cb(struct urb *urb)
145{
146 struct sk_buff *skb = (struct sk_buff *) urb->context;
147 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
148 struct ieee80211_hw *dev = info->dev;
149 struct p54u_priv *priv = dev->priv;
150
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100151 skb_unlink(skb, &priv->rx_queue);
152
Michael Wueff1a592007-09-25 18:11:01 -0700153 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100154 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700155 return;
156 }
157
Michael Wueff1a592007-09-25 18:11:01 -0700158 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200159
160 if (priv->hw_type == P54U_NET2280)
161 skb_pull(skb, priv->common.tx_hdr_len);
162 if (priv->common.fw_interface == FW_LM87) {
163 skb_pull(skb, 4);
164 skb_put(skb, 4);
165 }
Michael Wueff1a592007-09-25 18:11:01 -0700166
167 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200168 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700169 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700170 /* TODO check rx queue length and refill *somewhere* */
171 return;
172 }
173
174 info = (struct p54u_rx_info *) skb->cb;
175 info->urb = urb;
176 info->dev = dev;
177 urb->transfer_buffer = skb_tail_pointer(skb);
178 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700179 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200180 if (priv->hw_type == P54U_NET2280)
181 skb_push(skb, priv->common.tx_hdr_len);
182 if (priv->common.fw_interface == FW_LM87) {
183 skb_push(skb, 4);
184 skb_put(skb, 4);
185 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200186 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700187 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200188 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700189 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100190 skb_queue_tail(&priv->rx_queue, skb);
191 usb_anchor_urb(urb, &priv->submitted);
192 if (usb_submit_urb(urb, GFP_ATOMIC)) {
193 skb_unlink(skb, &priv->rx_queue);
194 usb_unanchor_urb(urb);
195 dev_kfree_skb_irq(skb);
196 }
Michael Wueff1a592007-09-25 18:11:01 -0700197}
198
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100199static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200200{
201 struct sk_buff *skb = urb->context;
Joe Perchesb2767362010-11-30 13:42:08 -0800202 struct ieee80211_hw *dev =
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200203 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
204
Christian Lampartere2fe1542009-01-20 00:27:57 +0100205 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100206}
207
208static void p54u_tx_dummy_cb(struct urb *urb) { }
209
210static void p54u_free_urbs(struct ieee80211_hw *dev)
211{
212 struct p54u_priv *priv = dev->priv;
213 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200214}
215
Michael Wueff1a592007-09-25 18:11:01 -0700216static int p54u_init_urbs(struct ieee80211_hw *dev)
217{
218 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100219 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700220 struct sk_buff *skb;
221 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100222 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700223
224 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200225 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100226 if (!skb) {
227 ret = -ENOMEM;
228 goto err;
229 }
Michael Wueff1a592007-09-25 18:11:01 -0700230 entry = usb_alloc_urb(0, GFP_KERNEL);
231 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100232 ret = -ENOMEM;
233 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700234 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100235
Christian Lamparter4e416a62008-09-01 22:48:41 +0200236 usb_fill_bulk_urb(entry, priv->udev,
237 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
238 skb_tail_pointer(skb),
239 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700240 info = (struct p54u_rx_info *) skb->cb;
241 info->urb = entry;
242 info->dev = dev;
243 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100244
245 usb_anchor_urb(entry, &priv->submitted);
246 ret = usb_submit_urb(entry, GFP_KERNEL);
247 if (ret) {
248 skb_unlink(skb, &priv->rx_queue);
249 usb_unanchor_urb(entry);
250 goto err;
251 }
252 usb_free_urb(entry);
253 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700254 }
255
256 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700257
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100258 err:
259 usb_free_urb(entry);
260 kfree_skb(skb);
261 p54u_free_urbs(dev);
262 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700263}
264
Johannes Bergc9127652008-12-01 18:19:36 +0100265static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200266{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500267 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200268
269 length >>= 2;
270 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100271 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200272 chk = (chk >> 5) ^ (chk << 3);
273 }
274
Larry Finger1f1c0e32008-09-25 14:54:28 -0500275 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200276}
277
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100278static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200279{
280 struct p54u_priv *priv = dev->priv;
281 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100282 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200283
284 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200285 if (!data_urb) {
286 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200287 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200288 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200289
Christian Lampartere2fe1542009-01-20 00:27:57 +0100290 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
291 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200292
293 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200294 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100295 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
296 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100297 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200298
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100299 usb_anchor_urb(data_urb, &priv->submitted);
300 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
301 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100302 p54_free_skb(dev, skb);
303 }
304 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200305}
306
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100307static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700308{
309 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200310 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100311 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200312 struct net2280_reg_write *reg = NULL;
313 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700314
315 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
316 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200317 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700318
319 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200320 if (!int_urb)
321 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700322
323 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200324 if (!data_urb)
325 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700326
327 reg->port = cpu_to_le16(NET2280_DEV_U32);
328 reg->addr = cpu_to_le32(P54U_DEV_BASE);
329 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
330
Michael Wueff1a592007-09-25 18:11:01 -0700331 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100332 hdr->len = cpu_to_le16(skb->len);
333 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700334
335 usb_fill_bulk_urb(int_urb, priv->udev,
336 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100337 p54u_tx_dummy_cb, dev);
338
339 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200340 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
341 * free what is inside the transfer_buffer after the last reference to
342 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100343 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100344 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200345 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700346
347 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200348 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100349 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
350 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100351 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100352
353 usb_anchor_urb(int_urb, &priv->submitted);
354 err = usb_submit_urb(int_urb, GFP_ATOMIC);
355 if (err) {
356 usb_unanchor_urb(int_urb);
357 goto out;
358 }
359
360 usb_anchor_urb(data_urb, &priv->submitted);
361 err = usb_submit_urb(data_urb, GFP_ATOMIC);
362 if (err) {
363 usb_unanchor_urb(data_urb);
364 goto out;
365 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200366out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100367 usb_free_urb(int_urb);
368 usb_free_urb(data_urb);
369
370 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200371 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100372 p54_free_skb(dev, skb);
373 }
Michael Wueff1a592007-09-25 18:11:01 -0700374}
375
376static int p54u_write(struct p54u_priv *priv,
377 struct net2280_reg_write *buf,
378 enum net2280_op_type type,
379 __le32 addr, __le32 val)
380{
381 unsigned int ep;
382 int alen;
383
384 if (type & 0x0800)
385 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
386 else
387 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
388
389 buf->port = cpu_to_le16(type);
390 buf->addr = addr;
391 buf->val = val;
392
393 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
394}
395
396static int p54u_read(struct p54u_priv *priv, void *buf,
397 enum net2280_op_type type,
398 __le32 addr, __le32 *val)
399{
400 struct net2280_reg_read *read = buf;
401 __le32 *reg = buf;
402 unsigned int ep;
403 int alen, err;
404
405 if (type & 0x0800)
406 ep = P54U_PIPE_DEV;
407 else
408 ep = P54U_PIPE_BRG;
409
410 read->port = cpu_to_le16(type);
411 read->addr = addr;
412
413 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
414 read, sizeof(*read), &alen, 1000);
415 if (err)
416 return err;
417
418 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
419 reg, sizeof(*reg), &alen, 1000);
420 if (err)
421 return err;
422
423 *val = *reg;
424 return 0;
425}
426
427static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
428 void *data, size_t len)
429{
430 int alen;
431 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
432 data, len, &alen, 2000);
433}
434
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200435static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100436{
437 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100438 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100439
Christian Lamparterc88a7682009-01-16 20:24:31 +0100440 if (lock) {
441 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
442 if (ret < 0) {
443 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200444 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100445 return ret;
446 }
Christian Lamparter69828692008-12-26 19:08:31 +0100447 }
448
449 ret = usb_reset_device(priv->udev);
450 if (lock)
451 usb_unlock_device(priv->udev);
452
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200453 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100454 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200455 "device (%d)!\n", ret);
456
457 return ret;
458}
459
460static const char p54u_romboot_3887[] = "~~~~";
461static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
462{
463 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600464 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200465 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100466
Julia Lawall27b81bb2010-05-15 23:22:55 +0200467 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600468 if (!buf)
469 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100470 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600471 buf, 4);
472 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100473 if (ret)
474 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200475 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100476
477 return ret;
478}
479
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200480static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700481static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
482{
Michael Wueff1a592007-09-25 18:11:01 -0700483 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700484 int err, alen;
485 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100486 u8 *buf, *tmp;
487 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700488 unsigned int left, remains, block_size;
489 struct x2_header *hdr;
490 unsigned long timeout;
491
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200492 err = p54u_firmware_reset_3887(dev);
493 if (err)
494 return err;
495
Michael Wueff1a592007-09-25 18:11:01 -0700496 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
497 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100498 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
499 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200500 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700501 }
502
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200503 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100504 strcpy(buf, p54u_firmware_upload_3887);
505 left -= strlen(p54u_firmware_upload_3887);
506 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700507
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200508 data = priv->fw->data;
509 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700510
Christian Lamparter69828692008-12-26 19:08:31 +0100511 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700512 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
513 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200514 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700515 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
516 sizeof(u32)*2));
517 left -= sizeof(*hdr);
518 tmp += sizeof(*hdr);
519
520 while (remains) {
521 while (left--) {
522 if (carry) {
523 *tmp++ = carry;
524 carry = 0;
525 remains--;
526 continue;
527 }
528 switch (*data) {
529 case '~':
530 *tmp++ = '}';
531 carry = '^';
532 break;
533 case '}':
534 *tmp++ = '}';
535 carry = ']';
536 break;
537 default:
538 *tmp++ = *data;
539 remains--;
540 break;
541 }
542 data++;
543 }
544
545 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
546 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100547 dev_err(&priv->udev->dev, "(p54usb) firmware "
548 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700549 goto err_upload_failed;
550 }
551
552 tmp = buf;
553 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
554 }
555
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200556 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
557 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700558 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
559 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100560 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700561 goto err_upload_failed;
562 }
Michael Wueff1a592007-09-25 18:11:01 -0700563 timeout = jiffies + msecs_to_jiffies(1000);
564 while (!(err = usb_bulk_msg(priv->udev,
565 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
566 if (alen > 2 && !memcmp(buf, "OK", 2))
567 break;
568
569 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700570 err = -EINVAL;
571 break;
572 }
573
574 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100575 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
576 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700577 err = -ETIMEDOUT;
578 break;
579 }
580 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100581 if (err) {
582 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700583 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100584 }
Michael Wueff1a592007-09-25 18:11:01 -0700585
586 buf[0] = 'g';
587 buf[1] = '\r';
588 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
589 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100590 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700591 goto err_upload_failed;
592 }
593
594 timeout = jiffies + msecs_to_jiffies(1000);
595 while (!(err = usb_bulk_msg(priv->udev,
596 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
597 if (alen > 0 && buf[0] == 'g')
598 break;
599
600 if (time_after(jiffies, timeout)) {
601 err = -ETIMEDOUT;
602 break;
603 }
604 }
605 if (err)
606 goto err_upload_failed;
607
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200608err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700609 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700610 return err;
611}
612
613static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
614{
615 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700616 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
617 int err, alen;
618 void *buf;
619 __le32 reg;
620 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100621 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700622
623 buf = kmalloc(512, GFP_KERNEL);
624 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100625 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
626 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700627 return -ENOMEM;
628 }
629
Michael Wueff1a592007-09-25 18:11:01 -0700630#define P54U_WRITE(type, addr, data) \
631 do {\
632 err = p54u_write(priv, buf, type,\
633 cpu_to_le32((u32)(unsigned long)addr), data);\
634 if (err) \
635 goto fail;\
636 } while (0)
637
638#define P54U_READ(type, addr) \
639 do {\
640 err = p54u_read(priv, buf, type,\
641 cpu_to_le32((u32)(unsigned long)addr), &reg);\
642 if (err)\
643 goto fail;\
644 } while (0)
645
646 /* power down net2280 bridge */
647 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
648 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
649 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
650 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
651
652 mdelay(100);
653
654 /* power up bridge */
655 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
656 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
657 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
658
659 mdelay(100);
660
661 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
662 cpu_to_le32(NET2280_CLK_30Mhz |
663 NET2280_PCI_ENABLE |
664 NET2280_PCI_SOFT_RESET));
665
666 mdelay(20);
667
668 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
669 cpu_to_le32(PCI_COMMAND_MEMORY |
670 PCI_COMMAND_MASTER));
671
672 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
673 cpu_to_le32(NET2280_BASE));
674
675 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
676 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
677 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
678
679 // TODO: we really need this?
680 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
681
682 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
683 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
684 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
685 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
686
687 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
688 cpu_to_le32(NET2280_BASE2));
689
690 /* finally done setting up the bridge */
691
692 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
693 cpu_to_le32(PCI_COMMAND_MEMORY |
694 PCI_COMMAND_MASTER));
695
696 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
697 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
698 cpu_to_le32(P54U_DEV_BASE));
699
700 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
701 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
702 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
703
704 /* do romboot */
705 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
706
707 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
708 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
709 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
710 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
711 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
712
713 mdelay(20);
714
715 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
716 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
717
718 mdelay(20);
719
720 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
721 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
722
723 mdelay(100);
724
725 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
726 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
727
728 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200729 remains = priv->fw->size;
730 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700731 offset = ISL38XX_DEV_FIRMWARE_ADDR;
732
733 while (remains) {
734 unsigned int block_len = min(remains, (unsigned int)512);
735 memcpy(buf, data, block_len);
736
737 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
738 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100739 dev_err(&priv->udev->dev, "(p54usb) firmware block "
740 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700741 goto fail;
742 }
743
744 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
745 cpu_to_le32(0xc0000f00));
746
747 P54U_WRITE(NET2280_DEV_U32,
748 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
749 P54U_WRITE(NET2280_DEV_U32,
750 0x0020 | (unsigned long)&devreg->direct_mem_win,
751 cpu_to_le32(1));
752
753 P54U_WRITE(NET2280_DEV_U32,
754 0x0024 | (unsigned long)&devreg->direct_mem_win,
755 cpu_to_le32(block_len));
756 P54U_WRITE(NET2280_DEV_U32,
757 0x0028 | (unsigned long)&devreg->direct_mem_win,
758 cpu_to_le32(offset));
759
760 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
761 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
762 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
763 cpu_to_le32(block_len >> 2));
764 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
765 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
766
767 mdelay(10);
768
769 P54U_READ(NET2280_DEV_U32,
770 0x002C | (unsigned long)&devreg->direct_mem_win);
771 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
772 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100773 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
774 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700775 goto fail;
776 }
777
778 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
779 cpu_to_le32(NET2280_FIFO_FLUSH));
780
781 remains -= block_len;
782 data += block_len;
783 offset += block_len;
784 }
785
786 /* do ramboot */
787 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
788 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
789 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
790 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
791 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
792
793 mdelay(20);
794
795 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
796 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
797
798 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
799 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
800
801 mdelay(100);
802
803 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
804 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
805
806 /* start up the firmware */
807 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
808 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
809
810 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
811 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
812
813 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
814 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
815 NET2280_USB_INTERRUPT_ENABLE));
816
817 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
818 cpu_to_le32(ISL38XX_DEV_INT_RESET));
819
820 err = usb_interrupt_msg(priv->udev,
821 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
822 buf, sizeof(__le32), &alen, 1000);
823 if (err || alen != sizeof(__le32))
824 goto fail;
825
826 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
827 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
828
829 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
830 err = -EINVAL;
831
832 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
833 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
834 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
835
836#undef P54U_WRITE
837#undef P54U_READ
838
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200839fail:
Michael Wueff1a592007-09-25 18:11:01 -0700840 kfree(buf);
841 return err;
842}
843
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200844static int p54u_load_firmware(struct ieee80211_hw *dev)
845{
846 struct p54u_priv *priv = dev->priv;
847 int err, i;
848
849 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
850
851 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
852 if (p54u_fwlist[i].type == priv->hw_type)
853 break;
854
855 if (i == __NUM_P54U_HWTYPES)
856 return -EOPNOTSUPP;
857
858 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
859 if (err) {
860 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
861 "(%d)!\n", p54u_fwlist[i].fw, err);
862
863 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
864 &priv->udev->dev);
865 if (err)
866 return err;
867 }
868
869 err = p54_parse_firmware(dev, priv->fw);
870 if (err)
871 goto out;
872
873 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
874 dev_err(&priv->udev->dev, "wrong firmware, please get "
875 "a firmware for \"%s\" and try again.\n",
876 p54u_fwlist[i].hw);
877 err = -EINVAL;
878 }
879
880out:
881 if (err)
882 release_firmware(priv->fw);
883
884 return err;
885}
886
Michael Wueff1a592007-09-25 18:11:01 -0700887static int p54u_open(struct ieee80211_hw *dev)
888{
889 struct p54u_priv *priv = dev->priv;
890 int err;
891
892 err = p54u_init_urbs(dev);
893 if (err) {
894 return err;
895 }
896
897 priv->common.open = p54u_init_urbs;
898
899 return 0;
900}
901
902static void p54u_stop(struct ieee80211_hw *dev)
903{
904 /* TODO: figure out how to reliably stop the 3887 and net2280 so
905 the hardware is still usable next time we want to start it.
906 until then, we just stop listening to the hardware.. */
907 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700908}
909
910static int __devinit p54u_probe(struct usb_interface *intf,
911 const struct usb_device_id *id)
912{
913 struct usb_device *udev = interface_to_usbdev(intf);
914 struct ieee80211_hw *dev;
915 struct p54u_priv *priv;
916 int err;
917 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700918
919 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100920
Michael Wueff1a592007-09-25 18:11:01 -0700921 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100922 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700923 return -ENOMEM;
924 }
925
926 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200927 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700928
929 SET_IEEE80211_DEV(dev, &intf->dev);
930 usb_set_intfdata(intf, dev);
931 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100932 priv->intf = intf;
933 skb_queue_head_init(&priv->rx_queue);
934 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700935
936 usb_get_dev(udev);
937
938 /* really lazy and simple way of figuring out if we're a 3887 */
939 /* TODO: should just stick the identification in the device table */
940 i = intf->altsetting->desc.bNumEndpoints;
941 recognized_pipes = 0;
942 while (i--) {
943 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
944 case P54U_PIPE_DATA:
945 case P54U_PIPE_MGMT:
946 case P54U_PIPE_BRG:
947 case P54U_PIPE_DEV:
948 case P54U_PIPE_DATA | USB_DIR_IN:
949 case P54U_PIPE_MGMT | USB_DIR_IN:
950 case P54U_PIPE_BRG | USB_DIR_IN:
951 case P54U_PIPE_DEV | USB_DIR_IN:
952 case P54U_PIPE_INT | USB_DIR_IN:
953 recognized_pipes++;
954 }
955 }
956 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200957 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700958 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200959#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200960 /* ISL3887 needs a full reset on resume */
961 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200962#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200963 err = p54u_device_reset(dev);
964
Michael Wueff1a592007-09-25 18:11:01 -0700965 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200966 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
967 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
968 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200969 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700970 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200971 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700972 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
973 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
974 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200975 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200976 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200977 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700978 if (err)
979 goto err_free_dev;
980
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200981 err = priv->upload_fw(dev);
982 if (err)
983 goto err_free_fw;
984
Christian Lamparter7cb77072008-09-01 22:48:51 +0200985 p54u_open(dev);
986 err = p54_read_eeprom(dev);
987 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700988 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200989 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700990
Christian Lamparter2ac71072009-03-05 21:30:10 +0100991 err = p54_register_common(dev, &udev->dev);
992 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200993 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700994
Michael Wueff1a592007-09-25 18:11:01 -0700995 return 0;
996
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200997err_free_fw:
998 release_firmware(priv->fw);
999
1000err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -05001001 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001002 usb_set_intfdata(intf, NULL);
1003 usb_put_dev(udev);
1004 return err;
1005}
1006
1007static void __devexit p54u_disconnect(struct usb_interface *intf)
1008{
1009 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1010 struct p54u_priv *priv;
1011
1012 if (!dev)
1013 return;
1014
Christian Lamparterd8c92102009-06-23 10:39:45 -05001015 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001016
1017 priv = dev->priv;
1018 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001019 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001020 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001021}
1022
Christian Lamparter69828692008-12-26 19:08:31 +01001023static int p54u_pre_reset(struct usb_interface *intf)
1024{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001025 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1026
1027 if (!dev)
1028 return -ENODEV;
1029
1030 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001031 return 0;
1032}
1033
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001034static int p54u_resume(struct usb_interface *intf)
1035{
1036 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1037 struct p54u_priv *priv;
1038
1039 if (!dev)
1040 return -ENODEV;
1041
1042 priv = dev->priv;
1043 if (unlikely(!(priv->upload_fw && priv->fw)))
1044 return 0;
1045
1046 return priv->upload_fw(dev);
1047}
1048
Christian Lamparter69828692008-12-26 19:08:31 +01001049static int p54u_post_reset(struct usb_interface *intf)
1050{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001051 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1052 struct p54u_priv *priv;
1053 int err;
1054
1055 err = p54u_resume(intf);
1056 if (err)
1057 return err;
1058
1059 /* reinitialize old device state */
1060 priv = dev->priv;
1061 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1062 ieee80211_restart_hw(dev);
1063
Christian Lamparter69828692008-12-26 19:08:31 +01001064 return 0;
1065}
1066
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001067#ifdef CONFIG_PM
1068
1069static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1070{
1071 return p54u_pre_reset(intf);
1072}
1073
1074#endif /* CONFIG_PM */
1075
Michael Wueff1a592007-09-25 18:11:01 -07001076static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001077 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001078 .id_table = p54u_table,
1079 .probe = p54u_probe,
1080 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001081 .pre_reset = p54u_pre_reset,
1082 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001083#ifdef CONFIG_PM
1084 .suspend = p54u_suspend,
1085 .resume = p54u_resume,
1086 .reset_resume = p54u_resume,
1087#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001088 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001089};
1090
Greg Kroah-Hartmand632eb12011-11-18 09:44:20 -08001091module_usb_driver(p54u_driver);