blob: e18358725b69813077de8d9e55f8a98d5fa7a021 [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>
23#include <net/mac80211.h>
24
25#include "p54.h"
Christian Lamparterd8c92102009-06-23 10:39:45 -050026#include "lmac.h"
Michael Wueff1a592007-09-25 18:11:01 -070027#include "p54usb.h"
28
29MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
30MODULE_DESCRIPTION("Prism54 USB wireless driver");
31MODULE_LICENSE("GPL");
32MODULE_ALIAS("prism54usb");
Christian Lamparter9a8675d2008-10-18 23:04:15 +020033MODULE_FIRMWARE("isl3886usb");
34MODULE_FIRMWARE("isl3887usb");
Michael Wueff1a592007-09-25 18:11:01 -070035
Christian Lamparter1a927952010-10-01 22:01:24 +020036/*
37 * Note:
38 *
39 * Always update our wiki's device list (located at:
40 * http://wireless.kernel.org/en/users/Drivers/p54/devices ),
41 * whenever you add a new device.
42 */
43
Michael Wueff1a592007-09-25 18:11:01 -070044static struct usb_device_id p54u_table[] __devinitdata = {
45 /* Version 1 devices (pci chip + net2280) */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010046 {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */
Christian Lamparter1a927952010-10-01 22:01:24 +020047 {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
Michael Wueff1a592007-09-25 18:11:01 -070048 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
Hans de Goede05a9a162010-03-17 14:37:16 +010049 {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
Michael Wueff1a592007-09-25 18:11:01 -070050 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090051 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070052 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
53 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050054 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070055 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
56 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
57 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020058 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Christian Lamparter22010762011-04-02 11:31:29 +020059 {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */
Michael Wueff1a592007-09-25 18:11:01 -070060 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010061 {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
Christian Lamparter1a927952010-10-01 22:01:24 +020062 {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
Michael Wueff1a592007-09-25 18:11:01 -070063 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010064 {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
Eduardo Costa56e64172010-12-14 14:37:59 -060065 {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
Christian Lamparter1a927952010-10-01 22:01:24 +020066 {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010067 {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
Michael Wueff1a592007-09-25 18:11:01 -070068 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
69 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
70 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
71 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
Christian Lamparter22010762011-04-02 11:31:29 +020072 {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */
Michael Wueff1a592007-09-25 18:11:01 -070073 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
74 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
75
76 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070077 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070078 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
79 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
80 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Christian Lamparter1a927952010-10-01 22:01:24 +020081 {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
Michiel878e6a42009-01-04 17:22:28 -060082 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070083 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
84 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060085 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070086 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
87 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
88 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
89 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
90 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070091 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
92 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070093 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020094 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070095 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070096 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020097 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050098 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040099 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +0200100 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700101 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter1a927952010-10-01 22:01:24 +0200102 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Christian Lamparter2b799a62011-02-26 12:58:06 +0100103 {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */
Michael Wueff1a592007-09-25 18:11:01 -0700104 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +0100105 {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
Jason Dravet0f666a02010-06-05 15:08:29 -0500106 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700107 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
108 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
109 {}
110};
111
112MODULE_DEVICE_TABLE(usb, p54u_table);
113
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200114static const struct {
115 u32 intf;
116 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200117 const char *fw;
118 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200119 char hw[20];
120} p54u_fwlist[__NUM_P54U_HWTYPES] = {
121 {
122 .type = P54U_NET2280,
123 .intf = FW_LM86,
124 .fw = "isl3886usb",
125 .fw_legacy = "isl3890usb",
126 .hw = "ISL3886 + net2280",
127 },
128 {
129 .type = P54U_3887,
130 .intf = FW_LM87,
131 .fw = "isl3887usb",
132 .fw_legacy = "isl3887usb_bare",
133 .hw = "ISL3887",
134 },
135};
136
Michael Wueff1a592007-09-25 18:11:01 -0700137static void p54u_rx_cb(struct urb *urb)
138{
139 struct sk_buff *skb = (struct sk_buff *) urb->context;
140 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
141 struct ieee80211_hw *dev = info->dev;
142 struct p54u_priv *priv = dev->priv;
143
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100144 skb_unlink(skb, &priv->rx_queue);
145
Michael Wueff1a592007-09-25 18:11:01 -0700146 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100147 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700148 return;
149 }
150
Michael Wueff1a592007-09-25 18:11:01 -0700151 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200152
153 if (priv->hw_type == P54U_NET2280)
154 skb_pull(skb, priv->common.tx_hdr_len);
155 if (priv->common.fw_interface == FW_LM87) {
156 skb_pull(skb, 4);
157 skb_put(skb, 4);
158 }
Michael Wueff1a592007-09-25 18:11:01 -0700159
160 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200161 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700162 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700163 /* TODO check rx queue length and refill *somewhere* */
164 return;
165 }
166
167 info = (struct p54u_rx_info *) skb->cb;
168 info->urb = urb;
169 info->dev = dev;
170 urb->transfer_buffer = skb_tail_pointer(skb);
171 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700172 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200173 if (priv->hw_type == P54U_NET2280)
174 skb_push(skb, priv->common.tx_hdr_len);
175 if (priv->common.fw_interface == FW_LM87) {
176 skb_push(skb, 4);
177 skb_put(skb, 4);
178 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200179 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700180 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200181 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700182 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100183 skb_queue_tail(&priv->rx_queue, skb);
184 usb_anchor_urb(urb, &priv->submitted);
185 if (usb_submit_urb(urb, GFP_ATOMIC)) {
186 skb_unlink(skb, &priv->rx_queue);
187 usb_unanchor_urb(urb);
188 dev_kfree_skb_irq(skb);
189 }
Michael Wueff1a592007-09-25 18:11:01 -0700190}
191
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100192static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200193{
194 struct sk_buff *skb = urb->context;
Joe Perchesb2767362010-11-30 13:42:08 -0800195 struct ieee80211_hw *dev =
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200196 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
197
Christian Lampartere2fe1542009-01-20 00:27:57 +0100198 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100199}
200
201static void p54u_tx_dummy_cb(struct urb *urb) { }
202
203static void p54u_free_urbs(struct ieee80211_hw *dev)
204{
205 struct p54u_priv *priv = dev->priv;
206 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200207}
208
Michael Wueff1a592007-09-25 18:11:01 -0700209static int p54u_init_urbs(struct ieee80211_hw *dev)
210{
211 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100212 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700213 struct sk_buff *skb;
214 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100215 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700216
217 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200218 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100219 if (!skb) {
220 ret = -ENOMEM;
221 goto err;
222 }
Michael Wueff1a592007-09-25 18:11:01 -0700223 entry = usb_alloc_urb(0, GFP_KERNEL);
224 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100225 ret = -ENOMEM;
226 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700227 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100228
Christian Lamparter4e416a62008-09-01 22:48:41 +0200229 usb_fill_bulk_urb(entry, priv->udev,
230 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
231 skb_tail_pointer(skb),
232 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700233 info = (struct p54u_rx_info *) skb->cb;
234 info->urb = entry;
235 info->dev = dev;
236 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100237
238 usb_anchor_urb(entry, &priv->submitted);
239 ret = usb_submit_urb(entry, GFP_KERNEL);
240 if (ret) {
241 skb_unlink(skb, &priv->rx_queue);
242 usb_unanchor_urb(entry);
243 goto err;
244 }
245 usb_free_urb(entry);
246 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700247 }
248
249 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700250
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100251 err:
252 usb_free_urb(entry);
253 kfree_skb(skb);
254 p54u_free_urbs(dev);
255 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700256}
257
Johannes Bergc9127652008-12-01 18:19:36 +0100258static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200259{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500260 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200261
262 length >>= 2;
263 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100264 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200265 chk = (chk >> 5) ^ (chk << 3);
266 }
267
Larry Finger1f1c0e32008-09-25 14:54:28 -0500268 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200269}
270
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100271static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200272{
273 struct p54u_priv *priv = dev->priv;
274 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100275 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200276
277 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200278 if (!data_urb) {
279 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200280 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200281 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200282
Christian Lampartere2fe1542009-01-20 00:27:57 +0100283 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
284 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200285
286 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200287 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100288 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
289 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100290 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200291
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100292 usb_anchor_urb(data_urb, &priv->submitted);
293 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
294 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100295 p54_free_skb(dev, skb);
296 }
297 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200298}
299
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100300static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700301{
302 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200303 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100304 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200305 struct net2280_reg_write *reg = NULL;
306 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700307
308 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
309 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200310 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700311
312 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200313 if (!int_urb)
314 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700315
316 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200317 if (!data_urb)
318 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700319
320 reg->port = cpu_to_le16(NET2280_DEV_U32);
321 reg->addr = cpu_to_le32(P54U_DEV_BASE);
322 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
323
Michael Wueff1a592007-09-25 18:11:01 -0700324 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100325 hdr->len = cpu_to_le16(skb->len);
326 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700327
328 usb_fill_bulk_urb(int_urb, priv->udev,
329 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100330 p54u_tx_dummy_cb, dev);
331
332 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200333 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
334 * free what is inside the transfer_buffer after the last reference to
335 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100336 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100337 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200338 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700339
340 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200341 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100342 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
343 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100344 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100345
346 usb_anchor_urb(int_urb, &priv->submitted);
347 err = usb_submit_urb(int_urb, GFP_ATOMIC);
348 if (err) {
349 usb_unanchor_urb(int_urb);
350 goto out;
351 }
352
353 usb_anchor_urb(data_urb, &priv->submitted);
354 err = usb_submit_urb(data_urb, GFP_ATOMIC);
355 if (err) {
356 usb_unanchor_urb(data_urb);
357 goto out;
358 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200359out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100360 usb_free_urb(int_urb);
361 usb_free_urb(data_urb);
362
363 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200364 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100365 p54_free_skb(dev, skb);
366 }
Michael Wueff1a592007-09-25 18:11:01 -0700367}
368
369static int p54u_write(struct p54u_priv *priv,
370 struct net2280_reg_write *buf,
371 enum net2280_op_type type,
372 __le32 addr, __le32 val)
373{
374 unsigned int ep;
375 int alen;
376
377 if (type & 0x0800)
378 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
379 else
380 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
381
382 buf->port = cpu_to_le16(type);
383 buf->addr = addr;
384 buf->val = val;
385
386 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
387}
388
389static int p54u_read(struct p54u_priv *priv, void *buf,
390 enum net2280_op_type type,
391 __le32 addr, __le32 *val)
392{
393 struct net2280_reg_read *read = buf;
394 __le32 *reg = buf;
395 unsigned int ep;
396 int alen, err;
397
398 if (type & 0x0800)
399 ep = P54U_PIPE_DEV;
400 else
401 ep = P54U_PIPE_BRG;
402
403 read->port = cpu_to_le16(type);
404 read->addr = addr;
405
406 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
407 read, sizeof(*read), &alen, 1000);
408 if (err)
409 return err;
410
411 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
412 reg, sizeof(*reg), &alen, 1000);
413 if (err)
414 return err;
415
416 *val = *reg;
417 return 0;
418}
419
420static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
421 void *data, size_t len)
422{
423 int alen;
424 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
425 data, len, &alen, 2000);
426}
427
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200428static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100429{
430 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100431 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100432
Christian Lamparterc88a7682009-01-16 20:24:31 +0100433 if (lock) {
434 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
435 if (ret < 0) {
436 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200437 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100438 return ret;
439 }
Christian Lamparter69828692008-12-26 19:08:31 +0100440 }
441
442 ret = usb_reset_device(priv->udev);
443 if (lock)
444 usb_unlock_device(priv->udev);
445
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200446 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100447 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200448 "device (%d)!\n", ret);
449
450 return ret;
451}
452
453static const char p54u_romboot_3887[] = "~~~~";
454static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
455{
456 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600457 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200458 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100459
Julia Lawall27b81bb2010-05-15 23:22:55 +0200460 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600461 if (!buf)
462 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100463 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600464 buf, 4);
465 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100466 if (ret)
467 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200468 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100469
470 return ret;
471}
472
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200473static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700474static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
475{
Michael Wueff1a592007-09-25 18:11:01 -0700476 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700477 int err, alen;
478 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100479 u8 *buf, *tmp;
480 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700481 unsigned int left, remains, block_size;
482 struct x2_header *hdr;
483 unsigned long timeout;
484
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200485 err = p54u_firmware_reset_3887(dev);
486 if (err)
487 return err;
488
Michael Wueff1a592007-09-25 18:11:01 -0700489 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
490 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100491 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
492 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200493 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700494 }
495
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200496 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100497 strcpy(buf, p54u_firmware_upload_3887);
498 left -= strlen(p54u_firmware_upload_3887);
499 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700500
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200501 data = priv->fw->data;
502 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700503
Christian Lamparter69828692008-12-26 19:08:31 +0100504 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700505 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
506 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200507 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700508 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
509 sizeof(u32)*2));
510 left -= sizeof(*hdr);
511 tmp += sizeof(*hdr);
512
513 while (remains) {
514 while (left--) {
515 if (carry) {
516 *tmp++ = carry;
517 carry = 0;
518 remains--;
519 continue;
520 }
521 switch (*data) {
522 case '~':
523 *tmp++ = '}';
524 carry = '^';
525 break;
526 case '}':
527 *tmp++ = '}';
528 carry = ']';
529 break;
530 default:
531 *tmp++ = *data;
532 remains--;
533 break;
534 }
535 data++;
536 }
537
538 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
539 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100540 dev_err(&priv->udev->dev, "(p54usb) firmware "
541 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700542 goto err_upload_failed;
543 }
544
545 tmp = buf;
546 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
547 }
548
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200549 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
550 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700551 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
552 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100553 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700554 goto err_upload_failed;
555 }
Michael Wueff1a592007-09-25 18:11:01 -0700556 timeout = jiffies + msecs_to_jiffies(1000);
557 while (!(err = usb_bulk_msg(priv->udev,
558 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
559 if (alen > 2 && !memcmp(buf, "OK", 2))
560 break;
561
562 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700563 err = -EINVAL;
564 break;
565 }
566
567 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100568 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
569 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700570 err = -ETIMEDOUT;
571 break;
572 }
573 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100574 if (err) {
575 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700576 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100577 }
Michael Wueff1a592007-09-25 18:11:01 -0700578
579 buf[0] = 'g';
580 buf[1] = '\r';
581 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
582 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100583 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700584 goto err_upload_failed;
585 }
586
587 timeout = jiffies + msecs_to_jiffies(1000);
588 while (!(err = usb_bulk_msg(priv->udev,
589 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
590 if (alen > 0 && buf[0] == 'g')
591 break;
592
593 if (time_after(jiffies, timeout)) {
594 err = -ETIMEDOUT;
595 break;
596 }
597 }
598 if (err)
599 goto err_upload_failed;
600
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200601err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700602 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700603 return err;
604}
605
606static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
607{
608 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700609 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
610 int err, alen;
611 void *buf;
612 __le32 reg;
613 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100614 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700615
616 buf = kmalloc(512, GFP_KERNEL);
617 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100618 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
619 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700620 return -ENOMEM;
621 }
622
Michael Wueff1a592007-09-25 18:11:01 -0700623#define P54U_WRITE(type, addr, data) \
624 do {\
625 err = p54u_write(priv, buf, type,\
626 cpu_to_le32((u32)(unsigned long)addr), data);\
627 if (err) \
628 goto fail;\
629 } while (0)
630
631#define P54U_READ(type, addr) \
632 do {\
633 err = p54u_read(priv, buf, type,\
634 cpu_to_le32((u32)(unsigned long)addr), &reg);\
635 if (err)\
636 goto fail;\
637 } while (0)
638
639 /* power down net2280 bridge */
640 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
641 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
642 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
643 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
644
645 mdelay(100);
646
647 /* power up bridge */
648 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
649 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
650 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
651
652 mdelay(100);
653
654 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
655 cpu_to_le32(NET2280_CLK_30Mhz |
656 NET2280_PCI_ENABLE |
657 NET2280_PCI_SOFT_RESET));
658
659 mdelay(20);
660
661 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
662 cpu_to_le32(PCI_COMMAND_MEMORY |
663 PCI_COMMAND_MASTER));
664
665 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
666 cpu_to_le32(NET2280_BASE));
667
668 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
669 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
670 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
671
672 // TODO: we really need this?
673 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
674
675 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
676 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
677 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
678 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
679
680 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
681 cpu_to_le32(NET2280_BASE2));
682
683 /* finally done setting up the bridge */
684
685 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
686 cpu_to_le32(PCI_COMMAND_MEMORY |
687 PCI_COMMAND_MASTER));
688
689 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
690 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
691 cpu_to_le32(P54U_DEV_BASE));
692
693 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
694 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
695 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
696
697 /* do romboot */
698 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
699
700 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
701 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
702 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
703 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
704 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
705
706 mdelay(20);
707
708 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
709 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
710
711 mdelay(20);
712
713 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
714 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
715
716 mdelay(100);
717
718 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
719 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
720
721 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200722 remains = priv->fw->size;
723 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700724 offset = ISL38XX_DEV_FIRMWARE_ADDR;
725
726 while (remains) {
727 unsigned int block_len = min(remains, (unsigned int)512);
728 memcpy(buf, data, block_len);
729
730 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
731 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100732 dev_err(&priv->udev->dev, "(p54usb) firmware block "
733 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700734 goto fail;
735 }
736
737 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
738 cpu_to_le32(0xc0000f00));
739
740 P54U_WRITE(NET2280_DEV_U32,
741 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
742 P54U_WRITE(NET2280_DEV_U32,
743 0x0020 | (unsigned long)&devreg->direct_mem_win,
744 cpu_to_le32(1));
745
746 P54U_WRITE(NET2280_DEV_U32,
747 0x0024 | (unsigned long)&devreg->direct_mem_win,
748 cpu_to_le32(block_len));
749 P54U_WRITE(NET2280_DEV_U32,
750 0x0028 | (unsigned long)&devreg->direct_mem_win,
751 cpu_to_le32(offset));
752
753 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
754 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
755 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
756 cpu_to_le32(block_len >> 2));
757 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
758 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
759
760 mdelay(10);
761
762 P54U_READ(NET2280_DEV_U32,
763 0x002C | (unsigned long)&devreg->direct_mem_win);
764 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
765 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100766 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
767 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700768 goto fail;
769 }
770
771 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
772 cpu_to_le32(NET2280_FIFO_FLUSH));
773
774 remains -= block_len;
775 data += block_len;
776 offset += block_len;
777 }
778
779 /* do ramboot */
780 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
781 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
782 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
783 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
784 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
785
786 mdelay(20);
787
788 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
789 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
790
791 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
792 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
793
794 mdelay(100);
795
796 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
797 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
798
799 /* start up the firmware */
800 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
801 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
802
803 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
804 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
805
806 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
807 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
808 NET2280_USB_INTERRUPT_ENABLE));
809
810 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
811 cpu_to_le32(ISL38XX_DEV_INT_RESET));
812
813 err = usb_interrupt_msg(priv->udev,
814 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
815 buf, sizeof(__le32), &alen, 1000);
816 if (err || alen != sizeof(__le32))
817 goto fail;
818
819 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
820 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
821
822 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
823 err = -EINVAL;
824
825 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
826 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
827 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
828
829#undef P54U_WRITE
830#undef P54U_READ
831
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200832fail:
Michael Wueff1a592007-09-25 18:11:01 -0700833 kfree(buf);
834 return err;
835}
836
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200837static int p54u_load_firmware(struct ieee80211_hw *dev)
838{
839 struct p54u_priv *priv = dev->priv;
840 int err, i;
841
842 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
843
844 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
845 if (p54u_fwlist[i].type == priv->hw_type)
846 break;
847
848 if (i == __NUM_P54U_HWTYPES)
849 return -EOPNOTSUPP;
850
851 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
852 if (err) {
853 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
854 "(%d)!\n", p54u_fwlist[i].fw, err);
855
856 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
857 &priv->udev->dev);
858 if (err)
859 return err;
860 }
861
862 err = p54_parse_firmware(dev, priv->fw);
863 if (err)
864 goto out;
865
866 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
867 dev_err(&priv->udev->dev, "wrong firmware, please get "
868 "a firmware for \"%s\" and try again.\n",
869 p54u_fwlist[i].hw);
870 err = -EINVAL;
871 }
872
873out:
874 if (err)
875 release_firmware(priv->fw);
876
877 return err;
878}
879
Michael Wueff1a592007-09-25 18:11:01 -0700880static int p54u_open(struct ieee80211_hw *dev)
881{
882 struct p54u_priv *priv = dev->priv;
883 int err;
884
885 err = p54u_init_urbs(dev);
886 if (err) {
887 return err;
888 }
889
890 priv->common.open = p54u_init_urbs;
891
892 return 0;
893}
894
895static void p54u_stop(struct ieee80211_hw *dev)
896{
897 /* TODO: figure out how to reliably stop the 3887 and net2280 so
898 the hardware is still usable next time we want to start it.
899 until then, we just stop listening to the hardware.. */
900 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700901}
902
903static int __devinit p54u_probe(struct usb_interface *intf,
904 const struct usb_device_id *id)
905{
906 struct usb_device *udev = interface_to_usbdev(intf);
907 struct ieee80211_hw *dev;
908 struct p54u_priv *priv;
909 int err;
910 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700911
912 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100913
Michael Wueff1a592007-09-25 18:11:01 -0700914 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100915 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700916 return -ENOMEM;
917 }
918
919 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200920 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700921
922 SET_IEEE80211_DEV(dev, &intf->dev);
923 usb_set_intfdata(intf, dev);
924 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100925 priv->intf = intf;
926 skb_queue_head_init(&priv->rx_queue);
927 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700928
929 usb_get_dev(udev);
930
931 /* really lazy and simple way of figuring out if we're a 3887 */
932 /* TODO: should just stick the identification in the device table */
933 i = intf->altsetting->desc.bNumEndpoints;
934 recognized_pipes = 0;
935 while (i--) {
936 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
937 case P54U_PIPE_DATA:
938 case P54U_PIPE_MGMT:
939 case P54U_PIPE_BRG:
940 case P54U_PIPE_DEV:
941 case P54U_PIPE_DATA | USB_DIR_IN:
942 case P54U_PIPE_MGMT | USB_DIR_IN:
943 case P54U_PIPE_BRG | USB_DIR_IN:
944 case P54U_PIPE_DEV | USB_DIR_IN:
945 case P54U_PIPE_INT | USB_DIR_IN:
946 recognized_pipes++;
947 }
948 }
949 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200950 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700951 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200952#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200953 /* ISL3887 needs a full reset on resume */
954 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200955#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200956 err = p54u_device_reset(dev);
957
Michael Wueff1a592007-09-25 18:11:01 -0700958 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200959 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
960 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
961 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200962 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700963 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200964 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700965 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
966 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
967 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200968 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200969 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200970 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700971 if (err)
972 goto err_free_dev;
973
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200974 err = priv->upload_fw(dev);
975 if (err)
976 goto err_free_fw;
977
Christian Lamparter7cb77072008-09-01 22:48:51 +0200978 p54u_open(dev);
979 err = p54_read_eeprom(dev);
980 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700981 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200982 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700983
Christian Lamparter2ac71072009-03-05 21:30:10 +0100984 err = p54_register_common(dev, &udev->dev);
985 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200986 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700987
Michael Wueff1a592007-09-25 18:11:01 -0700988 return 0;
989
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200990err_free_fw:
991 release_firmware(priv->fw);
992
993err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500994 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700995 usb_set_intfdata(intf, NULL);
996 usb_put_dev(udev);
997 return err;
998}
999
1000static void __devexit p54u_disconnect(struct usb_interface *intf)
1001{
1002 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1003 struct p54u_priv *priv;
1004
1005 if (!dev)
1006 return;
1007
Christian Lamparterd8c92102009-06-23 10:39:45 -05001008 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001009
1010 priv = dev->priv;
1011 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001012 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001013 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001014}
1015
Christian Lamparter69828692008-12-26 19:08:31 +01001016static int p54u_pre_reset(struct usb_interface *intf)
1017{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001018 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1019
1020 if (!dev)
1021 return -ENODEV;
1022
1023 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001024 return 0;
1025}
1026
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001027static int p54u_resume(struct usb_interface *intf)
1028{
1029 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1030 struct p54u_priv *priv;
1031
1032 if (!dev)
1033 return -ENODEV;
1034
1035 priv = dev->priv;
1036 if (unlikely(!(priv->upload_fw && priv->fw)))
1037 return 0;
1038
1039 return priv->upload_fw(dev);
1040}
1041
Christian Lamparter69828692008-12-26 19:08:31 +01001042static int p54u_post_reset(struct usb_interface *intf)
1043{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001044 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1045 struct p54u_priv *priv;
1046 int err;
1047
1048 err = p54u_resume(intf);
1049 if (err)
1050 return err;
1051
1052 /* reinitialize old device state */
1053 priv = dev->priv;
1054 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1055 ieee80211_restart_hw(dev);
1056
Christian Lamparter69828692008-12-26 19:08:31 +01001057 return 0;
1058}
1059
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001060#ifdef CONFIG_PM
1061
1062static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1063{
1064 return p54u_pre_reset(intf);
1065}
1066
1067#endif /* CONFIG_PM */
1068
Michael Wueff1a592007-09-25 18:11:01 -07001069static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001070 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001071 .id_table = p54u_table,
1072 .probe = p54u_probe,
1073 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001074 .pre_reset = p54u_pre_reset,
1075 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001076#ifdef CONFIG_PM
1077 .suspend = p54u_suspend,
1078 .resume = p54u_resume,
1079 .reset_resume = p54u_resume,
1080#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001081 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001082};
1083
1084static int __init p54u_init(void)
1085{
1086 return usb_register(&p54u_driver);
1087}
1088
1089static void __exit p54u_exit(void)
1090{
1091 usb_deregister(&p54u_driver);
1092}
1093
1094module_init(p54u_init);
1095module_exit(p54u_exit);