blob: d5bc21e5a02c7520d6599ad5822eafe85b267823 [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 Lamparter1a927952010-10-01 22:01:24 +020046 {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
Michael Wueff1a592007-09-25 18:11:01 -070047 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
Hans de Goede05a9a162010-03-17 14:37:16 +010048 {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
Michael Wueff1a592007-09-25 18:11:01 -070049 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090050 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070051 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
52 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050053 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070054 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
55 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
56 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020057 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070058 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
Christian Lamparter1a927952010-10-01 22:01:24 +020059 {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
Michael Wueff1a592007-09-25 18:11:01 -070060 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
Christian Lamparter1a927952010-10-01 22:01:24 +020061 {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
Michael Wueff1a592007-09-25 18:11:01 -070062 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
63 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
64 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
65 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
66 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
67 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
68
69 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070070 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070071 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
72 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
73 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Christian Lamparter1a927952010-10-01 22:01:24 +020074 {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
Michiel878e6a42009-01-04 17:22:28 -060075 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070076 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
77 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060078 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070079 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
80 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
81 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
82 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
83 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070084 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
85 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070086 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020087 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070088 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070089 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020090 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050091 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040092 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020093 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070094 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter1a927952010-10-01 22:01:24 +020095 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Michael Wueff1a592007-09-25 18:11:01 -070096 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Jason Dravet0f666a02010-06-05 15:08:29 -050097 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070098 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
99 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
100 {}
101};
102
103MODULE_DEVICE_TABLE(usb, p54u_table);
104
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200105static const struct {
106 u32 intf;
107 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200108 const char *fw;
109 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200110 char hw[20];
111} p54u_fwlist[__NUM_P54U_HWTYPES] = {
112 {
113 .type = P54U_NET2280,
114 .intf = FW_LM86,
115 .fw = "isl3886usb",
116 .fw_legacy = "isl3890usb",
117 .hw = "ISL3886 + net2280",
118 },
119 {
120 .type = P54U_3887,
121 .intf = FW_LM87,
122 .fw = "isl3887usb",
123 .fw_legacy = "isl3887usb_bare",
124 .hw = "ISL3887",
125 },
126};
127
Michael Wueff1a592007-09-25 18:11:01 -0700128static void p54u_rx_cb(struct urb *urb)
129{
130 struct sk_buff *skb = (struct sk_buff *) urb->context;
131 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
132 struct ieee80211_hw *dev = info->dev;
133 struct p54u_priv *priv = dev->priv;
134
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100135 skb_unlink(skb, &priv->rx_queue);
136
Michael Wueff1a592007-09-25 18:11:01 -0700137 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100138 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700139 return;
140 }
141
Michael Wueff1a592007-09-25 18:11:01 -0700142 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200143
144 if (priv->hw_type == P54U_NET2280)
145 skb_pull(skb, priv->common.tx_hdr_len);
146 if (priv->common.fw_interface == FW_LM87) {
147 skb_pull(skb, 4);
148 skb_put(skb, 4);
149 }
Michael Wueff1a592007-09-25 18:11:01 -0700150
151 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200152 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700153 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700154 /* TODO check rx queue length and refill *somewhere* */
155 return;
156 }
157
158 info = (struct p54u_rx_info *) skb->cb;
159 info->urb = urb;
160 info->dev = dev;
161 urb->transfer_buffer = skb_tail_pointer(skb);
162 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700163 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200164 if (priv->hw_type == P54U_NET2280)
165 skb_push(skb, priv->common.tx_hdr_len);
166 if (priv->common.fw_interface == FW_LM87) {
167 skb_push(skb, 4);
168 skb_put(skb, 4);
169 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200170 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700171 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200172 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700173 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100174 skb_queue_tail(&priv->rx_queue, skb);
175 usb_anchor_urb(urb, &priv->submitted);
176 if (usb_submit_urb(urb, GFP_ATOMIC)) {
177 skb_unlink(skb, &priv->rx_queue);
178 usb_unanchor_urb(urb);
179 dev_kfree_skb_irq(skb);
180 }
Michael Wueff1a592007-09-25 18:11:01 -0700181}
182
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100183static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200184{
185 struct sk_buff *skb = urb->context;
186 struct ieee80211_hw *dev = (struct ieee80211_hw *)
187 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
188
Christian Lampartere2fe1542009-01-20 00:27:57 +0100189 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100190}
191
192static void p54u_tx_dummy_cb(struct urb *urb) { }
193
194static void p54u_free_urbs(struct ieee80211_hw *dev)
195{
196 struct p54u_priv *priv = dev->priv;
197 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200198}
199
Michael Wueff1a592007-09-25 18:11:01 -0700200static int p54u_init_urbs(struct ieee80211_hw *dev)
201{
202 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100203 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700204 struct sk_buff *skb;
205 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100206 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700207
208 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200209 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100210 if (!skb) {
211 ret = -ENOMEM;
212 goto err;
213 }
Michael Wueff1a592007-09-25 18:11:01 -0700214 entry = usb_alloc_urb(0, GFP_KERNEL);
215 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100216 ret = -ENOMEM;
217 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700218 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100219
Christian Lamparter4e416a62008-09-01 22:48:41 +0200220 usb_fill_bulk_urb(entry, priv->udev,
221 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
222 skb_tail_pointer(skb),
223 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700224 info = (struct p54u_rx_info *) skb->cb;
225 info->urb = entry;
226 info->dev = dev;
227 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100228
229 usb_anchor_urb(entry, &priv->submitted);
230 ret = usb_submit_urb(entry, GFP_KERNEL);
231 if (ret) {
232 skb_unlink(skb, &priv->rx_queue);
233 usb_unanchor_urb(entry);
234 goto err;
235 }
236 usb_free_urb(entry);
237 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700238 }
239
240 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700241
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100242 err:
243 usb_free_urb(entry);
244 kfree_skb(skb);
245 p54u_free_urbs(dev);
246 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700247}
248
Johannes Bergc9127652008-12-01 18:19:36 +0100249static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200250{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500251 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200252
253 length >>= 2;
254 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100255 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200256 chk = (chk >> 5) ^ (chk << 3);
257 }
258
Larry Finger1f1c0e32008-09-25 14:54:28 -0500259 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200260}
261
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100262static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200263{
264 struct p54u_priv *priv = dev->priv;
265 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100266 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200267
268 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200269 if (!data_urb) {
270 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200271 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200272 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200273
Christian Lampartere2fe1542009-01-20 00:27:57 +0100274 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
275 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200276
277 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200278 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100279 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
280 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100281 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200282
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100283 usb_anchor_urb(data_urb, &priv->submitted);
284 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
285 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100286 p54_free_skb(dev, skb);
287 }
288 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200289}
290
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100291static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700292{
293 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200294 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100295 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200296 struct net2280_reg_write *reg = NULL;
297 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700298
299 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
300 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200301 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700302
303 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200304 if (!int_urb)
305 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700306
307 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200308 if (!data_urb)
309 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700310
311 reg->port = cpu_to_le16(NET2280_DEV_U32);
312 reg->addr = cpu_to_le32(P54U_DEV_BASE);
313 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
314
Michael Wueff1a592007-09-25 18:11:01 -0700315 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100316 hdr->len = cpu_to_le16(skb->len);
317 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700318
319 usb_fill_bulk_urb(int_urb, priv->udev,
320 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100321 p54u_tx_dummy_cb, dev);
322
323 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200324 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
325 * free what is inside the transfer_buffer after the last reference to
326 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100327 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100328 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200329 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700330
331 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200332 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100333 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
334 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100335 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100336
337 usb_anchor_urb(int_urb, &priv->submitted);
338 err = usb_submit_urb(int_urb, GFP_ATOMIC);
339 if (err) {
340 usb_unanchor_urb(int_urb);
341 goto out;
342 }
343
344 usb_anchor_urb(data_urb, &priv->submitted);
345 err = usb_submit_urb(data_urb, GFP_ATOMIC);
346 if (err) {
347 usb_unanchor_urb(data_urb);
348 goto out;
349 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200350out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100351 usb_free_urb(int_urb);
352 usb_free_urb(data_urb);
353
354 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200355 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100356 p54_free_skb(dev, skb);
357 }
Michael Wueff1a592007-09-25 18:11:01 -0700358}
359
360static int p54u_write(struct p54u_priv *priv,
361 struct net2280_reg_write *buf,
362 enum net2280_op_type type,
363 __le32 addr, __le32 val)
364{
365 unsigned int ep;
366 int alen;
367
368 if (type & 0x0800)
369 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
370 else
371 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
372
373 buf->port = cpu_to_le16(type);
374 buf->addr = addr;
375 buf->val = val;
376
377 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
378}
379
380static int p54u_read(struct p54u_priv *priv, void *buf,
381 enum net2280_op_type type,
382 __le32 addr, __le32 *val)
383{
384 struct net2280_reg_read *read = buf;
385 __le32 *reg = buf;
386 unsigned int ep;
387 int alen, err;
388
389 if (type & 0x0800)
390 ep = P54U_PIPE_DEV;
391 else
392 ep = P54U_PIPE_BRG;
393
394 read->port = cpu_to_le16(type);
395 read->addr = addr;
396
397 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
398 read, sizeof(*read), &alen, 1000);
399 if (err)
400 return err;
401
402 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
403 reg, sizeof(*reg), &alen, 1000);
404 if (err)
405 return err;
406
407 *val = *reg;
408 return 0;
409}
410
411static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
412 void *data, size_t len)
413{
414 int alen;
415 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
416 data, len, &alen, 2000);
417}
418
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200419static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100420{
421 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100422 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100423
Christian Lamparterc88a7682009-01-16 20:24:31 +0100424 if (lock) {
425 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
426 if (ret < 0) {
427 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200428 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100429 return ret;
430 }
Christian Lamparter69828692008-12-26 19:08:31 +0100431 }
432
433 ret = usb_reset_device(priv->udev);
434 if (lock)
435 usb_unlock_device(priv->udev);
436
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200437 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100438 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200439 "device (%d)!\n", ret);
440
441 return ret;
442}
443
444static const char p54u_romboot_3887[] = "~~~~";
445static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
446{
447 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600448 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200449 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100450
Julia Lawall27b81bb2010-05-15 23:22:55 +0200451 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600452 if (!buf)
453 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100454 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600455 buf, 4);
456 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100457 if (ret)
458 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200459 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100460
461 return ret;
462}
463
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200464static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700465static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
466{
Michael Wueff1a592007-09-25 18:11:01 -0700467 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700468 int err, alen;
469 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100470 u8 *buf, *tmp;
471 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700472 unsigned int left, remains, block_size;
473 struct x2_header *hdr;
474 unsigned long timeout;
475
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200476 err = p54u_firmware_reset_3887(dev);
477 if (err)
478 return err;
479
Michael Wueff1a592007-09-25 18:11:01 -0700480 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
481 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100482 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
483 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200484 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700485 }
486
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200487 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100488 strcpy(buf, p54u_firmware_upload_3887);
489 left -= strlen(p54u_firmware_upload_3887);
490 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700491
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200492 data = priv->fw->data;
493 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700494
Christian Lamparter69828692008-12-26 19:08:31 +0100495 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700496 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
497 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200498 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700499 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
500 sizeof(u32)*2));
501 left -= sizeof(*hdr);
502 tmp += sizeof(*hdr);
503
504 while (remains) {
505 while (left--) {
506 if (carry) {
507 *tmp++ = carry;
508 carry = 0;
509 remains--;
510 continue;
511 }
512 switch (*data) {
513 case '~':
514 *tmp++ = '}';
515 carry = '^';
516 break;
517 case '}':
518 *tmp++ = '}';
519 carry = ']';
520 break;
521 default:
522 *tmp++ = *data;
523 remains--;
524 break;
525 }
526 data++;
527 }
528
529 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
530 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100531 dev_err(&priv->udev->dev, "(p54usb) firmware "
532 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700533 goto err_upload_failed;
534 }
535
536 tmp = buf;
537 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
538 }
539
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200540 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
541 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700542 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
543 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100544 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700545 goto err_upload_failed;
546 }
Michael Wueff1a592007-09-25 18:11:01 -0700547 timeout = jiffies + msecs_to_jiffies(1000);
548 while (!(err = usb_bulk_msg(priv->udev,
549 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
550 if (alen > 2 && !memcmp(buf, "OK", 2))
551 break;
552
553 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700554 err = -EINVAL;
555 break;
556 }
557
558 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100559 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
560 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700561 err = -ETIMEDOUT;
562 break;
563 }
564 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100565 if (err) {
566 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700567 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100568 }
Michael Wueff1a592007-09-25 18:11:01 -0700569
570 buf[0] = 'g';
571 buf[1] = '\r';
572 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
573 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100574 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700575 goto err_upload_failed;
576 }
577
578 timeout = jiffies + msecs_to_jiffies(1000);
579 while (!(err = usb_bulk_msg(priv->udev,
580 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
581 if (alen > 0 && buf[0] == 'g')
582 break;
583
584 if (time_after(jiffies, timeout)) {
585 err = -ETIMEDOUT;
586 break;
587 }
588 }
589 if (err)
590 goto err_upload_failed;
591
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200592err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700593 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700594 return err;
595}
596
597static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
598{
599 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700600 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
601 int err, alen;
602 void *buf;
603 __le32 reg;
604 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100605 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700606
607 buf = kmalloc(512, GFP_KERNEL);
608 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100609 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
610 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700611 return -ENOMEM;
612 }
613
Michael Wueff1a592007-09-25 18:11:01 -0700614#define P54U_WRITE(type, addr, data) \
615 do {\
616 err = p54u_write(priv, buf, type,\
617 cpu_to_le32((u32)(unsigned long)addr), data);\
618 if (err) \
619 goto fail;\
620 } while (0)
621
622#define P54U_READ(type, addr) \
623 do {\
624 err = p54u_read(priv, buf, type,\
625 cpu_to_le32((u32)(unsigned long)addr), &reg);\
626 if (err)\
627 goto fail;\
628 } while (0)
629
630 /* power down net2280 bridge */
631 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
632 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
633 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
634 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
635
636 mdelay(100);
637
638 /* power up bridge */
639 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
640 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
641 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
642
643 mdelay(100);
644
645 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
646 cpu_to_le32(NET2280_CLK_30Mhz |
647 NET2280_PCI_ENABLE |
648 NET2280_PCI_SOFT_RESET));
649
650 mdelay(20);
651
652 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
653 cpu_to_le32(PCI_COMMAND_MEMORY |
654 PCI_COMMAND_MASTER));
655
656 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
657 cpu_to_le32(NET2280_BASE));
658
659 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
660 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
661 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
662
663 // TODO: we really need this?
664 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
665
666 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
667 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
668 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
669 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
670
671 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
672 cpu_to_le32(NET2280_BASE2));
673
674 /* finally done setting up the bridge */
675
676 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
677 cpu_to_le32(PCI_COMMAND_MEMORY |
678 PCI_COMMAND_MASTER));
679
680 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
681 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
682 cpu_to_le32(P54U_DEV_BASE));
683
684 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
685 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
686 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
687
688 /* do romboot */
689 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
690
691 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
692 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
693 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
694 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
695 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
696
697 mdelay(20);
698
699 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
700 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
701
702 mdelay(20);
703
704 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
705 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
706
707 mdelay(100);
708
709 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
710 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
711
712 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200713 remains = priv->fw->size;
714 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700715 offset = ISL38XX_DEV_FIRMWARE_ADDR;
716
717 while (remains) {
718 unsigned int block_len = min(remains, (unsigned int)512);
719 memcpy(buf, data, block_len);
720
721 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
722 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100723 dev_err(&priv->udev->dev, "(p54usb) firmware block "
724 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700725 goto fail;
726 }
727
728 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
729 cpu_to_le32(0xc0000f00));
730
731 P54U_WRITE(NET2280_DEV_U32,
732 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
733 P54U_WRITE(NET2280_DEV_U32,
734 0x0020 | (unsigned long)&devreg->direct_mem_win,
735 cpu_to_le32(1));
736
737 P54U_WRITE(NET2280_DEV_U32,
738 0x0024 | (unsigned long)&devreg->direct_mem_win,
739 cpu_to_le32(block_len));
740 P54U_WRITE(NET2280_DEV_U32,
741 0x0028 | (unsigned long)&devreg->direct_mem_win,
742 cpu_to_le32(offset));
743
744 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
745 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
746 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
747 cpu_to_le32(block_len >> 2));
748 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
749 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
750
751 mdelay(10);
752
753 P54U_READ(NET2280_DEV_U32,
754 0x002C | (unsigned long)&devreg->direct_mem_win);
755 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
756 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100757 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
758 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700759 goto fail;
760 }
761
762 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
763 cpu_to_le32(NET2280_FIFO_FLUSH));
764
765 remains -= block_len;
766 data += block_len;
767 offset += block_len;
768 }
769
770 /* do ramboot */
771 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
772 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
773 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
774 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
775 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
776
777 mdelay(20);
778
779 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
780 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
781
782 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
783 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
784
785 mdelay(100);
786
787 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
788 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
789
790 /* start up the firmware */
791 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
792 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
793
794 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
795 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
796
797 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
798 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
799 NET2280_USB_INTERRUPT_ENABLE));
800
801 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
802 cpu_to_le32(ISL38XX_DEV_INT_RESET));
803
804 err = usb_interrupt_msg(priv->udev,
805 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
806 buf, sizeof(__le32), &alen, 1000);
807 if (err || alen != sizeof(__le32))
808 goto fail;
809
810 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
811 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
812
813 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
814 err = -EINVAL;
815
816 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
817 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
818 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
819
820#undef P54U_WRITE
821#undef P54U_READ
822
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200823fail:
Michael Wueff1a592007-09-25 18:11:01 -0700824 kfree(buf);
825 return err;
826}
827
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200828static int p54u_load_firmware(struct ieee80211_hw *dev)
829{
830 struct p54u_priv *priv = dev->priv;
831 int err, i;
832
833 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
834
835 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
836 if (p54u_fwlist[i].type == priv->hw_type)
837 break;
838
839 if (i == __NUM_P54U_HWTYPES)
840 return -EOPNOTSUPP;
841
842 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
843 if (err) {
844 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
845 "(%d)!\n", p54u_fwlist[i].fw, err);
846
847 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
848 &priv->udev->dev);
849 if (err)
850 return err;
851 }
852
853 err = p54_parse_firmware(dev, priv->fw);
854 if (err)
855 goto out;
856
857 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
858 dev_err(&priv->udev->dev, "wrong firmware, please get "
859 "a firmware for \"%s\" and try again.\n",
860 p54u_fwlist[i].hw);
861 err = -EINVAL;
862 }
863
864out:
865 if (err)
866 release_firmware(priv->fw);
867
868 return err;
869}
870
Michael Wueff1a592007-09-25 18:11:01 -0700871static int p54u_open(struct ieee80211_hw *dev)
872{
873 struct p54u_priv *priv = dev->priv;
874 int err;
875
876 err = p54u_init_urbs(dev);
877 if (err) {
878 return err;
879 }
880
881 priv->common.open = p54u_init_urbs;
882
883 return 0;
884}
885
886static void p54u_stop(struct ieee80211_hw *dev)
887{
888 /* TODO: figure out how to reliably stop the 3887 and net2280 so
889 the hardware is still usable next time we want to start it.
890 until then, we just stop listening to the hardware.. */
891 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700892}
893
894static int __devinit p54u_probe(struct usb_interface *intf,
895 const struct usb_device_id *id)
896{
897 struct usb_device *udev = interface_to_usbdev(intf);
898 struct ieee80211_hw *dev;
899 struct p54u_priv *priv;
900 int err;
901 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700902
903 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100904
Michael Wueff1a592007-09-25 18:11:01 -0700905 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100906 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700907 return -ENOMEM;
908 }
909
910 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200911 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700912
913 SET_IEEE80211_DEV(dev, &intf->dev);
914 usb_set_intfdata(intf, dev);
915 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100916 priv->intf = intf;
917 skb_queue_head_init(&priv->rx_queue);
918 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700919
920 usb_get_dev(udev);
921
922 /* really lazy and simple way of figuring out if we're a 3887 */
923 /* TODO: should just stick the identification in the device table */
924 i = intf->altsetting->desc.bNumEndpoints;
925 recognized_pipes = 0;
926 while (i--) {
927 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
928 case P54U_PIPE_DATA:
929 case P54U_PIPE_MGMT:
930 case P54U_PIPE_BRG:
931 case P54U_PIPE_DEV:
932 case P54U_PIPE_DATA | USB_DIR_IN:
933 case P54U_PIPE_MGMT | USB_DIR_IN:
934 case P54U_PIPE_BRG | USB_DIR_IN:
935 case P54U_PIPE_DEV | USB_DIR_IN:
936 case P54U_PIPE_INT | USB_DIR_IN:
937 recognized_pipes++;
938 }
939 }
940 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200941 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700942 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200943#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200944 /* ISL3887 needs a full reset on resume */
945 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200946#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200947 err = p54u_device_reset(dev);
948
Michael Wueff1a592007-09-25 18:11:01 -0700949 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200950 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
951 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
952 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200953 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700954 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200955 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700956 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
957 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
958 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200959 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200960 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200961 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700962 if (err)
963 goto err_free_dev;
964
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200965 err = priv->upload_fw(dev);
966 if (err)
967 goto err_free_fw;
968
Christian Lamparter7cb77072008-09-01 22:48:51 +0200969 p54u_open(dev);
970 err = p54_read_eeprom(dev);
971 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700972 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200973 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700974
Christian Lamparter2ac71072009-03-05 21:30:10 +0100975 err = p54_register_common(dev, &udev->dev);
976 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200977 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700978
Michael Wueff1a592007-09-25 18:11:01 -0700979 return 0;
980
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200981err_free_fw:
982 release_firmware(priv->fw);
983
984err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500985 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700986 usb_set_intfdata(intf, NULL);
987 usb_put_dev(udev);
988 return err;
989}
990
991static void __devexit p54u_disconnect(struct usb_interface *intf)
992{
993 struct ieee80211_hw *dev = usb_get_intfdata(intf);
994 struct p54u_priv *priv;
995
996 if (!dev)
997 return;
998
Christian Lamparterd8c92102009-06-23 10:39:45 -0500999 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001000
1001 priv = dev->priv;
1002 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001003 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001004 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001005}
1006
Christian Lamparter69828692008-12-26 19:08:31 +01001007static int p54u_pre_reset(struct usb_interface *intf)
1008{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001009 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1010
1011 if (!dev)
1012 return -ENODEV;
1013
1014 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001015 return 0;
1016}
1017
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001018static int p54u_resume(struct usb_interface *intf)
1019{
1020 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1021 struct p54u_priv *priv;
1022
1023 if (!dev)
1024 return -ENODEV;
1025
1026 priv = dev->priv;
1027 if (unlikely(!(priv->upload_fw && priv->fw)))
1028 return 0;
1029
1030 return priv->upload_fw(dev);
1031}
1032
Christian Lamparter69828692008-12-26 19:08:31 +01001033static int p54u_post_reset(struct usb_interface *intf)
1034{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001035 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1036 struct p54u_priv *priv;
1037 int err;
1038
1039 err = p54u_resume(intf);
1040 if (err)
1041 return err;
1042
1043 /* reinitialize old device state */
1044 priv = dev->priv;
1045 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1046 ieee80211_restart_hw(dev);
1047
Christian Lamparter69828692008-12-26 19:08:31 +01001048 return 0;
1049}
1050
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001051#ifdef CONFIG_PM
1052
1053static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1054{
1055 return p54u_pre_reset(intf);
1056}
1057
1058#endif /* CONFIG_PM */
1059
Michael Wueff1a592007-09-25 18:11:01 -07001060static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001061 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001062 .id_table = p54u_table,
1063 .probe = p54u_probe,
1064 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001065 .pre_reset = p54u_pre_reset,
1066 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001067#ifdef CONFIG_PM
1068 .suspend = p54u_suspend,
1069 .resume = p54u_resume,
1070 .reset_resume = p54u_resume,
1071#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001072 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001073};
1074
1075static int __init p54u_init(void)
1076{
1077 return usb_register(&p54u_driver);
1078}
1079
1080static void __exit p54u_exit(void)
1081{
1082 usb_deregister(&p54u_driver);
1083}
1084
1085module_init(p54u_init);
1086module_exit(p54u_exit);