blob: e44460ff149cb4a4eddd82fc600af71fc63c3e90 [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 */
39 {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
40 {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
Ivo Couckuyt1a175822008-02-20 14:58:00 -050041 {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
Michael Wueff1a592007-09-25 18:11:01 -070042 {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
43 {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
44 {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
Christian Lamparterec366eb2008-10-13 23:41:53 +020045 {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
Michael Wueff1a592007-09-25 18:11:01 -070046 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
47 {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
48 {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
49 {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
50 {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
51 {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
52 {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
53 {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
54
55 /* Version 2 devices (3887) */
Felix Homann45460022008-05-29 00:36:45 -070056 {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
Michael Wueff1a592007-09-25 18:11:01 -070057 {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
58 {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
59 {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
Michiel878e6a42009-01-04 17:22:28 -060060 {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
Michael Wueff1a592007-09-25 18:11:01 -070061 {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
62 {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
63 {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
64 {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
65 {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
66 {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
67 {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
68 {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
69 {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
70 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070071 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020072 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050073 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040074 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020075 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070076 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
77 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
78 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
79 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
80 {}
81};
82
83MODULE_DEVICE_TABLE(usb, p54u_table);
84
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020085static const struct {
86 u32 intf;
87 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020088 const char *fw;
89 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020090 char hw[20];
91} p54u_fwlist[__NUM_P54U_HWTYPES] = {
92 {
93 .type = P54U_NET2280,
94 .intf = FW_LM86,
95 .fw = "isl3886usb",
96 .fw_legacy = "isl3890usb",
97 .hw = "ISL3886 + net2280",
98 },
99 {
100 .type = P54U_3887,
101 .intf = FW_LM87,
102 .fw = "isl3887usb",
103 .fw_legacy = "isl3887usb_bare",
104 .hw = "ISL3887",
105 },
106};
107
Michael Wueff1a592007-09-25 18:11:01 -0700108static void p54u_rx_cb(struct urb *urb)
109{
110 struct sk_buff *skb = (struct sk_buff *) urb->context;
111 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
112 struct ieee80211_hw *dev = info->dev;
113 struct p54u_priv *priv = dev->priv;
114
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100115 skb_unlink(skb, &priv->rx_queue);
116
Michael Wueff1a592007-09-25 18:11:01 -0700117 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100118 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700119 return;
120 }
121
Michael Wueff1a592007-09-25 18:11:01 -0700122 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200123
124 if (priv->hw_type == P54U_NET2280)
125 skb_pull(skb, priv->common.tx_hdr_len);
126 if (priv->common.fw_interface == FW_LM87) {
127 skb_pull(skb, 4);
128 skb_put(skb, 4);
129 }
Michael Wueff1a592007-09-25 18:11:01 -0700130
131 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200132 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700133 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700134 /* TODO check rx queue length and refill *somewhere* */
135 return;
136 }
137
138 info = (struct p54u_rx_info *) skb->cb;
139 info->urb = urb;
140 info->dev = dev;
141 urb->transfer_buffer = skb_tail_pointer(skb);
142 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700143 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200144 if (priv->hw_type == P54U_NET2280)
145 skb_push(skb, priv->common.tx_hdr_len);
146 if (priv->common.fw_interface == FW_LM87) {
147 skb_push(skb, 4);
148 skb_put(skb, 4);
149 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200150 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700151 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200152 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700153 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100154 skb_queue_tail(&priv->rx_queue, skb);
155 usb_anchor_urb(urb, &priv->submitted);
156 if (usb_submit_urb(urb, GFP_ATOMIC)) {
157 skb_unlink(skb, &priv->rx_queue);
158 usb_unanchor_urb(urb);
159 dev_kfree_skb_irq(skb);
160 }
Michael Wueff1a592007-09-25 18:11:01 -0700161}
162
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100163static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200164{
165 struct sk_buff *skb = urb->context;
166 struct ieee80211_hw *dev = (struct ieee80211_hw *)
167 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
168
Christian Lampartere2fe1542009-01-20 00:27:57 +0100169 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100170}
171
172static void p54u_tx_dummy_cb(struct urb *urb) { }
173
174static void p54u_free_urbs(struct ieee80211_hw *dev)
175{
176 struct p54u_priv *priv = dev->priv;
177 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200178}
179
Michael Wueff1a592007-09-25 18:11:01 -0700180static int p54u_init_urbs(struct ieee80211_hw *dev)
181{
182 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100183 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700184 struct sk_buff *skb;
185 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100186 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700187
188 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200189 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100190 if (!skb) {
191 ret = -ENOMEM;
192 goto err;
193 }
Michael Wueff1a592007-09-25 18:11:01 -0700194 entry = usb_alloc_urb(0, GFP_KERNEL);
195 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100196 ret = -ENOMEM;
197 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700198 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100199
Christian Lamparter4e416a62008-09-01 22:48:41 +0200200 usb_fill_bulk_urb(entry, priv->udev,
201 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
202 skb_tail_pointer(skb),
203 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700204 info = (struct p54u_rx_info *) skb->cb;
205 info->urb = entry;
206 info->dev = dev;
207 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100208
209 usb_anchor_urb(entry, &priv->submitted);
210 ret = usb_submit_urb(entry, GFP_KERNEL);
211 if (ret) {
212 skb_unlink(skb, &priv->rx_queue);
213 usb_unanchor_urb(entry);
214 goto err;
215 }
216 usb_free_urb(entry);
217 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700218 }
219
220 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700221
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100222 err:
223 usb_free_urb(entry);
224 kfree_skb(skb);
225 p54u_free_urbs(dev);
226 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700227}
228
Johannes Bergc9127652008-12-01 18:19:36 +0100229static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200230{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500231 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200232
233 length >>= 2;
234 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100235 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200236 chk = (chk >> 5) ^ (chk << 3);
237 }
238
Larry Finger1f1c0e32008-09-25 14:54:28 -0500239 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200240}
241
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100242static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200243{
244 struct p54u_priv *priv = dev->priv;
245 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100246 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200247
248 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200249 if (!data_urb) {
250 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200251 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200252 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200253
Christian Lampartere2fe1542009-01-20 00:27:57 +0100254 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
255 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200256
257 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200258 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100259 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
260 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100261 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200262
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100263 usb_anchor_urb(data_urb, &priv->submitted);
264 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
265 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100266 p54_free_skb(dev, skb);
267 }
268 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200269}
270
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100271static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700272{
273 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200274 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100275 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200276 struct net2280_reg_write *reg = NULL;
277 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700278
279 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
280 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200281 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700282
283 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200284 if (!int_urb)
285 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700286
287 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200288 if (!data_urb)
289 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700290
291 reg->port = cpu_to_le16(NET2280_DEV_U32);
292 reg->addr = cpu_to_le32(P54U_DEV_BASE);
293 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
294
Michael Wueff1a592007-09-25 18:11:01 -0700295 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100296 hdr->len = cpu_to_le16(skb->len);
297 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700298
299 usb_fill_bulk_urb(int_urb, priv->udev,
300 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100301 p54u_tx_dummy_cb, dev);
302
303 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200304 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
305 * free what is inside the transfer_buffer after the last reference to
306 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100307 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100308 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200309 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700310
311 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200312 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100313 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
314 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100315 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100316
317 usb_anchor_urb(int_urb, &priv->submitted);
318 err = usb_submit_urb(int_urb, GFP_ATOMIC);
319 if (err) {
320 usb_unanchor_urb(int_urb);
321 goto out;
322 }
323
324 usb_anchor_urb(data_urb, &priv->submitted);
325 err = usb_submit_urb(data_urb, GFP_ATOMIC);
326 if (err) {
327 usb_unanchor_urb(data_urb);
328 goto out;
329 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200330out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100331 usb_free_urb(int_urb);
332 usb_free_urb(data_urb);
333
334 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200335 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100336 p54_free_skb(dev, skb);
337 }
Michael Wueff1a592007-09-25 18:11:01 -0700338}
339
340static int p54u_write(struct p54u_priv *priv,
341 struct net2280_reg_write *buf,
342 enum net2280_op_type type,
343 __le32 addr, __le32 val)
344{
345 unsigned int ep;
346 int alen;
347
348 if (type & 0x0800)
349 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
350 else
351 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
352
353 buf->port = cpu_to_le16(type);
354 buf->addr = addr;
355 buf->val = val;
356
357 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
358}
359
360static int p54u_read(struct p54u_priv *priv, void *buf,
361 enum net2280_op_type type,
362 __le32 addr, __le32 *val)
363{
364 struct net2280_reg_read *read = buf;
365 __le32 *reg = buf;
366 unsigned int ep;
367 int alen, err;
368
369 if (type & 0x0800)
370 ep = P54U_PIPE_DEV;
371 else
372 ep = P54U_PIPE_BRG;
373
374 read->port = cpu_to_le16(type);
375 read->addr = addr;
376
377 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
378 read, sizeof(*read), &alen, 1000);
379 if (err)
380 return err;
381
382 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
383 reg, sizeof(*reg), &alen, 1000);
384 if (err)
385 return err;
386
387 *val = *reg;
388 return 0;
389}
390
391static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
392 void *data, size_t len)
393{
394 int alen;
395 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
396 data, len, &alen, 2000);
397}
398
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200399static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100400{
401 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100402 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100403
Christian Lamparterc88a7682009-01-16 20:24:31 +0100404 if (lock) {
405 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
406 if (ret < 0) {
407 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200408 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100409 return ret;
410 }
Christian Lamparter69828692008-12-26 19:08:31 +0100411 }
412
413 ret = usb_reset_device(priv->udev);
414 if (lock)
415 usb_unlock_device(priv->udev);
416
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200417 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100418 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200419 "device (%d)!\n", ret);
420
421 return ret;
422}
423
424static const char p54u_romboot_3887[] = "~~~~";
425static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
426{
427 struct p54u_priv *priv = dev->priv;
428 u8 buf[4];
429 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100430
431 memcpy(&buf, p54u_romboot_3887, sizeof(buf));
432 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
433 buf, sizeof(buf));
434 if (ret)
435 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200436 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100437
438 return ret;
439}
440
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200441static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700442static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
443{
Michael Wueff1a592007-09-25 18:11:01 -0700444 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700445 int err, alen;
446 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100447 u8 *buf, *tmp;
448 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700449 unsigned int left, remains, block_size;
450 struct x2_header *hdr;
451 unsigned long timeout;
452
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200453 err = p54u_firmware_reset_3887(dev);
454 if (err)
455 return err;
456
Michael Wueff1a592007-09-25 18:11:01 -0700457 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
458 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100459 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
460 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200461 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700462 }
463
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200464 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100465 strcpy(buf, p54u_firmware_upload_3887);
466 left -= strlen(p54u_firmware_upload_3887);
467 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700468
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200469 data = priv->fw->data;
470 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700471
Christian Lamparter69828692008-12-26 19:08:31 +0100472 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700473 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
474 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200475 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700476 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
477 sizeof(u32)*2));
478 left -= sizeof(*hdr);
479 tmp += sizeof(*hdr);
480
481 while (remains) {
482 while (left--) {
483 if (carry) {
484 *tmp++ = carry;
485 carry = 0;
486 remains--;
487 continue;
488 }
489 switch (*data) {
490 case '~':
491 *tmp++ = '}';
492 carry = '^';
493 break;
494 case '}':
495 *tmp++ = '}';
496 carry = ']';
497 break;
498 default:
499 *tmp++ = *data;
500 remains--;
501 break;
502 }
503 data++;
504 }
505
506 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
507 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100508 dev_err(&priv->udev->dev, "(p54usb) firmware "
509 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700510 goto err_upload_failed;
511 }
512
513 tmp = buf;
514 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
515 }
516
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200517 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
518 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700519 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
520 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100521 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700522 goto err_upload_failed;
523 }
Michael Wueff1a592007-09-25 18:11:01 -0700524 timeout = jiffies + msecs_to_jiffies(1000);
525 while (!(err = usb_bulk_msg(priv->udev,
526 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
527 if (alen > 2 && !memcmp(buf, "OK", 2))
528 break;
529
530 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700531 err = -EINVAL;
532 break;
533 }
534
535 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100536 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
537 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700538 err = -ETIMEDOUT;
539 break;
540 }
541 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100542 if (err) {
543 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700544 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100545 }
Michael Wueff1a592007-09-25 18:11:01 -0700546
547 buf[0] = 'g';
548 buf[1] = '\r';
549 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
550 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100551 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700552 goto err_upload_failed;
553 }
554
555 timeout = jiffies + msecs_to_jiffies(1000);
556 while (!(err = usb_bulk_msg(priv->udev,
557 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
558 if (alen > 0 && buf[0] == 'g')
559 break;
560
561 if (time_after(jiffies, timeout)) {
562 err = -ETIMEDOUT;
563 break;
564 }
565 }
566 if (err)
567 goto err_upload_failed;
568
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200569err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700570 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700571 return err;
572}
573
574static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
575{
576 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700577 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
578 int err, alen;
579 void *buf;
580 __le32 reg;
581 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100582 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700583
584 buf = kmalloc(512, GFP_KERNEL);
585 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100586 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
587 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700588 return -ENOMEM;
589 }
590
Michael Wueff1a592007-09-25 18:11:01 -0700591#define P54U_WRITE(type, addr, data) \
592 do {\
593 err = p54u_write(priv, buf, type,\
594 cpu_to_le32((u32)(unsigned long)addr), data);\
595 if (err) \
596 goto fail;\
597 } while (0)
598
599#define P54U_READ(type, addr) \
600 do {\
601 err = p54u_read(priv, buf, type,\
602 cpu_to_le32((u32)(unsigned long)addr), &reg);\
603 if (err)\
604 goto fail;\
605 } while (0)
606
607 /* power down net2280 bridge */
608 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
609 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
610 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
611 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
612
613 mdelay(100);
614
615 /* power up bridge */
616 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
617 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
618 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
619
620 mdelay(100);
621
622 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
623 cpu_to_le32(NET2280_CLK_30Mhz |
624 NET2280_PCI_ENABLE |
625 NET2280_PCI_SOFT_RESET));
626
627 mdelay(20);
628
629 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
630 cpu_to_le32(PCI_COMMAND_MEMORY |
631 PCI_COMMAND_MASTER));
632
633 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
634 cpu_to_le32(NET2280_BASE));
635
636 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
637 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
638 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
639
640 // TODO: we really need this?
641 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
642
643 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
644 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
645 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
646 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
647
648 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
649 cpu_to_le32(NET2280_BASE2));
650
651 /* finally done setting up the bridge */
652
653 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
654 cpu_to_le32(PCI_COMMAND_MEMORY |
655 PCI_COMMAND_MASTER));
656
657 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
658 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
659 cpu_to_le32(P54U_DEV_BASE));
660
661 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
662 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
663 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
664
665 /* do romboot */
666 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
667
668 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
669 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
670 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
671 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
672 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
673
674 mdelay(20);
675
676 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
677 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
678
679 mdelay(20);
680
681 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
682 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
683
684 mdelay(100);
685
686 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
687 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
688
689 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200690 remains = priv->fw->size;
691 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700692 offset = ISL38XX_DEV_FIRMWARE_ADDR;
693
694 while (remains) {
695 unsigned int block_len = min(remains, (unsigned int)512);
696 memcpy(buf, data, block_len);
697
698 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
699 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100700 dev_err(&priv->udev->dev, "(p54usb) firmware block "
701 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700702 goto fail;
703 }
704
705 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
706 cpu_to_le32(0xc0000f00));
707
708 P54U_WRITE(NET2280_DEV_U32,
709 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
710 P54U_WRITE(NET2280_DEV_U32,
711 0x0020 | (unsigned long)&devreg->direct_mem_win,
712 cpu_to_le32(1));
713
714 P54U_WRITE(NET2280_DEV_U32,
715 0x0024 | (unsigned long)&devreg->direct_mem_win,
716 cpu_to_le32(block_len));
717 P54U_WRITE(NET2280_DEV_U32,
718 0x0028 | (unsigned long)&devreg->direct_mem_win,
719 cpu_to_le32(offset));
720
721 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
722 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
723 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
724 cpu_to_le32(block_len >> 2));
725 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
726 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
727
728 mdelay(10);
729
730 P54U_READ(NET2280_DEV_U32,
731 0x002C | (unsigned long)&devreg->direct_mem_win);
732 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
733 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100734 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
735 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700736 goto fail;
737 }
738
739 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
740 cpu_to_le32(NET2280_FIFO_FLUSH));
741
742 remains -= block_len;
743 data += block_len;
744 offset += block_len;
745 }
746
747 /* do ramboot */
748 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
749 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
750 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
751 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
752 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
753
754 mdelay(20);
755
756 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
757 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
758
759 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
760 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
761
762 mdelay(100);
763
764 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
765 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
766
767 /* start up the firmware */
768 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
769 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
770
771 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
772 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
773
774 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
775 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
776 NET2280_USB_INTERRUPT_ENABLE));
777
778 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
779 cpu_to_le32(ISL38XX_DEV_INT_RESET));
780
781 err = usb_interrupt_msg(priv->udev,
782 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
783 buf, sizeof(__le32), &alen, 1000);
784 if (err || alen != sizeof(__le32))
785 goto fail;
786
787 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
788 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
789
790 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
791 err = -EINVAL;
792
793 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
794 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
795 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
796
797#undef P54U_WRITE
798#undef P54U_READ
799
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200800fail:
Michael Wueff1a592007-09-25 18:11:01 -0700801 kfree(buf);
802 return err;
803}
804
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200805static int p54u_load_firmware(struct ieee80211_hw *dev)
806{
807 struct p54u_priv *priv = dev->priv;
808 int err, i;
809
810 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
811
812 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
813 if (p54u_fwlist[i].type == priv->hw_type)
814 break;
815
816 if (i == __NUM_P54U_HWTYPES)
817 return -EOPNOTSUPP;
818
819 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
820 if (err) {
821 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
822 "(%d)!\n", p54u_fwlist[i].fw, err);
823
824 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
825 &priv->udev->dev);
826 if (err)
827 return err;
828 }
829
830 err = p54_parse_firmware(dev, priv->fw);
831 if (err)
832 goto out;
833
834 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
835 dev_err(&priv->udev->dev, "wrong firmware, please get "
836 "a firmware for \"%s\" and try again.\n",
837 p54u_fwlist[i].hw);
838 err = -EINVAL;
839 }
840
841out:
842 if (err)
843 release_firmware(priv->fw);
844
845 return err;
846}
847
Michael Wueff1a592007-09-25 18:11:01 -0700848static int p54u_open(struct ieee80211_hw *dev)
849{
850 struct p54u_priv *priv = dev->priv;
851 int err;
852
853 err = p54u_init_urbs(dev);
854 if (err) {
855 return err;
856 }
857
858 priv->common.open = p54u_init_urbs;
859
860 return 0;
861}
862
863static void p54u_stop(struct ieee80211_hw *dev)
864{
865 /* TODO: figure out how to reliably stop the 3887 and net2280 so
866 the hardware is still usable next time we want to start it.
867 until then, we just stop listening to the hardware.. */
868 p54u_free_urbs(dev);
869 return;
870}
871
872static int __devinit p54u_probe(struct usb_interface *intf,
873 const struct usb_device_id *id)
874{
875 struct usb_device *udev = interface_to_usbdev(intf);
876 struct ieee80211_hw *dev;
877 struct p54u_priv *priv;
878 int err;
879 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700880
881 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100882
Michael Wueff1a592007-09-25 18:11:01 -0700883 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100884 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700885 return -ENOMEM;
886 }
887
888 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200889 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700890
891 SET_IEEE80211_DEV(dev, &intf->dev);
892 usb_set_intfdata(intf, dev);
893 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100894 priv->intf = intf;
895 skb_queue_head_init(&priv->rx_queue);
896 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700897
898 usb_get_dev(udev);
899
900 /* really lazy and simple way of figuring out if we're a 3887 */
901 /* TODO: should just stick the identification in the device table */
902 i = intf->altsetting->desc.bNumEndpoints;
903 recognized_pipes = 0;
904 while (i--) {
905 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
906 case P54U_PIPE_DATA:
907 case P54U_PIPE_MGMT:
908 case P54U_PIPE_BRG:
909 case P54U_PIPE_DEV:
910 case P54U_PIPE_DATA | USB_DIR_IN:
911 case P54U_PIPE_MGMT | USB_DIR_IN:
912 case P54U_PIPE_BRG | USB_DIR_IN:
913 case P54U_PIPE_DEV | USB_DIR_IN:
914 case P54U_PIPE_INT | USB_DIR_IN:
915 recognized_pipes++;
916 }
917 }
918 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200919 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700920 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200921#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200922 /* ISL3887 needs a full reset on resume */
923 udev->reset_resume = 1;
924 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200925#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200926
Michael Wueff1a592007-09-25 18:11:01 -0700927 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200928 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
929 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
930 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200931 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700932 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200933 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700934 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
935 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
936 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200937 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200938 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200939 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700940 if (err)
941 goto err_free_dev;
942
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200943 err = priv->upload_fw(dev);
944 if (err)
945 goto err_free_fw;
946
Christian Lamparter7cb77072008-09-01 22:48:51 +0200947 p54u_open(dev);
948 err = p54_read_eeprom(dev);
949 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700950 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200951 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700952
Christian Lamparter2ac71072009-03-05 21:30:10 +0100953 err = p54_register_common(dev, &udev->dev);
954 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200955 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700956
Michael Wueff1a592007-09-25 18:11:01 -0700957 return 0;
958
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200959err_free_fw:
960 release_firmware(priv->fw);
961
962err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500963 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700964 usb_set_intfdata(intf, NULL);
965 usb_put_dev(udev);
966 return err;
967}
968
969static void __devexit p54u_disconnect(struct usb_interface *intf)
970{
971 struct ieee80211_hw *dev = usb_get_intfdata(intf);
972 struct p54u_priv *priv;
973
974 if (!dev)
975 return;
976
Christian Lamparterd8c92102009-06-23 10:39:45 -0500977 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700978
979 priv = dev->priv;
980 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200981 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700982 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700983}
984
Christian Lamparter69828692008-12-26 19:08:31 +0100985static int p54u_pre_reset(struct usb_interface *intf)
986{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200987 struct ieee80211_hw *dev = usb_get_intfdata(intf);
988
989 if (!dev)
990 return -ENODEV;
991
992 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +0100993 return 0;
994}
995
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200996static int p54u_resume(struct usb_interface *intf)
997{
998 struct ieee80211_hw *dev = usb_get_intfdata(intf);
999 struct p54u_priv *priv;
1000
1001 if (!dev)
1002 return -ENODEV;
1003
1004 priv = dev->priv;
1005 if (unlikely(!(priv->upload_fw && priv->fw)))
1006 return 0;
1007
1008 return priv->upload_fw(dev);
1009}
1010
Christian Lamparter69828692008-12-26 19:08:31 +01001011static int p54u_post_reset(struct usb_interface *intf)
1012{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001013 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1014 struct p54u_priv *priv;
1015 int err;
1016
1017 err = p54u_resume(intf);
1018 if (err)
1019 return err;
1020
1021 /* reinitialize old device state */
1022 priv = dev->priv;
1023 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1024 ieee80211_restart_hw(dev);
1025
Christian Lamparter69828692008-12-26 19:08:31 +01001026 return 0;
1027}
1028
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001029#ifdef CONFIG_PM
1030
1031static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1032{
1033 return p54u_pre_reset(intf);
1034}
1035
1036#endif /* CONFIG_PM */
1037
Michael Wueff1a592007-09-25 18:11:01 -07001038static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001039 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001040 .id_table = p54u_table,
1041 .probe = p54u_probe,
1042 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001043 .pre_reset = p54u_pre_reset,
1044 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001045#ifdef CONFIG_PM
1046 .suspend = p54u_suspend,
1047 .resume = p54u_resume,
1048 .reset_resume = p54u_resume,
1049#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001050 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001051};
1052
1053static int __init p54u_init(void)
1054{
1055 return usb_register(&p54u_driver);
1056}
1057
1058static void __exit p54u_exit(void)
1059{
1060 usb_deregister(&p54u_driver);
1061}
1062
1063module_init(p54u_init);
1064module_exit(p54u_exit);