blob: 92af9b96bb7a2bb51f3adba3316db4ca86bf1beb [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 */
Christian Lamparterf7f71172009-09-14 23:08:43 +020070 {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
Michael Wueff1a592007-09-25 18:11:01 -070071 {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
Jan Slupski43557e12008-03-10 22:41:18 -070072 {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
Christian Lamparterec366eb2008-10-13 23:41:53 +020073 {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
John W. Linville387e1002008-02-20 15:06:02 -050074 {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
Martti Huttunenc1098102007-10-04 00:06:00 -040075 {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
Christian Lampartere3062402009-03-29 22:50:28 +020076 {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
Michael Wueff1a592007-09-25 18:11:01 -070077 {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
78 {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
79 {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
80 {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
81 {}
82};
83
84MODULE_DEVICE_TABLE(usb, p54u_table);
85
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020086static const struct {
87 u32 intf;
88 enum p54u_hw_type type;
Samuel Ortiz328d84f2009-05-27 10:12:51 +020089 const char *fw;
90 const char *fw_legacy;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +020091 char hw[20];
92} p54u_fwlist[__NUM_P54U_HWTYPES] = {
93 {
94 .type = P54U_NET2280,
95 .intf = FW_LM86,
96 .fw = "isl3886usb",
97 .fw_legacy = "isl3890usb",
98 .hw = "ISL3886 + net2280",
99 },
100 {
101 .type = P54U_3887,
102 .intf = FW_LM87,
103 .fw = "isl3887usb",
104 .fw_legacy = "isl3887usb_bare",
105 .hw = "ISL3887",
106 },
107};
108
Michael Wueff1a592007-09-25 18:11:01 -0700109static void p54u_rx_cb(struct urb *urb)
110{
111 struct sk_buff *skb = (struct sk_buff *) urb->context;
112 struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
113 struct ieee80211_hw *dev = info->dev;
114 struct p54u_priv *priv = dev->priv;
115
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100116 skb_unlink(skb, &priv->rx_queue);
117
Michael Wueff1a592007-09-25 18:11:01 -0700118 if (unlikely(urb->status)) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100119 dev_kfree_skb_irq(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700120 return;
121 }
122
Michael Wueff1a592007-09-25 18:11:01 -0700123 skb_put(skb, urb->actual_length);
Christian Lamparter2b808482008-09-04 12:29:38 +0200124
125 if (priv->hw_type == P54U_NET2280)
126 skb_pull(skb, priv->common.tx_hdr_len);
127 if (priv->common.fw_interface == FW_LM87) {
128 skb_pull(skb, 4);
129 skb_put(skb, 4);
130 }
Michael Wueff1a592007-09-25 18:11:01 -0700131
132 if (p54_rx(dev, skb)) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200133 skb = dev_alloc_skb(priv->common.rx_mtu + 32);
Michael Wueff1a592007-09-25 18:11:01 -0700134 if (unlikely(!skb)) {
Michael Wueff1a592007-09-25 18:11:01 -0700135 /* TODO check rx queue length and refill *somewhere* */
136 return;
137 }
138
139 info = (struct p54u_rx_info *) skb->cb;
140 info->urb = urb;
141 info->dev = dev;
142 urb->transfer_buffer = skb_tail_pointer(skb);
143 urb->context = skb;
Michael Wueff1a592007-09-25 18:11:01 -0700144 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200145 if (priv->hw_type == P54U_NET2280)
146 skb_push(skb, priv->common.tx_hdr_len);
147 if (priv->common.fw_interface == FW_LM87) {
148 skb_push(skb, 4);
149 skb_put(skb, 4);
150 }
Christian Lamparterd47c3ce2008-08-13 23:41:48 +0200151 skb_reset_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700152 skb_trim(skb, 0);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200153 urb->transfer_buffer = skb_tail_pointer(skb);
Michael Wueff1a592007-09-25 18:11:01 -0700154 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100155 skb_queue_tail(&priv->rx_queue, skb);
156 usb_anchor_urb(urb, &priv->submitted);
157 if (usb_submit_urb(urb, GFP_ATOMIC)) {
158 skb_unlink(skb, &priv->rx_queue);
159 usb_unanchor_urb(urb);
160 dev_kfree_skb_irq(skb);
161 }
Michael Wueff1a592007-09-25 18:11:01 -0700162}
163
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100164static void p54u_tx_cb(struct urb *urb)
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200165{
166 struct sk_buff *skb = urb->context;
167 struct ieee80211_hw *dev = (struct ieee80211_hw *)
168 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
169
Christian Lampartere2fe1542009-01-20 00:27:57 +0100170 p54_free_skb(dev, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100171}
172
173static void p54u_tx_dummy_cb(struct urb *urb) { }
174
175static void p54u_free_urbs(struct ieee80211_hw *dev)
176{
177 struct p54u_priv *priv = dev->priv;
178 usb_kill_anchored_urbs(&priv->submitted);
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200179}
180
Michael Wueff1a592007-09-25 18:11:01 -0700181static int p54u_init_urbs(struct ieee80211_hw *dev)
182{
183 struct p54u_priv *priv = dev->priv;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100184 struct urb *entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700185 struct sk_buff *skb;
186 struct p54u_rx_info *info;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100187 int ret = 0;
Michael Wueff1a592007-09-25 18:11:01 -0700188
189 while (skb_queue_len(&priv->rx_queue) < 32) {
Christian Lamparter4e416a62008-09-01 22:48:41 +0200190 skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100191 if (!skb) {
192 ret = -ENOMEM;
193 goto err;
194 }
Michael Wueff1a592007-09-25 18:11:01 -0700195 entry = usb_alloc_urb(0, GFP_KERNEL);
196 if (!entry) {
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100197 ret = -ENOMEM;
198 goto err;
Michael Wueff1a592007-09-25 18:11:01 -0700199 }
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100200
Christian Lamparter4e416a62008-09-01 22:48:41 +0200201 usb_fill_bulk_urb(entry, priv->udev,
202 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
203 skb_tail_pointer(skb),
204 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
Michael Wueff1a592007-09-25 18:11:01 -0700205 info = (struct p54u_rx_info *) skb->cb;
206 info->urb = entry;
207 info->dev = dev;
208 skb_queue_tail(&priv->rx_queue, skb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100209
210 usb_anchor_urb(entry, &priv->submitted);
211 ret = usb_submit_urb(entry, GFP_KERNEL);
212 if (ret) {
213 skb_unlink(skb, &priv->rx_queue);
214 usb_unanchor_urb(entry);
215 goto err;
216 }
217 usb_free_urb(entry);
218 entry = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700219 }
220
221 return 0;
Michael Wueff1a592007-09-25 18:11:01 -0700222
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100223 err:
224 usb_free_urb(entry);
225 kfree_skb(skb);
226 p54u_free_urbs(dev);
227 return ret;
Michael Wueff1a592007-09-25 18:11:01 -0700228}
229
Johannes Bergc9127652008-12-01 18:19:36 +0100230static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
Christian Lamparter2b808482008-09-04 12:29:38 +0200231{
Larry Finger1f1c0e32008-09-25 14:54:28 -0500232 u32 chk = 0;
Christian Lamparter2b808482008-09-04 12:29:38 +0200233
234 length >>= 2;
235 while (length--) {
Johannes Bergc9127652008-12-01 18:19:36 +0100236 chk ^= le32_to_cpu(*data++);
Christian Lamparter2b808482008-09-04 12:29:38 +0200237 chk = (chk >> 5) ^ (chk << 3);
238 }
239
Larry Finger1f1c0e32008-09-25 14:54:28 -0500240 return cpu_to_le32(chk);
Christian Lamparter2b808482008-09-04 12:29:38 +0200241}
242
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100243static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
Christian Lamparter2b808482008-09-04 12:29:38 +0200244{
245 struct p54u_priv *priv = dev->priv;
246 struct urb *data_urb;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100247 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter2b808482008-09-04 12:29:38 +0200248
249 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200250 if (!data_urb) {
251 p54_free_skb(dev, skb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200252 return;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200253 }
Christian Lamparter2b808482008-09-04 12:29:38 +0200254
Christian Lampartere2fe1542009-01-20 00:27:57 +0100255 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
256 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
Christian Lamparter2b808482008-09-04 12:29:38 +0200257
258 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200259 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100260 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
261 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparter00627f22008-12-20 02:21:56 +0100262 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparter2b808482008-09-04 12:29:38 +0200263
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100264 usb_anchor_urb(data_urb, &priv->submitted);
265 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
266 usb_unanchor_urb(data_urb);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100267 p54_free_skb(dev, skb);
268 }
269 usb_free_urb(data_urb);
Christian Lamparter2b808482008-09-04 12:29:38 +0200270}
271
Christian Lamparter0a5ec962008-12-14 15:05:42 +0100272static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
Michael Wueff1a592007-09-25 18:11:01 -0700273{
274 struct p54u_priv *priv = dev->priv;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200275 struct urb *int_urb = NULL, *data_urb = NULL;
Christian Lampartere2fe1542009-01-20 00:27:57 +0100276 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200277 struct net2280_reg_write *reg = NULL;
278 int err = -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700279
280 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
281 if (!reg)
Christian Lamparter6d541a62009-07-06 15:17:56 +0200282 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700283
284 int_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200285 if (!int_urb)
286 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700287
288 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
Christian Lamparter6d541a62009-07-06 15:17:56 +0200289 if (!data_urb)
290 goto out;
Michael Wueff1a592007-09-25 18:11:01 -0700291
292 reg->port = cpu_to_le16(NET2280_DEV_U32);
293 reg->addr = cpu_to_le32(P54U_DEV_BASE);
294 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
295
Michael Wueff1a592007-09-25 18:11:01 -0700296 memset(hdr, 0, sizeof(*hdr));
Christian Lampartere2fe1542009-01-20 00:27:57 +0100297 hdr->len = cpu_to_le16(skb->len);
298 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
Michael Wueff1a592007-09-25 18:11:01 -0700299
300 usb_fill_bulk_urb(int_urb, priv->udev,
301 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100302 p54u_tx_dummy_cb, dev);
303
304 /*
Christian Lamparter6d541a62009-07-06 15:17:56 +0200305 * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
306 * free what is inside the transfer_buffer after the last reference to
307 * the int_urb is dropped.
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100308 */
Christian Lamparterb4068a82009-01-20 23:11:21 +0100309 int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
Christian Lamparter6d541a62009-07-06 15:17:56 +0200310 reg = NULL;
Michael Wueff1a592007-09-25 18:11:01 -0700311
312 usb_fill_bulk_urb(data_urb, priv->udev,
Christian Lamparterb92f30d2008-10-15 04:07:16 +0200313 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
Christian Lampartere2fe1542009-01-20 00:27:57 +0100314 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
315 p54u_tx_cb : p54u_tx_dummy_cb, skb);
Christian Lamparterb4068a82009-01-20 23:11:21 +0100316 data_urb->transfer_flags |= URB_ZERO_PACKET;
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100317
318 usb_anchor_urb(int_urb, &priv->submitted);
319 err = usb_submit_urb(int_urb, GFP_ATOMIC);
320 if (err) {
321 usb_unanchor_urb(int_urb);
322 goto out;
323 }
324
325 usb_anchor_urb(data_urb, &priv->submitted);
326 err = usb_submit_urb(data_urb, GFP_ATOMIC);
327 if (err) {
328 usb_unanchor_urb(data_urb);
329 goto out;
330 }
Christian Lamparter6d541a62009-07-06 15:17:56 +0200331out:
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100332 usb_free_urb(int_urb);
333 usb_free_urb(data_urb);
334
335 if (err) {
Christian Lamparter6d541a62009-07-06 15:17:56 +0200336 kfree(reg);
Christian Lamparterdd397dc2008-12-09 15:14:37 +0100337 p54_free_skb(dev, skb);
338 }
Michael Wueff1a592007-09-25 18:11:01 -0700339}
340
341static int p54u_write(struct p54u_priv *priv,
342 struct net2280_reg_write *buf,
343 enum net2280_op_type type,
344 __le32 addr, __le32 val)
345{
346 unsigned int ep;
347 int alen;
348
349 if (type & 0x0800)
350 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
351 else
352 ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
353
354 buf->port = cpu_to_le16(type);
355 buf->addr = addr;
356 buf->val = val;
357
358 return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
359}
360
361static int p54u_read(struct p54u_priv *priv, void *buf,
362 enum net2280_op_type type,
363 __le32 addr, __le32 *val)
364{
365 struct net2280_reg_read *read = buf;
366 __le32 *reg = buf;
367 unsigned int ep;
368 int alen, err;
369
370 if (type & 0x0800)
371 ep = P54U_PIPE_DEV;
372 else
373 ep = P54U_PIPE_BRG;
374
375 read->port = cpu_to_le16(type);
376 read->addr = addr;
377
378 err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
379 read, sizeof(*read), &alen, 1000);
380 if (err)
381 return err;
382
383 err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
384 reg, sizeof(*reg), &alen, 1000);
385 if (err)
386 return err;
387
388 *val = *reg;
389 return 0;
390}
391
392static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
393 void *data, size_t len)
394{
395 int alen;
396 return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
397 data, len, &alen, 2000);
398}
399
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200400static int p54u_device_reset(struct ieee80211_hw *dev)
Christian Lamparter69828692008-12-26 19:08:31 +0100401{
402 struct p54u_priv *priv = dev->priv;
Christian Lamparterc88a7682009-01-16 20:24:31 +0100403 int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
Christian Lamparter69828692008-12-26 19:08:31 +0100404
Christian Lamparterc88a7682009-01-16 20:24:31 +0100405 if (lock) {
406 ret = usb_lock_device_for_reset(priv->udev, priv->intf);
407 if (ret < 0) {
408 dev_err(&priv->udev->dev, "(p54usb) unable to lock "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200409 "device for reset (%d)!\n", ret);
Christian Lamparterc88a7682009-01-16 20:24:31 +0100410 return ret;
411 }
Christian Lamparter69828692008-12-26 19:08:31 +0100412 }
413
414 ret = usb_reset_device(priv->udev);
415 if (lock)
416 usb_unlock_device(priv->udev);
417
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200418 if (ret)
Christian Lamparter69828692008-12-26 19:08:31 +0100419 dev_err(&priv->udev->dev, "(p54usb) unable to reset "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200420 "device (%d)!\n", ret);
421
422 return ret;
423}
424
425static const char p54u_romboot_3887[] = "~~~~";
426static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
427{
428 struct p54u_priv *priv = dev->priv;
Larry Finger21d6c272009-11-11 18:02:29 -0600429 u8 *buf;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200430 int ret;
Christian Lamparter69828692008-12-26 19:08:31 +0100431
Larry Finger21d6c272009-11-11 18:02:29 -0600432 buf = kmalloc(4, GFP_KERNEL);
433 if (!buf)
434 return -ENOMEM;
435 memcpy(buf, p54u_romboot_3887, 4);
Christian Lamparter69828692008-12-26 19:08:31 +0100436 ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
Larry Finger21d6c272009-11-11 18:02:29 -0600437 buf, 4);
438 kfree(buf);
Christian Lamparter69828692008-12-26 19:08:31 +0100439 if (ret)
440 dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200441 "boot ROM (%d)!\n", ret);
Christian Lamparter69828692008-12-26 19:08:31 +0100442
443 return ret;
444}
445
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200446static const char p54u_firmware_upload_3887[] = "<\r";
Michael Wueff1a592007-09-25 18:11:01 -0700447static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
448{
Michael Wueff1a592007-09-25 18:11:01 -0700449 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700450 int err, alen;
451 u8 carry = 0;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100452 u8 *buf, *tmp;
453 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700454 unsigned int left, remains, block_size;
455 struct x2_header *hdr;
456 unsigned long timeout;
457
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200458 err = p54u_firmware_reset_3887(dev);
459 if (err)
460 return err;
461
Michael Wueff1a592007-09-25 18:11:01 -0700462 tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
463 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100464 dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
465 "upload buffer!\n");
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200466 return -ENOMEM;
Michael Wueff1a592007-09-25 18:11:01 -0700467 }
468
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200469 left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
Christian Lamparter69828692008-12-26 19:08:31 +0100470 strcpy(buf, p54u_firmware_upload_3887);
471 left -= strlen(p54u_firmware_upload_3887);
472 tmp += strlen(p54u_firmware_upload_3887);
Michael Wueff1a592007-09-25 18:11:01 -0700473
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200474 data = priv->fw->data;
475 remains = priv->fw->size;
Michael Wueff1a592007-09-25 18:11:01 -0700476
Christian Lamparter69828692008-12-26 19:08:31 +0100477 hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
Michael Wueff1a592007-09-25 18:11:01 -0700478 memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
479 hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200480 hdr->fw_length = cpu_to_le32(priv->fw->size);
Michael Wueff1a592007-09-25 18:11:01 -0700481 hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
482 sizeof(u32)*2));
483 left -= sizeof(*hdr);
484 tmp += sizeof(*hdr);
485
486 while (remains) {
487 while (left--) {
488 if (carry) {
489 *tmp++ = carry;
490 carry = 0;
491 remains--;
492 continue;
493 }
494 switch (*data) {
495 case '~':
496 *tmp++ = '}';
497 carry = '^';
498 break;
499 case '}':
500 *tmp++ = '}';
501 carry = ']';
502 break;
503 default:
504 *tmp++ = *data;
505 remains--;
506 break;
507 }
508 data++;
509 }
510
511 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
512 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100513 dev_err(&priv->udev->dev, "(p54usb) firmware "
514 "upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700515 goto err_upload_failed;
516 }
517
518 tmp = buf;
519 left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
520 }
521
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200522 *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
523 priv->fw->size));
Michael Wueff1a592007-09-25 18:11:01 -0700524 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
525 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100526 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700527 goto err_upload_failed;
528 }
Michael Wueff1a592007-09-25 18:11:01 -0700529 timeout = jiffies + msecs_to_jiffies(1000);
530 while (!(err = usb_bulk_msg(priv->udev,
531 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
532 if (alen > 2 && !memcmp(buf, "OK", 2))
533 break;
534
535 if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
Michael Wueff1a592007-09-25 18:11:01 -0700536 err = -EINVAL;
537 break;
538 }
539
540 if (time_after(jiffies, timeout)) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100541 dev_err(&priv->udev->dev, "(p54usb) firmware boot "
542 "timed out!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700543 err = -ETIMEDOUT;
544 break;
545 }
546 }
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100547 if (err) {
548 dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700549 goto err_upload_failed;
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100550 }
Michael Wueff1a592007-09-25 18:11:01 -0700551
552 buf[0] = 'g';
553 buf[1] = '\r';
554 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
555 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100556 dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700557 goto err_upload_failed;
558 }
559
560 timeout = jiffies + msecs_to_jiffies(1000);
561 while (!(err = usb_bulk_msg(priv->udev,
562 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
563 if (alen > 0 && buf[0] == 'g')
564 break;
565
566 if (time_after(jiffies, timeout)) {
567 err = -ETIMEDOUT;
568 break;
569 }
570 }
571 if (err)
572 goto err_upload_failed;
573
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200574err_upload_failed:
Michael Wueff1a592007-09-25 18:11:01 -0700575 kfree(buf);
Michael Wueff1a592007-09-25 18:11:01 -0700576 return err;
577}
578
579static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
580{
581 struct p54u_priv *priv = dev->priv;
Michael Wueff1a592007-09-25 18:11:01 -0700582 const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
583 int err, alen;
584 void *buf;
585 __le32 reg;
586 unsigned int remains, offset;
David Woodhouse8b72eb42008-05-24 00:08:55 +0100587 const u8 *data;
Michael Wueff1a592007-09-25 18:11:01 -0700588
589 buf = kmalloc(512, GFP_KERNEL);
590 if (!buf) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100591 dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
592 "alloc failed!\n");
Michael Wueff1a592007-09-25 18:11:01 -0700593 return -ENOMEM;
594 }
595
Michael Wueff1a592007-09-25 18:11:01 -0700596#define P54U_WRITE(type, addr, data) \
597 do {\
598 err = p54u_write(priv, buf, type,\
599 cpu_to_le32((u32)(unsigned long)addr), data);\
600 if (err) \
601 goto fail;\
602 } while (0)
603
604#define P54U_READ(type, addr) \
605 do {\
606 err = p54u_read(priv, buf, type,\
607 cpu_to_le32((u32)(unsigned long)addr), &reg);\
608 if (err)\
609 goto fail;\
610 } while (0)
611
612 /* power down net2280 bridge */
613 P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
614 reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
615 reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
616 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
617
618 mdelay(100);
619
620 /* power up bridge */
621 reg |= cpu_to_le32(P54U_BRG_POWER_UP);
622 reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
623 P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
624
625 mdelay(100);
626
627 P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
628 cpu_to_le32(NET2280_CLK_30Mhz |
629 NET2280_PCI_ENABLE |
630 NET2280_PCI_SOFT_RESET));
631
632 mdelay(20);
633
634 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
635 cpu_to_le32(PCI_COMMAND_MEMORY |
636 PCI_COMMAND_MASTER));
637
638 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
639 cpu_to_le32(NET2280_BASE));
640
641 P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
642 reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
643 P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
644
645 // TODO: we really need this?
646 P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
647
648 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
649 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
650 P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
651 cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
652
653 P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
654 cpu_to_le32(NET2280_BASE2));
655
656 /* finally done setting up the bridge */
657
658 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
659 cpu_to_le32(PCI_COMMAND_MEMORY |
660 PCI_COMMAND_MASTER));
661
662 P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
663 P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
664 cpu_to_le32(P54U_DEV_BASE));
665
666 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
667 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
668 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
669
670 /* do romboot */
671 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
672
673 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
674 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
675 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
676 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
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(20);
685
686 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
687 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
688
689 mdelay(100);
690
691 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
692 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
693
694 /* finally, we can upload firmware now! */
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200695 remains = priv->fw->size;
696 data = priv->fw->data;
Michael Wueff1a592007-09-25 18:11:01 -0700697 offset = ISL38XX_DEV_FIRMWARE_ADDR;
698
699 while (remains) {
700 unsigned int block_len = min(remains, (unsigned int)512);
701 memcpy(buf, data, block_len);
702
703 err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
704 if (err) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100705 dev_err(&priv->udev->dev, "(p54usb) firmware block "
706 "upload failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700707 goto fail;
708 }
709
710 P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
711 cpu_to_le32(0xc0000f00));
712
713 P54U_WRITE(NET2280_DEV_U32,
714 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
715 P54U_WRITE(NET2280_DEV_U32,
716 0x0020 | (unsigned long)&devreg->direct_mem_win,
717 cpu_to_le32(1));
718
719 P54U_WRITE(NET2280_DEV_U32,
720 0x0024 | (unsigned long)&devreg->direct_mem_win,
721 cpu_to_le32(block_len));
722 P54U_WRITE(NET2280_DEV_U32,
723 0x0028 | (unsigned long)&devreg->direct_mem_win,
724 cpu_to_le32(offset));
725
726 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
727 cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
728 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
729 cpu_to_le32(block_len >> 2));
730 P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
731 cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
732
733 mdelay(10);
734
735 P54U_READ(NET2280_DEV_U32,
736 0x002C | (unsigned long)&devreg->direct_mem_win);
737 if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
738 !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100739 dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
740 "transfer failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700741 goto fail;
742 }
743
744 P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
745 cpu_to_le32(NET2280_FIFO_FLUSH));
746
747 remains -= block_len;
748 data += block_len;
749 offset += block_len;
750 }
751
752 /* do ramboot */
753 P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
754 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
755 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
756 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
757 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
758
759 mdelay(20);
760
761 reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
762 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
763
764 reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
765 P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
766
767 mdelay(100);
768
769 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
770 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
771
772 /* start up the firmware */
773 P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
774 cpu_to_le32(ISL38XX_INT_IDENT_INIT));
775
776 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
777 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
778
779 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
780 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
781 NET2280_USB_INTERRUPT_ENABLE));
782
783 P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
784 cpu_to_le32(ISL38XX_DEV_INT_RESET));
785
786 err = usb_interrupt_msg(priv->udev,
787 usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
788 buf, sizeof(__le32), &alen, 1000);
789 if (err || alen != sizeof(__le32))
790 goto fail;
791
792 P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
793 P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
794
795 if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
796 err = -EINVAL;
797
798 P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
799 P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
800 cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
801
802#undef P54U_WRITE
803#undef P54U_READ
804
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200805fail:
Michael Wueff1a592007-09-25 18:11:01 -0700806 kfree(buf);
807 return err;
808}
809
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200810static int p54u_load_firmware(struct ieee80211_hw *dev)
811{
812 struct p54u_priv *priv = dev->priv;
813 int err, i;
814
815 BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
816
817 for (i = 0; i < __NUM_P54U_HWTYPES; i++)
818 if (p54u_fwlist[i].type == priv->hw_type)
819 break;
820
821 if (i == __NUM_P54U_HWTYPES)
822 return -EOPNOTSUPP;
823
824 err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
825 if (err) {
826 dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
827 "(%d)!\n", p54u_fwlist[i].fw, err);
828
829 err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
830 &priv->udev->dev);
831 if (err)
832 return err;
833 }
834
835 err = p54_parse_firmware(dev, priv->fw);
836 if (err)
837 goto out;
838
839 if (priv->common.fw_interface != p54u_fwlist[i].intf) {
840 dev_err(&priv->udev->dev, "wrong firmware, please get "
841 "a firmware for \"%s\" and try again.\n",
842 p54u_fwlist[i].hw);
843 err = -EINVAL;
844 }
845
846out:
847 if (err)
848 release_firmware(priv->fw);
849
850 return err;
851}
852
Michael Wueff1a592007-09-25 18:11:01 -0700853static int p54u_open(struct ieee80211_hw *dev)
854{
855 struct p54u_priv *priv = dev->priv;
856 int err;
857
858 err = p54u_init_urbs(dev);
859 if (err) {
860 return err;
861 }
862
863 priv->common.open = p54u_init_urbs;
864
865 return 0;
866}
867
868static void p54u_stop(struct ieee80211_hw *dev)
869{
870 /* TODO: figure out how to reliably stop the 3887 and net2280 so
871 the hardware is still usable next time we want to start it.
872 until then, we just stop listening to the hardware.. */
873 p54u_free_urbs(dev);
874 return;
875}
876
877static int __devinit p54u_probe(struct usb_interface *intf,
878 const struct usb_device_id *id)
879{
880 struct usb_device *udev = interface_to_usbdev(intf);
881 struct ieee80211_hw *dev;
882 struct p54u_priv *priv;
883 int err;
884 unsigned int i, recognized_pipes;
Michael Wueff1a592007-09-25 18:11:01 -0700885
886 dev = p54_init_common(sizeof(*priv));
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100887
Michael Wueff1a592007-09-25 18:11:01 -0700888 if (!dev) {
Christian Lamparter02e37ba2008-11-29 22:39:08 +0100889 dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
Michael Wueff1a592007-09-25 18:11:01 -0700890 return -ENOMEM;
891 }
892
893 priv = dev->priv;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200894 priv->hw_type = P54U_INVALID_HW;
Michael Wueff1a592007-09-25 18:11:01 -0700895
896 SET_IEEE80211_DEV(dev, &intf->dev);
897 usb_set_intfdata(intf, dev);
898 priv->udev = udev;
Christian Lamparter69828692008-12-26 19:08:31 +0100899 priv->intf = intf;
900 skb_queue_head_init(&priv->rx_queue);
901 init_usb_anchor(&priv->submitted);
Michael Wueff1a592007-09-25 18:11:01 -0700902
903 usb_get_dev(udev);
904
905 /* really lazy and simple way of figuring out if we're a 3887 */
906 /* TODO: should just stick the identification in the device table */
907 i = intf->altsetting->desc.bNumEndpoints;
908 recognized_pipes = 0;
909 while (i--) {
910 switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
911 case P54U_PIPE_DATA:
912 case P54U_PIPE_MGMT:
913 case P54U_PIPE_BRG:
914 case P54U_PIPE_DEV:
915 case P54U_PIPE_DATA | USB_DIR_IN:
916 case P54U_PIPE_MGMT | USB_DIR_IN:
917 case P54U_PIPE_BRG | USB_DIR_IN:
918 case P54U_PIPE_DEV | USB_DIR_IN:
919 case P54U_PIPE_INT | USB_DIR_IN:
920 recognized_pipes++;
921 }
922 }
923 priv->common.open = p54u_open;
Christian Lamparter2b808482008-09-04 12:29:38 +0200924 priv->common.stop = p54u_stop;
Michael Wueff1a592007-09-25 18:11:01 -0700925 if (recognized_pipes < P54U_PIPE_NUMBER) {
Hauke Mehrtens13792572009-05-01 13:12:36 +0200926#ifdef CONFIG_PM
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200927 /* ISL3887 needs a full reset on resume */
928 udev->reset_resume = 1;
929 err = p54u_device_reset(dev);
Hauke Mehrtens13792572009-05-01 13:12:36 +0200930#endif
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200931
Michael Wueff1a592007-09-25 18:11:01 -0700932 priv->hw_type = P54U_3887;
Christian Lampartera406ac02009-04-25 21:11:55 +0200933 dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
934 priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
935 priv->common.tx = p54u_tx_lm87;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200936 priv->upload_fw = p54u_upload_firmware_3887;
Michael Wueff1a592007-09-25 18:11:01 -0700937 } else {
Christian Lamparter2b808482008-09-04 12:29:38 +0200938 priv->hw_type = P54U_NET2280;
Michael Wueff1a592007-09-25 18:11:01 -0700939 dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
940 priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
941 priv->common.tx = p54u_tx_net2280;
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200942 priv->upload_fw = p54u_upload_firmware_net2280;
Christian Lamparter2b808482008-09-04 12:29:38 +0200943 }
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200944 err = p54u_load_firmware(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700945 if (err)
946 goto err_free_dev;
947
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200948 err = priv->upload_fw(dev);
949 if (err)
950 goto err_free_fw;
951
Christian Lamparter7cb77072008-09-01 22:48:51 +0200952 p54u_open(dev);
953 err = p54_read_eeprom(dev);
954 p54u_stop(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700955 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200956 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700957
Christian Lamparter2ac71072009-03-05 21:30:10 +0100958 err = p54_register_common(dev, &udev->dev);
959 if (err)
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200960 goto err_free_fw;
Michael Wueff1a592007-09-25 18:11:01 -0700961
Michael Wueff1a592007-09-25 18:11:01 -0700962 return 0;
963
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200964err_free_fw:
965 release_firmware(priv->fw);
966
967err_free_dev:
Christian Lamparterd8c92102009-06-23 10:39:45 -0500968 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700969 usb_set_intfdata(intf, NULL);
970 usb_put_dev(udev);
971 return err;
972}
973
974static void __devexit p54u_disconnect(struct usb_interface *intf)
975{
976 struct ieee80211_hw *dev = usb_get_intfdata(intf);
977 struct p54u_priv *priv;
978
979 if (!dev)
980 return;
981
Christian Lamparterd8c92102009-06-23 10:39:45 -0500982 p54_unregister_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700983
984 priv = dev->priv;
985 usb_put_dev(interface_to_usbdev(intf));
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200986 release_firmware(priv->fw);
Michael Wueff1a592007-09-25 18:11:01 -0700987 p54_free_common(dev);
Michael Wueff1a592007-09-25 18:11:01 -0700988}
989
Christian Lamparter69828692008-12-26 19:08:31 +0100990static int p54u_pre_reset(struct usb_interface *intf)
991{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +0200992 struct ieee80211_hw *dev = usb_get_intfdata(intf);
993
994 if (!dev)
995 return -ENODEV;
996
997 p54u_stop(dev);
Christian Lamparter69828692008-12-26 19:08:31 +0100998 return 0;
999}
1000
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001001static int p54u_resume(struct usb_interface *intf)
1002{
1003 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1004 struct p54u_priv *priv;
1005
1006 if (!dev)
1007 return -ENODEV;
1008
1009 priv = dev->priv;
1010 if (unlikely(!(priv->upload_fw && priv->fw)))
1011 return 0;
1012
1013 return priv->upload_fw(dev);
1014}
1015
Christian Lamparter69828692008-12-26 19:08:31 +01001016static int p54u_post_reset(struct usb_interface *intf)
1017{
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001018 struct ieee80211_hw *dev = usb_get_intfdata(intf);
1019 struct p54u_priv *priv;
1020 int err;
1021
1022 err = p54u_resume(intf);
1023 if (err)
1024 return err;
1025
1026 /* reinitialize old device state */
1027 priv = dev->priv;
1028 if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1029 ieee80211_restart_hw(dev);
1030
Christian Lamparter69828692008-12-26 19:08:31 +01001031 return 0;
1032}
1033
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001034#ifdef CONFIG_PM
1035
1036static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1037{
1038 return p54u_pre_reset(intf);
1039}
1040
1041#endif /* CONFIG_PM */
1042
Michael Wueff1a592007-09-25 18:11:01 -07001043static struct usb_driver p54u_driver = {
Christian Lamparter32ddf072008-08-08 21:17:37 +02001044 .name = "p54usb",
Michael Wueff1a592007-09-25 18:11:01 -07001045 .id_table = p54u_table,
1046 .probe = p54u_probe,
1047 .disconnect = p54u_disconnect,
Christian Lamparter69828692008-12-26 19:08:31 +01001048 .pre_reset = p54u_pre_reset,
1049 .post_reset = p54u_post_reset,
Christian Lamparter1ca5f2e2009-04-25 21:12:09 +02001050#ifdef CONFIG_PM
1051 .suspend = p54u_suspend,
1052 .resume = p54u_resume,
1053 .reset_resume = p54u_resume,
1054#endif /* CONFIG_PM */
Christian Lamparterfbf95292009-03-05 21:29:51 +01001055 .soft_unbind = 1,
Michael Wueff1a592007-09-25 18:11:01 -07001056};
1057
1058static int __init p54u_init(void)
1059{
1060 return usb_register(&p54u_driver);
1061}
1062
1063static void __exit p54u_exit(void)
1064{
1065 usb_deregister(&p54u_driver);
1066}
1067
1068module_init(p54u_init);
1069module_exit(p54u_exit);