blob: a8f3bc740dfaf8354abff344f5ab7665bd8faf58 [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 */
Christian Lamparter9368a9a2011-05-13 21:47:23 +020085 {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060086 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070087 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
88 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
89 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
90 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
91 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070092 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
93 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070094 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020095 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070096 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070097 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020098 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050099 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -0400100 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +0200101 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700102 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter1a927952010-10-01 22:01:24 +0200103 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Christian Lamparter2b799a62011-02-26 12:58:06 +0100104 {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */
Michael Wueff1a592007-09-25 18:11:01 -0700105 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +0100106 {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
Jason Dravet0f666a02010-06-05 15:08:29 -0500107 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700108 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
109 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
110 {}
111};
112
113MODULE_DEVICE_TABLE(usb, p54u_table);
114
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200115static const struct {
116 u32 intf;
117 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200118 const char *fw;
119 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200120 char hw[20];
121} p54u_fwlist[__NUM_P54U_HWTYPES] = {
122 {
123 .type = P54U_NET2280,
124 .intf = FW_LM86,
125 .fw = "isl3886usb",
126 .fw_legacy = "isl3890usb",
127 .hw = "ISL3886 + net2280",
128 },
129 {
130 .type = P54U_3887,
131 .intf = FW_LM87,
132 .fw = "isl3887usb",
133 .fw_legacy = "isl3887usb_bare",
134 .hw = "ISL3887",
135 },
136};
137
Michael Wueff1a592007-09-25 18:11:01 -0700138static void p54u_rx_cb(struct urb *urb)
139{
140 struct sk_buff *skb = (struct sk_buff *) urb->context;
141 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
142 struct ieee80211_hw *dev = info->dev;
143 struct p54u_priv *priv = dev->priv;
144
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100145 skb_unlink(skb, &priv->rx_queue);
146
Michael Wueff1a592007-09-25 18:11:01 -0700147 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100148 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700149 return;
150 }
151
Michael Wueff1a592007-09-25 18:11:01 -0700152 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200153
154 if (priv->hw_type == P54U_NET2280)
155 skb_pull(skb, priv->common.tx_hdr_len);
156 if (priv->common.fw_interface == FW_LM87) {
157 skb_pull(skb, 4);
158 skb_put(skb, 4);
159 }
Michael Wueff1a592007-09-25 18:11:01 -0700160
161 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200162 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700163 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700164 /* TODO check rx queue length and refill *somewhere* */
165 return;
166 }
167
168 info = (struct p54u_rx_info *) skb->cb;
169 info->urb = urb;
170 info->dev = dev;
171 urb->transfer_buffer = skb_tail_pointer(skb);
172 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700173 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200174 if (priv->hw_type == P54U_NET2280)
175 skb_push(skb, priv->common.tx_hdr_len);
176 if (priv->common.fw_interface == FW_LM87) {
177 skb_push(skb, 4);
178 skb_put(skb, 4);
179 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200180 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700181 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200182 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700183 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100184 skb_queue_tail(&priv->rx_queue, skb);
185 usb_anchor_urb(urb, &priv->submitted);
186 if (usb_submit_urb(urb, GFP_ATOMIC)) {
187 skb_unlink(skb, &priv->rx_queue);
188 usb_unanchor_urb(urb);
189 dev_kfree_skb_irq(skb);
190 }
Michael Wueff1a592007-09-25 18:11:01 -0700191}
192
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100193static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200194{
195 struct sk_buff *skb = urb->context;
Joe Perchesb2767362010-11-30 13:42:08 -0800196 struct ieee80211_hw *dev =
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200197 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
198
Christian Lampartere2fe1542009-01-20 00:27:57 +0100199 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100200}
201
202static void p54u_tx_dummy_cb(struct urb *urb) { }
203
204static void p54u_free_urbs(struct ieee80211_hw *dev)
205{
206 struct p54u_priv *priv = dev->priv;
207 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200208}
209
Michael Wueff1a592007-09-25 18:11:01 -0700210static int p54u_init_urbs(struct ieee80211_hw *dev)
211{
212 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100213 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700214 struct sk_buff *skb;
215 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100216 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700217
218 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200219 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100220 if (!skb) {
221 ret = -ENOMEM;
222 goto err;
223 }
Michael Wueff1a592007-09-25 18:11:01 -0700224 entry = usb_alloc_urb(0, GFP_KERNEL);
225 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100226 ret = -ENOMEM;
227 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700228 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100229
Christian Lamparter4e416a62008-09-01 22:48:41 +0200230 usb_fill_bulk_urb(entry, priv->udev,
231 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
232 skb_tail_pointer(skb),
233 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700234 info = (struct p54u_rx_info *) skb->cb;
235 info->urb = entry;
236 info->dev = dev;
237 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100238
239 usb_anchor_urb(entry, &priv->submitted);
240 ret = usb_submit_urb(entry, GFP_KERNEL);
241 if (ret) {
242 skb_unlink(skb, &priv->rx_queue);
243 usb_unanchor_urb(entry);
244 goto err;
245 }
246 usb_free_urb(entry);
247 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700248 }
249
250 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700251
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100252 err:
253 usb_free_urb(entry);
254 kfree_skb(skb);
255 p54u_free_urbs(dev);
256 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700257}
258
Johannes Bergc9127652008-12-01 18:19:36 +0100259static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200260{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500261 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200262
263 length >>= 2;
264 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100265 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200266 chk = (chk >> 5) ^ (chk << 3);
267 }
268
Larry Finger1f1c0e32008-09-25 14:54:28 -0500269 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200270}
271
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100272static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200273{
274 struct p54u_priv *priv = dev->priv;
275 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100276 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200277
278 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200279 if (!data_urb) {
280 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200281 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200282 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200283
Christian Lampartere2fe1542009-01-20 00:27:57 +0100284 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
285 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200286
287 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200288 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100289 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
290 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100291 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200292
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100293 usb_anchor_urb(data_urb, &priv->submitted);
294 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
295 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100296 p54_free_skb(dev, skb);
297 }
298 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200299}
300
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100301static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700302{
303 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200304 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100305 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200306 struct net2280_reg_write *reg = NULL;
307 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700308
309 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
310 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200311 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700312
313 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200314 if (!int_urb)
315 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700316
317 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200318 if (!data_urb)
319 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700320
321 reg->port = cpu_to_le16(NET2280_DEV_U32);
322 reg->addr = cpu_to_le32(P54U_DEV_BASE);
323 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
324
Michael Wueff1a592007-09-25 18:11:01 -0700325 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100326 hdr->len = cpu_to_le16(skb->len);
327 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700328
329 usb_fill_bulk_urb(int_urb, priv->udev,
330 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100331 p54u_tx_dummy_cb, dev);
332
333 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200334 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
335 * free what is inside the transfer_buffer after the last reference to
336 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100337 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100338 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200339 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700340
341 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200342 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100343 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
344 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100345 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100346
347 usb_anchor_urb(int_urb, &priv->submitted);
348 err = usb_submit_urb(int_urb, GFP_ATOMIC);
349 if (err) {
350 usb_unanchor_urb(int_urb);
351 goto out;
352 }
353
354 usb_anchor_urb(data_urb, &priv->submitted);
355 err = usb_submit_urb(data_urb, GFP_ATOMIC);
356 if (err) {
357 usb_unanchor_urb(data_urb);
358 goto out;
359 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200360out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100361 usb_free_urb(int_urb);
362 usb_free_urb(data_urb);
363
364 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200365 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100366 p54_free_skb(dev, skb);
367 }
Michael Wueff1a592007-09-25 18:11:01 -0700368}
369
370static int p54u_write(struct p54u_priv *priv,
371 struct net2280_reg_write *buf,
372 enum net2280_op_type type,
373 __le32 addr, __le32 val)
374{
375 unsigned int ep;
376 int alen;
377
378 if (type & 0x0800)
379 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
380 else
381 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
382
383 buf->port = cpu_to_le16(type);
384 buf->addr = addr;
385 buf->val = val;
386
387 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
388}
389
390static int p54u_read(struct p54u_priv *priv, void *buf,
391 enum net2280_op_type type,
392 __le32 addr, __le32 *val)
393{
394 struct net2280_reg_read *read = buf;
395 __le32 *reg = buf;
396 unsigned int ep;
397 int alen, err;
398
399 if (type & 0x0800)
400 ep = P54U_PIPE_DEV;
401 else
402 ep = P54U_PIPE_BRG;
403
404 read->port = cpu_to_le16(type);
405 read->addr = addr;
406
407 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
408 read, sizeof(*read), &alen, 1000);
409 if (err)
410 return err;
411
412 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
413 reg, sizeof(*reg), &alen, 1000);
414 if (err)
415 return err;
416
417 *val = *reg;
418 return 0;
419}
420
421static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
422 void *data, size_t len)
423{
424 int alen;
425 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
426 data, len, &alen, 2000);
427}
428
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200429static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100430{
431 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100432 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100433
Christian Lamparterc88a7682009-01-16 20:24:31 +0100434 if (lock) {
435 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
436 if (ret < 0) {
437 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200438 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100439 return ret;
440 }
Christian Lamparter69828692008-12-26 19:08:31 +0100441 }
442
443 ret = usb_reset_device(priv->udev);
444 if (lock)
445 usb_unlock_device(priv->udev);
446
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200447 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100448 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200449 "device (%d)!\n", ret);
450
451 return ret;
452}
453
454static const char p54u_romboot_3887[] = "~~~~";
455static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
456{
457 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600458 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200459 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100460
Julia Lawall27b81bb2010-05-15 23:22:55 +0200461 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600462 if (!buf)
463 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100464 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600465 buf, 4);
466 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100467 if (ret)
468 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200469 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100470
471 return ret;
472}
473
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200474static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700475static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
476{
Michael Wueff1a592007-09-25 18:11:01 -0700477 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700478 int err, alen;
479 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100480 u8 *buf, *tmp;
481 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700482 unsigned int left, remains, block_size;
483 struct x2_header *hdr;
484 unsigned long timeout;
485
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200486 err = p54u_firmware_reset_3887(dev);
487 if (err)
488 return err;
489
Michael Wueff1a592007-09-25 18:11:01 -0700490 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
491 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100492 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
493 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200494 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700495 }
496
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200497 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100498 strcpy(buf, p54u_firmware_upload_3887);
499 left -= strlen(p54u_firmware_upload_3887);
500 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700501
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200502 data = priv->fw->data;
503 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700504
Christian Lamparter69828692008-12-26 19:08:31 +0100505 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700506 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
507 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200508 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700509 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
510 sizeof(u32)*2));
511 left -= sizeof(*hdr);
512 tmp += sizeof(*hdr);
513
514 while (remains) {
515 while (left--) {
516 if (carry) {
517 *tmp++ = carry;
518 carry = 0;
519 remains--;
520 continue;
521 }
522 switch (*data) {
523 case '~':
524 *tmp++ = '}';
525 carry = '^';
526 break;
527 case '}':
528 *tmp++ = '}';
529 carry = ']';
530 break;
531 default:
532 *tmp++ = *data;
533 remains--;
534 break;
535 }
536 data++;
537 }
538
539 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
540 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100541 dev_err(&priv->udev->dev, "(p54usb) firmware "
542 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700543 goto err_upload_failed;
544 }
545
546 tmp = buf;
547 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
548 }
549
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200550 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
551 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700552 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
553 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100554 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700555 goto err_upload_failed;
556 }
Michael Wueff1a592007-09-25 18:11:01 -0700557 timeout = jiffies + msecs_to_jiffies(1000);
558 while (!(err = usb_bulk_msg(priv->udev,
559 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
560 if (alen > 2 && !memcmp(buf, "OK", 2))
561 break;
562
563 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700564 err = -EINVAL;
565 break;
566 }
567
568 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100569 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
570 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700571 err = -ETIMEDOUT;
572 break;
573 }
574 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100575 if (err) {
576 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700577 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100578 }
Michael Wueff1a592007-09-25 18:11:01 -0700579
580 buf[0] = 'g';
581 buf[1] = '\r';
582 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
583 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100584 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700585 goto err_upload_failed;
586 }
587
588 timeout = jiffies + msecs_to_jiffies(1000);
589 while (!(err = usb_bulk_msg(priv->udev,
590 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
591 if (alen > 0 && buf[0] == 'g')
592 break;
593
594 if (time_after(jiffies, timeout)) {
595 err = -ETIMEDOUT;
596 break;
597 }
598 }
599 if (err)
600 goto err_upload_failed;
601
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200602err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700603 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700604 return err;
605}
606
607static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
608{
609 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700610 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
611 int err, alen;
612 void *buf;
613 __le32 reg;
614 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100615 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700616
617 buf = kmalloc(512, GFP_KERNEL);
618 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100619 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
620 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700621 return -ENOMEM;
622 }
623
Michael Wueff1a592007-09-25 18:11:01 -0700624#define P54U_WRITE(type, addr, data) \
625 do {\
626 err = p54u_write(priv, buf, type,\
627 cpu_to_le32((u32)(unsigned long)addr), data);\
628 if (err) \
629 goto fail;\
630 } while (0)
631
632#define P54U_READ(type, addr) \
633 do {\
634 err = p54u_read(priv, buf, type,\
635 cpu_to_le32((u32)(unsigned long)addr), &reg);\
636 if (err)\
637 goto fail;\
638 } while (0)
639
640 /* power down net2280 bridge */
641 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
642 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
643 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
644 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
645
646 mdelay(100);
647
648 /* power up bridge */
649 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
650 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
651 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
652
653 mdelay(100);
654
655 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
656 cpu_to_le32(NET2280_CLK_30Mhz |
657 NET2280_PCI_ENABLE |
658 NET2280_PCI_SOFT_RESET));
659
660 mdelay(20);
661
662 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
663 cpu_to_le32(PCI_COMMAND_MEMORY |
664 PCI_COMMAND_MASTER));
665
666 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
667 cpu_to_le32(NET2280_BASE));
668
669 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
670 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
671 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
672
673 // TODO: we really need this?
674 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
675
676 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
677 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
678 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
679 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
680
681 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
682 cpu_to_le32(NET2280_BASE2));
683
684 /* finally done setting up the bridge */
685
686 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
687 cpu_to_le32(PCI_COMMAND_MEMORY |
688 PCI_COMMAND_MASTER));
689
690 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
691 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
692 cpu_to_le32(P54U_DEV_BASE));
693
694 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
695 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
696 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
697
698 /* do romboot */
699 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
700
701 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
702 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
703 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
704 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
705 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
706
707 mdelay(20);
708
709 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
710 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
711
712 mdelay(20);
713
714 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
715 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
716
717 mdelay(100);
718
719 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
720 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
721
722 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200723 remains = priv->fw->size;
724 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700725 offset = ISL38XX_DEV_FIRMWARE_ADDR;
726
727 while (remains) {
728 unsigned int block_len = min(remains, (unsigned int)512);
729 memcpy(buf, data, block_len);
730
731 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
732 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100733 dev_err(&priv->udev->dev, "(p54usb) firmware block "
734 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700735 goto fail;
736 }
737
738 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
739 cpu_to_le32(0xc0000f00));
740
741 P54U_WRITE(NET2280_DEV_U32,
742 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
743 P54U_WRITE(NET2280_DEV_U32,
744 0x0020 | (unsigned long)&devreg->direct_mem_win,
745 cpu_to_le32(1));
746
747 P54U_WRITE(NET2280_DEV_U32,
748 0x0024 | (unsigned long)&devreg->direct_mem_win,
749 cpu_to_le32(block_len));
750 P54U_WRITE(NET2280_DEV_U32,
751 0x0028 | (unsigned long)&devreg->direct_mem_win,
752 cpu_to_le32(offset));
753
754 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
755 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
756 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
757 cpu_to_le32(block_len >> 2));
758 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
759 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
760
761 mdelay(10);
762
763 P54U_READ(NET2280_DEV_U32,
764 0x002C | (unsigned long)&devreg->direct_mem_win);
765 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
766 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100767 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
768 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700769 goto fail;
770 }
771
772 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
773 cpu_to_le32(NET2280_FIFO_FLUSH));
774
775 remains -= block_len;
776 data += block_len;
777 offset += block_len;
778 }
779
780 /* do ramboot */
781 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
782 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
783 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
784 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
785 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
786
787 mdelay(20);
788
789 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
790 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
791
792 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
793 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
794
795 mdelay(100);
796
797 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
798 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
799
800 /* start up the firmware */
801 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
802 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
803
804 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
805 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
806
807 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
808 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
809 NET2280_USB_INTERRUPT_ENABLE));
810
811 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
812 cpu_to_le32(ISL38XX_DEV_INT_RESET));
813
814 err = usb_interrupt_msg(priv->udev,
815 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
816 buf, sizeof(__le32), &alen, 1000);
817 if (err || alen != sizeof(__le32))
818 goto fail;
819
820 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
821 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
822
823 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
824 err = -EINVAL;
825
826 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
827 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
828 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
829
830#undef P54U_WRITE
831#undef P54U_READ
832
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200833fail:
Michael Wueff1a592007-09-25 18:11:01 -0700834 kfree(buf);
835 return err;
836}
837
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200838static int p54u_load_firmware(struct ieee80211_hw *dev)
839{
840 struct p54u_priv *priv = dev->priv;
841 int err, i;
842
843 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
844
845 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
846 if (p54u_fwlist[i].type == priv->hw_type)
847 break;
848
849 if (i == __NUM_P54U_HWTYPES)
850 return -EOPNOTSUPP;
851
852 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
853 if (err) {
854 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
855 "(%d)!\n", p54u_fwlist[i].fw, err);
856
857 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
858 &priv->udev->dev);
859 if (err)
860 return err;
861 }
862
863 err = p54_parse_firmware(dev, priv->fw);
864 if (err)
865 goto out;
866
867 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
868 dev_err(&priv->udev->dev, "wrong firmware, please get "
869 "a firmware for \"%s\" and try again.\n",
870 p54u_fwlist[i].hw);
871 err = -EINVAL;
872 }
873
874out:
875 if (err)
876 release_firmware(priv->fw);
877
878 return err;
879}
880
Michael Wueff1a592007-09-25 18:11:01 -0700881static int p54u_open(struct ieee80211_hw *dev)
882{
883 struct p54u_priv *priv = dev->priv;
884 int err;
885
886 err = p54u_init_urbs(dev);
887 if (err) {
888 return err;
889 }
890
891 priv->common.open = p54u_init_urbs;
892
893 return 0;
894}
895
896static void p54u_stop(struct ieee80211_hw *dev)
897{
898 /* TODO: figure out how to reliably stop the 3887 and net2280 so
899 the hardware is still usable next time we want to start it.
900 until then, we just stop listening to the hardware.. */
901 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700902}
903
904static int __devinit p54u_probe(struct usb_interface *intf,
905 const struct usb_device_id *id)
906{
907 struct usb_device *udev = interface_to_usbdev(intf);
908 struct ieee80211_hw *dev;
909 struct p54u_priv *priv;
910 int err;
911 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700912
913 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100914
Michael Wueff1a592007-09-25 18:11:01 -0700915 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100916 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700917 return -ENOMEM;
918 }
919
920 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200921 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700922
923 SET_IEEE80211_DEV(dev, &intf->dev);
924 usb_set_intfdata(intf, dev);
925 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100926 priv->intf = intf;
927 skb_queue_head_init(&priv->rx_queue);
928 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700929
930 usb_get_dev(udev);
931
932 /* really lazy and simple way of figuring out if we're a 3887 */
933 /* TODO: should just stick the identification in the device table */
934 i = intf->altsetting->desc.bNumEndpoints;
935 recognized_pipes = 0;
936 while (i--) {
937 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
938 case P54U_PIPE_DATA:
939 case P54U_PIPE_MGMT:
940 case P54U_PIPE_BRG:
941 case P54U_PIPE_DEV:
942 case P54U_PIPE_DATA | USB_DIR_IN:
943 case P54U_PIPE_MGMT | USB_DIR_IN:
944 case P54U_PIPE_BRG | USB_DIR_IN:
945 case P54U_PIPE_DEV | USB_DIR_IN:
946 case P54U_PIPE_INT | USB_DIR_IN:
947 recognized_pipes++;
948 }
949 }
950 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200951 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700952 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200953#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200954 /* ISL3887 needs a full reset on resume */
955 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200956#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200957 err = p54u_device_reset(dev);
958
Michael Wueff1a592007-09-25 18:11:01 -0700959 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200960 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
961 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
962 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200963 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700964 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200965 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700966 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
967 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
968 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200969 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200970 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200971 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700972 if (err)
973 goto err_free_dev;
974
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200975 err = priv->upload_fw(dev);
976 if (err)
977 goto err_free_fw;
978
Christian Lamparter7cb77072008-09-01 22:48:51 +0200979 p54u_open(dev);
980 err = p54_read_eeprom(dev);
981 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700982 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200983 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700984
Christian Lamparter2ac71072009-03-05 21:30:10 +0100985 err = p54_register_common(dev, &udev->dev);
986 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200987 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700988
Michael Wueff1a592007-09-25 18:11:01 -0700989 return 0;
990
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200991err_free_fw:
992 release_firmware(priv->fw);
993
994err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500995 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700996 usb_set_intfdata(intf, NULL);
997 usb_put_dev(udev);
998 return err;
999}
1000
1001static void __devexit p54u_disconnect(struct usb_interface *intf)
1002{
1003 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1004 struct p54u_priv *priv;
1005
1006 if (!dev)
1007 return;
1008
Christian Lamparterd8c92102009-06-23 10:39:45 -05001009 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001010
1011 priv = dev->priv;
1012 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001013 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001014 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001015}
1016
Christian Lamparter69828692008-12-26 19:08:31 +01001017static int p54u_pre_reset(struct usb_interface *intf)
1018{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001019 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1020
1021 if (!dev)
1022 return -ENODEV;
1023
1024 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001025 return 0;
1026}
1027
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001028static int p54u_resume(struct usb_interface *intf)
1029{
1030 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1031 struct p54u_priv *priv;
1032
1033 if (!dev)
1034 return -ENODEV;
1035
1036 priv = dev->priv;
1037 if (unlikely(!(priv->upload_fw && priv->fw)))
1038 return 0;
1039
1040 return priv->upload_fw(dev);
1041}
1042
Christian Lamparter69828692008-12-26 19:08:31 +01001043static int p54u_post_reset(struct usb_interface *intf)
1044{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001045 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1046 struct p54u_priv *priv;
1047 int err;
1048
1049 err = p54u_resume(intf);
1050 if (err)
1051 return err;
1052
1053 /* reinitialize old device state */
1054 priv = dev->priv;
1055 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1056 ieee80211_restart_hw(dev);
1057
Christian Lamparter69828692008-12-26 19:08:31 +01001058 return 0;
1059}
1060
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001061#ifdef CONFIG_PM
1062
1063static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1064{
1065 return p54u_pre_reset(intf);
1066}
1067
1068#endif /* CONFIG_PM */
1069
Michael Wueff1a592007-09-25 18:11:01 -07001070static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001071 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001072 .id_table = p54u_table,
1073 .probe = p54u_probe,
1074 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001075 .pre_reset = p54u_pre_reset,
1076 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001077#ifdef CONFIG_PM
1078 .suspend = p54u_suspend,
1079 .resume = p54u_resume,
1080 .reset_resume = p54u_resume,
1081#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001082 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001083};
1084
1085static int __init p54u_init(void)
1086{
1087 return usb_register(&p54u_driver);
1088}
1089
1090static void __exit p54u_exit(void)
1091{
1092 usb_deregister(&p54u_driver);
1093}
1094
1095module_init(p54u_init);
1096module_exit(p54u_exit);