blob: b0318ea59b7fa70e189dc5d608e3d6a20c29b732 [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
36static struct usb_device_id p54u_table[] __devinitdata = {
37 /* Version 1 devices (pci chip + net2280) */
38 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
Hans de Goede05a9a162010-03-17 14:37:16 +010039 {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
Michael Wueff1a592007-09-25 18:11:01 -070040 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090041 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070042 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
43 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050044 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070045 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
46 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
47 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020048 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070049 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
50 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
51 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
52 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
53 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
54 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
55 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
56 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
57
58 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070059 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070060 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
61 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
62 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060063 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070064 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
65 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060066 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070067 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
68 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
69 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
70 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
71 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
72 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
73 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020074 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070075 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070076 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020077 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050078 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040079 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020080 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070081 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
82 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
Jason Dravet0f666a02010-06-05 15:08:29 -050083 {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070084 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
85 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
86 {}
87};
88
89MODULE_DEVICE_TABLE(usb, p54u_table);
90
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020091static const struct {
92 u32 intf;
93 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020094 const char *fw;
95 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020096 char hw[20];
97} p54u_fwlist[__NUM_P54U_HWTYPES] = {
98 {
99 .type = P54U_NET2280,
100 .intf = FW_LM86,
101 .fw = "isl3886usb",
102 .fw_legacy = "isl3890usb",
103 .hw = "ISL3886 + net2280",
104 },
105 {
106 .type = P54U_3887,
107 .intf = FW_LM87,
108 .fw = "isl3887usb",
109 .fw_legacy = "isl3887usb_bare",
110 .hw = "ISL3887",
111 },
112};
113
Michael Wueff1a592007-09-25 18:11:01 -0700114static void p54u_rx_cb(struct urb *urb)
115{
116 struct sk_buff *skb = (struct sk_buff *) urb->context;
117 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
118 struct ieee80211_hw *dev = info->dev;
119 struct p54u_priv *priv = dev->priv;
120
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100121 skb_unlink(skb, &priv->rx_queue);
122
Michael Wueff1a592007-09-25 18:11:01 -0700123 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100124 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700125 return;
126 }
127
Michael Wueff1a592007-09-25 18:11:01 -0700128 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200129
130 if (priv->hw_type == P54U_NET2280)
131 skb_pull(skb, priv->common.tx_hdr_len);
132 if (priv->common.fw_interface == FW_LM87) {
133 skb_pull(skb, 4);
134 skb_put(skb, 4);
135 }
Michael Wueff1a592007-09-25 18:11:01 -0700136
137 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200138 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700139 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700140 /* TODO check rx queue length and refill *somewhere* */
141 return;
142 }
143
144 info = (struct p54u_rx_info *) skb->cb;
145 info->urb = urb;
146 info->dev = dev;
147 urb->transfer_buffer = skb_tail_pointer(skb);
148 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700149 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200150 if (priv->hw_type == P54U_NET2280)
151 skb_push(skb, priv->common.tx_hdr_len);
152 if (priv->common.fw_interface == FW_LM87) {
153 skb_push(skb, 4);
154 skb_put(skb, 4);
155 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200156 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700157 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200158 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700159 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100160 skb_queue_tail(&priv->rx_queue, skb);
161 usb_anchor_urb(urb, &priv->submitted);
162 if (usb_submit_urb(urb, GFP_ATOMIC)) {
163 skb_unlink(skb, &priv->rx_queue);
164 usb_unanchor_urb(urb);
165 dev_kfree_skb_irq(skb);
166 }
Michael Wueff1a592007-09-25 18:11:01 -0700167}
168
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100169static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200170{
171 struct sk_buff *skb = urb->context;
172 struct ieee80211_hw *dev = (struct ieee80211_hw *)
173 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
174
Christian Lampartere2fe1542009-01-20 00:27:57 +0100175 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100176}
177
178static void p54u_tx_dummy_cb(struct urb *urb) { }
179
180static void p54u_free_urbs(struct ieee80211_hw *dev)
181{
182 struct p54u_priv *priv = dev->priv;
183 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200184}
185
Michael Wueff1a592007-09-25 18:11:01 -0700186static int p54u_init_urbs(struct ieee80211_hw *dev)
187{
188 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100189 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700190 struct sk_buff *skb;
191 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100192 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700193
194 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200195 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100196 if (!skb) {
197 ret = -ENOMEM;
198 goto err;
199 }
Michael Wueff1a592007-09-25 18:11:01 -0700200 entry = usb_alloc_urb(0, GFP_KERNEL);
201 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100202 ret = -ENOMEM;
203 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700204 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100205
Christian Lamparter4e416a62008-09-01 22:48:41 +0200206 usb_fill_bulk_urb(entry, priv->udev,
207 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
208 skb_tail_pointer(skb),
209 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700210 info = (struct p54u_rx_info *) skb->cb;
211 info->urb = entry;
212 info->dev = dev;
213 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100214
215 usb_anchor_urb(entry, &priv->submitted);
216 ret = usb_submit_urb(entry, GFP_KERNEL);
217 if (ret) {
218 skb_unlink(skb, &priv->rx_queue);
219 usb_unanchor_urb(entry);
220 goto err;
221 }
222 usb_free_urb(entry);
223 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700224 }
225
226 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700227
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100228 err:
229 usb_free_urb(entry);
230 kfree_skb(skb);
231 p54u_free_urbs(dev);
232 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700233}
234
Johannes Bergc9127652008-12-01 18:19:36 +0100235static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200236{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500237 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200238
239 length >>= 2;
240 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100241 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200242 chk = (chk >> 5) ^ (chk << 3);
243 }
244
Larry Finger1f1c0e32008-09-25 14:54:28 -0500245 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200246}
247
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100248static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200249{
250 struct p54u_priv *priv = dev->priv;
251 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100252 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200253
254 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200255 if (!data_urb) {
256 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200257 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200258 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200259
Christian Lampartere2fe1542009-01-20 00:27:57 +0100260 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
261 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200262
263 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200264 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100265 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
266 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100267 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200268
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100269 usb_anchor_urb(data_urb, &priv->submitted);
270 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
271 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100272 p54_free_skb(dev, skb);
273 }
274 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200275}
276
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100277static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700278{
279 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200280 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100281 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200282 struct net2280_reg_write *reg = NULL;
283 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700284
285 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
286 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200287 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700288
289 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200290 if (!int_urb)
291 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700292
293 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200294 if (!data_urb)
295 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700296
297 reg->port = cpu_to_le16(NET2280_DEV_U32);
298 reg->addr = cpu_to_le32(P54U_DEV_BASE);
299 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
300
Michael Wueff1a592007-09-25 18:11:01 -0700301 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100302 hdr->len = cpu_to_le16(skb->len);
303 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700304
305 usb_fill_bulk_urb(int_urb, priv->udev,
306 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100307 p54u_tx_dummy_cb, dev);
308
309 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200310 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
311 * free what is inside the transfer_buffer after the last reference to
312 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100313 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100314 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200315 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700316
317 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200318 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100319 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
320 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100321 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100322
323 usb_anchor_urb(int_urb, &priv->submitted);
324 err = usb_submit_urb(int_urb, GFP_ATOMIC);
325 if (err) {
326 usb_unanchor_urb(int_urb);
327 goto out;
328 }
329
330 usb_anchor_urb(data_urb, &priv->submitted);
331 err = usb_submit_urb(data_urb, GFP_ATOMIC);
332 if (err) {
333 usb_unanchor_urb(data_urb);
334 goto out;
335 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200336out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100337 usb_free_urb(int_urb);
338 usb_free_urb(data_urb);
339
340 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200341 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100342 p54_free_skb(dev, skb);
343 }
Michael Wueff1a592007-09-25 18:11:01 -0700344}
345
346static int p54u_write(struct p54u_priv *priv,
347 struct net2280_reg_write *buf,
348 enum net2280_op_type type,
349 __le32 addr, __le32 val)
350{
351 unsigned int ep;
352 int alen;
353
354 if (type & 0x0800)
355 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
356 else
357 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
358
359 buf->port = cpu_to_le16(type);
360 buf->addr = addr;
361 buf->val = val;
362
363 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
364}
365
366static int p54u_read(struct p54u_priv *priv, void *buf,
367 enum net2280_op_type type,
368 __le32 addr, __le32 *val)
369{
370 struct net2280_reg_read *read = buf;
371 __le32 *reg = buf;
372 unsigned int ep;
373 int alen, err;
374
375 if (type & 0x0800)
376 ep = P54U_PIPE_DEV;
377 else
378 ep = P54U_PIPE_BRG;
379
380 read->port = cpu_to_le16(type);
381 read->addr = addr;
382
383 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
384 read, sizeof(*read), &alen, 1000);
385 if (err)
386 return err;
387
388 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
389 reg, sizeof(*reg), &alen, 1000);
390 if (err)
391 return err;
392
393 *val = *reg;
394 return 0;
395}
396
397static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
398 void *data, size_t len)
399{
400 int alen;
401 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
402 data, len, &alen, 2000);
403}
404
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200405static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100406{
407 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100408 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100409
Christian Lamparterc88a7682009-01-16 20:24:31 +0100410 if (lock) {
411 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
412 if (ret < 0) {
413 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200414 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100415 return ret;
416 }
Christian Lamparter69828692008-12-26 19:08:31 +0100417 }
418
419 ret = usb_reset_device(priv->udev);
420 if (lock)
421 usb_unlock_device(priv->udev);
422
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200423 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100424 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200425 "device (%d)!\n", ret);
426
427 return ret;
428}
429
430static const char p54u_romboot_3887[] = "~~~~";
431static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
432{
433 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600434 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200435 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100436
Julia Lawall27b81bb2010-05-15 23:22:55 +0200437 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600438 if (!buf)
439 return -ENOMEM;
Christian Lamparter69828692008-12-26 19:08:31 +0100440 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600441 buf, 4);
442 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100443 if (ret)
444 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200445 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100446
447 return ret;
448}
449
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200450static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700451static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
452{
Michael Wueff1a592007-09-25 18:11:01 -0700453 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700454 int err, alen;
455 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100456 u8 *buf, *tmp;
457 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700458 unsigned int left, remains, block_size;
459 struct x2_header *hdr;
460 unsigned long timeout;
461
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200462 err = p54u_firmware_reset_3887(dev);
463 if (err)
464 return err;
465
Michael Wueff1a592007-09-25 18:11:01 -0700466 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
467 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100468 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
469 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200470 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700471 }
472
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200473 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100474 strcpy(buf, p54u_firmware_upload_3887);
475 left -= strlen(p54u_firmware_upload_3887);
476 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700477
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200478 data = priv->fw->data;
479 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700480
Christian Lamparter69828692008-12-26 19:08:31 +0100481 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700482 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
483 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200484 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700485 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
486 sizeof(u32)*2));
487 left -= sizeof(*hdr);
488 tmp += sizeof(*hdr);
489
490 while (remains) {
491 while (left--) {
492 if (carry) {
493 *tmp++ = carry;
494 carry = 0;
495 remains--;
496 continue;
497 }
498 switch (*data) {
499 case '~':
500 *tmp++ = '}';
501 carry = '^';
502 break;
503 case '}':
504 *tmp++ = '}';
505 carry = ']';
506 break;
507 default:
508 *tmp++ = *data;
509 remains--;
510 break;
511 }
512 data++;
513 }
514
515 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
516 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100517 dev_err(&priv->udev->dev, "(p54usb) firmware "
518 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700519 goto err_upload_failed;
520 }
521
522 tmp = buf;
523 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
524 }
525
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200526 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
527 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700528 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
529 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100530 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700531 goto err_upload_failed;
532 }
Michael Wueff1a592007-09-25 18:11:01 -0700533 timeout = jiffies + msecs_to_jiffies(1000);
534 while (!(err = usb_bulk_msg(priv->udev,
535 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
536 if (alen > 2 && !memcmp(buf, "OK", 2))
537 break;
538
539 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700540 err = -EINVAL;
541 break;
542 }
543
544 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100545 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
546 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700547 err = -ETIMEDOUT;
548 break;
549 }
550 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100551 if (err) {
552 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700553 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100554 }
Michael Wueff1a592007-09-25 18:11:01 -0700555
556 buf[0] = 'g';
557 buf[1] = '\r';
558 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
559 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100560 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700561 goto err_upload_failed;
562 }
563
564 timeout = jiffies + msecs_to_jiffies(1000);
565 while (!(err = usb_bulk_msg(priv->udev,
566 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
567 if (alen > 0 && buf[0] == 'g')
568 break;
569
570 if (time_after(jiffies, timeout)) {
571 err = -ETIMEDOUT;
572 break;
573 }
574 }
575 if (err)
576 goto err_upload_failed;
577
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200578err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700579 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700580 return err;
581}
582
583static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
584{
585 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700586 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
587 int err, alen;
588 void *buf;
589 __le32 reg;
590 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100591 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700592
593 buf = kmalloc(512, GFP_KERNEL);
594 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100595 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
596 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700597 return -ENOMEM;
598 }
599
Michael Wueff1a592007-09-25 18:11:01 -0700600#define P54U_WRITE(type, addr, data) \
601 do {\
602 err = p54u_write(priv, buf, type,\
603 cpu_to_le32((u32)(unsigned long)addr), data);\
604 if (err) \
605 goto fail;\
606 } while (0)
607
608#define P54U_READ(type, addr) \
609 do {\
610 err = p54u_read(priv, buf, type,\
611 cpu_to_le32((u32)(unsigned long)addr), &reg);\
612 if (err)\
613 goto fail;\
614 } while (0)
615
616 /* power down net2280 bridge */
617 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
618 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
619 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
620 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
621
622 mdelay(100);
623
624 /* power up bridge */
625 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
626 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
627 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
628
629 mdelay(100);
630
631 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
632 cpu_to_le32(NET2280_CLK_30Mhz |
633 NET2280_PCI_ENABLE |
634 NET2280_PCI_SOFT_RESET));
635
636 mdelay(20);
637
638 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
639 cpu_to_le32(PCI_COMMAND_MEMORY |
640 PCI_COMMAND_MASTER));
641
642 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
643 cpu_to_le32(NET2280_BASE));
644
645 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
646 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
647 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
648
649 // TODO: we really need this?
650 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
651
652 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
653 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
654 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
655 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
656
657 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
658 cpu_to_le32(NET2280_BASE2));
659
660 /* finally done setting up the bridge */
661
662 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
663 cpu_to_le32(PCI_COMMAND_MEMORY |
664 PCI_COMMAND_MASTER));
665
666 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
667 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
668 cpu_to_le32(P54U_DEV_BASE));
669
670 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
671 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
672 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
673
674 /* do romboot */
675 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
676
677 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
678 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
679 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
680 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
681 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
682
683 mdelay(20);
684
685 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
686 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
687
688 mdelay(20);
689
690 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
691 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
692
693 mdelay(100);
694
695 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
696 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
697
698 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200699 remains = priv->fw->size;
700 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700701 offset = ISL38XX_DEV_FIRMWARE_ADDR;
702
703 while (remains) {
704 unsigned int block_len = min(remains, (unsigned int)512);
705 memcpy(buf, data, block_len);
706
707 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
708 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100709 dev_err(&priv->udev->dev, "(p54usb) firmware block "
710 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700711 goto fail;
712 }
713
714 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
715 cpu_to_le32(0xc0000f00));
716
717 P54U_WRITE(NET2280_DEV_U32,
718 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
719 P54U_WRITE(NET2280_DEV_U32,
720 0x0020 | (unsigned long)&devreg->direct_mem_win,
721 cpu_to_le32(1));
722
723 P54U_WRITE(NET2280_DEV_U32,
724 0x0024 | (unsigned long)&devreg->direct_mem_win,
725 cpu_to_le32(block_len));
726 P54U_WRITE(NET2280_DEV_U32,
727 0x0028 | (unsigned long)&devreg->direct_mem_win,
728 cpu_to_le32(offset));
729
730 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
731 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
732 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
733 cpu_to_le32(block_len >> 2));
734 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
735 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
736
737 mdelay(10);
738
739 P54U_READ(NET2280_DEV_U32,
740 0x002C | (unsigned long)&devreg->direct_mem_win);
741 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
742 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100743 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
744 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700745 goto fail;
746 }
747
748 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
749 cpu_to_le32(NET2280_FIFO_FLUSH));
750
751 remains -= block_len;
752 data += block_len;
753 offset += block_len;
754 }
755
756 /* do ramboot */
757 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
758 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
759 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
760 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
761 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
762
763 mdelay(20);
764
765 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
766 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
767
768 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
769 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
770
771 mdelay(100);
772
773 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
774 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
775
776 /* start up the firmware */
777 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
778 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
779
780 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
781 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
782
783 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
784 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
785 NET2280_USB_INTERRUPT_ENABLE));
786
787 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
788 cpu_to_le32(ISL38XX_DEV_INT_RESET));
789
790 err = usb_interrupt_msg(priv->udev,
791 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
792 buf, sizeof(__le32), &alen, 1000);
793 if (err || alen != sizeof(__le32))
794 goto fail;
795
796 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
797 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
798
799 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
800 err = -EINVAL;
801
802 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
803 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
804 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
805
806#undef P54U_WRITE
807#undef P54U_READ
808
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200809fail:
Michael Wueff1a592007-09-25 18:11:01 -0700810 kfree(buf);
811 return err;
812}
813
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200814static int p54u_load_firmware(struct ieee80211_hw *dev)
815{
816 struct p54u_priv *priv = dev->priv;
817 int err, i;
818
819 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
820
821 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
822 if (p54u_fwlist[i].type == priv->hw_type)
823 break;
824
825 if (i == __NUM_P54U_HWTYPES)
826 return -EOPNOTSUPP;
827
828 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
829 if (err) {
830 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
831 "(%d)!\n", p54u_fwlist[i].fw, err);
832
833 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
834 &priv->udev->dev);
835 if (err)
836 return err;
837 }
838
839 err = p54_parse_firmware(dev, priv->fw);
840 if (err)
841 goto out;
842
843 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
844 dev_err(&priv->udev->dev, "wrong firmware, please get "
845 "a firmware for \"%s\" and try again.\n",
846 p54u_fwlist[i].hw);
847 err = -EINVAL;
848 }
849
850out:
851 if (err)
852 release_firmware(priv->fw);
853
854 return err;
855}
856
Michael Wueff1a592007-09-25 18:11:01 -0700857static int p54u_open(struct ieee80211_hw *dev)
858{
859 struct p54u_priv *priv = dev->priv;
860 int err;
861
862 err = p54u_init_urbs(dev);
863 if (err) {
864 return err;
865 }
866
867 priv->common.open = p54u_init_urbs;
868
869 return 0;
870}
871
872static void p54u_stop(struct ieee80211_hw *dev)
873{
874 /* TODO: figure out how to reliably stop the 3887 and net2280 so
875 the hardware is still usable next time we want to start it.
876 until then, we just stop listening to the hardware.. */
877 p54u_free_urbs(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700878}
879
880static int __devinit p54u_probe(struct usb_interface *intf,
881 const struct usb_device_id *id)
882{
883 struct usb_device *udev = interface_to_usbdev(intf);
884 struct ieee80211_hw *dev;
885 struct p54u_priv *priv;
886 int err;
887 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700888
889 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100890
Michael Wueff1a592007-09-25 18:11:01 -0700891 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100892 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700893 return -ENOMEM;
894 }
895
896 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200897 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700898
899 SET_IEEE80211_DEV(dev, &intf->dev);
900 usb_set_intfdata(intf, dev);
901 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100902 priv->intf = intf;
903 skb_queue_head_init(&priv->rx_queue);
904 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700905
906 usb_get_dev(udev);
907
908 /* really lazy and simple way of figuring out if we're a 3887 */
909 /* TODO: should just stick the identification in the device table */
910 i = intf->altsetting->desc.bNumEndpoints;
911 recognized_pipes = 0;
912 while (i--) {
913 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
914 case P54U_PIPE_DATA:
915 case P54U_PIPE_MGMT:
916 case P54U_PIPE_BRG:
917 case P54U_PIPE_DEV:
918 case P54U_PIPE_DATA | USB_DIR_IN:
919 case P54U_PIPE_MGMT | USB_DIR_IN:
920 case P54U_PIPE_BRG | USB_DIR_IN:
921 case P54U_PIPE_DEV | USB_DIR_IN:
922 case P54U_PIPE_INT | USB_DIR_IN:
923 recognized_pipes++;
924 }
925 }
926 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200927 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700928 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200929#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200930 /* ISL3887 needs a full reset on resume */
931 udev->reset_resume = 1;
932 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200933#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200934
Michael Wueff1a592007-09-25 18:11:01 -0700935 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200936 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
937 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
938 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200939 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700940 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200941 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700942 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
943 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
944 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200945 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200946 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200947 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700948 if (err)
949 goto err_free_dev;
950
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200951 err = priv->upload_fw(dev);
952 if (err)
953 goto err_free_fw;
954
Christian Lamparter7cb77072008-09-01 22:48:51 +0200955 p54u_open(dev);
956 err = p54_read_eeprom(dev);
957 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700958 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200959 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700960
Christian Lamparter2ac71072009-03-05 21:30:10 +0100961 err = p54_register_common(dev, &udev->dev);
962 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200963 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700964
Michael Wueff1a592007-09-25 18:11:01 -0700965 return 0;
966
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200967err_free_fw:
968 release_firmware(priv->fw);
969
970err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500971 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700972 usb_set_intfdata(intf, NULL);
973 usb_put_dev(udev);
974 return err;
975}
976
977static void __devexit p54u_disconnect(struct usb_interface *intf)
978{
979 struct ieee80211_hw *dev = usb_get_intfdata(intf);
980 struct p54u_priv *priv;
981
982 if (!dev)
983 return;
984
Christian Lamparterd8c92102009-06-23 10:39:45 -0500985 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700986
987 priv = dev->priv;
988 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200989 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700990 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700991}
992
Christian Lamparter69828692008-12-26 19:08:31 +0100993static int p54u_pre_reset(struct usb_interface *intf)
994{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200995 struct ieee80211_hw *dev = usb_get_intfdata(intf);
996
997 if (!dev)
998 return -ENODEV;
999
1000 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001001 return 0;
1002}
1003
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001004static int p54u_resume(struct usb_interface *intf)
1005{
1006 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1007 struct p54u_priv *priv;
1008
1009 if (!dev)
1010 return -ENODEV;
1011
1012 priv = dev->priv;
1013 if (unlikely(!(priv->upload_fw && priv->fw)))
1014 return 0;
1015
1016 return priv->upload_fw(dev);
1017}
1018
Christian Lamparter69828692008-12-26 19:08:31 +01001019static int p54u_post_reset(struct usb_interface *intf)
1020{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001021 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1022 struct p54u_priv *priv;
1023 int err;
1024
1025 err = p54u_resume(intf);
1026 if (err)
1027 return err;
1028
1029 /* reinitialize old device state */
1030 priv = dev->priv;
1031 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1032 ieee80211_restart_hw(dev);
1033
Christian Lamparter69828692008-12-26 19:08:31 +01001034 return 0;
1035}
1036
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001037#ifdef CONFIG_PM
1038
1039static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1040{
1041 return p54u_pre_reset(intf);
1042}
1043
1044#endif /* CONFIG_PM */
1045
Michael Wueff1a592007-09-25 18:11:01 -07001046static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001047 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001048 .id_table = p54u_table,
1049 .probe = p54u_probe,
1050 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001051 .pre_reset = p54u_pre_reset,
1052 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001053#ifdef CONFIG_PM
1054 .suspend = p54u_suspend,
1055 .resume = p54u_resume,
1056 .reset_resume = p54u_resume,
1057#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001058 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001059};
1060
1061static int __init p54u_init(void)
1062{
1063 return usb_register(&p54u_driver);
1064}
1065
1066static void __exit p54u_exit(void)
1067{
1068 usb_deregister(&p54u_driver);
1069}
1070
1071module_init(p54u_init);
1072module_exit(p54u_exit);