blob: 2325e56a9b0bd8cc35c7ee958be19ed5ff2adf2f [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 */
Michael Wueff1a592007-09-25 18:11:01 -070059 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010060 {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
Christian Lamparter1a927952010-10-01 22:01:24 +020061 {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
Michael Wueff1a592007-09-25 18:11:01 -070062 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010063 {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
Eduardo Costa56e64172010-12-14 14:37:59 -060064 {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
Christian Lamparter1a927952010-10-01 22:01:24 +020065 {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
Christian Lamparter16cad7f2010-12-11 12:19:48 +010066 {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
Michael Wueff1a592007-09-25 18:11:01 -070067 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
68 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
69 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
70 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
71 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
72 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
73
74 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070075 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070076 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
77 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
78 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Christian Lamparter1a927952010-10-01 22:01:24 +020079 {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
Michiel878e6a42009-01-04 17:22:28 -060080 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070081 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
82 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060083 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070084 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
85 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
86 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
87 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
88 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
Leann Ogasawara7484bdc2010-06-15 14:01:51 -070089 /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
90 * just noting it here for clarity */
Michael Wueff1a592007-09-25 18:11:01 -070091 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020092 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070093 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070094 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020095 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050096 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040097 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020098 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070099 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
Christian Lamparter1a927952010-10-01 22:01:24 +0200100 {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
Michael Wueff1a592007-09-25 18:11:01 -0700101 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Christian Lamparter16cad7f2010-12-11 12:19:48 +0100102 {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
Jason Dravet0f666a02010-06-05 15:08:29 -0500103 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -0700104 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
105 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
106 {}
107};
108
109MODULE_DEVICE_TABLE(usb, p54u_table);
110
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200111static const struct {
112 u32 intf;
113 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +0200114 const char *fw;
115 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200116 char hw[20];
117} p54u_fwlist[__NUM_P54U_HWTYPES] = {
118 {
119 .type = P54U_NET2280,
120 .intf = FW_LM86,
121 .fw = "isl3886usb",
122 .fw_legacy = "isl3890usb",
123 .hw = "ISL3886 + net2280",
124 },
125 {
126 .type = P54U_3887,
127 .intf = FW_LM87,
128 .fw = "isl3887usb",
129 .fw_legacy = "isl3887usb_bare",
130 .hw = "ISL3887",
131 },
132};
133
Michael Wueff1a592007-09-25 18:11:01 -0700134static void p54u_rx_cb(struct urb *urb)
135{
136 struct sk_buff *skb = (struct sk_buff *) urb->context;
137 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
138 struct ieee80211_hw *dev = info->dev;
139 struct p54u_priv *priv = dev->priv;
140
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100141 skb_unlink(skb, &priv->rx_queue);
142
Michael Wueff1a592007-09-25 18:11:01 -0700143 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100144 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700145 return;
146 }
147
Michael Wueff1a592007-09-25 18:11:01 -0700148 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200149
150 if (priv->hw_type == P54U_NET2280)
151 skb_pull(skb, priv->common.tx_hdr_len);
152 if (priv->common.fw_interface == FW_LM87) {
153 skb_pull(skb, 4);
154 skb_put(skb, 4);
155 }
Michael Wueff1a592007-09-25 18:11:01 -0700156
157 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200158 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700159 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700160 /* TODO check rx queue length and refill *somewhere* */
161 return;
162 }
163
164 info = (struct p54u_rx_info *) skb->cb;
165 info->urb = urb;
166 info->dev = dev;
167 urb->transfer_buffer = skb_tail_pointer(skb);
168 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700169 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200170 if (priv->hw_type == P54U_NET2280)
171 skb_push(skb, priv->common.tx_hdr_len);
172 if (priv->common.fw_interface == FW_LM87) {
173 skb_push(skb, 4);
174 skb_put(skb, 4);
175 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200176 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700177 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200178 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700179 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100180 skb_queue_tail(&priv->rx_queue, skb);
181 usb_anchor_urb(urb, &priv->submitted);
182 if (usb_submit_urb(urb, GFP_ATOMIC)) {
183 skb_unlink(skb, &priv->rx_queue);
184 usb_unanchor_urb(urb);
185 dev_kfree_skb_irq(skb);
186 }
Michael Wueff1a592007-09-25 18:11:01 -0700187}
188
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100189static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200190{
191 struct sk_buff *skb = urb->context;
192 struct ieee80211_hw *dev = (struct ieee80211_hw *)
193 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
194
Christian Lampartere2fe1542009-01-20 00:27:57 +0100195 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100196}
197
198static void p54u_tx_dummy_cb(struct urb *urb) { }
199
200static void p54u_free_urbs(struct ieee80211_hw *dev)
201{
202 struct p54u_priv *priv = dev->priv;
203 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200204}
205
Michael Wueff1a592007-09-25 18:11:01 -0700206static int p54u_init_urbs(struct ieee80211_hw *dev)
207{
208 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100209 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700210 struct sk_buff *skb;
211 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100212 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700213
214 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200215 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100216 if (!skb) {
217 ret = -ENOMEM;
218 goto err;
219 }
Michael Wueff1a592007-09-25 18:11:01 -0700220 entry = usb_alloc_urb(0, GFP_KERNEL);
221 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100222 ret = -ENOMEM;
223 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700224 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100225
Christian Lamparter4e416a62008-09-01 22:48:41 +0200226 usb_fill_bulk_urb(entry, priv->udev,
227 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
228 skb_tail_pointer(skb),
229 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700230 info = (struct p54u_rx_info *) skb->cb;
231 info->urb = entry;
232 info->dev = dev;
233 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100234
235 usb_anchor_urb(entry, &priv->submitted);
236 ret = usb_submit_urb(entry, GFP_KERNEL);
237 if (ret) {
238 skb_unlink(skb, &priv->rx_queue);
239 usb_unanchor_urb(entry);
240 goto err;
241 }
242 usb_free_urb(entry);
243 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700244 }
245
246 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700247
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100248 err:
249 usb_free_urb(entry);
250 kfree_skb(skb);
251 p54u_free_urbs(dev);
252 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700253}
254
Johannes Bergc9127652008-12-01 18:19:36 +0100255static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200256{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500257 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200258
259 length >>= 2;
260 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100261 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200262 chk = (chk >> 5) ^ (chk << 3);
263 }
264
Larry Finger1f1c0e32008-09-25 14:54:28 -0500265 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200266}
267
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100268static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200269{
270 struct p54u_priv *priv = dev->priv;
271 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100272 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200273
274 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200275 if (!data_urb) {
276 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200277 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200278 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200279
Christian Lampartere2fe1542009-01-20 00:27:57 +0100280 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
281 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200282
283 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200284 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100285 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
286 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100287 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200288
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100289 usb_anchor_urb(data_urb, &priv->submitted);
290 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
291 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100292 p54_free_skb(dev, skb);
293 }
294 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200295}
296
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100297static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700298{
299 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200300 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100301 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200302 struct net2280_reg_write *reg = NULL;
303 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700304
305 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
306 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200307 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700308
309 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200310 if (!int_urb)
311 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700312
313 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200314 if (!data_urb)
315 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700316
317 reg->port = cpu_to_le16(NET2280_DEV_U32);
318 reg->addr = cpu_to_le32(P54U_DEV_BASE);
319 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
320
Michael Wueff1a592007-09-25 18:11:01 -0700321 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100322 hdr->len = cpu_to_le16(skb->len);
323 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700324
325 usb_fill_bulk_urb(int_urb, priv->udev,
326 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100327 p54u_tx_dummy_cb, dev);
328
329 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200330 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
331 * free what is inside the transfer_buffer after the last reference to
332 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100333 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100334 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200335 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700336
337 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200338 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100339 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
340 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100341 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100342
343 usb_anchor_urb(int_urb, &priv->submitted);
344 err = usb_submit_urb(int_urb, GFP_ATOMIC);
345 if (err) {
346 usb_unanchor_urb(int_urb);
347 goto out;
348 }
349
350 usb_anchor_urb(data_urb, &priv->submitted);
351 err = usb_submit_urb(data_urb, GFP_ATOMIC);
352 if (err) {
353 usb_unanchor_urb(data_urb);
354 goto out;
355 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200356out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100357 usb_free_urb(int_urb);
358 usb_free_urb(data_urb);
359
360 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200361 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100362 p54_free_skb(dev, skb);
363 }
Michael Wueff1a592007-09-25 18:11:01 -0700364}
365
366static int p54u_write(struct p54u_priv *priv,
367 struct net2280_reg_write *buf,
368 enum net2280_op_type type,
369 __le32 addr, __le32 val)
370{
371 unsigned int ep;
372 int alen;
373
374 if (type & 0x0800)
375 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
376 else
377 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
378
379 buf->port = cpu_to_le16(type);
380 buf->addr = addr;
381 buf->val = val;
382
383 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
384}
385
386static int p54u_read(struct p54u_priv *priv, void *buf,
387 enum net2280_op_type type,
388 __le32 addr, __le32 *val)
389{
390 struct net2280_reg_read *read = buf;
391 __le32 *reg = buf;
392 unsigned int ep;
393 int alen, err;
394
395 if (type & 0x0800)
396 ep = P54U_PIPE_DEV;
397 else
398 ep = P54U_PIPE_BRG;
399
400 read->port = cpu_to_le16(type);
401 read->addr = addr;
402
403 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
404 read, sizeof(*read), &alen, 1000);
405 if (err)
406 return err;
407
408 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
409 reg, sizeof(*reg), &alen, 1000);
410 if (err)
411 return err;
412
413 *val = *reg;
414 return 0;
415}
416
417static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
418 void *data, size_t len)
419{
420 int alen;
421 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
422 data, len, &alen, 2000);
423}
424
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200425static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100426{
427 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100428 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100429
Christian Lamparterc88a7682009-01-16 20:24:31 +0100430 if (lock) {
431 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
432 if (ret < 0) {
433 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200434 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100435 return ret;
436 }
Christian Lamparter69828692008-12-26 19:08:31 +0100437 }
438
439 ret = usb_reset_device(priv->udev);
440 if (lock)
441 usb_unlock_device(priv->udev);
442
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200443 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100444 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200445 "device (%d)!\n", ret);
446
447 return ret;
448}
449
450static const char p54u_romboot_3887[] = "~~~~";
451static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
452{
453 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600454 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200455 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100456
Julia Lawall27b81bb2010-05-15 23:22:55 +0200457 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600458 if (!buf)
459 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100460 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600461 buf, 4);
462 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100463 if (ret)
464 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200465 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100466
467 return ret;
468}
469
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200470static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700471static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
472{
Michael Wueff1a592007-09-25 18:11:01 -0700473 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700474 int err, alen;
475 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100476 u8 *buf, *tmp;
477 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700478 unsigned int left, remains, block_size;
479 struct x2_header *hdr;
480 unsigned long timeout;
481
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200482 err = p54u_firmware_reset_3887(dev);
483 if (err)
484 return err;
485
Michael Wueff1a592007-09-25 18:11:01 -0700486 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
487 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100488 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
489 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200490 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700491 }
492
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200493 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100494 strcpy(buf, p54u_firmware_upload_3887);
495 left -= strlen(p54u_firmware_upload_3887);
496 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700497
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200498 data = priv->fw->data;
499 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700500
Christian Lamparter69828692008-12-26 19:08:31 +0100501 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700502 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
503 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200504 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700505 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
506 sizeof(u32)*2));
507 left -= sizeof(*hdr);
508 tmp += sizeof(*hdr);
509
510 while (remains) {
511 while (left--) {
512 if (carry) {
513 *tmp++ = carry;
514 carry = 0;
515 remains--;
516 continue;
517 }
518 switch (*data) {
519 case '~':
520 *tmp++ = '}';
521 carry = '^';
522 break;
523 case '}':
524 *tmp++ = '}';
525 carry = ']';
526 break;
527 default:
528 *tmp++ = *data;
529 remains--;
530 break;
531 }
532 data++;
533 }
534
535 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
536 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100537 dev_err(&priv->udev->dev, "(p54usb) firmware "
538 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700539 goto err_upload_failed;
540 }
541
542 tmp = buf;
543 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
544 }
545
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200546 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
547 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700548 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
549 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100550 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700551 goto err_upload_failed;
552 }
Michael Wueff1a592007-09-25 18:11:01 -0700553 timeout = jiffies + msecs_to_jiffies(1000);
554 while (!(err = usb_bulk_msg(priv->udev,
555 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
556 if (alen > 2 && !memcmp(buf, "OK", 2))
557 break;
558
559 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700560 err = -EINVAL;
561 break;
562 }
563
564 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100565 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
566 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700567 err = -ETIMEDOUT;
568 break;
569 }
570 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100571 if (err) {
572 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700573 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100574 }
Michael Wueff1a592007-09-25 18:11:01 -0700575
576 buf[0] = 'g';
577 buf[1] = '\r';
578 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
579 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100580 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700581 goto err_upload_failed;
582 }
583
584 timeout = jiffies + msecs_to_jiffies(1000);
585 while (!(err = usb_bulk_msg(priv->udev,
586 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
587 if (alen > 0 && buf[0] == 'g')
588 break;
589
590 if (time_after(jiffies, timeout)) {
591 err = -ETIMEDOUT;
592 break;
593 }
594 }
595 if (err)
596 goto err_upload_failed;
597
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200598err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700599 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700600 return err;
601}
602
603static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
604{
605 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700606 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
607 int err, alen;
608 void *buf;
609 __le32 reg;
610 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100611 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700612
613 buf = kmalloc(512, GFP_KERNEL);
614 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100615 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
616 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700617 return -ENOMEM;
618 }
619
Michael Wueff1a592007-09-25 18:11:01 -0700620#define P54U_WRITE(type, addr, data) \
621 do {\
622 err = p54u_write(priv, buf, type,\
623 cpu_to_le32((u32)(unsigned long)addr), data);\
624 if (err) \
625 goto fail;\
626 } while (0)
627
628#define P54U_READ(type, addr) \
629 do {\
630 err = p54u_read(priv, buf, type,\
631 cpu_to_le32((u32)(unsigned long)addr), &reg);\
632 if (err)\
633 goto fail;\
634 } while (0)
635
636 /* power down net2280 bridge */
637 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
638 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
639 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
640 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
641
642 mdelay(100);
643
644 /* power up bridge */
645 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
646 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
647 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
648
649 mdelay(100);
650
651 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
652 cpu_to_le32(NET2280_CLK_30Mhz |
653 NET2280_PCI_ENABLE |
654 NET2280_PCI_SOFT_RESET));
655
656 mdelay(20);
657
658 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
659 cpu_to_le32(PCI_COMMAND_MEMORY |
660 PCI_COMMAND_MASTER));
661
662 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
663 cpu_to_le32(NET2280_BASE));
664
665 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
666 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
667 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
668
669 // TODO: we really need this?
670 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
671
672 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
673 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
674 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
675 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
676
677 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
678 cpu_to_le32(NET2280_BASE2));
679
680 /* finally done setting up the bridge */
681
682 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
683 cpu_to_le32(PCI_COMMAND_MEMORY |
684 PCI_COMMAND_MASTER));
685
686 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
687 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
688 cpu_to_le32(P54U_DEV_BASE));
689
690 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
691 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
692 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
693
694 /* do romboot */
695 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
696
697 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
698 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
699 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
700 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
701 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
702
703 mdelay(20);
704
705 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
706 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
707
708 mdelay(20);
709
710 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
711 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
712
713 mdelay(100);
714
715 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
716 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
717
718 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200719 remains = priv->fw->size;
720 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700721 offset = ISL38XX_DEV_FIRMWARE_ADDR;
722
723 while (remains) {
724 unsigned int block_len = min(remains, (unsigned int)512);
725 memcpy(buf, data, block_len);
726
727 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
728 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100729 dev_err(&priv->udev->dev, "(p54usb) firmware block "
730 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700731 goto fail;
732 }
733
734 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
735 cpu_to_le32(0xc0000f00));
736
737 P54U_WRITE(NET2280_DEV_U32,
738 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
739 P54U_WRITE(NET2280_DEV_U32,
740 0x0020 | (unsigned long)&devreg->direct_mem_win,
741 cpu_to_le32(1));
742
743 P54U_WRITE(NET2280_DEV_U32,
744 0x0024 | (unsigned long)&devreg->direct_mem_win,
745 cpu_to_le32(block_len));
746 P54U_WRITE(NET2280_DEV_U32,
747 0x0028 | (unsigned long)&devreg->direct_mem_win,
748 cpu_to_le32(offset));
749
750 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
751 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
752 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
753 cpu_to_le32(block_len >> 2));
754 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
755 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
756
757 mdelay(10);
758
759 P54U_READ(NET2280_DEV_U32,
760 0x002C | (unsigned long)&devreg->direct_mem_win);
761 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
762 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100763 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
764 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700765 goto fail;
766 }
767
768 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
769 cpu_to_le32(NET2280_FIFO_FLUSH));
770
771 remains -= block_len;
772 data += block_len;
773 offset += block_len;
774 }
775
776 /* do ramboot */
777 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
778 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
779 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
780 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
781 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
782
783 mdelay(20);
784
785 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
786 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
787
788 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
789 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
790
791 mdelay(100);
792
793 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
794 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
795
796 /* start up the firmware */
797 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
798 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
799
800 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
801 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
802
803 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
804 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
805 NET2280_USB_INTERRUPT_ENABLE));
806
807 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
808 cpu_to_le32(ISL38XX_DEV_INT_RESET));
809
810 err = usb_interrupt_msg(priv->udev,
811 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
812 buf, sizeof(__le32), &alen, 1000);
813 if (err || alen != sizeof(__le32))
814 goto fail;
815
816 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
817 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
818
819 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
820 err = -EINVAL;
821
822 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
823 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
824 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
825
826#undef P54U_WRITE
827#undef P54U_READ
828
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200829fail:
Michael Wueff1a592007-09-25 18:11:01 -0700830 kfree(buf);
831 return err;
832}
833
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200834static int p54u_load_firmware(struct ieee80211_hw *dev)
835{
836 struct p54u_priv *priv = dev->priv;
837 int err, i;
838
839 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
840
841 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
842 if (p54u_fwlist[i].type == priv->hw_type)
843 break;
844
845 if (i == __NUM_P54U_HWTYPES)
846 return -EOPNOTSUPP;
847
848 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
849 if (err) {
850 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
851 "(%d)!\n", p54u_fwlist[i].fw, err);
852
853 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
854 &priv->udev->dev);
855 if (err)
856 return err;
857 }
858
859 err = p54_parse_firmware(dev, priv->fw);
860 if (err)
861 goto out;
862
863 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
864 dev_err(&priv->udev->dev, "wrong firmware, please get "
865 "a firmware for \"%s\" and try again.\n",
866 p54u_fwlist[i].hw);
867 err = -EINVAL;
868 }
869
870out:
871 if (err)
872 release_firmware(priv->fw);
873
874 return err;
875}
876
Michael Wueff1a592007-09-25 18:11:01 -0700877static int p54u_open(struct ieee80211_hw *dev)
878{
879 struct p54u_priv *priv = dev->priv;
880 int err;
881
882 err = p54u_init_urbs(dev);
883 if (err) {
884 return err;
885 }
886
887 priv->common.open = p54u_init_urbs;
888
889 return 0;
890}
891
892static void p54u_stop(struct ieee80211_hw *dev)
893{
894 /* TODO: figure out how to reliably stop the 3887 and net2280 so
895 the hardware is still usable next time we want to start it.
896 until then, we just stop listening to the hardware.. */
897 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700898}
899
900static int __devinit p54u_probe(struct usb_interface *intf,
901 const struct usb_device_id *id)
902{
903 struct usb_device *udev = interface_to_usbdev(intf);
904 struct ieee80211_hw *dev;
905 struct p54u_priv *priv;
906 int err;
907 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700908
909 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100910
Michael Wueff1a592007-09-25 18:11:01 -0700911 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100912 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700913 return -ENOMEM;
914 }
915
916 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200917 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700918
919 SET_IEEE80211_DEV(dev, &intf->dev);
920 usb_set_intfdata(intf, dev);
921 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100922 priv->intf = intf;
923 skb_queue_head_init(&priv->rx_queue);
924 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700925
926 usb_get_dev(udev);
927
928 /* really lazy and simple way of figuring out if we're a 3887 */
929 /* TODO: should just stick the identification in the device table */
930 i = intf->altsetting->desc.bNumEndpoints;
931 recognized_pipes = 0;
932 while (i--) {
933 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
934 case P54U_PIPE_DATA:
935 case P54U_PIPE_MGMT:
936 case P54U_PIPE_BRG:
937 case P54U_PIPE_DEV:
938 case P54U_PIPE_DATA | USB_DIR_IN:
939 case P54U_PIPE_MGMT | USB_DIR_IN:
940 case P54U_PIPE_BRG | USB_DIR_IN:
941 case P54U_PIPE_DEV | USB_DIR_IN:
942 case P54U_PIPE_INT | USB_DIR_IN:
943 recognized_pipes++;
944 }
945 }
946 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200947 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700948 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200949#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200950 /* ISL3887 needs a full reset on resume */
951 udev->reset_resume = 1;
Christian Lamparter11791a62010-08-22 22:41:33 +0200952#endif /* CONFIG_PM */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200953 err = p54u_device_reset(dev);
954
Michael Wueff1a592007-09-25 18:11:01 -0700955 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200956 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
957 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
958 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200959 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700960 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200961 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700962 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
963 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
964 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200965 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200966 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200967 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700968 if (err)
969 goto err_free_dev;
970
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200971 err = priv->upload_fw(dev);
972 if (err)
973 goto err_free_fw;
974
Christian Lamparter7cb77072008-09-01 22:48:51 +0200975 p54u_open(dev);
976 err = p54_read_eeprom(dev);
977 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700978 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200979 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700980
Christian Lamparter2ac71072009-03-05 21:30:10 +0100981 err = p54_register_common(dev, &udev->dev);
982 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200983 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700984
Michael Wueff1a592007-09-25 18:11:01 -0700985 return 0;
986
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200987err_free_fw:
988 release_firmware(priv->fw);
989
990err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500991 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700992 usb_set_intfdata(intf, NULL);
993 usb_put_dev(udev);
994 return err;
995}
996
997static void __devexit p54u_disconnect(struct usb_interface *intf)
998{
999 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1000 struct p54u_priv *priv;
1001
1002 if (!dev)
1003 return;
1004
Christian Lamparterd8c92102009-06-23 10:39:45 -05001005 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001006
1007 priv = dev->priv;
1008 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001009 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -07001010 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -07001011}
1012
Christian Lamparter69828692008-12-26 19:08:31 +01001013static int p54u_pre_reset(struct usb_interface *intf)
1014{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001015 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1016
1017 if (!dev)
1018 return -ENODEV;
1019
1020 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001021 return 0;
1022}
1023
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001024static int p54u_resume(struct usb_interface *intf)
1025{
1026 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1027 struct p54u_priv *priv;
1028
1029 if (!dev)
1030 return -ENODEV;
1031
1032 priv = dev->priv;
1033 if (unlikely(!(priv->upload_fw && priv->fw)))
1034 return 0;
1035
1036 return priv->upload_fw(dev);
1037}
1038
Christian Lamparter69828692008-12-26 19:08:31 +01001039static int p54u_post_reset(struct usb_interface *intf)
1040{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001041 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1042 struct p54u_priv *priv;
1043 int err;
1044
1045 err = p54u_resume(intf);
1046 if (err)
1047 return err;
1048
1049 /* reinitialize old device state */
1050 priv = dev->priv;
1051 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1052 ieee80211_restart_hw(dev);
1053
Christian Lamparter69828692008-12-26 19:08:31 +01001054 return 0;
1055}
1056
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001057#ifdef CONFIG_PM
1058
1059static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1060{
1061 return p54u_pre_reset(intf);
1062}
1063
1064#endif /* CONFIG_PM */
1065
Michael Wueff1a592007-09-25 18:11:01 -07001066static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001067 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001068 .id_table = p54u_table,
1069 .probe = p54u_probe,
1070 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001071 .pre_reset = p54u_pre_reset,
1072 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001073#ifdef CONFIG_PM
1074 .suspend = p54u_suspend,
1075 .resume = p54u_resume,
1076 .reset_resume = p54u_resume,
1077#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001078 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001079};
1080
1081static int __init p54u_init(void)
1082{
1083 return usb_register(&p54u_driver);
1084}
1085
1086static void __exit p54u_exit(void)
1087{
1088 usb_deregister(&p54u_driver);
1089}
1090
1091module_init(p54u_init);
1092module_exit(p54u_exit);