blob: a068621307036b0a2415123549c2be01b5c381e2 [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 */
83 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
84 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
85 {}
86};
87
88MODULE_DEVICE_TABLE(usb, p54u_table);
89
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020090static const struct {
91 u32 intf;
92 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020093 const char *fw;
94 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020095 char hw[20];
96} p54u_fwlist[__NUM_P54U_HWTYPES] = {
97 {
98 .type = P54U_NET2280,
99 .intf = FW_LM86,
100 .fw = "isl3886usb",
101 .fw_legacy = "isl3890usb",
102 .hw = "ISL3886 + net2280",
103 },
104 {
105 .type = P54U_3887,
106 .intf = FW_LM87,
107 .fw = "isl3887usb",
108 .fw_legacy = "isl3887usb_bare",
109 .hw = "ISL3887",
110 },
111};
112
Michael Wueff1a592007-09-25 18:11:01 -0700113static void p54u_rx_cb(struct urb *urb)
114{
115 struct sk_buff *skb = (struct sk_buff *) urb->context;
116 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
117 struct ieee80211_hw *dev = info->dev;
118 struct p54u_priv *priv = dev->priv;
119
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100120 skb_unlink(skb, &priv->rx_queue);
121
Michael Wueff1a592007-09-25 18:11:01 -0700122 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100123 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700124 return;
125 }
126
Michael Wueff1a592007-09-25 18:11:01 -0700127 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200128
129 if (priv->hw_type == P54U_NET2280)
130 skb_pull(skb, priv->common.tx_hdr_len);
131 if (priv->common.fw_interface == FW_LM87) {
132 skb_pull(skb, 4);
133 skb_put(skb, 4);
134 }
Michael Wueff1a592007-09-25 18:11:01 -0700135
136 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200137 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700138 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700139 /* TODO check rx queue length and refill *somewhere* */
140 return;
141 }
142
143 info = (struct p54u_rx_info *) skb->cb;
144 info->urb = urb;
145 info->dev = dev;
146 urb->transfer_buffer = skb_tail_pointer(skb);
147 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700148 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200149 if (priv->hw_type == P54U_NET2280)
150 skb_push(skb, priv->common.tx_hdr_len);
151 if (priv->common.fw_interface == FW_LM87) {
152 skb_push(skb, 4);
153 skb_put(skb, 4);
154 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200155 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700156 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200157 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700158 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100159 skb_queue_tail(&priv->rx_queue, skb);
160 usb_anchor_urb(urb, &priv->submitted);
161 if (usb_submit_urb(urb, GFP_ATOMIC)) {
162 skb_unlink(skb, &priv->rx_queue);
163 usb_unanchor_urb(urb);
164 dev_kfree_skb_irq(skb);
165 }
Michael Wueff1a592007-09-25 18:11:01 -0700166}
167
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100168static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200169{
170 struct sk_buff *skb = urb->context;
171 struct ieee80211_hw *dev = (struct ieee80211_hw *)
172 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
173
Christian Lampartere2fe1542009-01-20 00:27:57 +0100174 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100175}
176
177static void p54u_tx_dummy_cb(struct urb *urb) { }
178
179static void p54u_free_urbs(struct ieee80211_hw *dev)
180{
181 struct p54u_priv *priv = dev->priv;
182 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200183}
184
Michael Wueff1a592007-09-25 18:11:01 -0700185static int p54u_init_urbs(struct ieee80211_hw *dev)
186{
187 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100188 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700189 struct sk_buff *skb;
190 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100191 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700192
193 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200194 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100195 if (!skb) {
196 ret = -ENOMEM;
197 goto err;
198 }
Michael Wueff1a592007-09-25 18:11:01 -0700199 entry = usb_alloc_urb(0, GFP_KERNEL);
200 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100201 ret = -ENOMEM;
202 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700203 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100204
Christian Lamparter4e416a62008-09-01 22:48:41 +0200205 usb_fill_bulk_urb(entry, priv->udev,
206 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
207 skb_tail_pointer(skb),
208 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700209 info = (struct p54u_rx_info *) skb->cb;
210 info->urb = entry;
211 info->dev = dev;
212 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100213
214 usb_anchor_urb(entry, &priv->submitted);
215 ret = usb_submit_urb(entry, GFP_KERNEL);
216 if (ret) {
217 skb_unlink(skb, &priv->rx_queue);
218 usb_unanchor_urb(entry);
219 goto err;
220 }
221 usb_free_urb(entry);
222 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700223 }
224
225 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700226
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100227 err:
228 usb_free_urb(entry);
229 kfree_skb(skb);
230 p54u_free_urbs(dev);
231 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700232}
233
Johannes Bergc9127652008-12-01 18:19:36 +0100234static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200235{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500236 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200237
238 length >>= 2;
239 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100240 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200241 chk = (chk >> 5) ^ (chk << 3);
242 }
243
Larry Finger1f1c0e32008-09-25 14:54:28 -0500244 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200245}
246
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100247static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200248{
249 struct p54u_priv *priv = dev->priv;
250 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100251 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200252
253 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200254 if (!data_urb) {
255 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200256 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200257 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200258
Christian Lampartere2fe1542009-01-20 00:27:57 +0100259 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
260 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200261
262 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200263 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100264 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
265 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100266 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200267
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100268 usb_anchor_urb(data_urb, &priv->submitted);
269 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
270 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100271 p54_free_skb(dev, skb);
272 }
273 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200274}
275
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100276static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700277{
278 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200279 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100280 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200281 struct net2280_reg_write *reg = NULL;
282 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700283
284 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
285 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200286 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700287
288 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200289 if (!int_urb)
290 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700291
292 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200293 if (!data_urb)
294 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700295
296 reg->port = cpu_to_le16(NET2280_DEV_U32);
297 reg->addr = cpu_to_le32(P54U_DEV_BASE);
298 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
299
Michael Wueff1a592007-09-25 18:11:01 -0700300 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100301 hdr->len = cpu_to_le16(skb->len);
302 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700303
304 usb_fill_bulk_urb(int_urb, priv->udev,
305 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100306 p54u_tx_dummy_cb, dev);
307
308 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200309 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
310 * free what is inside the transfer_buffer after the last reference to
311 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100312 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100313 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200314 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700315
316 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200317 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100318 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
319 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100320 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100321
322 usb_anchor_urb(int_urb, &priv->submitted);
323 err = usb_submit_urb(int_urb, GFP_ATOMIC);
324 if (err) {
325 usb_unanchor_urb(int_urb);
326 goto out;
327 }
328
329 usb_anchor_urb(data_urb, &priv->submitted);
330 err = usb_submit_urb(data_urb, GFP_ATOMIC);
331 if (err) {
332 usb_unanchor_urb(data_urb);
333 goto out;
334 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200335out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100336 usb_free_urb(int_urb);
337 usb_free_urb(data_urb);
338
339 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200340 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100341 p54_free_skb(dev, skb);
342 }
Michael Wueff1a592007-09-25 18:11:01 -0700343}
344
345static int p54u_write(struct p54u_priv *priv,
346 struct net2280_reg_write *buf,
347 enum net2280_op_type type,
348 __le32 addr, __le32 val)
349{
350 unsigned int ep;
351 int alen;
352
353 if (type & 0x0800)
354 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
355 else
356 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
357
358 buf->port = cpu_to_le16(type);
359 buf->addr = addr;
360 buf->val = val;
361
362 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
363}
364
365static int p54u_read(struct p54u_priv *priv, void *buf,
366 enum net2280_op_type type,
367 __le32 addr, __le32 *val)
368{
369 struct net2280_reg_read *read = buf;
370 __le32 *reg = buf;
371 unsigned int ep;
372 int alen, err;
373
374 if (type & 0x0800)
375 ep = P54U_PIPE_DEV;
376 else
377 ep = P54U_PIPE_BRG;
378
379 read->port = cpu_to_le16(type);
380 read->addr = addr;
381
382 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
383 read, sizeof(*read), &alen, 1000);
384 if (err)
385 return err;
386
387 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
388 reg, sizeof(*reg), &alen, 1000);
389 if (err)
390 return err;
391
392 *val = *reg;
393 return 0;
394}
395
396static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
397 void *data, size_t len)
398{
399 int alen;
400 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
401 data, len, &alen, 2000);
402}
403
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200404static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100405{
406 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100407 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100408
Christian Lamparterc88a7682009-01-16 20:24:31 +0100409 if (lock) {
410 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
411 if (ret < 0) {
412 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200413 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100414 return ret;
415 }
Christian Lamparter69828692008-12-26 19:08:31 +0100416 }
417
418 ret = usb_reset_device(priv->udev);
419 if (lock)
420 usb_unlock_device(priv->udev);
421
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200422 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100423 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200424 "device (%d)!\n", ret);
425
426 return ret;
427}
428
429static const char p54u_romboot_3887[] = "~~~~";
430static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
431{
432 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600433 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200434 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100435
Julia Lawall27b81bb2010-05-15 23:22:55 +0200436 buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
Larry Finger21d6c272009-11-11 18:02:29 -0600437 if (!buf)
438 return -ENOMEM;
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);
Michael Wueff1a592007-09-25 18:11:01 -0700877}
878
879static int __devinit p54u_probe(struct usb_interface *intf,
880 const struct usb_device_id *id)
881{
882 struct usb_device *udev = interface_to_usbdev(intf);
883 struct ieee80211_hw *dev;
884 struct p54u_priv *priv;
885 int err;
886 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700887
888 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100889
Michael Wueff1a592007-09-25 18:11:01 -0700890 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100891 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700892 return -ENOMEM;
893 }
894
895 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200896 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700897
898 SET_IEEE80211_DEV(dev, &intf->dev);
899 usb_set_intfdata(intf, dev);
900 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100901 priv->intf = intf;
902 skb_queue_head_init(&priv->rx_queue);
903 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700904
905 usb_get_dev(udev);
906
907 /* really lazy and simple way of figuring out if we're a 3887 */
908 /* TODO: should just stick the identification in the device table */
909 i = intf->altsetting->desc.bNumEndpoints;
910 recognized_pipes = 0;
911 while (i--) {
912 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
913 case P54U_PIPE_DATA:
914 case P54U_PIPE_MGMT:
915 case P54U_PIPE_BRG:
916 case P54U_PIPE_DEV:
917 case P54U_PIPE_DATA | USB_DIR_IN:
918 case P54U_PIPE_MGMT | USB_DIR_IN:
919 case P54U_PIPE_BRG | USB_DIR_IN:
920 case P54U_PIPE_DEV | USB_DIR_IN:
921 case P54U_PIPE_INT | USB_DIR_IN:
922 recognized_pipes++;
923 }
924 }
925 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200926 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700927 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200928#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200929 /* ISL3887 needs a full reset on resume */
930 udev->reset_resume = 1;
931 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200932#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200933
Michael Wueff1a592007-09-25 18:11:01 -0700934 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200935 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
936 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
937 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200938 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700939 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200940 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700941 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
942 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
943 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200944 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200945 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200946 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700947 if (err)
948 goto err_free_dev;
949
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200950 err = priv->upload_fw(dev);
951 if (err)
952 goto err_free_fw;
953
Christian Lamparter7cb77072008-09-01 22:48:51 +0200954 p54u_open(dev);
955 err = p54_read_eeprom(dev);
956 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700957 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200958 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700959
Christian Lamparter2ac71072009-03-05 21:30:10 +0100960 err = p54_register_common(dev, &udev->dev);
961 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200962 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700963
Michael Wueff1a592007-09-25 18:11:01 -0700964 return 0;
965
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200966err_free_fw:
967 release_firmware(priv->fw);
968
969err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500970 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700971 usb_set_intfdata(intf, NULL);
972 usb_put_dev(udev);
973 return err;
974}
975
976static void __devexit p54u_disconnect(struct usb_interface *intf)
977{
978 struct ieee80211_hw *dev = usb_get_intfdata(intf);
979 struct p54u_priv *priv;
980
981 if (!dev)
982 return;
983
Christian Lamparterd8c92102009-06-23 10:39:45 -0500984 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700985
986 priv = dev->priv;
987 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200988 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700989 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700990}
991
Christian Lamparter69828692008-12-26 19:08:31 +0100992static int p54u_pre_reset(struct usb_interface *intf)
993{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200994 struct ieee80211_hw *dev = usb_get_intfdata(intf);
995
996 if (!dev)
997 return -ENODEV;
998
999 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +01001000 return 0;
1001}
1002
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001003static int p54u_resume(struct usb_interface *intf)
1004{
1005 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1006 struct p54u_priv *priv;
1007
1008 if (!dev)
1009 return -ENODEV;
1010
1011 priv = dev->priv;
1012 if (unlikely(!(priv->upload_fw && priv->fw)))
1013 return 0;
1014
1015 return priv->upload_fw(dev);
1016}
1017
Christian Lamparter69828692008-12-26 19:08:31 +01001018static int p54u_post_reset(struct usb_interface *intf)
1019{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001020 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1021 struct p54u_priv *priv;
1022 int err;
1023
1024 err = p54u_resume(intf);
1025 if (err)
1026 return err;
1027
1028 /* reinitialize old device state */
1029 priv = dev->priv;
1030 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1031 ieee80211_restart_hw(dev);
1032
Christian Lamparter69828692008-12-26 19:08:31 +01001033 return 0;
1034}
1035
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001036#ifdef CONFIG_PM
1037
1038static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1039{
1040 return p54u_pre_reset(intf);
1041}
1042
1043#endif /* CONFIG_PM */
1044
Michael Wueff1a592007-09-25 18:11:01 -07001045static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001046 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001047 .id_table = p54u_table,
1048 .probe = p54u_probe,
1049 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001050 .pre_reset = p54u_pre_reset,
1051 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001052#ifdef CONFIG_PM
1053 .suspend = p54u_suspend,
1054 .resume = p54u_resume,
1055 .reset_resume = p54u_resume,
1056#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001057 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001058};
1059
1060static int __init p54u_init(void)
1061{
1062 return usb_register(&p54u_driver);
1063}
1064
1065static void __exit p54u_exit(void)
1066{
1067 usb_deregister(&p54u_driver);
1068}
1069
1070module_init(p54u_init);
1071module_exit(p54u_exit);