1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d3466830SKalle Valo
3d3466830SKalle Valo /*
4d3466830SKalle Valo * Linux device driver for USB based Prism54
5d3466830SKalle Valo *
6d3466830SKalle Valo * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
7d3466830SKalle Valo *
8d3466830SKalle Valo * Based on the islsm (softmac prism54) driver, which is:
9d3466830SKalle Valo * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
10d3466830SKalle Valo */
11d3466830SKalle Valo
12d3466830SKalle Valo #include <linux/usb.h>
13d3466830SKalle Valo #include <linux/pci.h>
14d3466830SKalle Valo #include <linux/slab.h>
15d3466830SKalle Valo #include <linux/firmware.h>
16d3466830SKalle Valo #include <linux/etherdevice.h>
17d3466830SKalle Valo #include <linux/delay.h>
18d3466830SKalle Valo #include <linux/crc32.h>
19d3466830SKalle Valo #include <linux/module.h>
20d3466830SKalle Valo #include <net/mac80211.h>
21d3466830SKalle Valo
22d3466830SKalle Valo #include "p54.h"
23d3466830SKalle Valo #include "lmac.h"
24d3466830SKalle Valo #include "p54usb.h"
25d3466830SKalle Valo
26d3466830SKalle Valo MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
27d3466830SKalle Valo MODULE_DESCRIPTION("Prism54 USB wireless driver");
28d3466830SKalle Valo MODULE_LICENSE("GPL");
29d3466830SKalle Valo MODULE_ALIAS("prism54usb");
30d3466830SKalle Valo MODULE_FIRMWARE("isl3886usb");
31d3466830SKalle Valo MODULE_FIRMWARE("isl3887usb");
32d3466830SKalle Valo
336e41e225SAlan Stern static struct usb_driver p54u_driver;
346e41e225SAlan Stern
35d3466830SKalle Valo /*
36d3466830SKalle Valo * Note:
37d3466830SKalle Valo *
38d3466830SKalle Valo * Always update our wiki's device list (located at:
39*4dd9e7e0SFlavio Suligoi * http://wireless.wiki.kernel.org/en/users/Drivers/p54/devices ),
40d3466830SKalle Valo * whenever you add a new device.
41d3466830SKalle Valo */
42d3466830SKalle Valo
4354c9f216SArvind Yadav static const struct usb_device_id p54u_table[] = {
44d3466830SKalle Valo /* Version 1 devices (pci chip + net2280) */
45d3466830SKalle Valo {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */
46d3466830SKalle Valo {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
47d3466830SKalle Valo {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
48d3466830SKalle Valo {USB_DEVICE(0x0675, 0x0530)}, /* DrayTek Vigor 530 */
49d3466830SKalle Valo {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
50d3466830SKalle Valo {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
51d3466830SKalle Valo {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
52d3466830SKalle Valo {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
53d3466830SKalle Valo {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
54d3466830SKalle Valo {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
55d3466830SKalle Valo {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
56d3466830SKalle Valo {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
57d3466830SKalle Valo {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
58d3466830SKalle Valo {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
59d3466830SKalle Valo {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */
60d3466830SKalle Valo {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
61d3466830SKalle Valo {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
62d3466830SKalle Valo {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
63d3466830SKalle Valo {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
6463e49a9fSGiuseppe Marco Randazzo {USB_DEVICE(0x124a, 0x4026)}, /* AirVasT USB wireless device */
65d3466830SKalle Valo {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
66d3466830SKalle Valo {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
67d3466830SKalle Valo {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
68d3466830SKalle Valo {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
69d3466830SKalle Valo {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
70d3466830SKalle Valo {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
71d3466830SKalle Valo {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
72d3466830SKalle Valo {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
73d3466830SKalle Valo {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */
74d3466830SKalle Valo {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
75d3466830SKalle Valo {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
76d3466830SKalle Valo
77d3466830SKalle Valo /* Version 2 devices (3887) */
78d3466830SKalle Valo {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
79d3466830SKalle Valo {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
80d3466830SKalle Valo {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
81d3466830SKalle Valo {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
82d3466830SKalle Valo {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
83d3466830SKalle Valo {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
84d3466830SKalle Valo {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
85d3466830SKalle Valo {USB_DEVICE(0x07aa, 0x0020)}, /* Corega WLUSB2GTST USB */
86d3466830SKalle Valo {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */
87d3466830SKalle Valo {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
88d3466830SKalle Valo {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */
89d3466830SKalle Valo {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
90d3466830SKalle Valo {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
91d3466830SKalle Valo {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
92d3466830SKalle Valo {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
93d3466830SKalle Valo {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
94d3466830SKalle Valo {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
95d3466830SKalle Valo {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
96d3466830SKalle Valo /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
97d3466830SKalle Valo * just noting it here for clarity */
98d3466830SKalle Valo {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
99d3466830SKalle Valo {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
100d3466830SKalle Valo {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
101d3466830SKalle Valo {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
102d3466830SKalle Valo {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
103d3466830SKalle Valo {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
104d3466830SKalle Valo {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
105d3466830SKalle Valo {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
106d3466830SKalle Valo {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
107d3466830SKalle Valo /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */
108d3466830SKalle Valo {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
109d3466830SKalle Valo {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */
110d3466830SKalle Valo {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
111d3466830SKalle Valo {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
112d3466830SKalle Valo {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
113d3466830SKalle Valo {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
114d3466830SKalle Valo {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
115d3466830SKalle Valo {}
116d3466830SKalle Valo };
117d3466830SKalle Valo
118d3466830SKalle Valo MODULE_DEVICE_TABLE(usb, p54u_table);
119d3466830SKalle Valo
120d3466830SKalle Valo static const struct {
121d3466830SKalle Valo u32 intf;
122d3466830SKalle Valo enum p54u_hw_type type;
123d3466830SKalle Valo const char *fw;
124d3466830SKalle Valo char hw[20];
125d3466830SKalle Valo } p54u_fwlist[__NUM_P54U_HWTYPES] = {
126d3466830SKalle Valo {
127d3466830SKalle Valo .type = P54U_NET2280,
128d3466830SKalle Valo .intf = FW_LM86,
129d3466830SKalle Valo .fw = "isl3886usb",
130d3466830SKalle Valo .hw = "ISL3886 + net2280",
131d3466830SKalle Valo },
132d3466830SKalle Valo {
133d3466830SKalle Valo .type = P54U_3887,
134d3466830SKalle Valo .intf = FW_LM87,
135d3466830SKalle Valo .fw = "isl3887usb",
136d3466830SKalle Valo .hw = "ISL3887",
137d3466830SKalle Valo },
138d3466830SKalle Valo };
139d3466830SKalle Valo
p54u_rx_cb(struct urb * urb)140d3466830SKalle Valo static void p54u_rx_cb(struct urb *urb)
141d3466830SKalle Valo {
142d3466830SKalle Valo struct sk_buff *skb = (struct sk_buff *) urb->context;
143d3466830SKalle Valo struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
144d3466830SKalle Valo struct ieee80211_hw *dev = info->dev;
145d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
146d3466830SKalle Valo
147d3466830SKalle Valo skb_unlink(skb, &priv->rx_queue);
148d3466830SKalle Valo
149d3466830SKalle Valo if (unlikely(urb->status)) {
150d3466830SKalle Valo dev_kfree_skb_irq(skb);
151d3466830SKalle Valo return;
152d3466830SKalle Valo }
153d3466830SKalle Valo
154d3466830SKalle Valo skb_put(skb, urb->actual_length);
155d3466830SKalle Valo
156d3466830SKalle Valo if (priv->hw_type == P54U_NET2280)
157d3466830SKalle Valo skb_pull(skb, priv->common.tx_hdr_len);
158d3466830SKalle Valo if (priv->common.fw_interface == FW_LM87) {
159d3466830SKalle Valo skb_pull(skb, 4);
160d3466830SKalle Valo skb_put(skb, 4);
161d3466830SKalle Valo }
162d3466830SKalle Valo
163d3466830SKalle Valo if (p54_rx(dev, skb)) {
164d3466830SKalle Valo skb = dev_alloc_skb(priv->common.rx_mtu + 32);
165d3466830SKalle Valo if (unlikely(!skb)) {
166d3466830SKalle Valo /* TODO check rx queue length and refill *somewhere* */
167d3466830SKalle Valo return;
168d3466830SKalle Valo }
169d3466830SKalle Valo
170d3466830SKalle Valo info = (struct p54u_rx_info *) skb->cb;
171d3466830SKalle Valo info->urb = urb;
172d3466830SKalle Valo info->dev = dev;
173d3466830SKalle Valo urb->transfer_buffer = skb_tail_pointer(skb);
174d3466830SKalle Valo urb->context = skb;
175d3466830SKalle Valo } else {
176d3466830SKalle Valo if (priv->hw_type == P54U_NET2280)
177d3466830SKalle Valo skb_push(skb, priv->common.tx_hdr_len);
178d3466830SKalle Valo if (priv->common.fw_interface == FW_LM87) {
179d3466830SKalle Valo skb_push(skb, 4);
180d3466830SKalle Valo skb_put(skb, 4);
181d3466830SKalle Valo }
182d3466830SKalle Valo skb_reset_tail_pointer(skb);
183d3466830SKalle Valo skb_trim(skb, 0);
184d3466830SKalle Valo urb->transfer_buffer = skb_tail_pointer(skb);
185d3466830SKalle Valo }
186d3466830SKalle Valo skb_queue_tail(&priv->rx_queue, skb);
187d3466830SKalle Valo usb_anchor_urb(urb, &priv->submitted);
188d3466830SKalle Valo if (usb_submit_urb(urb, GFP_ATOMIC)) {
189d3466830SKalle Valo skb_unlink(skb, &priv->rx_queue);
190d3466830SKalle Valo usb_unanchor_urb(urb);
191d3466830SKalle Valo dev_kfree_skb_irq(skb);
192d3466830SKalle Valo }
193d3466830SKalle Valo }
194d3466830SKalle Valo
p54u_tx_cb(struct urb * urb)195d3466830SKalle Valo static void p54u_tx_cb(struct urb *urb)
196d3466830SKalle Valo {
197d3466830SKalle Valo struct sk_buff *skb = urb->context;
198d3466830SKalle Valo struct ieee80211_hw *dev =
199d3466830SKalle Valo usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
200d3466830SKalle Valo
201d3466830SKalle Valo p54_free_skb(dev, skb);
202d3466830SKalle Valo }
203d3466830SKalle Valo
p54u_tx_dummy_cb(struct urb * urb)204d3466830SKalle Valo static void p54u_tx_dummy_cb(struct urb *urb) { }
205d3466830SKalle Valo
p54u_free_urbs(struct ieee80211_hw * dev)206d3466830SKalle Valo static void p54u_free_urbs(struct ieee80211_hw *dev)
207d3466830SKalle Valo {
208d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
209d3466830SKalle Valo usb_kill_anchored_urbs(&priv->submitted);
210d3466830SKalle Valo }
211d3466830SKalle Valo
p54u_stop(struct ieee80211_hw * dev)212d3466830SKalle Valo static void p54u_stop(struct ieee80211_hw *dev)
213d3466830SKalle Valo {
214d3466830SKalle Valo /*
215d3466830SKalle Valo * TODO: figure out how to reliably stop the 3887 and net2280 so
216d3466830SKalle Valo * the hardware is still usable next time we want to start it.
217d3466830SKalle Valo * until then, we just stop listening to the hardware..
218d3466830SKalle Valo */
219d3466830SKalle Valo p54u_free_urbs(dev);
220d3466830SKalle Valo }
221d3466830SKalle Valo
p54u_init_urbs(struct ieee80211_hw * dev)222d3466830SKalle Valo static int p54u_init_urbs(struct ieee80211_hw *dev)
223d3466830SKalle Valo {
224d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
225d3466830SKalle Valo struct urb *entry = NULL;
226d3466830SKalle Valo struct sk_buff *skb;
227d3466830SKalle Valo struct p54u_rx_info *info;
228d3466830SKalle Valo int ret = 0;
229d3466830SKalle Valo
230d3466830SKalle Valo while (skb_queue_len(&priv->rx_queue) < 32) {
231d3466830SKalle Valo skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
232d3466830SKalle Valo if (!skb) {
233d3466830SKalle Valo ret = -ENOMEM;
234d3466830SKalle Valo goto err;
235d3466830SKalle Valo }
236d3466830SKalle Valo entry = usb_alloc_urb(0, GFP_KERNEL);
237d3466830SKalle Valo if (!entry) {
238d3466830SKalle Valo ret = -ENOMEM;
239d3466830SKalle Valo goto err;
240d3466830SKalle Valo }
241d3466830SKalle Valo
242d3466830SKalle Valo usb_fill_bulk_urb(entry, priv->udev,
243d3466830SKalle Valo usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
244d3466830SKalle Valo skb_tail_pointer(skb),
245d3466830SKalle Valo priv->common.rx_mtu + 32, p54u_rx_cb, skb);
246d3466830SKalle Valo info = (struct p54u_rx_info *) skb->cb;
247d3466830SKalle Valo info->urb = entry;
248d3466830SKalle Valo info->dev = dev;
249d3466830SKalle Valo skb_queue_tail(&priv->rx_queue, skb);
250d3466830SKalle Valo
251d3466830SKalle Valo usb_anchor_urb(entry, &priv->submitted);
252d3466830SKalle Valo ret = usb_submit_urb(entry, GFP_KERNEL);
253d3466830SKalle Valo if (ret) {
254d3466830SKalle Valo skb_unlink(skb, &priv->rx_queue);
255d3466830SKalle Valo usb_unanchor_urb(entry);
256d3466830SKalle Valo goto err;
257d3466830SKalle Valo }
258d3466830SKalle Valo usb_free_urb(entry);
259d3466830SKalle Valo entry = NULL;
260d3466830SKalle Valo }
261d3466830SKalle Valo
262d3466830SKalle Valo return 0;
263d3466830SKalle Valo
264d3466830SKalle Valo err:
265d3466830SKalle Valo usb_free_urb(entry);
266d3466830SKalle Valo kfree_skb(skb);
267d3466830SKalle Valo p54u_free_urbs(dev);
268d3466830SKalle Valo return ret;
269d3466830SKalle Valo }
270d3466830SKalle Valo
p54u_open(struct ieee80211_hw * dev)271d3466830SKalle Valo static int p54u_open(struct ieee80211_hw *dev)
272d3466830SKalle Valo {
273d3466830SKalle Valo /*
274d3466830SKalle Valo * TODO: Because we don't know how to reliably stop the 3887 and
275d3466830SKalle Valo * the isl3886+net2280, other than brutally cut off all
276d3466830SKalle Valo * communications. We have to reinitialize the urbs on every start.
277d3466830SKalle Valo */
278d3466830SKalle Valo return p54u_init_urbs(dev);
279d3466830SKalle Valo }
280d3466830SKalle Valo
p54u_lm87_chksum(const __le32 * data,size_t length)281d3466830SKalle Valo static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
282d3466830SKalle Valo {
283d3466830SKalle Valo u32 chk = 0;
284d3466830SKalle Valo
285d3466830SKalle Valo length >>= 2;
286d3466830SKalle Valo while (length--) {
287d3466830SKalle Valo chk ^= le32_to_cpu(*data++);
288d3466830SKalle Valo chk = (chk >> 5) ^ (chk << 3);
289d3466830SKalle Valo }
290d3466830SKalle Valo
291d3466830SKalle Valo return cpu_to_le32(chk);
292d3466830SKalle Valo }
293d3466830SKalle Valo
p54u_tx_lm87(struct ieee80211_hw * dev,struct sk_buff * skb)294d3466830SKalle Valo static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
295d3466830SKalle Valo {
296d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
297d3466830SKalle Valo struct urb *data_urb;
298d3466830SKalle Valo struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
299d3466830SKalle Valo
300d3466830SKalle Valo data_urb = usb_alloc_urb(0, GFP_ATOMIC);
301d3466830SKalle Valo if (!data_urb) {
302d3466830SKalle Valo p54_free_skb(dev, skb);
303d3466830SKalle Valo return;
304d3466830SKalle Valo }
305d3466830SKalle Valo
306d3466830SKalle Valo hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
307d3466830SKalle Valo hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
308d3466830SKalle Valo
309d3466830SKalle Valo usb_fill_bulk_urb(data_urb, priv->udev,
310d3466830SKalle Valo usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
311d3466830SKalle Valo hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
312d3466830SKalle Valo p54u_tx_cb : p54u_tx_dummy_cb, skb);
313d3466830SKalle Valo data_urb->transfer_flags |= URB_ZERO_PACKET;
314d3466830SKalle Valo
315d3466830SKalle Valo usb_anchor_urb(data_urb, &priv->submitted);
316d3466830SKalle Valo if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
317d3466830SKalle Valo usb_unanchor_urb(data_urb);
318d3466830SKalle Valo p54_free_skb(dev, skb);
319d3466830SKalle Valo }
320d3466830SKalle Valo usb_free_urb(data_urb);
321d3466830SKalle Valo }
322d3466830SKalle Valo
p54u_tx_net2280(struct ieee80211_hw * dev,struct sk_buff * skb)323d3466830SKalle Valo static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
324d3466830SKalle Valo {
325d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
326d3466830SKalle Valo struct urb *int_urb = NULL, *data_urb = NULL;
327d3466830SKalle Valo struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
328d3466830SKalle Valo struct net2280_reg_write *reg = NULL;
329d3466830SKalle Valo int err = -ENOMEM;
330d3466830SKalle Valo
331d3466830SKalle Valo reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
332d3466830SKalle Valo if (!reg)
333d3466830SKalle Valo goto out;
334d3466830SKalle Valo
335d3466830SKalle Valo int_urb = usb_alloc_urb(0, GFP_ATOMIC);
336d3466830SKalle Valo if (!int_urb)
337d3466830SKalle Valo goto out;
338d3466830SKalle Valo
339d3466830SKalle Valo data_urb = usb_alloc_urb(0, GFP_ATOMIC);
340d3466830SKalle Valo if (!data_urb)
341d3466830SKalle Valo goto out;
342d3466830SKalle Valo
343d3466830SKalle Valo reg->port = cpu_to_le16(NET2280_DEV_U32);
344d3466830SKalle Valo reg->addr = cpu_to_le32(P54U_DEV_BASE);
345d3466830SKalle Valo reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
346d3466830SKalle Valo
347d3466830SKalle Valo memset(hdr, 0, sizeof(*hdr));
348d3466830SKalle Valo hdr->len = cpu_to_le16(skb->len);
349d3466830SKalle Valo hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
350d3466830SKalle Valo
351d3466830SKalle Valo usb_fill_bulk_urb(int_urb, priv->udev,
352d3466830SKalle Valo usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
353d3466830SKalle Valo p54u_tx_dummy_cb, dev);
354d3466830SKalle Valo
355d3466830SKalle Valo /*
356d3466830SKalle Valo * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
357d3466830SKalle Valo * free what is inside the transfer_buffer after the last reference to
358d3466830SKalle Valo * the int_urb is dropped.
359d3466830SKalle Valo */
360d3466830SKalle Valo int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
361d3466830SKalle Valo reg = NULL;
362d3466830SKalle Valo
363d3466830SKalle Valo usb_fill_bulk_urb(data_urb, priv->udev,
364d3466830SKalle Valo usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
365d3466830SKalle Valo hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
366d3466830SKalle Valo p54u_tx_cb : p54u_tx_dummy_cb, skb);
367d3466830SKalle Valo data_urb->transfer_flags |= URB_ZERO_PACKET;
368d3466830SKalle Valo
369d3466830SKalle Valo usb_anchor_urb(int_urb, &priv->submitted);
370d3466830SKalle Valo err = usb_submit_urb(int_urb, GFP_ATOMIC);
371d3466830SKalle Valo if (err) {
372d3466830SKalle Valo usb_unanchor_urb(int_urb);
373d3466830SKalle Valo goto out;
374d3466830SKalle Valo }
375d3466830SKalle Valo
376d3466830SKalle Valo usb_anchor_urb(data_urb, &priv->submitted);
377d3466830SKalle Valo err = usb_submit_urb(data_urb, GFP_ATOMIC);
378d3466830SKalle Valo if (err) {
379d3466830SKalle Valo usb_unanchor_urb(data_urb);
380d3466830SKalle Valo goto out;
381d3466830SKalle Valo }
382d3466830SKalle Valo out:
383d3466830SKalle Valo usb_free_urb(int_urb);
384d3466830SKalle Valo usb_free_urb(data_urb);
385d3466830SKalle Valo
386d3466830SKalle Valo if (err) {
387d3466830SKalle Valo kfree(reg);
388d3466830SKalle Valo p54_free_skb(dev, skb);
389d3466830SKalle Valo }
390d3466830SKalle Valo }
391d3466830SKalle Valo
p54u_write(struct p54u_priv * priv,struct net2280_reg_write * buf,enum net2280_op_type type,__le32 addr,__le32 val)392d3466830SKalle Valo static int p54u_write(struct p54u_priv *priv,
393d3466830SKalle Valo struct net2280_reg_write *buf,
394d3466830SKalle Valo enum net2280_op_type type,
395d3466830SKalle Valo __le32 addr, __le32 val)
396d3466830SKalle Valo {
397d3466830SKalle Valo unsigned int ep;
398d3466830SKalle Valo int alen;
399d3466830SKalle Valo
400d3466830SKalle Valo if (type & 0x0800)
401d3466830SKalle Valo ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
402d3466830SKalle Valo else
403d3466830SKalle Valo ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
404d3466830SKalle Valo
405d3466830SKalle Valo buf->port = cpu_to_le16(type);
406d3466830SKalle Valo buf->addr = addr;
407d3466830SKalle Valo buf->val = val;
408d3466830SKalle Valo
409d3466830SKalle Valo return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
410d3466830SKalle Valo }
411d3466830SKalle Valo
p54u_read(struct p54u_priv * priv,void * buf,enum net2280_op_type type,__le32 addr,__le32 * val)412d3466830SKalle Valo static int p54u_read(struct p54u_priv *priv, void *buf,
413d3466830SKalle Valo enum net2280_op_type type,
414d3466830SKalle Valo __le32 addr, __le32 *val)
415d3466830SKalle Valo {
416d3466830SKalle Valo struct net2280_reg_read *read = buf;
417d3466830SKalle Valo __le32 *reg = buf;
418d3466830SKalle Valo unsigned int ep;
419d3466830SKalle Valo int alen, err;
420d3466830SKalle Valo
421d3466830SKalle Valo if (type & 0x0800)
422d3466830SKalle Valo ep = P54U_PIPE_DEV;
423d3466830SKalle Valo else
424d3466830SKalle Valo ep = P54U_PIPE_BRG;
425d3466830SKalle Valo
426d3466830SKalle Valo read->port = cpu_to_le16(type);
427d3466830SKalle Valo read->addr = addr;
428d3466830SKalle Valo
429d3466830SKalle Valo err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
430d3466830SKalle Valo read, sizeof(*read), &alen, 1000);
431d3466830SKalle Valo if (err)
432d3466830SKalle Valo return err;
433d3466830SKalle Valo
434d3466830SKalle Valo err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
435d3466830SKalle Valo reg, sizeof(*reg), &alen, 1000);
436d3466830SKalle Valo if (err)
437d3466830SKalle Valo return err;
438d3466830SKalle Valo
439d3466830SKalle Valo *val = *reg;
440d3466830SKalle Valo return 0;
441d3466830SKalle Valo }
442d3466830SKalle Valo
p54u_bulk_msg(struct p54u_priv * priv,unsigned int ep,void * data,size_t len)443d3466830SKalle Valo static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
444d3466830SKalle Valo void *data, size_t len)
445d3466830SKalle Valo {
446d3466830SKalle Valo int alen;
447d3466830SKalle Valo return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
448d3466830SKalle Valo data, len, &alen, 2000);
449d3466830SKalle Valo }
450d3466830SKalle Valo
p54u_device_reset(struct ieee80211_hw * dev)451d3466830SKalle Valo static int p54u_device_reset(struct ieee80211_hw *dev)
452d3466830SKalle Valo {
453d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
454d3466830SKalle Valo int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
455d3466830SKalle Valo
456d3466830SKalle Valo if (lock) {
457d3466830SKalle Valo ret = usb_lock_device_for_reset(priv->udev, priv->intf);
458d3466830SKalle Valo if (ret < 0) {
459d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) unable to lock "
460d3466830SKalle Valo "device for reset (%d)!\n", ret);
461d3466830SKalle Valo return ret;
462d3466830SKalle Valo }
463d3466830SKalle Valo }
464d3466830SKalle Valo
465d3466830SKalle Valo ret = usb_reset_device(priv->udev);
466d3466830SKalle Valo if (lock)
467d3466830SKalle Valo usb_unlock_device(priv->udev);
468d3466830SKalle Valo
469d3466830SKalle Valo if (ret)
470d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) unable to reset "
471d3466830SKalle Valo "device (%d)!\n", ret);
472d3466830SKalle Valo
473d3466830SKalle Valo return ret;
474d3466830SKalle Valo }
475d3466830SKalle Valo
476d3466830SKalle Valo static const char p54u_romboot_3887[] = "~~~~";
p54u_firmware_reset_3887(struct ieee80211_hw * dev)477d3466830SKalle Valo static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
478d3466830SKalle Valo {
479d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
480d3466830SKalle Valo u8 *buf;
481d3466830SKalle Valo int ret;
482d3466830SKalle Valo
483d3466830SKalle Valo buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
484d3466830SKalle Valo if (!buf)
485d3466830SKalle Valo return -ENOMEM;
486d3466830SKalle Valo ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
487d3466830SKalle Valo buf, 4);
488d3466830SKalle Valo kfree(buf);
489d3466830SKalle Valo if (ret)
490d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
491d3466830SKalle Valo "boot ROM (%d)!\n", ret);
492d3466830SKalle Valo
493d3466830SKalle Valo return ret;
494d3466830SKalle Valo }
495d3466830SKalle Valo
496d3466830SKalle Valo static const char p54u_firmware_upload_3887[] = "<\r";
p54u_upload_firmware_3887(struct ieee80211_hw * dev)497d3466830SKalle Valo static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
498d3466830SKalle Valo {
499d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
500d3466830SKalle Valo int err, alen;
501d3466830SKalle Valo u8 carry = 0;
502d3466830SKalle Valo u8 *buf, *tmp;
503d3466830SKalle Valo const u8 *data;
504d3466830SKalle Valo unsigned int left, remains, block_size;
505d3466830SKalle Valo struct x2_header *hdr;
506d3466830SKalle Valo unsigned long timeout;
507d3466830SKalle Valo
508d3466830SKalle Valo err = p54u_firmware_reset_3887(dev);
509d3466830SKalle Valo if (err)
510d3466830SKalle Valo return err;
511d3466830SKalle Valo
512d3466830SKalle Valo tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
513d3466830SKalle Valo if (!buf)
514d3466830SKalle Valo return -ENOMEM;
515d3466830SKalle Valo
516d3466830SKalle Valo left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size);
517d3466830SKalle Valo strcpy(buf, p54u_firmware_upload_3887);
518d3466830SKalle Valo left -= strlen(p54u_firmware_upload_3887);
519d3466830SKalle Valo tmp += strlen(p54u_firmware_upload_3887);
520d3466830SKalle Valo
521d3466830SKalle Valo data = priv->fw->data;
522d3466830SKalle Valo remains = priv->fw->size;
523d3466830SKalle Valo
524d3466830SKalle Valo hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
525d3466830SKalle Valo memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
526d3466830SKalle Valo hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
527d3466830SKalle Valo hdr->fw_length = cpu_to_le32(priv->fw->size);
528d3466830SKalle Valo hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
529d3466830SKalle Valo sizeof(u32)*2));
530d3466830SKalle Valo left -= sizeof(*hdr);
531d3466830SKalle Valo tmp += sizeof(*hdr);
532d3466830SKalle Valo
533d3466830SKalle Valo while (remains) {
534d3466830SKalle Valo while (left--) {
535d3466830SKalle Valo if (carry) {
536d3466830SKalle Valo *tmp++ = carry;
537d3466830SKalle Valo carry = 0;
538d3466830SKalle Valo remains--;
539d3466830SKalle Valo continue;
540d3466830SKalle Valo }
541d3466830SKalle Valo switch (*data) {
542d3466830SKalle Valo case '~':
543d3466830SKalle Valo *tmp++ = '}';
544d3466830SKalle Valo carry = '^';
545d3466830SKalle Valo break;
546d3466830SKalle Valo case '}':
547d3466830SKalle Valo *tmp++ = '}';
548d3466830SKalle Valo carry = ']';
549d3466830SKalle Valo break;
550d3466830SKalle Valo default:
551d3466830SKalle Valo *tmp++ = *data;
552d3466830SKalle Valo remains--;
553d3466830SKalle Valo break;
554d3466830SKalle Valo }
555d3466830SKalle Valo data++;
556d3466830SKalle Valo }
557d3466830SKalle Valo
558d3466830SKalle Valo err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
559d3466830SKalle Valo if (err) {
560d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware "
561d3466830SKalle Valo "upload failed!\n");
562d3466830SKalle Valo goto err_upload_failed;
563d3466830SKalle Valo }
564d3466830SKalle Valo
565d3466830SKalle Valo tmp = buf;
566d3466830SKalle Valo left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
567d3466830SKalle Valo }
568d3466830SKalle Valo
569d3466830SKalle Valo *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
570d3466830SKalle Valo priv->fw->size));
571d3466830SKalle Valo err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
572d3466830SKalle Valo if (err) {
573d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
574d3466830SKalle Valo goto err_upload_failed;
575d3466830SKalle Valo }
576d3466830SKalle Valo timeout = jiffies + msecs_to_jiffies(1000);
577d3466830SKalle Valo while (!(err = usb_bulk_msg(priv->udev,
578d3466830SKalle Valo usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
579d3466830SKalle Valo if (alen > 2 && !memcmp(buf, "OK", 2))
580d3466830SKalle Valo break;
581d3466830SKalle Valo
582d3466830SKalle Valo if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
583d3466830SKalle Valo err = -EINVAL;
584d3466830SKalle Valo break;
585d3466830SKalle Valo }
586d3466830SKalle Valo
587d3466830SKalle Valo if (time_after(jiffies, timeout)) {
588d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware boot "
589d3466830SKalle Valo "timed out!\n");
590d3466830SKalle Valo err = -ETIMEDOUT;
591d3466830SKalle Valo break;
592d3466830SKalle Valo }
593d3466830SKalle Valo }
594d3466830SKalle Valo if (err) {
595d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
596d3466830SKalle Valo goto err_upload_failed;
597d3466830SKalle Valo }
598d3466830SKalle Valo
599d3466830SKalle Valo buf[0] = 'g';
600d3466830SKalle Valo buf[1] = '\r';
601d3466830SKalle Valo err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
602d3466830SKalle Valo if (err) {
603d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
604d3466830SKalle Valo goto err_upload_failed;
605d3466830SKalle Valo }
606d3466830SKalle Valo
607d3466830SKalle Valo timeout = jiffies + msecs_to_jiffies(1000);
608d3466830SKalle Valo while (!(err = usb_bulk_msg(priv->udev,
609d3466830SKalle Valo usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
610d3466830SKalle Valo if (alen > 0 && buf[0] == 'g')
611d3466830SKalle Valo break;
612d3466830SKalle Valo
613d3466830SKalle Valo if (time_after(jiffies, timeout)) {
614d3466830SKalle Valo err = -ETIMEDOUT;
615d3466830SKalle Valo break;
616d3466830SKalle Valo }
617d3466830SKalle Valo }
618d3466830SKalle Valo if (err)
619d3466830SKalle Valo goto err_upload_failed;
620d3466830SKalle Valo
621d3466830SKalle Valo err_upload_failed:
622d3466830SKalle Valo kfree(buf);
623d3466830SKalle Valo return err;
624d3466830SKalle Valo }
625d3466830SKalle Valo
p54u_upload_firmware_net2280(struct ieee80211_hw * dev)626d3466830SKalle Valo static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
627d3466830SKalle Valo {
628d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
629d3466830SKalle Valo const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
630d3466830SKalle Valo int err, alen;
631d3466830SKalle Valo void *buf;
632d3466830SKalle Valo __le32 reg;
633d3466830SKalle Valo unsigned int remains, offset;
634d3466830SKalle Valo const u8 *data;
635d3466830SKalle Valo
636d3466830SKalle Valo buf = kmalloc(512, GFP_KERNEL);
637d3466830SKalle Valo if (!buf)
638d3466830SKalle Valo return -ENOMEM;
639d3466830SKalle Valo
640d3466830SKalle Valo #define P54U_WRITE(type, addr, data) \
641d3466830SKalle Valo do {\
642d3466830SKalle Valo err = p54u_write(priv, buf, type,\
643d3466830SKalle Valo cpu_to_le32((u32)(unsigned long)addr), data);\
644d3466830SKalle Valo if (err) \
645d3466830SKalle Valo goto fail;\
646d3466830SKalle Valo } while (0)
647d3466830SKalle Valo
648d3466830SKalle Valo #define P54U_READ(type, addr) \
649d3466830SKalle Valo do {\
650d3466830SKalle Valo err = p54u_read(priv, buf, type,\
651d3466830SKalle Valo cpu_to_le32((u32)(unsigned long)addr), ®);\
652d3466830SKalle Valo if (err)\
653d3466830SKalle Valo goto fail;\
654d3466830SKalle Valo } while (0)
655d3466830SKalle Valo
656d3466830SKalle Valo /* power down net2280 bridge */
657d3466830SKalle Valo P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
658d3466830SKalle Valo reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
659d3466830SKalle Valo reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
660d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
661d3466830SKalle Valo
662d3466830SKalle Valo mdelay(100);
663d3466830SKalle Valo
664d3466830SKalle Valo /* power up bridge */
665d3466830SKalle Valo reg |= cpu_to_le32(P54U_BRG_POWER_UP);
666d3466830SKalle Valo reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
667d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
668d3466830SKalle Valo
669d3466830SKalle Valo mdelay(100);
670d3466830SKalle Valo
671d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
672d3466830SKalle Valo cpu_to_le32(NET2280_CLK_30Mhz |
673d3466830SKalle Valo NET2280_PCI_ENABLE |
674d3466830SKalle Valo NET2280_PCI_SOFT_RESET));
675d3466830SKalle Valo
676d3466830SKalle Valo mdelay(20);
677d3466830SKalle Valo
678d3466830SKalle Valo P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
679d3466830SKalle Valo cpu_to_le32(PCI_COMMAND_MEMORY |
680d3466830SKalle Valo PCI_COMMAND_MASTER));
681d3466830SKalle Valo
682d3466830SKalle Valo P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
683d3466830SKalle Valo cpu_to_le32(NET2280_BASE));
684d3466830SKalle Valo
685d3466830SKalle Valo P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
686d3466830SKalle Valo reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
687d3466830SKalle Valo P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
688d3466830SKalle Valo
689d3466830SKalle Valo // TODO: we really need this?
690d3466830SKalle Valo P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
691d3466830SKalle Valo
692d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
693d3466830SKalle Valo cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
694d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
695d3466830SKalle Valo cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
696d3466830SKalle Valo
697d3466830SKalle Valo P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
698d3466830SKalle Valo cpu_to_le32(NET2280_BASE2));
699d3466830SKalle Valo
700d3466830SKalle Valo /* finally done setting up the bridge */
701d3466830SKalle Valo
702d3466830SKalle Valo P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
703d3466830SKalle Valo cpu_to_le32(PCI_COMMAND_MEMORY |
704d3466830SKalle Valo PCI_COMMAND_MASTER));
705d3466830SKalle Valo
706d3466830SKalle Valo P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
707d3466830SKalle Valo P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
708d3466830SKalle Valo cpu_to_le32(P54U_DEV_BASE));
709d3466830SKalle Valo
710d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
711d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
712d3466830SKalle Valo cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
713d3466830SKalle Valo
714d3466830SKalle Valo /* do romboot */
715d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
716d3466830SKalle Valo
717d3466830SKalle Valo P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
718d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
719d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
720d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
721d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
722d3466830SKalle Valo
723d3466830SKalle Valo mdelay(20);
724d3466830SKalle Valo
725d3466830SKalle Valo reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
726d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
727d3466830SKalle Valo
728d3466830SKalle Valo mdelay(20);
729d3466830SKalle Valo
730d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
731d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
732d3466830SKalle Valo
733d3466830SKalle Valo mdelay(100);
734d3466830SKalle Valo
735d3466830SKalle Valo P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
736d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
737d3466830SKalle Valo
738d3466830SKalle Valo /* finally, we can upload firmware now! */
739d3466830SKalle Valo remains = priv->fw->size;
740d3466830SKalle Valo data = priv->fw->data;
741d3466830SKalle Valo offset = ISL38XX_DEV_FIRMWARE_ADDR;
742d3466830SKalle Valo
743d3466830SKalle Valo while (remains) {
744d3466830SKalle Valo unsigned int block_len = min(remains, (unsigned int)512);
745d3466830SKalle Valo memcpy(buf, data, block_len);
746d3466830SKalle Valo
747d3466830SKalle Valo err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
748d3466830SKalle Valo if (err) {
749d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware block "
750d3466830SKalle Valo "upload failed\n");
751d3466830SKalle Valo goto fail;
752d3466830SKalle Valo }
753d3466830SKalle Valo
754d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
755d3466830SKalle Valo cpu_to_le32(0xc0000f00));
756d3466830SKalle Valo
757d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32,
758d3466830SKalle Valo 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
759d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32,
760d3466830SKalle Valo 0x0020 | (unsigned long)&devreg->direct_mem_win,
761d3466830SKalle Valo cpu_to_le32(1));
762d3466830SKalle Valo
763d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32,
764d3466830SKalle Valo 0x0024 | (unsigned long)&devreg->direct_mem_win,
765d3466830SKalle Valo cpu_to_le32(block_len));
766d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32,
767d3466830SKalle Valo 0x0028 | (unsigned long)&devreg->direct_mem_win,
768d3466830SKalle Valo cpu_to_le32(offset));
769d3466830SKalle Valo
770d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
771d3466830SKalle Valo cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
772d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
773d3466830SKalle Valo cpu_to_le32(block_len >> 2));
774d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
775d3466830SKalle Valo cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
776d3466830SKalle Valo
777d3466830SKalle Valo mdelay(10);
778d3466830SKalle Valo
779d3466830SKalle Valo P54U_READ(NET2280_DEV_U32,
780d3466830SKalle Valo 0x002C | (unsigned long)&devreg->direct_mem_win);
781d3466830SKalle Valo if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
782d3466830SKalle Valo !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
783d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
784d3466830SKalle Valo "transfer failed\n");
785d3466830SKalle Valo goto fail;
786d3466830SKalle Valo }
787d3466830SKalle Valo
788d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
789d3466830SKalle Valo cpu_to_le32(NET2280_FIFO_FLUSH));
790d3466830SKalle Valo
791d3466830SKalle Valo remains -= block_len;
792d3466830SKalle Valo data += block_len;
793d3466830SKalle Valo offset += block_len;
794d3466830SKalle Valo }
795d3466830SKalle Valo
796d3466830SKalle Valo /* do ramboot */
797d3466830SKalle Valo P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
798d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
799d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
800d3466830SKalle Valo reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
801d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
802d3466830SKalle Valo
803d3466830SKalle Valo mdelay(20);
804d3466830SKalle Valo
805d3466830SKalle Valo reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
806d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
807d3466830SKalle Valo
808d3466830SKalle Valo reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
809d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
810d3466830SKalle Valo
811d3466830SKalle Valo mdelay(100);
812d3466830SKalle Valo
813d3466830SKalle Valo P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
814d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
815d3466830SKalle Valo
816d3466830SKalle Valo /* start up the firmware */
817d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
818d3466830SKalle Valo cpu_to_le32(ISL38XX_INT_IDENT_INIT));
819d3466830SKalle Valo
820d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
821d3466830SKalle Valo cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
822d3466830SKalle Valo
823d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
824d3466830SKalle Valo cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
825d3466830SKalle Valo NET2280_USB_INTERRUPT_ENABLE));
826d3466830SKalle Valo
827d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
828d3466830SKalle Valo cpu_to_le32(ISL38XX_DEV_INT_RESET));
829d3466830SKalle Valo
830d3466830SKalle Valo err = usb_interrupt_msg(priv->udev,
831d3466830SKalle Valo usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
832d3466830SKalle Valo buf, sizeof(__le32), &alen, 1000);
833d3466830SKalle Valo if (err || alen != sizeof(__le32))
834d3466830SKalle Valo goto fail;
835d3466830SKalle Valo
836d3466830SKalle Valo P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
837d3466830SKalle Valo P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
838d3466830SKalle Valo
839d3466830SKalle Valo if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
840d3466830SKalle Valo err = -EINVAL;
841d3466830SKalle Valo
842d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
843d3466830SKalle Valo P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
844d3466830SKalle Valo cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
845d3466830SKalle Valo
846d3466830SKalle Valo #undef P54U_WRITE
847d3466830SKalle Valo #undef P54U_READ
848d3466830SKalle Valo
849d3466830SKalle Valo fail:
850d3466830SKalle Valo kfree(buf);
851d3466830SKalle Valo return err;
852d3466830SKalle Valo }
853d3466830SKalle Valo
p54_find_type(struct p54u_priv * priv)854d3466830SKalle Valo static int p54_find_type(struct p54u_priv *priv)
855d3466830SKalle Valo {
856d3466830SKalle Valo int i;
857d3466830SKalle Valo
858d3466830SKalle Valo for (i = 0; i < __NUM_P54U_HWTYPES; i++)
859d3466830SKalle Valo if (p54u_fwlist[i].type == priv->hw_type)
860d3466830SKalle Valo break;
861d3466830SKalle Valo if (i == __NUM_P54U_HWTYPES)
862d3466830SKalle Valo return -EOPNOTSUPP;
863d3466830SKalle Valo
864d3466830SKalle Valo return i;
865d3466830SKalle Valo }
866d3466830SKalle Valo
p54u_start_ops(struct p54u_priv * priv)867d3466830SKalle Valo static int p54u_start_ops(struct p54u_priv *priv)
868d3466830SKalle Valo {
869d3466830SKalle Valo struct ieee80211_hw *dev = priv->common.hw;
870d3466830SKalle Valo int ret;
871d3466830SKalle Valo
872d3466830SKalle Valo ret = p54_parse_firmware(dev, priv->fw);
873d3466830SKalle Valo if (ret)
874d3466830SKalle Valo goto err_out;
875d3466830SKalle Valo
876d3466830SKalle Valo ret = p54_find_type(priv);
877d3466830SKalle Valo if (ret < 0)
878d3466830SKalle Valo goto err_out;
879d3466830SKalle Valo
880d3466830SKalle Valo if (priv->common.fw_interface != p54u_fwlist[ret].intf) {
881d3466830SKalle Valo dev_err(&priv->udev->dev, "wrong firmware, please get "
882d3466830SKalle Valo "a firmware for \"%s\" and try again.\n",
883d3466830SKalle Valo p54u_fwlist[ret].hw);
884d3466830SKalle Valo ret = -ENODEV;
885d3466830SKalle Valo goto err_out;
886d3466830SKalle Valo }
887d3466830SKalle Valo
888d3466830SKalle Valo ret = priv->upload_fw(dev);
889d3466830SKalle Valo if (ret)
890d3466830SKalle Valo goto err_out;
891d3466830SKalle Valo
892d3466830SKalle Valo ret = p54u_open(dev);
893d3466830SKalle Valo if (ret)
894d3466830SKalle Valo goto err_out;
895d3466830SKalle Valo
896d3466830SKalle Valo ret = p54_read_eeprom(dev);
897d3466830SKalle Valo if (ret)
898d3466830SKalle Valo goto err_stop;
899d3466830SKalle Valo
900d3466830SKalle Valo p54u_stop(dev);
901d3466830SKalle Valo
902d3466830SKalle Valo ret = p54_register_common(dev, &priv->udev->dev);
903d3466830SKalle Valo if (ret)
904d3466830SKalle Valo goto err_stop;
905d3466830SKalle Valo
906d3466830SKalle Valo return 0;
907d3466830SKalle Valo
908d3466830SKalle Valo err_stop:
909d3466830SKalle Valo p54u_stop(dev);
910d3466830SKalle Valo
911d3466830SKalle Valo err_out:
912d3466830SKalle Valo /*
913d3466830SKalle Valo * p54u_disconnect will do the rest of the
914d3466830SKalle Valo * cleanup
915d3466830SKalle Valo */
916d3466830SKalle Valo return ret;
917d3466830SKalle Valo }
918d3466830SKalle Valo
p54u_load_firmware_cb(const struct firmware * firmware,void * context)919d3466830SKalle Valo static void p54u_load_firmware_cb(const struct firmware *firmware,
920d3466830SKalle Valo void *context)
921d3466830SKalle Valo {
922d3466830SKalle Valo struct p54u_priv *priv = context;
923d3466830SKalle Valo struct usb_device *udev = priv->udev;
9246e41e225SAlan Stern struct usb_interface *intf = priv->intf;
925d3466830SKalle Valo int err;
926d3466830SKalle Valo
927d3466830SKalle Valo if (firmware) {
928d3466830SKalle Valo priv->fw = firmware;
929d3466830SKalle Valo err = p54u_start_ops(priv);
930d3466830SKalle Valo } else {
931d3466830SKalle Valo err = -ENOENT;
932d3466830SKalle Valo dev_err(&udev->dev, "Firmware not found.\n");
933d3466830SKalle Valo }
934d3466830SKalle Valo
9356e41e225SAlan Stern complete(&priv->fw_wait_load);
936d3466830SKalle Valo /*
9376e41e225SAlan Stern * At this point p54u_disconnect may have already freed
938d3466830SKalle Valo * the "priv" context. Do not use it anymore!
939d3466830SKalle Valo */
940d3466830SKalle Valo priv = NULL;
941d3466830SKalle Valo
9426e41e225SAlan Stern if (err) {
9436e41e225SAlan Stern dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
9446e41e225SAlan Stern
9456e41e225SAlan Stern usb_lock_device(udev);
9466e41e225SAlan Stern usb_driver_release_interface(&p54u_driver, intf);
9476e41e225SAlan Stern usb_unlock_device(udev);
948d3466830SKalle Valo }
949d3466830SKalle Valo
9506e41e225SAlan Stern usb_put_intf(intf);
951d3466830SKalle Valo }
952d3466830SKalle Valo
p54u_load_firmware(struct ieee80211_hw * dev,struct usb_interface * intf)953d3466830SKalle Valo static int p54u_load_firmware(struct ieee80211_hw *dev,
954d3466830SKalle Valo struct usb_interface *intf)
955d3466830SKalle Valo {
956d3466830SKalle Valo struct usb_device *udev = interface_to_usbdev(intf);
957d3466830SKalle Valo struct p54u_priv *priv = dev->priv;
958d3466830SKalle Valo struct device *device = &udev->dev;
959d3466830SKalle Valo int err, i;
960d3466830SKalle Valo
961d3466830SKalle Valo BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
962d3466830SKalle Valo
963d3466830SKalle Valo init_completion(&priv->fw_wait_load);
964d3466830SKalle Valo i = p54_find_type(priv);
965d3466830SKalle Valo if (i < 0)
966d3466830SKalle Valo return i;
967d3466830SKalle Valo
968d3466830SKalle Valo dev_info(&priv->udev->dev, "Loading firmware file %s\n",
969d3466830SKalle Valo p54u_fwlist[i].fw);
970d3466830SKalle Valo
9716e41e225SAlan Stern usb_get_intf(intf);
972d3466830SKalle Valo err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
973d3466830SKalle Valo device, GFP_KERNEL, priv,
974d3466830SKalle Valo p54u_load_firmware_cb);
975d3466830SKalle Valo if (err) {
976d3466830SKalle Valo dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
977d3466830SKalle Valo "(%d)!\n", p54u_fwlist[i].fw, err);
9786e41e225SAlan Stern usb_put_intf(intf);
979d3466830SKalle Valo }
980d3466830SKalle Valo
981d3466830SKalle Valo return err;
982d3466830SKalle Valo }
983d3466830SKalle Valo
p54u_probe(struct usb_interface * intf,const struct usb_device_id * id)984d3466830SKalle Valo static int p54u_probe(struct usb_interface *intf,
985d3466830SKalle Valo const struct usb_device_id *id)
986d3466830SKalle Valo {
987d3466830SKalle Valo struct usb_device *udev = interface_to_usbdev(intf);
988d3466830SKalle Valo struct ieee80211_hw *dev;
989d3466830SKalle Valo struct p54u_priv *priv;
990d3466830SKalle Valo int err;
991d3466830SKalle Valo unsigned int i, recognized_pipes;
992d3466830SKalle Valo
993d3466830SKalle Valo dev = p54_init_common(sizeof(*priv));
994d3466830SKalle Valo
995d3466830SKalle Valo if (!dev) {
996d3466830SKalle Valo dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
997d3466830SKalle Valo return -ENOMEM;
998d3466830SKalle Valo }
999d3466830SKalle Valo
1000d3466830SKalle Valo priv = dev->priv;
1001d3466830SKalle Valo priv->hw_type = P54U_INVALID_HW;
1002d3466830SKalle Valo
1003d3466830SKalle Valo SET_IEEE80211_DEV(dev, &intf->dev);
1004d3466830SKalle Valo usb_set_intfdata(intf, dev);
1005d3466830SKalle Valo priv->udev = udev;
1006d3466830SKalle Valo priv->intf = intf;
1007d3466830SKalle Valo skb_queue_head_init(&priv->rx_queue);
1008d3466830SKalle Valo init_usb_anchor(&priv->submitted);
1009d3466830SKalle Valo
1010d3466830SKalle Valo /* really lazy and simple way of figuring out if we're a 3887 */
1011d3466830SKalle Valo /* TODO: should just stick the identification in the device table */
1012d3466830SKalle Valo i = intf->altsetting->desc.bNumEndpoints;
1013d3466830SKalle Valo recognized_pipes = 0;
1014d3466830SKalle Valo while (i--) {
1015d3466830SKalle Valo switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
1016d3466830SKalle Valo case P54U_PIPE_DATA:
1017d3466830SKalle Valo case P54U_PIPE_MGMT:
1018d3466830SKalle Valo case P54U_PIPE_BRG:
1019d3466830SKalle Valo case P54U_PIPE_DEV:
1020d3466830SKalle Valo case P54U_PIPE_DATA | USB_DIR_IN:
1021d3466830SKalle Valo case P54U_PIPE_MGMT | USB_DIR_IN:
1022d3466830SKalle Valo case P54U_PIPE_BRG | USB_DIR_IN:
1023d3466830SKalle Valo case P54U_PIPE_DEV | USB_DIR_IN:
1024d3466830SKalle Valo case P54U_PIPE_INT | USB_DIR_IN:
1025d3466830SKalle Valo recognized_pipes++;
1026d3466830SKalle Valo }
1027d3466830SKalle Valo }
1028d3466830SKalle Valo priv->common.open = p54u_open;
1029d3466830SKalle Valo priv->common.stop = p54u_stop;
1030d3466830SKalle Valo if (recognized_pipes < P54U_PIPE_NUMBER) {
1031d3466830SKalle Valo #ifdef CONFIG_PM
1032d3466830SKalle Valo /* ISL3887 needs a full reset on resume */
1033d3466830SKalle Valo udev->reset_resume = 1;
1034d3466830SKalle Valo #endif /* CONFIG_PM */
1035d3466830SKalle Valo err = p54u_device_reset(dev);
1036d3466830SKalle Valo
1037d3466830SKalle Valo priv->hw_type = P54U_3887;
1038d3466830SKalle Valo dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
1039d3466830SKalle Valo priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
1040d3466830SKalle Valo priv->common.tx = p54u_tx_lm87;
1041d3466830SKalle Valo priv->upload_fw = p54u_upload_firmware_3887;
1042d3466830SKalle Valo } else {
1043d3466830SKalle Valo priv->hw_type = P54U_NET2280;
1044d3466830SKalle Valo dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
1045d3466830SKalle Valo priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
1046d3466830SKalle Valo priv->common.tx = p54u_tx_net2280;
1047d3466830SKalle Valo priv->upload_fw = p54u_upload_firmware_net2280;
1048d3466830SKalle Valo }
1049d3466830SKalle Valo err = p54u_load_firmware(dev, intf);
10506e41e225SAlan Stern if (err)
1051d3466830SKalle Valo p54_free_common(dev);
1052d3466830SKalle Valo return err;
1053d3466830SKalle Valo }
1054d3466830SKalle Valo
p54u_disconnect(struct usb_interface * intf)1055d3466830SKalle Valo static void p54u_disconnect(struct usb_interface *intf)
1056d3466830SKalle Valo {
1057d3466830SKalle Valo struct ieee80211_hw *dev = usb_get_intfdata(intf);
1058d3466830SKalle Valo struct p54u_priv *priv;
1059d3466830SKalle Valo
1060d3466830SKalle Valo if (!dev)
1061d3466830SKalle Valo return;
1062d3466830SKalle Valo
1063d3466830SKalle Valo priv = dev->priv;
1064d3466830SKalle Valo wait_for_completion(&priv->fw_wait_load);
1065d3466830SKalle Valo p54_unregister_common(dev);
1066d3466830SKalle Valo
1067d3466830SKalle Valo release_firmware(priv->fw);
1068d3466830SKalle Valo p54_free_common(dev);
1069d3466830SKalle Valo }
1070d3466830SKalle Valo
p54u_pre_reset(struct usb_interface * intf)1071d3466830SKalle Valo static int p54u_pre_reset(struct usb_interface *intf)
1072d3466830SKalle Valo {
1073d3466830SKalle Valo struct ieee80211_hw *dev = usb_get_intfdata(intf);
1074d3466830SKalle Valo
1075d3466830SKalle Valo if (!dev)
1076d3466830SKalle Valo return -ENODEV;
1077d3466830SKalle Valo
1078d3466830SKalle Valo p54u_stop(dev);
1079d3466830SKalle Valo return 0;
1080d3466830SKalle Valo }
1081d3466830SKalle Valo
p54u_resume(struct usb_interface * intf)1082d3466830SKalle Valo static int p54u_resume(struct usb_interface *intf)
1083d3466830SKalle Valo {
1084d3466830SKalle Valo struct ieee80211_hw *dev = usb_get_intfdata(intf);
1085d3466830SKalle Valo struct p54u_priv *priv;
1086d3466830SKalle Valo
1087d3466830SKalle Valo if (!dev)
1088d3466830SKalle Valo return -ENODEV;
1089d3466830SKalle Valo
1090d3466830SKalle Valo priv = dev->priv;
1091d3466830SKalle Valo if (unlikely(!(priv->upload_fw && priv->fw)))
1092d3466830SKalle Valo return 0;
1093d3466830SKalle Valo
1094d3466830SKalle Valo return priv->upload_fw(dev);
1095d3466830SKalle Valo }
1096d3466830SKalle Valo
p54u_post_reset(struct usb_interface * intf)1097d3466830SKalle Valo static int p54u_post_reset(struct usb_interface *intf)
1098d3466830SKalle Valo {
1099d3466830SKalle Valo struct ieee80211_hw *dev = usb_get_intfdata(intf);
1100d3466830SKalle Valo struct p54u_priv *priv;
1101d3466830SKalle Valo int err;
1102d3466830SKalle Valo
1103d3466830SKalle Valo err = p54u_resume(intf);
1104d3466830SKalle Valo if (err)
1105d3466830SKalle Valo return err;
1106d3466830SKalle Valo
1107d3466830SKalle Valo /* reinitialize old device state */
1108d3466830SKalle Valo priv = dev->priv;
1109d3466830SKalle Valo if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
1110d3466830SKalle Valo ieee80211_restart_hw(dev);
1111d3466830SKalle Valo
1112d3466830SKalle Valo return 0;
1113d3466830SKalle Valo }
1114d3466830SKalle Valo
1115d3466830SKalle Valo #ifdef CONFIG_PM
1116d3466830SKalle Valo
p54u_suspend(struct usb_interface * intf,pm_message_t message)1117d3466830SKalle Valo static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
1118d3466830SKalle Valo {
1119d3466830SKalle Valo return p54u_pre_reset(intf);
1120d3466830SKalle Valo }
1121d3466830SKalle Valo
1122d3466830SKalle Valo #endif /* CONFIG_PM */
1123d3466830SKalle Valo
1124d3466830SKalle Valo static struct usb_driver p54u_driver = {
1125d3466830SKalle Valo .name = "p54usb",
1126d3466830SKalle Valo .id_table = p54u_table,
1127d3466830SKalle Valo .probe = p54u_probe,
1128d3466830SKalle Valo .disconnect = p54u_disconnect,
1129d3466830SKalle Valo .pre_reset = p54u_pre_reset,
1130d3466830SKalle Valo .post_reset = p54u_post_reset,
1131d3466830SKalle Valo #ifdef CONFIG_PM
1132d3466830SKalle Valo .suspend = p54u_suspend,
1133d3466830SKalle Valo .resume = p54u_resume,
1134d3466830SKalle Valo .reset_resume = p54u_resume,
1135d3466830SKalle Valo #endif /* CONFIG_PM */
1136d3466830SKalle Valo .soft_unbind = 1,
1137d3466830SKalle Valo .disable_hub_initiated_lpm = 1,
1138d3466830SKalle Valo };
1139d3466830SKalle Valo
1140d3466830SKalle Valo module_usb_driver(p54u_driver);
1141