blob: 762952d688e27d8e386a55b0068a38b377dc0205 [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 */
39 {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
Shimada Hirofumi15a69a82010-02-14 04:16:16 +090040 {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
Michael Wueff1a592007-09-25 18:11:01 -070041 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
42 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050043 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070044 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
45 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
46 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020047 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070048 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
49 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
50 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
51 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
52 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
53 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
54 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
55 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
56
57 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070058 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070059 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
60 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
61 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060062 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070063 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
64 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
Jean-François Moine5b9a9192010-02-17 10:59:31 -060065 {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
Michael Wueff1a592007-09-25 18:11:01 -070066 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
67 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
68 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
69 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
70 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
71 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
72 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
Christian Lamparterf7f71172009-09-14 23:08:43 +020073 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070074 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070075 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020076 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050077 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040078 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020079 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070080 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
81 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
82 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
83 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
84 {}
85};
86
87MODULE_DEVICE_TABLE(usb, p54u_table);
88
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020089static const struct {
90 u32 intf;
91 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020092 const char *fw;
93 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020094 char hw[20];
95} p54u_fwlist[__NUM_P54U_HWTYPES] = {
96 {
97 .type = P54U_NET2280,
98 .intf = FW_LM86,
99 .fw = "isl3886usb",
100 .fw_legacy = "isl3890usb",
101 .hw = "ISL3886 + net2280",
102 },
103 {
104 .type = P54U_3887,
105 .intf = FW_LM87,
106 .fw = "isl3887usb",
107 .fw_legacy = "isl3887usb_bare",
108 .hw = "ISL3887",
109 },
110};
111
Michael Wueff1a592007-09-25 18:11:01 -0700112static void p54u_rx_cb(struct urb *urb)
113{
114 struct sk_buff *skb = (struct sk_buff *) urb->context;
115 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
116 struct ieee80211_hw *dev = info->dev;
117 struct p54u_priv *priv = dev->priv;
118
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100119 skb_unlink(skb, &priv->rx_queue);
120
Michael Wueff1a592007-09-25 18:11:01 -0700121 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100122 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700123 return;
124 }
125
Michael Wueff1a592007-09-25 18:11:01 -0700126 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200127
128 if (priv->hw_type == P54U_NET2280)
129 skb_pull(skb, priv->common.tx_hdr_len);
130 if (priv->common.fw_interface == FW_LM87) {
131 skb_pull(skb, 4);
132 skb_put(skb, 4);
133 }
Michael Wueff1a592007-09-25 18:11:01 -0700134
135 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200136 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700137 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700138 /* TODO check rx queue length and refill *somewhere* */
139 return;
140 }
141
142 info = (struct p54u_rx_info *) skb->cb;
143 info->urb = urb;
144 info->dev = dev;
145 urb->transfer_buffer = skb_tail_pointer(skb);
146 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700147 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200148 if (priv->hw_type == P54U_NET2280)
149 skb_push(skb, priv->common.tx_hdr_len);
150 if (priv->common.fw_interface == FW_LM87) {
151 skb_push(skb, 4);
152 skb_put(skb, 4);
153 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200154 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700155 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200156 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700157 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100158 skb_queue_tail(&priv->rx_queue, skb);
159 usb_anchor_urb(urb, &priv->submitted);
160 if (usb_submit_urb(urb, GFP_ATOMIC)) {
161 skb_unlink(skb, &priv->rx_queue);
162 usb_unanchor_urb(urb);
163 dev_kfree_skb_irq(skb);
164 }
Michael Wueff1a592007-09-25 18:11:01 -0700165}
166
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100167static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200168{
169 struct sk_buff *skb = urb->context;
170 struct ieee80211_hw *dev = (struct ieee80211_hw *)
171 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
172
Christian Lampartere2fe1542009-01-20 00:27:57 +0100173 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100174}
175
176static void p54u_tx_dummy_cb(struct urb *urb) { }
177
178static void p54u_free_urbs(struct ieee80211_hw *dev)
179{
180 struct p54u_priv *priv = dev->priv;
181 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200182}
183
Michael Wueff1a592007-09-25 18:11:01 -0700184static int p54u_init_urbs(struct ieee80211_hw *dev)
185{
186 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100187 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700188 struct sk_buff *skb;
189 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100190 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700191
192 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200193 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100194 if (!skb) {
195 ret = -ENOMEM;
196 goto err;
197 }
Michael Wueff1a592007-09-25 18:11:01 -0700198 entry = usb_alloc_urb(0, GFP_KERNEL);
199 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100200 ret = -ENOMEM;
201 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700202 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100203
Christian Lamparter4e416a62008-09-01 22:48:41 +0200204 usb_fill_bulk_urb(entry, priv->udev,
205 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
206 skb_tail_pointer(skb),
207 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700208 info = (struct p54u_rx_info *) skb->cb;
209 info->urb = entry;
210 info->dev = dev;
211 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100212
213 usb_anchor_urb(entry, &priv->submitted);
214 ret = usb_submit_urb(entry, GFP_KERNEL);
215 if (ret) {
216 skb_unlink(skb, &priv->rx_queue);
217 usb_unanchor_urb(entry);
218 goto err;
219 }
220 usb_free_urb(entry);
221 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700222 }
223
224 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700225
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100226 err:
227 usb_free_urb(entry);
228 kfree_skb(skb);
229 p54u_free_urbs(dev);
230 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700231}
232
Johannes Bergc9127652008-12-01 18:19:36 +0100233static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200234{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500235 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200236
237 length >>= 2;
238 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100239 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200240 chk = (chk >> 5) ^ (chk << 3);
241 }
242
Larry Finger1f1c0e32008-09-25 14:54:28 -0500243 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200244}
245
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100246static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200247{
248 struct p54u_priv *priv = dev->priv;
249 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100250 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200251
252 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200253 if (!data_urb) {
254 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200255 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200256 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200257
Christian Lampartere2fe1542009-01-20 00:27:57 +0100258 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
259 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200260
261 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200262 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100263 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
264 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100265 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200266
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100267 usb_anchor_urb(data_urb, &priv->submitted);
268 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
269 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100270 p54_free_skb(dev, skb);
271 }
272 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200273}
274
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100275static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700276{
277 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200278 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100279 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200280 struct net2280_reg_write *reg = NULL;
281 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700282
283 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
284 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200285 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700286
287 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200288 if (!int_urb)
289 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700290
291 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200292 if (!data_urb)
293 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700294
295 reg->port = cpu_to_le16(NET2280_DEV_U32);
296 reg->addr = cpu_to_le32(P54U_DEV_BASE);
297 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
298
Michael Wueff1a592007-09-25 18:11:01 -0700299 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100300 hdr->len = cpu_to_le16(skb->len);
301 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700302
303 usb_fill_bulk_urb(int_urb, priv->udev,
304 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100305 p54u_tx_dummy_cb, dev);
306
307 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200308 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
309 * free what is inside the transfer_buffer after the last reference to
310 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100311 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100312 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200313 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700314
315 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200316 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100317 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
318 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100319 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100320
321 usb_anchor_urb(int_urb, &priv->submitted);
322 err = usb_submit_urb(int_urb, GFP_ATOMIC);
323 if (err) {
324 usb_unanchor_urb(int_urb);
325 goto out;
326 }
327
328 usb_anchor_urb(data_urb, &priv->submitted);
329 err = usb_submit_urb(data_urb, GFP_ATOMIC);
330 if (err) {
331 usb_unanchor_urb(data_urb);
332 goto out;
333 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200334out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100335 usb_free_urb(int_urb);
336 usb_free_urb(data_urb);
337
338 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200339 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100340 p54_free_skb(dev, skb);
341 }
Michael Wueff1a592007-09-25 18:11:01 -0700342}
343
344static int p54u_write(struct p54u_priv *priv,
345 struct net2280_reg_write *buf,
346 enum net2280_op_type type,
347 __le32 addr, __le32 val)
348{
349 unsigned int ep;
350 int alen;
351
352 if (type & 0x0800)
353 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
354 else
355 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
356
357 buf->port = cpu_to_le16(type);
358 buf->addr = addr;
359 buf->val = val;
360
361 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
362}
363
364static int p54u_read(struct p54u_priv *priv, void *buf,
365 enum net2280_op_type type,
366 __le32 addr, __le32 *val)
367{
368 struct net2280_reg_read *read = buf;
369 __le32 *reg = buf;
370 unsigned int ep;
371 int alen, err;
372
373 if (type & 0x0800)
374 ep = P54U_PIPE_DEV;
375 else
376 ep = P54U_PIPE_BRG;
377
378 read->port = cpu_to_le16(type);
379 read->addr = addr;
380
381 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
382 read, sizeof(*read), &alen, 1000);
383 if (err)
384 return err;
385
386 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
387 reg, sizeof(*reg), &alen, 1000);
388 if (err)
389 return err;
390
391 *val = *reg;
392 return 0;
393}
394
395static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
396 void *data, size_t len)
397{
398 int alen;
399 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
400 data, len, &alen, 2000);
401}
402
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200403static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100404{
405 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100406 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100407
Christian Lamparterc88a7682009-01-16 20:24:31 +0100408 if (lock) {
409 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
410 if (ret < 0) {
411 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200412 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100413 return ret;
414 }
Christian Lamparter69828692008-12-26 19:08:31 +0100415 }
416
417 ret = usb_reset_device(priv->udev);
418 if (lock)
419 usb_unlock_device(priv->udev);
420
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200421 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100422 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200423 "device (%d)!\n", ret);
424
425 return ret;
426}
427
428static const char p54u_romboot_3887[] = "~~~~";
429static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
430{
431 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600432 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200433 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100434
Larry Finger21d6c272009-11-11 18:02:29 -0600435 buf = kmalloc(4, GFP_KERNEL);
436 if (!buf)
437 return -ENOMEM;
438 memcpy(buf, p54u_romboot_3887, 4);
Christian Lamparter69828692008-12-26 19:08:31 +0100439 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600440 buf, 4);
441 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100442 if (ret)
443 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200444 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100445
446 return ret;
447}
448
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200449static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700450static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
451{
Michael Wueff1a592007-09-25 18:11:01 -0700452 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700453 int err, alen;
454 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100455 u8 *buf, *tmp;
456 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700457 unsigned int left, remains, block_size;
458 struct x2_header *hdr;
459 unsigned long timeout;
460
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200461 err = p54u_firmware_reset_3887(dev);
462 if (err)
463 return err;
464
Michael Wueff1a592007-09-25 18:11:01 -0700465 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
466 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100467 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
468 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200469 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700470 }
471
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200472 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100473 strcpy(buf, p54u_firmware_upload_3887);
474 left -= strlen(p54u_firmware_upload_3887);
475 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700476
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200477 data = priv->fw->data;
478 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700479
Christian Lamparter69828692008-12-26 19:08:31 +0100480 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700481 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
482 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200483 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700484 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
485 sizeof(u32)*2));
486 left -= sizeof(*hdr);
487 tmp += sizeof(*hdr);
488
489 while (remains) {
490 while (left--) {
491 if (carry) {
492 *tmp++ = carry;
493 carry = 0;
494 remains--;
495 continue;
496 }
497 switch (*data) {
498 case '~':
499 *tmp++ = '}';
500 carry = '^';
501 break;
502 case '}':
503 *tmp++ = '}';
504 carry = ']';
505 break;
506 default:
507 *tmp++ = *data;
508 remains--;
509 break;
510 }
511 data++;
512 }
513
514 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
515 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100516 dev_err(&priv->udev->dev, "(p54usb) firmware "
517 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700518 goto err_upload_failed;
519 }
520
521 tmp = buf;
522 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
523 }
524
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200525 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
526 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700527 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
528 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100529 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700530 goto err_upload_failed;
531 }
Michael Wueff1a592007-09-25 18:11:01 -0700532 timeout = jiffies + msecs_to_jiffies(1000);
533 while (!(err = usb_bulk_msg(priv->udev,
534 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
535 if (alen > 2 && !memcmp(buf, "OK", 2))
536 break;
537
538 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700539 err = -EINVAL;
540 break;
541 }
542
543 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100544 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
545 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700546 err = -ETIMEDOUT;
547 break;
548 }
549 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100550 if (err) {
551 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700552 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100553 }
Michael Wueff1a592007-09-25 18:11:01 -0700554
555 buf[0] = 'g';
556 buf[1] = '\r';
557 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
558 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100559 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700560 goto err_upload_failed;
561 }
562
563 timeout = jiffies + msecs_to_jiffies(1000);
564 while (!(err = usb_bulk_msg(priv->udev,
565 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
566 if (alen > 0 && buf[0] == 'g')
567 break;
568
569 if (time_after(jiffies, timeout)) {
570 err = -ETIMEDOUT;
571 break;
572 }
573 }
574 if (err)
575 goto err_upload_failed;
576
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200577err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700578 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700579 return err;
580}
581
582static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
583{
584 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700585 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
586 int err, alen;
587 void *buf;
588 __le32 reg;
589 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100590 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700591
592 buf = kmalloc(512, GFP_KERNEL);
593 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100594 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
595 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700596 return -ENOMEM;
597 }
598
Michael Wueff1a592007-09-25 18:11:01 -0700599#define P54U_WRITE(type, addr, data) \
600 do {\
601 err = p54u_write(priv, buf, type,\
602 cpu_to_le32((u32)(unsigned long)addr), data);\
603 if (err) \
604 goto fail;\
605 } while (0)
606
607#define P54U_READ(type, addr) \
608 do {\
609 err = p54u_read(priv, buf, type,\
610 cpu_to_le32((u32)(unsigned long)addr), &reg);\
611 if (err)\
612 goto fail;\
613 } while (0)
614
615 /* power down net2280 bridge */
616 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
617 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
618 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
619 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
620
621 mdelay(100);
622
623 /* power up bridge */
624 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
625 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
626 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
627
628 mdelay(100);
629
630 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
631 cpu_to_le32(NET2280_CLK_30Mhz |
632 NET2280_PCI_ENABLE |
633 NET2280_PCI_SOFT_RESET));
634
635 mdelay(20);
636
637 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
638 cpu_to_le32(PCI_COMMAND_MEMORY |
639 PCI_COMMAND_MASTER));
640
641 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
642 cpu_to_le32(NET2280_BASE));
643
644 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
645 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
646 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
647
648 // TODO: we really need this?
649 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
650
651 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
652 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
653 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
654 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
655
656 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
657 cpu_to_le32(NET2280_BASE2));
658
659 /* finally done setting up the bridge */
660
661 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
662 cpu_to_le32(PCI_COMMAND_MEMORY |
663 PCI_COMMAND_MASTER));
664
665 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
666 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
667 cpu_to_le32(P54U_DEV_BASE));
668
669 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
670 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
671 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
672
673 /* do romboot */
674 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
675
676 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
677 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
678 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
679 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
680 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
681
682 mdelay(20);
683
684 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
685 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
686
687 mdelay(20);
688
689 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
690 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
691
692 mdelay(100);
693
694 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
695 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
696
697 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200698 remains = priv->fw->size;
699 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700700 offset = ISL38XX_DEV_FIRMWARE_ADDR;
701
702 while (remains) {
703 unsigned int block_len = min(remains, (unsigned int)512);
704 memcpy(buf, data, block_len);
705
706 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
707 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100708 dev_err(&priv->udev->dev, "(p54usb) firmware block "
709 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700710 goto fail;
711 }
712
713 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
714 cpu_to_le32(0xc0000f00));
715
716 P54U_WRITE(NET2280_DEV_U32,
717 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
718 P54U_WRITE(NET2280_DEV_U32,
719 0x0020 | (unsigned long)&devreg->direct_mem_win,
720 cpu_to_le32(1));
721
722 P54U_WRITE(NET2280_DEV_U32,
723 0x0024 | (unsigned long)&devreg->direct_mem_win,
724 cpu_to_le32(block_len));
725 P54U_WRITE(NET2280_DEV_U32,
726 0x0028 | (unsigned long)&devreg->direct_mem_win,
727 cpu_to_le32(offset));
728
729 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
730 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
731 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
732 cpu_to_le32(block_len >> 2));
733 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
734 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
735
736 mdelay(10);
737
738 P54U_READ(NET2280_DEV_U32,
739 0x002C | (unsigned long)&devreg->direct_mem_win);
740 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
741 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100742 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
743 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700744 goto fail;
745 }
746
747 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
748 cpu_to_le32(NET2280_FIFO_FLUSH));
749
750 remains -= block_len;
751 data += block_len;
752 offset += block_len;
753 }
754
755 /* do ramboot */
756 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
757 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
758 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
759 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
760 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
761
762 mdelay(20);
763
764 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
765 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
766
767 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
768 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
769
770 mdelay(100);
771
772 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
773 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
774
775 /* start up the firmware */
776 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
777 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
778
779 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
780 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
781
782 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
783 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
784 NET2280_USB_INTERRUPT_ENABLE));
785
786 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
787 cpu_to_le32(ISL38XX_DEV_INT_RESET));
788
789 err = usb_interrupt_msg(priv->udev,
790 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
791 buf, sizeof(__le32), &alen, 1000);
792 if (err || alen != sizeof(__le32))
793 goto fail;
794
795 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
796 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
797
798 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
799 err = -EINVAL;
800
801 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
802 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
803 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
804
805#undef P54U_WRITE
806#undef P54U_READ
807
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200808fail:
Michael Wueff1a592007-09-25 18:11:01 -0700809 kfree(buf);
810 return err;
811}
812
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200813static int p54u_load_firmware(struct ieee80211_hw *dev)
814{
815 struct p54u_priv *priv = dev->priv;
816 int err, i;
817
818 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
819
820 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
821 if (p54u_fwlist[i].type == priv->hw_type)
822 break;
823
824 if (i == __NUM_P54U_HWTYPES)
825 return -EOPNOTSUPP;
826
827 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
828 if (err) {
829 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
830 "(%d)!\n", p54u_fwlist[i].fw, err);
831
832 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
833 &priv->udev->dev);
834 if (err)
835 return err;
836 }
837
838 err = p54_parse_firmware(dev, priv->fw);
839 if (err)
840 goto out;
841
842 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
843 dev_err(&priv->udev->dev, "wrong firmware, please get "
844 "a firmware for \"%s\" and try again.\n",
845 p54u_fwlist[i].hw);
846 err = -EINVAL;
847 }
848
849out:
850 if (err)
851 release_firmware(priv->fw);
852
853 return err;
854}
855
Michael Wueff1a592007-09-25 18:11:01 -0700856static int p54u_open(struct ieee80211_hw *dev)
857{
858 struct p54u_priv *priv = dev->priv;
859 int err;
860
861 err = p54u_init_urbs(dev);
862 if (err) {
863 return err;
864 }
865
866 priv->common.open = p54u_init_urbs;
867
868 return 0;
869}
870
871static void p54u_stop(struct ieee80211_hw *dev)
872{
873 /* TODO: figure out how to reliably stop the 3887 and net2280 so
874 the hardware is still usable next time we want to start it.
875 until then, we just stop listening to the hardware.. */
876 p54u_free_urbs(dev);
877 return;
878}
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);