blob: dcb484bd59849913cf3cd9e146d4180b341b111f [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>
18#include <linux/firmware.h>
19#include <linux/etherdevice.h>
20#include <linux/delay.h>
21#include <linux/crc32.h>
22#include <net/mac80211.h>
23
24#include "p54.h"
Christian Lamparterd8c92102009-06-23 10:39:45 -050025#include "lmac.h"
Michael Wueff1a592007-09-25 18:11:01 -070026#include "p54usb.h"
27
28MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
29MODULE_DESCRIPTION("Prism54 USB wireless driver");
30MODULE_LICENSE("GPL");
31MODULE_ALIAS("prism54usb");
Christian Lamparter9a8675d2008-10-18 23:04:15 +020032MODULE_FIRMWARE("isl3886usb");
33MODULE_FIRMWARE("isl3887usb");
Michael Wueff1a592007-09-25 18:11:01 -070034
35static struct usb_device_id p54u_table[] __devinitdata = {
36 /* Version 1 devices (pci chip + net2280) */
37 {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
38 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090039 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070040 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
41 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050042 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070043 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
44 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
45 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020046 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070047 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
48 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
49 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
50 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
51 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
52 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
53 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
54 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
55
56 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070057 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070058 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
59 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
60 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060061 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070062 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
63 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
64 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
65 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
66 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
67 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
68 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
69 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
70 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020071 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070072 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070073 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020074 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050075 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040076 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020077 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070078 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
79 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
80 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
81 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
82 {}
83};
84
85MODULE_DEVICE_TABLE(usb, p54u_table);
86
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020087static const struct {
88 u32 intf;
89 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020090 const char *fw;
91 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020092 char hw[20];
93} p54u_fwlist[__NUM_P54U_HWTYPES] = {
94 {
95 .type = P54U_NET2280,
96 .intf = FW_LM86,
97 .fw = "isl3886usb",
98 .fw_legacy = "isl3890usb",
99 .hw = "ISL3886 + net2280",
100 },
101 {
102 .type = P54U_3887,
103 .intf = FW_LM87,
104 .fw = "isl3887usb",
105 .fw_legacy = "isl3887usb_bare",
106 .hw = "ISL3887",
107 },
108};
109
Michael Wueff1a592007-09-25 18:11:01 -0700110static void p54u_rx_cb(struct urb *urb)
111{
112 struct sk_buff *skb = (struct sk_buff *) urb->context;
113 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
114 struct ieee80211_hw *dev = info->dev;
115 struct p54u_priv *priv = dev->priv;
116
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100117 skb_unlink(skb, &priv->rx_queue);
118
Michael Wueff1a592007-09-25 18:11:01 -0700119 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100120 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700121 return;
122 }
123
Michael Wueff1a592007-09-25 18:11:01 -0700124 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200125
126 if (priv->hw_type == P54U_NET2280)
127 skb_pull(skb, priv->common.tx_hdr_len);
128 if (priv->common.fw_interface == FW_LM87) {
129 skb_pull(skb, 4);
130 skb_put(skb, 4);
131 }
Michael Wueff1a592007-09-25 18:11:01 -0700132
133 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200134 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700135 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700136 /* TODO check rx queue length and refill *somewhere* */
137 return;
138 }
139
140 info = (struct p54u_rx_info *) skb->cb;
141 info->urb = urb;
142 info->dev = dev;
143 urb->transfer_buffer = skb_tail_pointer(skb);
144 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700145 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200146 if (priv->hw_type == P54U_NET2280)
147 skb_push(skb, priv->common.tx_hdr_len);
148 if (priv->common.fw_interface == FW_LM87) {
149 skb_push(skb, 4);
150 skb_put(skb, 4);
151 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200152 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700153 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200154 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700155 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100156 skb_queue_tail(&priv->rx_queue, skb);
157 usb_anchor_urb(urb, &priv->submitted);
158 if (usb_submit_urb(urb, GFP_ATOMIC)) {
159 skb_unlink(skb, &priv->rx_queue);
160 usb_unanchor_urb(urb);
161 dev_kfree_skb_irq(skb);
162 }
Michael Wueff1a592007-09-25 18:11:01 -0700163}
164
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100165static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200166{
167 struct sk_buff *skb = urb->context;
168 struct ieee80211_hw *dev = (struct ieee80211_hw *)
169 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
170
Christian Lampartere2fe1542009-01-20 00:27:57 +0100171 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100172}
173
174static void p54u_tx_dummy_cb(struct urb *urb) { }
175
176static void p54u_free_urbs(struct ieee80211_hw *dev)
177{
178 struct p54u_priv *priv = dev->priv;
179 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200180}
181
Michael Wueff1a592007-09-25 18:11:01 -0700182static int p54u_init_urbs(struct ieee80211_hw *dev)
183{
184 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100185 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700186 struct sk_buff *skb;
187 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100188 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700189
190 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200191 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100192 if (!skb) {
193 ret = -ENOMEM;
194 goto err;
195 }
Michael Wueff1a592007-09-25 18:11:01 -0700196 entry = usb_alloc_urb(0, GFP_KERNEL);
197 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100198 ret = -ENOMEM;
199 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700200 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100201
Christian Lamparter4e416a62008-09-01 22:48:41 +0200202 usb_fill_bulk_urb(entry, priv->udev,
203 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
204 skb_tail_pointer(skb),
205 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700206 info = (struct p54u_rx_info *) skb->cb;
207 info->urb = entry;
208 info->dev = dev;
209 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100210
211 usb_anchor_urb(entry, &priv->submitted);
212 ret = usb_submit_urb(entry, GFP_KERNEL);
213 if (ret) {
214 skb_unlink(skb, &priv->rx_queue);
215 usb_unanchor_urb(entry);
216 goto err;
217 }
218 usb_free_urb(entry);
219 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700220 }
221
222 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700223
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100224 err:
225 usb_free_urb(entry);
226 kfree_skb(skb);
227 p54u_free_urbs(dev);
228 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700229}
230
Johannes Bergc9127652008-12-01 18:19:36 +0100231static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200232{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500233 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200234
235 length >>= 2;
236 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100237 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200238 chk = (chk >> 5) ^ (chk << 3);
239 }
240
Larry Finger1f1c0e32008-09-25 14:54:28 -0500241 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200242}
243
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100244static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200245{
246 struct p54u_priv *priv = dev->priv;
247 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100248 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200249
250 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200251 if (!data_urb) {
252 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200253 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200254 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200255
Christian Lampartere2fe1542009-01-20 00:27:57 +0100256 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
257 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200258
259 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200260 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100261 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
262 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100263 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200264
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100265 usb_anchor_urb(data_urb, &priv->submitted);
266 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
267 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100268 p54_free_skb(dev, skb);
269 }
270 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200271}
272
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100273static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700274{
275 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200276 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100277 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200278 struct net2280_reg_write *reg = NULL;
279 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700280
281 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
282 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200283 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700284
285 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200286 if (!int_urb)
287 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700288
289 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200290 if (!data_urb)
291 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700292
293 reg->port = cpu_to_le16(NET2280_DEV_U32);
294 reg->addr = cpu_to_le32(P54U_DEV_BASE);
295 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
296
Michael Wueff1a592007-09-25 18:11:01 -0700297 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100298 hdr->len = cpu_to_le16(skb->len);
299 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700300
301 usb_fill_bulk_urb(int_urb, priv->udev,
302 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100303 p54u_tx_dummy_cb, dev);
304
305 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200306 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
307 * free what is inside the transfer_buffer after the last reference to
308 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100309 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100310 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200311 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700312
313 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200314 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100315 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
316 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100317 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100318
319 usb_anchor_urb(int_urb, &priv->submitted);
320 err = usb_submit_urb(int_urb, GFP_ATOMIC);
321 if (err) {
322 usb_unanchor_urb(int_urb);
323 goto out;
324 }
325
326 usb_anchor_urb(data_urb, &priv->submitted);
327 err = usb_submit_urb(data_urb, GFP_ATOMIC);
328 if (err) {
329 usb_unanchor_urb(data_urb);
330 goto out;
331 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200332out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100333 usb_free_urb(int_urb);
334 usb_free_urb(data_urb);
335
336 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200337 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100338 p54_free_skb(dev, skb);
339 }
Michael Wueff1a592007-09-25 18:11:01 -0700340}
341
342static int p54u_write(struct p54u_priv *priv,
343 struct net2280_reg_write *buf,
344 enum net2280_op_type type,
345 __le32 addr, __le32 val)
346{
347 unsigned int ep;
348 int alen;
349
350 if (type & 0x0800)
351 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
352 else
353 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
354
355 buf->port = cpu_to_le16(type);
356 buf->addr = addr;
357 buf->val = val;
358
359 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
360}
361
362static int p54u_read(struct p54u_priv *priv, void *buf,
363 enum net2280_op_type type,
364 __le32 addr, __le32 *val)
365{
366 struct net2280_reg_read *read = buf;
367 __le32 *reg = buf;
368 unsigned int ep;
369 int alen, err;
370
371 if (type & 0x0800)
372 ep = P54U_PIPE_DEV;
373 else
374 ep = P54U_PIPE_BRG;
375
376 read->port = cpu_to_le16(type);
377 read->addr = addr;
378
379 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
380 read, sizeof(*read), &alen, 1000);
381 if (err)
382 return err;
383
384 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
385 reg, sizeof(*reg), &alen, 1000);
386 if (err)
387 return err;
388
389 *val = *reg;
390 return 0;
391}
392
393static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
394 void *data, size_t len)
395{
396 int alen;
397 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
398 data, len, &alen, 2000);
399}
400
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200401static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100402{
403 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100404 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100405
Christian Lamparterc88a7682009-01-16 20:24:31 +0100406 if (lock) {
407 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
408 if (ret < 0) {
409 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200410 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100411 return ret;
412 }
Christian Lamparter69828692008-12-26 19:08:31 +0100413 }
414
415 ret = usb_reset_device(priv->udev);
416 if (lock)
417 usb_unlock_device(priv->udev);
418
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200419 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100420 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200421 "device (%d)!\n", ret);
422
423 return ret;
424}
425
426static const char p54u_romboot_3887[] = "~~~~";
427static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
428{
429 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600430 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200431 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100432
Larry Finger21d6c272009-11-11 18:02:29 -0600433 buf = kmalloc(4, GFP_KERNEL);
434 if (!buf)
435 return -ENOMEM;
436 memcpy(buf, p54u_romboot_3887, 4);
Christian Lamparter69828692008-12-26 19:08:31 +0100437 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600438 buf, 4);
439 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100440 if (ret)
441 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200442 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100443
444 return ret;
445}
446
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200447static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700448static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
449{
Michael Wueff1a592007-09-25 18:11:01 -0700450 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700451 int err, alen;
452 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100453 u8 *buf, *tmp;
454 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700455 unsigned int left, remains, block_size;
456 struct x2_header *hdr;
457 unsigned long timeout;
458
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200459 err = p54u_firmware_reset_3887(dev);
460 if (err)
461 return err;
462
Michael Wueff1a592007-09-25 18:11:01 -0700463 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
464 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100465 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
466 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200467 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700468 }
469
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200470 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100471 strcpy(buf, p54u_firmware_upload_3887);
472 left -= strlen(p54u_firmware_upload_3887);
473 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700474
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200475 data = priv->fw->data;
476 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700477
Christian Lamparter69828692008-12-26 19:08:31 +0100478 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700479 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
480 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200481 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700482 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
483 sizeof(u32)*2));
484 left -= sizeof(*hdr);
485 tmp += sizeof(*hdr);
486
487 while (remains) {
488 while (left--) {
489 if (carry) {
490 *tmp++ = carry;
491 carry = 0;
492 remains--;
493 continue;
494 }
495 switch (*data) {
496 case '~':
497 *tmp++ = '}';
498 carry = '^';
499 break;
500 case '}':
501 *tmp++ = '}';
502 carry = ']';
503 break;
504 default:
505 *tmp++ = *data;
506 remains--;
507 break;
508 }
509 data++;
510 }
511
512 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
513 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100514 dev_err(&priv->udev->dev, "(p54usb) firmware "
515 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700516 goto err_upload_failed;
517 }
518
519 tmp = buf;
520 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
521 }
522
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200523 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
524 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700525 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
526 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100527 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700528 goto err_upload_failed;
529 }
Michael Wueff1a592007-09-25 18:11:01 -0700530 timeout = jiffies + msecs_to_jiffies(1000);
531 while (!(err = usb_bulk_msg(priv->udev,
532 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
533 if (alen > 2 && !memcmp(buf, "OK", 2))
534 break;
535
536 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700537 err = -EINVAL;
538 break;
539 }
540
541 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100542 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
543 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700544 err = -ETIMEDOUT;
545 break;
546 }
547 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100548 if (err) {
549 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700550 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100551 }
Michael Wueff1a592007-09-25 18:11:01 -0700552
553 buf[0] = 'g';
554 buf[1] = '\r';
555 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
556 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100557 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700558 goto err_upload_failed;
559 }
560
561 timeout = jiffies + msecs_to_jiffies(1000);
562 while (!(err = usb_bulk_msg(priv->udev,
563 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
564 if (alen > 0 && buf[0] == 'g')
565 break;
566
567 if (time_after(jiffies, timeout)) {
568 err = -ETIMEDOUT;
569 break;
570 }
571 }
572 if (err)
573 goto err_upload_failed;
574
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200575err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700576 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700577 return err;
578}
579
580static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
581{
582 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700583 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
584 int err, alen;
585 void *buf;
586 __le32 reg;
587 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100588 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700589
590 buf = kmalloc(512, GFP_KERNEL);
591 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100592 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
593 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700594 return -ENOMEM;
595 }
596
Michael Wueff1a592007-09-25 18:11:01 -0700597#define P54U_WRITE(type, addr, data) \
598 do {\
599 err = p54u_write(priv, buf, type,\
600 cpu_to_le32((u32)(unsigned long)addr), data);\
601 if (err) \
602 goto fail;\
603 } while (0)
604
605#define P54U_READ(type, addr) \
606 do {\
607 err = p54u_read(priv, buf, type,\
608 cpu_to_le32((u32)(unsigned long)addr), &reg);\
609 if (err)\
610 goto fail;\
611 } while (0)
612
613 /* power down net2280 bridge */
614 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
615 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
616 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
617 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
618
619 mdelay(100);
620
621 /* power up bridge */
622 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
623 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
624 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
625
626 mdelay(100);
627
628 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
629 cpu_to_le32(NET2280_CLK_30Mhz |
630 NET2280_PCI_ENABLE |
631 NET2280_PCI_SOFT_RESET));
632
633 mdelay(20);
634
635 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
636 cpu_to_le32(PCI_COMMAND_MEMORY |
637 PCI_COMMAND_MASTER));
638
639 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
640 cpu_to_le32(NET2280_BASE));
641
642 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
643 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
644 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
645
646 // TODO: we really need this?
647 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
648
649 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
650 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
651 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
652 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
653
654 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
655 cpu_to_le32(NET2280_BASE2));
656
657 /* finally done setting up the bridge */
658
659 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
660 cpu_to_le32(PCI_COMMAND_MEMORY |
661 PCI_COMMAND_MASTER));
662
663 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
664 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
665 cpu_to_le32(P54U_DEV_BASE));
666
667 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
668 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
669 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
670
671 /* do romboot */
672 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
673
674 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
675 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
676 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
677 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
678 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
679
680 mdelay(20);
681
682 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
683 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
684
685 mdelay(20);
686
687 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
688 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
689
690 mdelay(100);
691
692 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
693 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
694
695 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200696 remains = priv->fw->size;
697 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700698 offset = ISL38XX_DEV_FIRMWARE_ADDR;
699
700 while (remains) {
701 unsigned int block_len = min(remains, (unsigned int)512);
702 memcpy(buf, data, block_len);
703
704 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
705 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100706 dev_err(&priv->udev->dev, "(p54usb) firmware block "
707 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700708 goto fail;
709 }
710
711 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
712 cpu_to_le32(0xc0000f00));
713
714 P54U_WRITE(NET2280_DEV_U32,
715 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
716 P54U_WRITE(NET2280_DEV_U32,
717 0x0020 | (unsigned long)&devreg->direct_mem_win,
718 cpu_to_le32(1));
719
720 P54U_WRITE(NET2280_DEV_U32,
721 0x0024 | (unsigned long)&devreg->direct_mem_win,
722 cpu_to_le32(block_len));
723 P54U_WRITE(NET2280_DEV_U32,
724 0x0028 | (unsigned long)&devreg->direct_mem_win,
725 cpu_to_le32(offset));
726
727 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
728 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
729 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
730 cpu_to_le32(block_len >> 2));
731 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
732 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
733
734 mdelay(10);
735
736 P54U_READ(NET2280_DEV_U32,
737 0x002C | (unsigned long)&devreg->direct_mem_win);
738 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
739 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100740 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
741 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700742 goto fail;
743 }
744
745 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
746 cpu_to_le32(NET2280_FIFO_FLUSH));
747
748 remains -= block_len;
749 data += block_len;
750 offset += block_len;
751 }
752
753 /* do ramboot */
754 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
755 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
756 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
757 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
758 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
759
760 mdelay(20);
761
762 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
763 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
764
765 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
766 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
767
768 mdelay(100);
769
770 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
771 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
772
773 /* start up the firmware */
774 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
775 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
776
777 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
778 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
779
780 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
781 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
782 NET2280_USB_INTERRUPT_ENABLE));
783
784 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
785 cpu_to_le32(ISL38XX_DEV_INT_RESET));
786
787 err = usb_interrupt_msg(priv->udev,
788 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
789 buf, sizeof(__le32), &alen, 1000);
790 if (err || alen != sizeof(__le32))
791 goto fail;
792
793 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
794 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
795
796 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
797 err = -EINVAL;
798
799 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
800 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
801 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
802
803#undef P54U_WRITE
804#undef P54U_READ
805
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200806fail:
Michael Wueff1a592007-09-25 18:11:01 -0700807 kfree(buf);
808 return err;
809}
810
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200811static int p54u_load_firmware(struct ieee80211_hw *dev)
812{
813 struct p54u_priv *priv = dev->priv;
814 int err, i;
815
816 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
817
818 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
819 if (p54u_fwlist[i].type == priv->hw_type)
820 break;
821
822 if (i == __NUM_P54U_HWTYPES)
823 return -EOPNOTSUPP;
824
825 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
826 if (err) {
827 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
828 "(%d)!\n", p54u_fwlist[i].fw, err);
829
830 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
831 &priv->udev->dev);
832 if (err)
833 return err;
834 }
835
836 err = p54_parse_firmware(dev, priv->fw);
837 if (err)
838 goto out;
839
840 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
841 dev_err(&priv->udev->dev, "wrong firmware, please get "
842 "a firmware for \"%s\" and try again.\n",
843 p54u_fwlist[i].hw);
844 err = -EINVAL;
845 }
846
847out:
848 if (err)
849 release_firmware(priv->fw);
850
851 return err;
852}
853
Michael Wueff1a592007-09-25 18:11:01 -0700854static int p54u_open(struct ieee80211_hw *dev)
855{
856 struct p54u_priv *priv = dev->priv;
857 int err;
858
859 err = p54u_init_urbs(dev);
860 if (err) {
861 return err;
862 }
863
864 priv->common.open = p54u_init_urbs;
865
866 return 0;
867}
868
869static void p54u_stop(struct ieee80211_hw *dev)
870{
871 /* TODO: figure out how to reliably stop the 3887 and net2280 so
872 the hardware is still usable next time we want to start it.
873 until then, we just stop listening to the hardware.. */
874 p54u_free_urbs(dev);
875 return;
876}
877
878static int __devinit p54u_probe(struct usb_interface *intf,
879 const struct usb_device_id *id)
880{
881 struct usb_device *udev = interface_to_usbdev(intf);
882 struct ieee80211_hw *dev;
883 struct p54u_priv *priv;
884 int err;
885 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700886
887 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100888
Michael Wueff1a592007-09-25 18:11:01 -0700889 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100890 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700891 return -ENOMEM;
892 }
893
894 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200895 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700896
897 SET_IEEE80211_DEV(dev, &intf->dev);
898 usb_set_intfdata(intf, dev);
899 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100900 priv->intf = intf;
901 skb_queue_head_init(&priv->rx_queue);
902 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700903
904 usb_get_dev(udev);
905
906 /* really lazy and simple way of figuring out if we're a 3887 */
907 /* TODO: should just stick the identification in the device table */
908 i = intf->altsetting->desc.bNumEndpoints;
909 recognized_pipes = 0;
910 while (i--) {
911 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
912 case P54U_PIPE_DATA:
913 case P54U_PIPE_MGMT:
914 case P54U_PIPE_BRG:
915 case P54U_PIPE_DEV:
916 case P54U_PIPE_DATA | USB_DIR_IN:
917 case P54U_PIPE_MGMT | USB_DIR_IN:
918 case P54U_PIPE_BRG | USB_DIR_IN:
919 case P54U_PIPE_DEV | USB_DIR_IN:
920 case P54U_PIPE_INT | USB_DIR_IN:
921 recognized_pipes++;
922 }
923 }
924 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200925 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700926 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200927#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200928 /* ISL3887 needs a full reset on resume */
929 udev->reset_resume = 1;
930 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200931#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200932
Michael Wueff1a592007-09-25 18:11:01 -0700933 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200934 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
935 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
936 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200937 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700938 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200939 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700940 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
941 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
942 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200943 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200944 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200945 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700946 if (err)
947 goto err_free_dev;
948
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200949 err = priv->upload_fw(dev);
950 if (err)
951 goto err_free_fw;
952
Christian Lamparter7cb77072008-09-01 22:48:51 +0200953 p54u_open(dev);
954 err = p54_read_eeprom(dev);
955 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700956 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200957 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700958
Christian Lamparter2ac71072009-03-05 21:30:10 +0100959 err = p54_register_common(dev, &udev->dev);
960 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200961 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700962
Michael Wueff1a592007-09-25 18:11:01 -0700963 return 0;
964
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200965err_free_fw:
966 release_firmware(priv->fw);
967
968err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500969 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700970 usb_set_intfdata(intf, NULL);
971 usb_put_dev(udev);
972 return err;
973}
974
975static void __devexit p54u_disconnect(struct usb_interface *intf)
976{
977 struct ieee80211_hw *dev = usb_get_intfdata(intf);
978 struct p54u_priv *priv;
979
980 if (!dev)
981 return;
982
Christian Lamparterd8c92102009-06-23 10:39:45 -0500983 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700984
985 priv = dev->priv;
986 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200987 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700988 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700989}
990
Christian Lamparter69828692008-12-26 19:08:31 +0100991static int p54u_pre_reset(struct usb_interface *intf)
992{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200993 struct ieee80211_hw *dev = usb_get_intfdata(intf);
994
995 if (!dev)
996 return -ENODEV;
997
998 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +0100999 return 0;
1000}
1001
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001002static int p54u_resume(struct usb_interface *intf)
1003{
1004 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1005 struct p54u_priv *priv;
1006
1007 if (!dev)
1008 return -ENODEV;
1009
1010 priv = dev->priv;
1011 if (unlikely(!(priv->upload_fw && priv->fw)))
1012 return 0;
1013
1014 return priv->upload_fw(dev);
1015}
1016
Christian Lamparter69828692008-12-26 19:08:31 +01001017static int p54u_post_reset(struct usb_interface *intf)
1018{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001019 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1020 struct p54u_priv *priv;
1021 int err;
1022
1023 err = p54u_resume(intf);
1024 if (err)
1025 return err;
1026
1027 /* reinitialize old device state */
1028 priv = dev->priv;
1029 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1030 ieee80211_restart_hw(dev);
1031
Christian Lamparter69828692008-12-26 19:08:31 +01001032 return 0;
1033}
1034
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001035#ifdef CONFIG_PM
1036
1037static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1038{
1039 return p54u_pre_reset(intf);
1040}
1041
1042#endif /* CONFIG_PM */
1043
Michael Wueff1a592007-09-25 18:11:01 -07001044static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001045 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001046 .id_table = p54u_table,
1047 .probe = p54u_probe,
1048 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001049 .pre_reset = p54u_pre_reset,
1050 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001051#ifdef CONFIG_PM
1052 .suspend = p54u_suspend,
1053 .resume = p54u_resume,
1054 .reset_resume = p54u_resume,
1055#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001056 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001057};
1058
1059static int __init p54u_init(void)
1060{
1061 return usb_register(&p54u_driver);
1062}
1063
1064static void __exit p54u_exit(void)
1065{
1066 usb_deregister(&p54u_driver);
1067}
1068
1069module_init(p54u_init);
1070module_exit(p54u_exit);