blob: f4d28c39aac794bfedb75855226e6773614ae583 [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
Michael Wueff1a592007-09-25 18:11:01 -070045static struct usb_device_id p54u_table[] __devinitdata = {
46 /* 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 */
Hans de Goede05a9a162010-03-17 14:37:16 +010050 {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
Michael Wueff1a592007-09-25 18:11:01 -070051 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090052 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070053 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
54 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050055 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070056 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
57 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
58 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020059 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Christian Lamparter22010762011-04-02 11:31:29 +020060 {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */
Michael Wueff1a592007-09-25 18:11:01 -070061 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010062 {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
Christian Lamparter1a927952010-10-01 22:01:24 +020063 {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
Michael Wueff1a592007-09-25 18:11:01 -070064 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010065 {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
Eduardo Costa56e64172010-12-14 14:37:59 -060066 {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
Christian Lamparter1a927952010-10-01 22:01:24 +020067 {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010068 {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
Michael Wueff1a592007-09-25 18:11:01 -070069 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
70 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
71 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
72 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
Christian Lamparter22010762011-04-02 11:31:29 +020073 {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */
Michael Wueff1a592007-09-25 18:11:01 -070074 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
75 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
76
77 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070078 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070079 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
80 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
81 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Christian Lamparter1a927952010-10-01 22:01:24 +020082 {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
Michiel878e6a42009-01-04 17:22:28 -060083 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070084 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
85 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Christian Lamparter9368a9a2011-05-13 21:47:23 +020086 {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060087 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070088 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
89 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
90 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
91 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
92 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070093 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
94 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070095 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020096 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070097 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070098 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020099 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -0500100 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -0400101 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +0200102 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700103 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter1a927952010-10-01 22:01:24 +0200104 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Christian Lamparter2b799a62011-02-26 12:58:06 +0100105 {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */
Michael Wueff1a592007-09-25 18:11:01 -0700106 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +0100107 {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
Jason Dravet0f666a02010-06-05 15:08:29 -0500108 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700109 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
110 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
111 {}
112};
113
114MODULE_DEVICE_TABLE(usb, p54u_table);
115
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200116static const struct {
117 u32 intf;
118 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200119 const char *fw;
120 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200121 char hw[20];
122} p54u_fwlist[__NUM_P54U_HWTYPES] = {
123 {
124 .type = P54U_NET2280,
125 .intf = FW_LM86,
126 .fw = "isl3886usb",
127 .fw_legacy = "isl3890usb",
128 .hw = "ISL3886 + net2280",
129 },
130 {
131 .type = P54U_3887,
132 .intf = FW_LM87,
133 .fw = "isl3887usb",
134 .fw_legacy = "isl3887usb_bare",
135 .hw = "ISL3887",
136 },
137};
138
Michael Wueff1a592007-09-25 18:11:01 -0700139static void p54u_rx_cb(struct urb *urb)
140{
141 struct sk_buff *skb = (struct sk_buff *) urb->context;
142 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
143 struct ieee80211_hw *dev = info->dev;
144 struct p54u_priv *priv = dev->priv;
145
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100146 skb_unlink(skb, &priv->rx_queue);
147
Michael Wueff1a592007-09-25 18:11:01 -0700148 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100149 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700150 return;
151 }
152
Michael Wueff1a592007-09-25 18:11:01 -0700153 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200154
155 if (priv->hw_type == P54U_NET2280)
156 skb_pull(skb, priv->common.tx_hdr_len);
157 if (priv->common.fw_interface == FW_LM87) {
158 skb_pull(skb, 4);
159 skb_put(skb, 4);
160 }
Michael Wueff1a592007-09-25 18:11:01 -0700161
162 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200163 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700164 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700165 /* TODO check rx queue length and refill *somewhere* */
166 return;
167 }
168
169 info = (struct p54u_rx_info *) skb->cb;
170 info->urb = urb;
171 info->dev = dev;
172 urb->transfer_buffer = skb_tail_pointer(skb);
173 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700174 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200175 if (priv->hw_type == P54U_NET2280)
176 skb_push(skb, priv->common.tx_hdr_len);
177 if (priv->common.fw_interface == FW_LM87) {
178 skb_push(skb, 4);
179 skb_put(skb, 4);
180 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200181 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700182 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200183 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700184 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100185 skb_queue_tail(&priv->rx_queue, skb);
186 usb_anchor_urb(urb, &priv->submitted);
187 if (usb_submit_urb(urb, GFP_ATOMIC)) {
188 skb_unlink(skb, &priv->rx_queue);
189 usb_unanchor_urb(urb);
190 dev_kfree_skb_irq(skb);
191 }
Michael Wueff1a592007-09-25 18:11:01 -0700192}
193
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100194static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200195{
196 struct sk_buff *skb = urb->context;
Joe Perchesb2767362010-11-30 13:42:08 -0800197 struct ieee80211_hw *dev =
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200198 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
199
Christian Lampartere2fe1542009-01-20 00:27:57 +0100200 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100201}
202
203static void p54u_tx_dummy_cb(struct urb *urb) { }
204
205static void p54u_free_urbs(struct ieee80211_hw *dev)
206{
207 struct p54u_priv *priv = dev->priv;
208 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200209}
210
Michael Wueff1a592007-09-25 18:11:01 -0700211static int p54u_init_urbs(struct ieee80211_hw *dev)
212{
213 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100214 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700215 struct sk_buff *skb;
216 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100217 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700218
219 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200220 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100221 if (!skb) {
222 ret = -ENOMEM;
223 goto err;
224 }
Michael Wueff1a592007-09-25 18:11:01 -0700225 entry = usb_alloc_urb(0, GFP_KERNEL);
226 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100227 ret = -ENOMEM;
228 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700229 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100230
Christian Lamparter4e416a62008-09-01 22:48:41 +0200231 usb_fill_bulk_urb(entry, priv->udev,
232 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
233 skb_tail_pointer(skb),
234 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700235 info = (struct p54u_rx_info *) skb->cb;
236 info->urb = entry;
237 info->dev = dev;
238 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100239
240 usb_anchor_urb(entry, &priv->submitted);
241 ret = usb_submit_urb(entry, GFP_KERNEL);
242 if (ret) {
243 skb_unlink(skb, &priv->rx_queue);
244 usb_unanchor_urb(entry);
245 goto err;
246 }
247 usb_free_urb(entry);
248 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700249 }
250
251 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700252
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100253 err:
254 usb_free_urb(entry);
255 kfree_skb(skb);
256 p54u_free_urbs(dev);
257 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700258}
259
Johannes Bergc9127652008-12-01 18:19:36 +0100260static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200261{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500262 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200263
264 length >>= 2;
265 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100266 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200267 chk = (chk >> 5) ^ (chk << 3);
268 }
269
Larry Finger1f1c0e32008-09-25 14:54:28 -0500270 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200271}
272
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100273static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200274{
275 struct p54u_priv *priv = dev->priv;
276 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100277 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200278
279 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200280 if (!data_urb) {
281 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200282 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200283 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200284
Christian Lampartere2fe1542009-01-20 00:27:57 +0100285 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
286 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200287
288 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200289 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100290 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
291 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100292 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200293
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100294 usb_anchor_urb(data_urb, &priv->submitted);
295 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
296 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100297 p54_free_skb(dev, skb);
298 }
299 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200300}
301
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100302static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700303{
304 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200305 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100306 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200307 struct net2280_reg_write *reg = NULL;
308 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700309
310 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
311 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200312 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700313
314 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200315 if (!int_urb)
316 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700317
318 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200319 if (!data_urb)
320 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700321
322 reg->port = cpu_to_le16(NET2280_DEV_U32);
323 reg->addr = cpu_to_le32(P54U_DEV_BASE);
324 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
325
Michael Wueff1a592007-09-25 18:11:01 -0700326 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100327 hdr->len = cpu_to_le16(skb->len);
328 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700329
330 usb_fill_bulk_urb(int_urb, priv->udev,
331 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100332 p54u_tx_dummy_cb, dev);
333
334 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200335 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
336 * free what is inside the transfer_buffer after the last reference to
337 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100338 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100339 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200340 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700341
342 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200343 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100344 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
345 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100346 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100347
348 usb_anchor_urb(int_urb, &priv->submitted);
349 err = usb_submit_urb(int_urb, GFP_ATOMIC);
350 if (err) {
351 usb_unanchor_urb(int_urb);
352 goto out;
353 }
354
355 usb_anchor_urb(data_urb, &priv->submitted);
356 err = usb_submit_urb(data_urb, GFP_ATOMIC);
357 if (err) {
358 usb_unanchor_urb(data_urb);
359 goto out;
360 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200361out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100362 usb_free_urb(int_urb);
363 usb_free_urb(data_urb);
364
365 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200366 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100367 p54_free_skb(dev, skb);
368 }
Michael Wueff1a592007-09-25 18:11:01 -0700369}
370
371static int p54u_write(struct p54u_priv *priv,
372 struct net2280_reg_write *buf,
373 enum net2280_op_type type,
374 __le32 addr, __le32 val)
375{
376 unsigned int ep;
377 int alen;
378
379 if (type & 0x0800)
380 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
381 else
382 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
383
384 buf->port = cpu_to_le16(type);
385 buf->addr = addr;
386 buf->val = val;
387
388 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
389}
390
391static int p54u_read(struct p54u_priv *priv, void *buf,
392 enum net2280_op_type type,
393 __le32 addr, __le32 *val)
394{
395 struct net2280_reg_read *read = buf;
396 __le32 *reg = buf;
397 unsigned int ep;
398 int alen, err;
399
400 if (type & 0x0800)
401 ep = P54U_PIPE_DEV;
402 else
403 ep = P54U_PIPE_BRG;
404
405 read->port = cpu_to_le16(type);
406 read->addr = addr;
407
408 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
409 read, sizeof(*read), &alen, 1000);
410 if (err)
411 return err;
412
413 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
414 reg, sizeof(*reg), &alen, 1000);
415 if (err)
416 return err;
417
418 *val = *reg;
419 return 0;
420}
421
422static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
423 void *data, size_t len)
424{
425 int alen;
426 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
427 data, len, &alen, 2000);
428}
429
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200430static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100431{
432 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100433 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100434
Christian Lamparterc88a7682009-01-16 20:24:31 +0100435 if (lock) {
436 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
437 if (ret < 0) {
438 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200439 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100440 return ret;
441 }
Christian Lamparter69828692008-12-26 19:08:31 +0100442 }
443
444 ret = usb_reset_device(priv->udev);
445 if (lock)
446 usb_unlock_device(priv->udev);
447
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200448 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100449 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200450 "device (%d)!\n", ret);
451
452 return ret;
453}
454
455static const char p54u_romboot_3887[] = "~~~~";
456static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
457{
458 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600459 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200460 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100461
Julia Lawall27b81bb2010-05-15 23:22:55 +0200462 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600463 if (!buf)
464 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100465 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600466 buf, 4);
467 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100468 if (ret)
469 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200470 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100471
472 return ret;
473}
474
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200475static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700476static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
477{
Michael Wueff1a592007-09-25 18:11:01 -0700478 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700479 int err, alen;
480 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100481 u8 *buf, *tmp;
482 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700483 unsigned int left, remains, block_size;
484 struct x2_header *hdr;
485 unsigned long timeout;
486
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200487 err = p54u_firmware_reset_3887(dev);
488 if (err)
489 return err;
490
Michael Wueff1a592007-09-25 18:11:01 -0700491 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
492 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100493 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
494 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200495 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700496 }
497
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200498 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100499 strcpy(buf, p54u_firmware_upload_3887);
500 left -= strlen(p54u_firmware_upload_3887);
501 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700502
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200503 data = priv->fw->data;
504 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700505
Christian Lamparter69828692008-12-26 19:08:31 +0100506 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700507 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
508 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200509 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700510 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
511 sizeof(u32)*2));
512 left -= sizeof(*hdr);
513 tmp += sizeof(*hdr);
514
515 while (remains) {
516 while (left--) {
517 if (carry) {
518 *tmp++ = carry;
519 carry = 0;
520 remains--;
521 continue;
522 }
523 switch (*data) {
524 case '~':
525 *tmp++ = '}';
526 carry = '^';
527 break;
528 case '}':
529 *tmp++ = '}';
530 carry = ']';
531 break;
532 default:
533 *tmp++ = *data;
534 remains--;
535 break;
536 }
537 data++;
538 }
539
540 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
541 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100542 dev_err(&priv->udev->dev, "(p54usb) firmware "
543 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700544 goto err_upload_failed;
545 }
546
547 tmp = buf;
548 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
549 }
550
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200551 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
552 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700553 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
554 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100555 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700556 goto err_upload_failed;
557 }
Michael Wueff1a592007-09-25 18:11:01 -0700558 timeout = jiffies + msecs_to_jiffies(1000);
559 while (!(err = usb_bulk_msg(priv->udev,
560 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
561 if (alen > 2 && !memcmp(buf, "OK", 2))
562 break;
563
564 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700565 err = -EINVAL;
566 break;
567 }
568
569 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100570 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
571 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700572 err = -ETIMEDOUT;
573 break;
574 }
575 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100576 if (err) {
577 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700578 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100579 }
Michael Wueff1a592007-09-25 18:11:01 -0700580
581 buf[0] = 'g';
582 buf[1] = '\r';
583 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
584 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100585 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700586 goto err_upload_failed;
587 }
588
589 timeout = jiffies + msecs_to_jiffies(1000);
590 while (!(err = usb_bulk_msg(priv->udev,
591 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
592 if (alen > 0 && buf[0] == 'g')
593 break;
594
595 if (time_after(jiffies, timeout)) {
596 err = -ETIMEDOUT;
597 break;
598 }
599 }
600 if (err)
601 goto err_upload_failed;
602
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200603err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700604 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700605 return err;
606}
607
608static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
609{
610 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700611 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
612 int err, alen;
613 void *buf;
614 __le32 reg;
615 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100616 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700617
618 buf = kmalloc(512, GFP_KERNEL);
619 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100620 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
621 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700622 return -ENOMEM;
623 }
624
Michael Wueff1a592007-09-25 18:11:01 -0700625#define P54U_WRITE(type, addr, data) \
626 do {\
627 err = p54u_write(priv, buf, type,\
628 cpu_to_le32((u32)(unsigned long)addr), data);\
629 if (err) \
630 goto fail;\
631 } while (0)
632
633#define P54U_READ(type, addr) \
634 do {\
635 err = p54u_read(priv, buf, type,\
636 cpu_to_le32((u32)(unsigned long)addr), &reg);\
637 if (err)\
638 goto fail;\
639 } while (0)
640
641 /* power down net2280 bridge */
642 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
643 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
644 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
645 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
646
647 mdelay(100);
648
649 /* power up bridge */
650 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
651 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
652 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
653
654 mdelay(100);
655
656 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
657 cpu_to_le32(NET2280_CLK_30Mhz |
658 NET2280_PCI_ENABLE |
659 NET2280_PCI_SOFT_RESET));
660
661 mdelay(20);
662
663 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
664 cpu_to_le32(PCI_COMMAND_MEMORY |
665 PCI_COMMAND_MASTER));
666
667 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
668 cpu_to_le32(NET2280_BASE));
669
670 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
671 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
672 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
673
674 // TODO: we really need this?
675 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
676
677 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
678 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
679 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
680 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
681
682 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
683 cpu_to_le32(NET2280_BASE2));
684
685 /* finally done setting up the bridge */
686
687 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
688 cpu_to_le32(PCI_COMMAND_MEMORY |
689 PCI_COMMAND_MASTER));
690
691 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
692 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
693 cpu_to_le32(P54U_DEV_BASE));
694
695 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
696 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
697 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
698
699 /* do romboot */
700 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
701
702 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
703 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
704 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
705 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
706 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
707
708 mdelay(20);
709
710 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
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(100);
719
720 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
721 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
722
723 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200724 remains = priv->fw->size;
725 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700726 offset = ISL38XX_DEV_FIRMWARE_ADDR;
727
728 while (remains) {
729 unsigned int block_len = min(remains, (unsigned int)512);
730 memcpy(buf, data, block_len);
731
732 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
733 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100734 dev_err(&priv->udev->dev, "(p54usb) firmware block "
735 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700736 goto fail;
737 }
738
739 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
740 cpu_to_le32(0xc0000f00));
741
742 P54U_WRITE(NET2280_DEV_U32,
743 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
744 P54U_WRITE(NET2280_DEV_U32,
745 0x0020 | (unsigned long)&devreg->direct_mem_win,
746 cpu_to_le32(1));
747
748 P54U_WRITE(NET2280_DEV_U32,
749 0x0024 | (unsigned long)&devreg->direct_mem_win,
750 cpu_to_le32(block_len));
751 P54U_WRITE(NET2280_DEV_U32,
752 0x0028 | (unsigned long)&devreg->direct_mem_win,
753 cpu_to_le32(offset));
754
755 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
756 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
757 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
758 cpu_to_le32(block_len >> 2));
759 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
760 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
761
762 mdelay(10);
763
764 P54U_READ(NET2280_DEV_U32,
765 0x002C | (unsigned long)&devreg->direct_mem_win);
766 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
767 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100768 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
769 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700770 goto fail;
771 }
772
773 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
774 cpu_to_le32(NET2280_FIFO_FLUSH));
775
776 remains -= block_len;
777 data += block_len;
778 offset += block_len;
779 }
780
781 /* do ramboot */
782 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
783 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
784 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
785 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
786 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
787
788 mdelay(20);
789
790 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
791 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
792
793 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
794 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
795
796 mdelay(100);
797
798 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
799 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
800
801 /* start up the firmware */
802 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
803 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
804
805 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
806 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
807
808 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
809 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
810 NET2280_USB_INTERRUPT_ENABLE));
811
812 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
813 cpu_to_le32(ISL38XX_DEV_INT_RESET));
814
815 err = usb_interrupt_msg(priv->udev,
816 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
817 buf, sizeof(__le32), &alen, 1000);
818 if (err || alen != sizeof(__le32))
819 goto fail;
820
821 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
822 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
823
824 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
825 err = -EINVAL;
826
827 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
828 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
829 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
830
831#undef P54U_WRITE
832#undef P54U_READ
833
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200834fail:
Michael Wueff1a592007-09-25 18:11:01 -0700835 kfree(buf);
836 return err;
837}
838
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200839static int p54u_load_firmware(struct ieee80211_hw *dev)
840{
841 struct p54u_priv *priv = dev->priv;
842 int err, i;
843
844 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
845
846 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
847 if (p54u_fwlist[i].type == priv->hw_type)
848 break;
849
850 if (i == __NUM_P54U_HWTYPES)
851 return -EOPNOTSUPP;
852
853 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
854 if (err) {
855 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
856 "(%d)!\n", p54u_fwlist[i].fw, err);
857
858 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
859 &priv->udev->dev);
860 if (err)
861 return err;
862 }
863
864 err = p54_parse_firmware(dev, priv->fw);
865 if (err)
866 goto out;
867
868 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
869 dev_err(&priv->udev->dev, "wrong firmware, please get "
870 "a firmware for \"%s\" and try again.\n",
871 p54u_fwlist[i].hw);
872 err = -EINVAL;
873 }
874
875out:
876 if (err)
877 release_firmware(priv->fw);
878
879 return err;
880}
881
Michael Wueff1a592007-09-25 18:11:01 -0700882static int p54u_open(struct ieee80211_hw *dev)
883{
884 struct p54u_priv *priv = dev->priv;
885 int err;
886
887 err = p54u_init_urbs(dev);
888 if (err) {
889 return err;
890 }
891
892 priv->common.open = p54u_init_urbs;
893
894 return 0;
895}
896
897static void p54u_stop(struct ieee80211_hw *dev)
898{
899 /* TODO: figure out how to reliably stop the 3887 and net2280 so
900 the hardware is still usable next time we want to start it.
901 until then, we just stop listening to the hardware.. */
902 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700903}
904
905static int __devinit p54u_probe(struct usb_interface *intf,
906 const struct usb_device_id *id)
907{
908 struct usb_device *udev = interface_to_usbdev(intf);
909 struct ieee80211_hw *dev;
910 struct p54u_priv *priv;
911 int err;
912 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700913
914 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100915
Michael Wueff1a592007-09-25 18:11:01 -0700916 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100917 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700918 return -ENOMEM;
919 }
920
921 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200922 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700923
924 SET_IEEE80211_DEV(dev, &intf->dev);
925 usb_set_intfdata(intf, dev);
926 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100927 priv->intf = intf;
928 skb_queue_head_init(&priv->rx_queue);
929 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700930
931 usb_get_dev(udev);
932
933 /* really lazy and simple way of figuring out if we're a 3887 */
934 /* TODO: should just stick the identification in the device table */
935 i = intf->altsetting->desc.bNumEndpoints;
936 recognized_pipes = 0;
937 while (i--) {
938 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
939 case P54U_PIPE_DATA:
940 case P54U_PIPE_MGMT:
941 case P54U_PIPE_BRG:
942 case P54U_PIPE_DEV:
943 case P54U_PIPE_DATA | USB_DIR_IN:
944 case P54U_PIPE_MGMT | USB_DIR_IN:
945 case P54U_PIPE_BRG | USB_DIR_IN:
946 case P54U_PIPE_DEV | USB_DIR_IN:
947 case P54U_PIPE_INT | USB_DIR_IN:
948 recognized_pipes++;
949 }
950 }
951 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200952 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700953 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200954#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200955 /* ISL3887 needs a full reset on resume */
956 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200957#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200958 err = p54u_device_reset(dev);
959
Michael Wueff1a592007-09-25 18:11:01 -0700960 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200961 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
962 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
963 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200964 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700965 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200966 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700967 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
968 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
969 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200970 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200971 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200972 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700973 if (err)
974 goto err_free_dev;
975
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200976 err = priv->upload_fw(dev);
977 if (err)
978 goto err_free_fw;
979
Christian Lamparter7cb77072008-09-01 22:48:51 +0200980 p54u_open(dev);
981 err = p54_read_eeprom(dev);
982 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700983 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200984 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700985
Christian Lamparter2ac71072009-03-05 21:30:10 +0100986 err = p54_register_common(dev, &udev->dev);
987 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200988 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700989
Michael Wueff1a592007-09-25 18:11:01 -0700990 return 0;
991
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200992err_free_fw:
993 release_firmware(priv->fw);
994
995err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500996 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700997 usb_set_intfdata(intf, NULL);
998 usb_put_dev(udev);
999 return err;
1000}
1001
1002static void __devexit p54u_disconnect(struct usb_interface *intf)
1003{
1004 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1005 struct p54u_priv *priv;
1006
1007 if (!dev)
1008 return;
1009
Christian Lamparterd8c92102009-06-23 10:39:45 -05001010 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001011
1012 priv = dev->priv;
1013 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001014 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001015 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001016}
1017
Christian Lamparter69828692008-12-26 19:08:31 +01001018static int p54u_pre_reset(struct usb_interface *intf)
1019{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001020 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1021
1022 if (!dev)
1023 return -ENODEV;
1024
1025 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001026 return 0;
1027}
1028
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001029static int p54u_resume(struct usb_interface *intf)
1030{
1031 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1032 struct p54u_priv *priv;
1033
1034 if (!dev)
1035 return -ENODEV;
1036
1037 priv = dev->priv;
1038 if (unlikely(!(priv->upload_fw && priv->fw)))
1039 return 0;
1040
1041 return priv->upload_fw(dev);
1042}
1043
Christian Lamparter69828692008-12-26 19:08:31 +01001044static int p54u_post_reset(struct usb_interface *intf)
1045{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001046 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1047 struct p54u_priv *priv;
1048 int err;
1049
1050 err = p54u_resume(intf);
1051 if (err)
1052 return err;
1053
1054 /* reinitialize old device state */
1055 priv = dev->priv;
1056 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1057 ieee80211_restart_hw(dev);
1058
Christian Lamparter69828692008-12-26 19:08:31 +01001059 return 0;
1060}
1061
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001062#ifdef CONFIG_PM
1063
1064static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1065{
1066 return p54u_pre_reset(intf);
1067}
1068
1069#endif /* CONFIG_PM */
1070
Michael Wueff1a592007-09-25 18:11:01 -07001071static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001072 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001073 .id_table = p54u_table,
1074 .probe = p54u_probe,
1075 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001076 .pre_reset = p54u_pre_reset,
1077 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001078#ifdef CONFIG_PM
1079 .suspend = p54u_suspend,
1080 .resume = p54u_resume,
1081 .reset_resume = p54u_resume,
1082#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001083 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001084};
1085
Greg Kroah-Hartmand632eb12011-11-18 09:44:20 -08001086module_usb_driver(p54u_driver);