xref: /freebsd/sys/contrib/dev/broadcom/brcm80211/brcmfmac/usb.c (revision 22741535bcf4b003e41c0ecd22cca578359ba434)
1b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2b4c3e9b5SBjoern A. Zeeb /*
3b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2011 Broadcom Corporation
4b4c3e9b5SBjoern A. Zeeb  */
5b4c3e9b5SBjoern A. Zeeb 
6b4c3e9b5SBjoern A. Zeeb #include <linux/kernel.h>
7b4c3e9b5SBjoern A. Zeeb #include <linux/module.h>
8b4c3e9b5SBjoern A. Zeeb #include <linux/firmware.h>
9b4c3e9b5SBjoern A. Zeeb #include <linux/usb.h>
10b4c3e9b5SBjoern A. Zeeb #include <linux/vmalloc.h>
11*22741535SBjoern A. Zeeb #if defined(__FreeBSD__)
12*22741535SBjoern A. Zeeb #include <linux/delay.h>
13*22741535SBjoern A. Zeeb #endif
14b4c3e9b5SBjoern A. Zeeb 
15b4c3e9b5SBjoern A. Zeeb #include <brcmu_utils.h>
16b4c3e9b5SBjoern A. Zeeb #include <brcm_hw_ids.h>
17b4c3e9b5SBjoern A. Zeeb #include <brcmu_wifi.h>
18b4c3e9b5SBjoern A. Zeeb #include "bus.h"
19b4c3e9b5SBjoern A. Zeeb #include "debug.h"
20b4c3e9b5SBjoern A. Zeeb #include "firmware.h"
21b4c3e9b5SBjoern A. Zeeb #include "usb.h"
22b4c3e9b5SBjoern A. Zeeb #include "core.h"
23b4c3e9b5SBjoern A. Zeeb #include "common.h"
24b4c3e9b5SBjoern A. Zeeb #include "bcdc.h"
25b4c3e9b5SBjoern A. Zeeb 
26b4c3e9b5SBjoern A. Zeeb 
27b4c3e9b5SBjoern A. Zeeb #define IOCTL_RESP_TIMEOUT		msecs_to_jiffies(2000)
28b4c3e9b5SBjoern A. Zeeb 
29b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_RESET_GETVER_SPINWAIT	100	/* in unit of ms */
30b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_RESET_GETVER_LOOP_CNT	10
31b4c3e9b5SBjoern A. Zeeb 
32b4c3e9b5SBjoern A. Zeeb #define BRCMF_POSTBOOT_ID		0xA123  /* ID to detect if dongle
33b4c3e9b5SBjoern A. Zeeb 						   has boot up */
34b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_NRXQ			50
35b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_NTXQ			50
36b4c3e9b5SBjoern A. Zeeb 
37b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_CBCTL_WRITE		0
38b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_CBCTL_READ		1
39b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_MAX_PKT_SIZE		1600
40b4c3e9b5SBjoern A. Zeeb 
41b4c3e9b5SBjoern A. Zeeb BRCMF_FW_DEF(43143, "brcmfmac43143");
42b4c3e9b5SBjoern A. Zeeb BRCMF_FW_DEF(43236B, "brcmfmac43236b");
43b4c3e9b5SBjoern A. Zeeb BRCMF_FW_DEF(43242A, "brcmfmac43242a");
44b4c3e9b5SBjoern A. Zeeb BRCMF_FW_DEF(43569, "brcmfmac43569");
45b4c3e9b5SBjoern A. Zeeb BRCMF_FW_DEF(4373, "brcmfmac4373");
46b4c3e9b5SBjoern A. Zeeb 
47b4c3e9b5SBjoern A. Zeeb static const struct brcmf_firmware_mapping brcmf_usb_fwnames[] = {
48b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
49b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43235_CHIP_ID, 0x00000008, 43236B),
50b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43236_CHIP_ID, 0x00000008, 43236B),
51b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43238_CHIP_ID, 0x00000008, 43236B),
52b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43242_CHIP_ID, 0xFFFFFFFF, 43242A),
53b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43566_CHIP_ID, 0xFFFFFFFF, 43569),
54b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43569),
55b4c3e9b5SBjoern A. Zeeb 	BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373)
56b4c3e9b5SBjoern A. Zeeb };
57b4c3e9b5SBjoern A. Zeeb 
58b4c3e9b5SBjoern A. Zeeb #define TRX_MAGIC		0x30524448	/* "HDR0" */
59b4c3e9b5SBjoern A. Zeeb #define TRX_MAX_OFFSET		3		/* Max number of file offsets */
60b4c3e9b5SBjoern A. Zeeb #define TRX_UNCOMP_IMAGE	0x20		/* Trx holds uncompressed img */
61b4c3e9b5SBjoern A. Zeeb #define TRX_RDL_CHUNK		1500		/* size of each dl transfer */
62b4c3e9b5SBjoern A. Zeeb #define TRX_OFFSETS_DLFWLEN_IDX	0
63b4c3e9b5SBjoern A. Zeeb 
64b4c3e9b5SBjoern A. Zeeb /* Control messages: bRequest values */
65b4c3e9b5SBjoern A. Zeeb #define DL_GETSTATE	0	/* returns the rdl_state_t struct */
66b4c3e9b5SBjoern A. Zeeb #define DL_CHECK_CRC	1	/* currently unused */
67b4c3e9b5SBjoern A. Zeeb #define DL_GO		2	/* execute downloaded image */
68b4c3e9b5SBjoern A. Zeeb #define DL_START	3	/* initialize dl state */
69b4c3e9b5SBjoern A. Zeeb #define DL_REBOOT	4	/* reboot the device in 2 seconds */
70b4c3e9b5SBjoern A. Zeeb #define DL_GETVER	5	/* returns the bootrom_id_t struct */
71b4c3e9b5SBjoern A. Zeeb #define DL_GO_PROTECTED	6	/* execute the downloaded code and set reset
72b4c3e9b5SBjoern A. Zeeb 				 * event to occur in 2 seconds.  It is the
73b4c3e9b5SBjoern A. Zeeb 				 * responsibility of the downloaded code to
74b4c3e9b5SBjoern A. Zeeb 				 * clear this event
75b4c3e9b5SBjoern A. Zeeb 				 */
76b4c3e9b5SBjoern A. Zeeb #define DL_EXEC		7	/* jump to a supplied address */
77b4c3e9b5SBjoern A. Zeeb #define DL_RESETCFG	8	/* To support single enum on dongle
78b4c3e9b5SBjoern A. Zeeb 				 * - Not used by bootloader
79b4c3e9b5SBjoern A. Zeeb 				 */
80b4c3e9b5SBjoern A. Zeeb #define DL_DEFER_RESP_OK 9	/* Potentially defer the response to setup
81b4c3e9b5SBjoern A. Zeeb 				 * if resp unavailable
82b4c3e9b5SBjoern A. Zeeb 				 */
83b4c3e9b5SBjoern A. Zeeb 
84b4c3e9b5SBjoern A. Zeeb /* states */
85b4c3e9b5SBjoern A. Zeeb #define DL_WAITING	0	/* waiting to rx first pkt */
86b4c3e9b5SBjoern A. Zeeb #define DL_READY	1	/* hdr was good, waiting for more of the
87b4c3e9b5SBjoern A. Zeeb 				 * compressed image
88b4c3e9b5SBjoern A. Zeeb 				 */
89b4c3e9b5SBjoern A. Zeeb #define DL_BAD_HDR	2	/* hdr was corrupted */
90b4c3e9b5SBjoern A. Zeeb #define DL_BAD_CRC	3	/* compressed image was corrupted */
91b4c3e9b5SBjoern A. Zeeb #define DL_RUNNABLE	4	/* download was successful,waiting for go cmd */
92b4c3e9b5SBjoern A. Zeeb #define DL_START_FAIL	5	/* failed to initialize correctly */
93b4c3e9b5SBjoern A. Zeeb #define DL_NVRAM_TOOBIG	6	/* host specified nvram data exceeds DL_NVRAM
94b4c3e9b5SBjoern A. Zeeb 				 * value
95b4c3e9b5SBjoern A. Zeeb 				 */
96b4c3e9b5SBjoern A. Zeeb #define DL_IMAGE_TOOBIG	7	/* firmware image too big */
97b4c3e9b5SBjoern A. Zeeb 
98b4c3e9b5SBjoern A. Zeeb 
99b4c3e9b5SBjoern A. Zeeb struct trx_header_le {
100b4c3e9b5SBjoern A. Zeeb 	__le32 magic;		/* "HDR0" */
101b4c3e9b5SBjoern A. Zeeb 	__le32 len;		/* Length of file including header */
102b4c3e9b5SBjoern A. Zeeb 	__le32 crc32;		/* CRC from flag_version to end of file */
103b4c3e9b5SBjoern A. Zeeb 	__le32 flag_version;	/* 0:15 flags, 16:31 version */
104b4c3e9b5SBjoern A. Zeeb 	__le32 offsets[TRX_MAX_OFFSET];	/* Offsets of partitions from start of
105b4c3e9b5SBjoern A. Zeeb 					 * header
106b4c3e9b5SBjoern A. Zeeb 					 */
107b4c3e9b5SBjoern A. Zeeb };
108b4c3e9b5SBjoern A. Zeeb 
109b4c3e9b5SBjoern A. Zeeb struct rdl_state_le {
110b4c3e9b5SBjoern A. Zeeb 	__le32 state;
111b4c3e9b5SBjoern A. Zeeb 	__le32 bytes;
112b4c3e9b5SBjoern A. Zeeb };
113b4c3e9b5SBjoern A. Zeeb 
114b4c3e9b5SBjoern A. Zeeb struct bootrom_id_le {
115b4c3e9b5SBjoern A. Zeeb 	__le32 chip;		/* Chip id */
116b4c3e9b5SBjoern A. Zeeb 	__le32 chiprev;		/* Chip rev */
117b4c3e9b5SBjoern A. Zeeb 	__le32 ramsize;		/* Size of  RAM */
118b4c3e9b5SBjoern A. Zeeb 	__le32 remapbase;	/* Current remap base address */
119b4c3e9b5SBjoern A. Zeeb 	__le32 boardtype;	/* Type of board */
120b4c3e9b5SBjoern A. Zeeb 	__le32 boardrev;	/* Board revision */
121b4c3e9b5SBjoern A. Zeeb };
122b4c3e9b5SBjoern A. Zeeb 
123b4c3e9b5SBjoern A. Zeeb struct brcmf_usbdev_info {
124b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev bus_pub; /* MUST BE FIRST */
125b4c3e9b5SBjoern A. Zeeb 	spinlock_t qlock;
126b4c3e9b5SBjoern A. Zeeb 	struct list_head rx_freeq;
127b4c3e9b5SBjoern A. Zeeb 	struct list_head rx_postq;
128b4c3e9b5SBjoern A. Zeeb 	struct list_head tx_freeq;
129b4c3e9b5SBjoern A. Zeeb 	struct list_head tx_postq;
130b4c3e9b5SBjoern A. Zeeb 	uint rx_pipe, tx_pipe;
131b4c3e9b5SBjoern A. Zeeb 
132b4c3e9b5SBjoern A. Zeeb 	int rx_low_watermark;
133b4c3e9b5SBjoern A. Zeeb 	int tx_low_watermark;
134b4c3e9b5SBjoern A. Zeeb 	int tx_high_watermark;
135b4c3e9b5SBjoern A. Zeeb 	int tx_freecount;
136b4c3e9b5SBjoern A. Zeeb 	bool tx_flowblock;
137b4c3e9b5SBjoern A. Zeeb 	spinlock_t tx_flowblock_lock;
138b4c3e9b5SBjoern A. Zeeb 
139b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq *tx_reqs;
140b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq *rx_reqs;
141b4c3e9b5SBjoern A. Zeeb 
142b4c3e9b5SBjoern A. Zeeb 	char fw_name[BRCMF_FW_NAME_LEN];
143b4c3e9b5SBjoern A. Zeeb 	const u8 *image;	/* buffer for combine fw and nvram */
144b4c3e9b5SBjoern A. Zeeb 	int image_len;
145b4c3e9b5SBjoern A. Zeeb 
146b4c3e9b5SBjoern A. Zeeb 	struct usb_device *usbdev;
147b4c3e9b5SBjoern A. Zeeb 	struct device *dev;
148b4c3e9b5SBjoern A. Zeeb 	struct completion dev_init_done;
149b4c3e9b5SBjoern A. Zeeb 
150b4c3e9b5SBjoern A. Zeeb 	int ctl_in_pipe, ctl_out_pipe;
151b4c3e9b5SBjoern A. Zeeb 	struct urb *ctl_urb; /* URB for control endpoint */
152b4c3e9b5SBjoern A. Zeeb 	struct usb_ctrlrequest ctl_write;
153b4c3e9b5SBjoern A. Zeeb 	struct usb_ctrlrequest ctl_read;
154b4c3e9b5SBjoern A. Zeeb 	u32 ctl_urb_actual_length;
155b4c3e9b5SBjoern A. Zeeb 	int ctl_urb_status;
156b4c3e9b5SBjoern A. Zeeb 	int ctl_completed;
157b4c3e9b5SBjoern A. Zeeb 	wait_queue_head_t ioctl_resp_wait;
158b4c3e9b5SBjoern A. Zeeb 	ulong ctl_op;
159b4c3e9b5SBjoern A. Zeeb 	u8 ifnum;
160b4c3e9b5SBjoern A. Zeeb 
161b4c3e9b5SBjoern A. Zeeb 	struct urb *bulk_urb; /* used for FW download */
162b4c3e9b5SBjoern A. Zeeb 
163b4c3e9b5SBjoern A. Zeeb 	struct brcmf_mp_device *settings;
164b4c3e9b5SBjoern A. Zeeb };
165b4c3e9b5SBjoern A. Zeeb 
166b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
167b4c3e9b5SBjoern A. Zeeb 				struct brcmf_usbreq  *req);
168b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_get_buspub(struct device * dev)169b4c3e9b5SBjoern A. Zeeb static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev)
170b4c3e9b5SBjoern A. Zeeb {
171b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
172b4c3e9b5SBjoern A. Zeeb 	return bus_if->bus_priv.usb;
173b4c3e9b5SBjoern A. Zeeb }
174b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_get_businfo(struct device * dev)175b4c3e9b5SBjoern A. Zeeb static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev)
176b4c3e9b5SBjoern A. Zeeb {
177b4c3e9b5SBjoern A. Zeeb 	return brcmf_usb_get_buspub(dev)->devinfo;
178b4c3e9b5SBjoern A. Zeeb }
179b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info * devinfo)180b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo)
181b4c3e9b5SBjoern A. Zeeb {
182b4c3e9b5SBjoern A. Zeeb 	return wait_event_timeout(devinfo->ioctl_resp_wait,
183b4c3e9b5SBjoern A. Zeeb 				  devinfo->ctl_completed, IOCTL_RESP_TIMEOUT);
184b4c3e9b5SBjoern A. Zeeb }
185b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info * devinfo)186b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
187b4c3e9b5SBjoern A. Zeeb {
188b4c3e9b5SBjoern A. Zeeb 	wake_up(&devinfo->ioctl_resp_wait);
189b4c3e9b5SBjoern A. Zeeb }
190b4c3e9b5SBjoern A. Zeeb 
191b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_ctl_complete(struct brcmf_usbdev_info * devinfo,int type,int status)192b4c3e9b5SBjoern A. Zeeb brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)
193b4c3e9b5SBjoern A. Zeeb {
194b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, status=%d\n", status);
195b4c3e9b5SBjoern A. Zeeb 
196b4c3e9b5SBjoern A. Zeeb 	if (unlikely(devinfo == NULL))
197b4c3e9b5SBjoern A. Zeeb 		return;
198b4c3e9b5SBjoern A. Zeeb 
199b4c3e9b5SBjoern A. Zeeb 	if (type == BRCMF_USB_CBCTL_READ) {
200b4c3e9b5SBjoern A. Zeeb 		if (status == 0)
201b4c3e9b5SBjoern A. Zeeb 			devinfo->bus_pub.stats.rx_ctlpkts++;
202b4c3e9b5SBjoern A. Zeeb 		else
203b4c3e9b5SBjoern A. Zeeb 			devinfo->bus_pub.stats.rx_ctlerrs++;
204b4c3e9b5SBjoern A. Zeeb 	} else if (type == BRCMF_USB_CBCTL_WRITE) {
205b4c3e9b5SBjoern A. Zeeb 		if (status == 0)
206b4c3e9b5SBjoern A. Zeeb 			devinfo->bus_pub.stats.tx_ctlpkts++;
207b4c3e9b5SBjoern A. Zeeb 		else
208b4c3e9b5SBjoern A. Zeeb 			devinfo->bus_pub.stats.tx_ctlerrs++;
209b4c3e9b5SBjoern A. Zeeb 	}
210b4c3e9b5SBjoern A. Zeeb 
211b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb_status = status;
212b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_completed = true;
213b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_ioctl_resp_wake(devinfo);
214b4c3e9b5SBjoern A. Zeeb }
215b4c3e9b5SBjoern A. Zeeb 
216b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_ctlread_complete(struct urb * urb)217b4c3e9b5SBjoern A. Zeeb brcmf_usb_ctlread_complete(struct urb *urb)
218b4c3e9b5SBjoern A. Zeeb {
219b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo =
220b4c3e9b5SBjoern A. Zeeb 		(struct brcmf_usbdev_info *)urb->context;
221b4c3e9b5SBjoern A. Zeeb 
222b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
223b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb_actual_length = urb->actual_length;
224b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,
225b4c3e9b5SBjoern A. Zeeb 		urb->status);
226b4c3e9b5SBjoern A. Zeeb }
227b4c3e9b5SBjoern A. Zeeb 
228b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_ctlwrite_complete(struct urb * urb)229b4c3e9b5SBjoern A. Zeeb brcmf_usb_ctlwrite_complete(struct urb *urb)
230b4c3e9b5SBjoern A. Zeeb {
231b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo =
232b4c3e9b5SBjoern A. Zeeb 		(struct brcmf_usbdev_info *)urb->context;
233b4c3e9b5SBjoern A. Zeeb 
234b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
235b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,
236b4c3e9b5SBjoern A. Zeeb 		urb->status);
237b4c3e9b5SBjoern A. Zeeb }
238b4c3e9b5SBjoern A. Zeeb 
239b4c3e9b5SBjoern A. Zeeb static int
brcmf_usb_send_ctl(struct brcmf_usbdev_info * devinfo,u8 * buf,int len)240b4c3e9b5SBjoern A. Zeeb brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
241b4c3e9b5SBjoern A. Zeeb {
242b4c3e9b5SBjoern A. Zeeb 	int ret;
243b4c3e9b5SBjoern A. Zeeb 	u16 size;
244b4c3e9b5SBjoern A. Zeeb 
245b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
246b4c3e9b5SBjoern A. Zeeb 	if (devinfo == NULL || buf == NULL ||
247b4c3e9b5SBjoern A. Zeeb 	    len == 0 || devinfo->ctl_urb == NULL)
248b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
249b4c3e9b5SBjoern A. Zeeb 
250b4c3e9b5SBjoern A. Zeeb 	size = len;
251b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_write.wLength = cpu_to_le16p(&size);
252b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb->transfer_buffer_length = size;
253b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb_status = 0;
254b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb_actual_length = 0;
255b4c3e9b5SBjoern A. Zeeb 
256b4c3e9b5SBjoern A. Zeeb 	usb_fill_control_urb(devinfo->ctl_urb,
257b4c3e9b5SBjoern A. Zeeb 		devinfo->usbdev,
258b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_out_pipe,
259b4c3e9b5SBjoern A. Zeeb 		(unsigned char *) &devinfo->ctl_write,
260b4c3e9b5SBjoern A. Zeeb 		buf, size,
261*22741535SBjoern A. Zeeb #if defined(__linux__)
262b4c3e9b5SBjoern A. Zeeb 		(usb_complete_t)brcmf_usb_ctlwrite_complete,
263*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
264*22741535SBjoern A. Zeeb 		brcmf_usb_ctlwrite_complete,
265*22741535SBjoern A. Zeeb #endif
266b4c3e9b5SBjoern A. Zeeb 		devinfo);
267b4c3e9b5SBjoern A. Zeeb 
268b4c3e9b5SBjoern A. Zeeb 	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
269b4c3e9b5SBjoern A. Zeeb 	if (ret < 0)
270b4c3e9b5SBjoern A. Zeeb 		brcmf_err("usb_submit_urb failed %d\n", ret);
271b4c3e9b5SBjoern A. Zeeb 
272b4c3e9b5SBjoern A. Zeeb 	return ret;
273b4c3e9b5SBjoern A. Zeeb }
274b4c3e9b5SBjoern A. Zeeb 
275b4c3e9b5SBjoern A. Zeeb static int
brcmf_usb_recv_ctl(struct brcmf_usbdev_info * devinfo,u8 * buf,int len)276b4c3e9b5SBjoern A. Zeeb brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
277b4c3e9b5SBjoern A. Zeeb {
278b4c3e9b5SBjoern A. Zeeb 	int ret;
279b4c3e9b5SBjoern A. Zeeb 	u16 size;
280b4c3e9b5SBjoern A. Zeeb 
281b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
282b4c3e9b5SBjoern A. Zeeb 	if ((devinfo == NULL) || (buf == NULL) || (len == 0)
283b4c3e9b5SBjoern A. Zeeb 		|| (devinfo->ctl_urb == NULL))
284b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
285b4c3e9b5SBjoern A. Zeeb 
286b4c3e9b5SBjoern A. Zeeb 	size = len;
287b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_read.wLength = cpu_to_le16p(&size);
288b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb->transfer_buffer_length = size;
289b4c3e9b5SBjoern A. Zeeb 
290b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_read.bRequestType = USB_DIR_IN
291b4c3e9b5SBjoern A. Zeeb 		| USB_TYPE_CLASS | USB_RECIP_INTERFACE;
292b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_read.bRequest = 1;
293b4c3e9b5SBjoern A. Zeeb 
294b4c3e9b5SBjoern A. Zeeb 	usb_fill_control_urb(devinfo->ctl_urb,
295b4c3e9b5SBjoern A. Zeeb 		devinfo->usbdev,
296b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_in_pipe,
297b4c3e9b5SBjoern A. Zeeb 		(unsigned char *) &devinfo->ctl_read,
298b4c3e9b5SBjoern A. Zeeb 		buf, size,
299*22741535SBjoern A. Zeeb #if defined(__linux__)
300b4c3e9b5SBjoern A. Zeeb 		(usb_complete_t)brcmf_usb_ctlread_complete,
301*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
302*22741535SBjoern A. Zeeb 		brcmf_usb_ctlread_complete,
303*22741535SBjoern A. Zeeb #endif
304b4c3e9b5SBjoern A. Zeeb 		devinfo);
305b4c3e9b5SBjoern A. Zeeb 
306b4c3e9b5SBjoern A. Zeeb 	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
307b4c3e9b5SBjoern A. Zeeb 	if (ret < 0)
308b4c3e9b5SBjoern A. Zeeb 		brcmf_err("usb_submit_urb failed %d\n", ret);
309b4c3e9b5SBjoern A. Zeeb 
310b4c3e9b5SBjoern A. Zeeb 	return ret;
311b4c3e9b5SBjoern A. Zeeb }
312b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_tx_ctlpkt(struct device * dev,u8 * buf,u32 len)313b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
314b4c3e9b5SBjoern A. Zeeb {
315b4c3e9b5SBjoern A. Zeeb 	int err = 0;
316b4c3e9b5SBjoern A. Zeeb 	int timeout = 0;
317b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
318b4c3e9b5SBjoern A. Zeeb 	struct usb_interface *intf = to_usb_interface(dev);
319b4c3e9b5SBjoern A. Zeeb 
320b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
321b4c3e9b5SBjoern A. Zeeb 
322b4c3e9b5SBjoern A. Zeeb 	err = usb_autopm_get_interface(intf);
323b4c3e9b5SBjoern A. Zeeb 	if (err)
324b4c3e9b5SBjoern A. Zeeb 		goto out;
325b4c3e9b5SBjoern A. Zeeb 
326b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
327b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
328b4c3e9b5SBjoern A. Zeeb 		goto fail;
329b4c3e9b5SBjoern A. Zeeb 	}
330b4c3e9b5SBjoern A. Zeeb 
331b4c3e9b5SBjoern A. Zeeb 	if (test_and_set_bit(0, &devinfo->ctl_op)) {
332b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
333b4c3e9b5SBjoern A. Zeeb 		goto fail;
334b4c3e9b5SBjoern A. Zeeb 	}
335b4c3e9b5SBjoern A. Zeeb 
336b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_completed = false;
337b4c3e9b5SBjoern A. Zeeb 	err = brcmf_usb_send_ctl(devinfo, buf, len);
338b4c3e9b5SBjoern A. Zeeb 	if (err) {
339b4c3e9b5SBjoern A. Zeeb 		brcmf_err("fail %d bytes: %d\n", err, len);
340b4c3e9b5SBjoern A. Zeeb 		clear_bit(0, &devinfo->ctl_op);
341b4c3e9b5SBjoern A. Zeeb 		goto fail;
342b4c3e9b5SBjoern A. Zeeb 	}
343b4c3e9b5SBjoern A. Zeeb 	timeout = brcmf_usb_ioctl_resp_wait(devinfo);
344b4c3e9b5SBjoern A. Zeeb 	if (!timeout) {
345b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Txctl wait timed out\n");
346b4c3e9b5SBjoern A. Zeeb 		usb_kill_urb(devinfo->ctl_urb);
347b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
348b4c3e9b5SBjoern A. Zeeb 		goto fail;
349b4c3e9b5SBjoern A. Zeeb 	}
350b4c3e9b5SBjoern A. Zeeb 	clear_bit(0, &devinfo->ctl_op);
351b4c3e9b5SBjoern A. Zeeb 
352b4c3e9b5SBjoern A. Zeeb fail:
353b4c3e9b5SBjoern A. Zeeb 	usb_autopm_put_interface(intf);
354b4c3e9b5SBjoern A. Zeeb out:
355b4c3e9b5SBjoern A. Zeeb 	return err;
356b4c3e9b5SBjoern A. Zeeb }
357b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_rx_ctlpkt(struct device * dev,u8 * buf,u32 len)358b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
359b4c3e9b5SBjoern A. Zeeb {
360b4c3e9b5SBjoern A. Zeeb 	int err = 0;
361b4c3e9b5SBjoern A. Zeeb 	int timeout = 0;
362b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
363b4c3e9b5SBjoern A. Zeeb 	struct usb_interface *intf = to_usb_interface(dev);
364b4c3e9b5SBjoern A. Zeeb 
365b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
366b4c3e9b5SBjoern A. Zeeb 
367b4c3e9b5SBjoern A. Zeeb 	err = usb_autopm_get_interface(intf);
368b4c3e9b5SBjoern A. Zeeb 	if (err)
369b4c3e9b5SBjoern A. Zeeb 		goto out;
370b4c3e9b5SBjoern A. Zeeb 
371b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
372b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
373b4c3e9b5SBjoern A. Zeeb 		goto fail;
374b4c3e9b5SBjoern A. Zeeb 	}
375b4c3e9b5SBjoern A. Zeeb 
376b4c3e9b5SBjoern A. Zeeb 	if (test_and_set_bit(0, &devinfo->ctl_op)) {
377b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
378b4c3e9b5SBjoern A. Zeeb 		goto fail;
379b4c3e9b5SBjoern A. Zeeb 	}
380b4c3e9b5SBjoern A. Zeeb 
381b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_completed = false;
382b4c3e9b5SBjoern A. Zeeb 	err = brcmf_usb_recv_ctl(devinfo, buf, len);
383b4c3e9b5SBjoern A. Zeeb 	if (err) {
384b4c3e9b5SBjoern A. Zeeb 		brcmf_err("fail %d bytes: %d\n", err, len);
385b4c3e9b5SBjoern A. Zeeb 		clear_bit(0, &devinfo->ctl_op);
386b4c3e9b5SBjoern A. Zeeb 		goto fail;
387b4c3e9b5SBjoern A. Zeeb 	}
388b4c3e9b5SBjoern A. Zeeb 	timeout = brcmf_usb_ioctl_resp_wait(devinfo);
389b4c3e9b5SBjoern A. Zeeb 	err = devinfo->ctl_urb_status;
390b4c3e9b5SBjoern A. Zeeb 	if (!timeout) {
391b4c3e9b5SBjoern A. Zeeb 		brcmf_err("rxctl wait timed out\n");
392b4c3e9b5SBjoern A. Zeeb 		usb_kill_urb(devinfo->ctl_urb);
393b4c3e9b5SBjoern A. Zeeb 		err = -EIO;
394b4c3e9b5SBjoern A. Zeeb 		goto fail;
395b4c3e9b5SBjoern A. Zeeb 	}
396b4c3e9b5SBjoern A. Zeeb 	clear_bit(0, &devinfo->ctl_op);
397b4c3e9b5SBjoern A. Zeeb fail:
398b4c3e9b5SBjoern A. Zeeb 	usb_autopm_put_interface(intf);
399b4c3e9b5SBjoern A. Zeeb 	if (!err)
400b4c3e9b5SBjoern A. Zeeb 		return devinfo->ctl_urb_actual_length;
401b4c3e9b5SBjoern A. Zeeb out:
402b4c3e9b5SBjoern A. Zeeb 	return err;
403b4c3e9b5SBjoern A. Zeeb }
404b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_deq(struct brcmf_usbdev_info * devinfo,struct list_head * q,int * counter)405b4c3e9b5SBjoern A. Zeeb static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo,
406b4c3e9b5SBjoern A. Zeeb 					  struct list_head *q, int *counter)
407b4c3e9b5SBjoern A. Zeeb {
408b4c3e9b5SBjoern A. Zeeb 	unsigned long flags;
409b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq  *req;
410b4c3e9b5SBjoern A. Zeeb 	spin_lock_irqsave(&devinfo->qlock, flags);
411b4c3e9b5SBjoern A. Zeeb 	if (list_empty(q)) {
412b4c3e9b5SBjoern A. Zeeb 		spin_unlock_irqrestore(&devinfo->qlock, flags);
413b4c3e9b5SBjoern A. Zeeb 		return NULL;
414b4c3e9b5SBjoern A. Zeeb 	}
415b4c3e9b5SBjoern A. Zeeb 	req = list_entry(q->next, struct brcmf_usbreq, list);
416b4c3e9b5SBjoern A. Zeeb 	list_del_init(q->next);
417b4c3e9b5SBjoern A. Zeeb 	if (counter)
418b4c3e9b5SBjoern A. Zeeb 		(*counter)--;
419b4c3e9b5SBjoern A. Zeeb 	spin_unlock_irqrestore(&devinfo->qlock, flags);
420b4c3e9b5SBjoern A. Zeeb 	return req;
421b4c3e9b5SBjoern A. Zeeb 
422b4c3e9b5SBjoern A. Zeeb }
423b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_enq(struct brcmf_usbdev_info * devinfo,struct list_head * q,struct brcmf_usbreq * req,int * counter)424b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo,
425b4c3e9b5SBjoern A. Zeeb 			  struct list_head *q, struct brcmf_usbreq *req,
426b4c3e9b5SBjoern A. Zeeb 			  int *counter)
427b4c3e9b5SBjoern A. Zeeb {
428b4c3e9b5SBjoern A. Zeeb 	unsigned long flags;
429b4c3e9b5SBjoern A. Zeeb 	spin_lock_irqsave(&devinfo->qlock, flags);
430b4c3e9b5SBjoern A. Zeeb 	list_add_tail(&req->list, q);
431b4c3e9b5SBjoern A. Zeeb 	if (counter)
432b4c3e9b5SBjoern A. Zeeb 		(*counter)++;
433b4c3e9b5SBjoern A. Zeeb 	spin_unlock_irqrestore(&devinfo->qlock, flags);
434b4c3e9b5SBjoern A. Zeeb }
435b4c3e9b5SBjoern A. Zeeb 
436b4c3e9b5SBjoern A. Zeeb static struct brcmf_usbreq *
brcmf_usbdev_qinit(struct list_head * q,int qsize)437b4c3e9b5SBjoern A. Zeeb brcmf_usbdev_qinit(struct list_head *q, int qsize)
438b4c3e9b5SBjoern A. Zeeb {
439b4c3e9b5SBjoern A. Zeeb 	int i;
440b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq *req, *reqs;
441b4c3e9b5SBjoern A. Zeeb 
442b4c3e9b5SBjoern A. Zeeb 	reqs = kcalloc(qsize, sizeof(struct brcmf_usbreq), GFP_ATOMIC);
443b4c3e9b5SBjoern A. Zeeb 	if (reqs == NULL)
444b4c3e9b5SBjoern A. Zeeb 		return NULL;
445b4c3e9b5SBjoern A. Zeeb 
446b4c3e9b5SBjoern A. Zeeb 	req = reqs;
447b4c3e9b5SBjoern A. Zeeb 
448b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < qsize; i++) {
449b4c3e9b5SBjoern A. Zeeb 		req->urb = usb_alloc_urb(0, GFP_ATOMIC);
450b4c3e9b5SBjoern A. Zeeb 		if (!req->urb)
451b4c3e9b5SBjoern A. Zeeb 			goto fail;
452b4c3e9b5SBjoern A. Zeeb 
453b4c3e9b5SBjoern A. Zeeb 		INIT_LIST_HEAD(&req->list);
454b4c3e9b5SBjoern A. Zeeb 		list_add_tail(&req->list, q);
455b4c3e9b5SBjoern A. Zeeb 		req++;
456b4c3e9b5SBjoern A. Zeeb 	}
457b4c3e9b5SBjoern A. Zeeb 	return reqs;
458b4c3e9b5SBjoern A. Zeeb fail:
459b4c3e9b5SBjoern A. Zeeb 	brcmf_err("fail!\n");
460b4c3e9b5SBjoern A. Zeeb 	while (!list_empty(q)) {
461b4c3e9b5SBjoern A. Zeeb 		req = list_entry(q->next, struct brcmf_usbreq, list);
462b4c3e9b5SBjoern A. Zeeb 		if (req)
463b4c3e9b5SBjoern A. Zeeb 			usb_free_urb(req->urb);
464b4c3e9b5SBjoern A. Zeeb 		list_del(q->next);
465b4c3e9b5SBjoern A. Zeeb 	}
466b4c3e9b5SBjoern A. Zeeb 	kfree(reqs);
467b4c3e9b5SBjoern A. Zeeb 	return NULL;
468b4c3e9b5SBjoern A. Zeeb 
469b4c3e9b5SBjoern A. Zeeb }
470b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_free_q(struct list_head * q)471b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_free_q(struct list_head *q)
472b4c3e9b5SBjoern A. Zeeb {
473b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq *req, *next;
474b4c3e9b5SBjoern A. Zeeb 
475b4c3e9b5SBjoern A. Zeeb 	list_for_each_entry_safe(req, next, q, list) {
476b4c3e9b5SBjoern A. Zeeb 		if (!req->urb) {
477b4c3e9b5SBjoern A. Zeeb 			brcmf_err("bad req\n");
478b4c3e9b5SBjoern A. Zeeb 			break;
479b4c3e9b5SBjoern A. Zeeb 		}
480b4c3e9b5SBjoern A. Zeeb 		usb_free_urb(req->urb);
481b4c3e9b5SBjoern A. Zeeb 		list_del_init(&req->list);
482b4c3e9b5SBjoern A. Zeeb 	}
483b4c3e9b5SBjoern A. Zeeb }
484b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_del_fromq(struct brcmf_usbdev_info * devinfo,struct brcmf_usbreq * req)485b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_del_fromq(struct brcmf_usbdev_info *devinfo,
486b4c3e9b5SBjoern A. Zeeb 				struct brcmf_usbreq *req)
487b4c3e9b5SBjoern A. Zeeb {
488b4c3e9b5SBjoern A. Zeeb 	unsigned long flags;
489b4c3e9b5SBjoern A. Zeeb 
490b4c3e9b5SBjoern A. Zeeb 	spin_lock_irqsave(&devinfo->qlock, flags);
491b4c3e9b5SBjoern A. Zeeb 	list_del_init(&req->list);
492b4c3e9b5SBjoern A. Zeeb 	spin_unlock_irqrestore(&devinfo->qlock, flags);
493b4c3e9b5SBjoern A. Zeeb }
494b4c3e9b5SBjoern A. Zeeb 
495b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_tx_complete(struct urb * urb)496b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_tx_complete(struct urb *urb)
497b4c3e9b5SBjoern A. Zeeb {
498b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
499b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = req->devinfo;
500b4c3e9b5SBjoern A. Zeeb 	unsigned long flags;
501b4c3e9b5SBjoern A. Zeeb 
502b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
503b4c3e9b5SBjoern A. Zeeb 		  req->skb);
504b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_del_fromq(devinfo, req);
505b4c3e9b5SBjoern A. Zeeb 
506b4c3e9b5SBjoern A. Zeeb 	brcmf_proto_bcdc_txcomplete(devinfo->dev, req->skb, urb->status == 0);
507b4c3e9b5SBjoern A. Zeeb 	req->skb = NULL;
508b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
509b4c3e9b5SBjoern A. Zeeb 	spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
510b4c3e9b5SBjoern A. Zeeb 	if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
511b4c3e9b5SBjoern A. Zeeb 		devinfo->tx_flowblock) {
512b4c3e9b5SBjoern A. Zeeb 		brcmf_proto_bcdc_txflowblock(devinfo->dev, false);
513b4c3e9b5SBjoern A. Zeeb 		devinfo->tx_flowblock = false;
514b4c3e9b5SBjoern A. Zeeb 	}
515b4c3e9b5SBjoern A. Zeeb 	spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
516b4c3e9b5SBjoern A. Zeeb }
517b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_rx_complete(struct urb * urb)518b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_rx_complete(struct urb *urb)
519b4c3e9b5SBjoern A. Zeeb {
520b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;
521b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = req->devinfo;
522b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *skb;
523b4c3e9b5SBjoern A. Zeeb 
524b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
525b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_del_fromq(devinfo, req);
526b4c3e9b5SBjoern A. Zeeb 	skb = req->skb;
527b4c3e9b5SBjoern A. Zeeb 	req->skb = NULL;
528b4c3e9b5SBjoern A. Zeeb 
529b4c3e9b5SBjoern A. Zeeb 	/* zero length packets indicate usb "failure". Do not refill */
530b4c3e9b5SBjoern A. Zeeb 	if (urb->status != 0 || !urb->actual_length) {
531b4c3e9b5SBjoern A. Zeeb 		brcmu_pkt_buf_free_skb(skb);
532b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
533b4c3e9b5SBjoern A. Zeeb 		return;
534b4c3e9b5SBjoern A. Zeeb 	}
535b4c3e9b5SBjoern A. Zeeb 
536b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP ||
537b4c3e9b5SBjoern A. Zeeb 	    devinfo->bus_pub.state == BRCMFMAC_USB_STATE_SLEEP) {
538b4c3e9b5SBjoern A. Zeeb 		skb_put(skb, urb->actual_length);
539b4c3e9b5SBjoern A. Zeeb 		brcmf_rx_frame(devinfo->dev, skb, true, true);
540b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_rx_refill(devinfo, req);
541b4c3e9b5SBjoern A. Zeeb 		usb_mark_last_busy(urb->dev);
542b4c3e9b5SBjoern A. Zeeb 	} else {
543b4c3e9b5SBjoern A. Zeeb 		brcmu_pkt_buf_free_skb(skb);
544b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
545b4c3e9b5SBjoern A. Zeeb 	}
546b4c3e9b5SBjoern A. Zeeb 	return;
547b4c3e9b5SBjoern A. Zeeb 
548b4c3e9b5SBjoern A. Zeeb }
549b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_rx_refill(struct brcmf_usbdev_info * devinfo,struct brcmf_usbreq * req)550b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
551b4c3e9b5SBjoern A. Zeeb 				struct brcmf_usbreq  *req)
552b4c3e9b5SBjoern A. Zeeb {
553b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *skb;
554b4c3e9b5SBjoern A. Zeeb 	int ret;
555b4c3e9b5SBjoern A. Zeeb 
556b4c3e9b5SBjoern A. Zeeb 	if (!req || !devinfo)
557b4c3e9b5SBjoern A. Zeeb 		return;
558b4c3e9b5SBjoern A. Zeeb 
559b4c3e9b5SBjoern A. Zeeb 	skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu);
560b4c3e9b5SBjoern A. Zeeb 	if (!skb) {
561b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
562b4c3e9b5SBjoern A. Zeeb 		return;
563b4c3e9b5SBjoern A. Zeeb 	}
564b4c3e9b5SBjoern A. Zeeb 	req->skb = skb;
565b4c3e9b5SBjoern A. Zeeb 
566b4c3e9b5SBjoern A. Zeeb 	usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe,
567b4c3e9b5SBjoern A. Zeeb 			  skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
568b4c3e9b5SBjoern A. Zeeb 			  req);
569b4c3e9b5SBjoern A. Zeeb 	req->devinfo = devinfo;
570b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_enq(devinfo, &devinfo->rx_postq, req, NULL);
571b4c3e9b5SBjoern A. Zeeb 
572b4c3e9b5SBjoern A. Zeeb 	ret = usb_submit_urb(req->urb, GFP_ATOMIC);
573b4c3e9b5SBjoern A. Zeeb 	if (ret) {
574b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_del_fromq(devinfo, req);
575b4c3e9b5SBjoern A. Zeeb 		brcmu_pkt_buf_free_skb(req->skb);
576b4c3e9b5SBjoern A. Zeeb 		req->skb = NULL;
577b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
578b4c3e9b5SBjoern A. Zeeb 	}
579b4c3e9b5SBjoern A. Zeeb 	return;
580b4c3e9b5SBjoern A. Zeeb }
581b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_rx_fill_all(struct brcmf_usbdev_info * devinfo)582b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
583b4c3e9b5SBjoern A. Zeeb {
584b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq *req;
585b4c3e9b5SBjoern A. Zeeb 
586b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
587b4c3e9b5SBjoern A. Zeeb 		brcmf_err("bus is not up=%d\n", devinfo->bus_pub.state);
588b4c3e9b5SBjoern A. Zeeb 		return;
589b4c3e9b5SBjoern A. Zeeb 	}
590b4c3e9b5SBjoern A. Zeeb 	while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL)
591b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_rx_refill(devinfo, req);
592b4c3e9b5SBjoern A. Zeeb }
593b4c3e9b5SBjoern A. Zeeb 
594b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_state_change(struct brcmf_usbdev_info * devinfo,int state)595b4c3e9b5SBjoern A. Zeeb brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
596b4c3e9b5SBjoern A. Zeeb {
597b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
598b4c3e9b5SBjoern A. Zeeb 
599b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n",
600b4c3e9b5SBjoern A. Zeeb 		  devinfo->bus_pub.state, state);
601b4c3e9b5SBjoern A. Zeeb 
602b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state == state)
603b4c3e9b5SBjoern A. Zeeb 		return;
604b4c3e9b5SBjoern A. Zeeb 
605b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.state = state;
606b4c3e9b5SBjoern A. Zeeb 
607b4c3e9b5SBjoern A. Zeeb 	/* update state of upper layer */
608b4c3e9b5SBjoern A. Zeeb 	if (state == BRCMFMAC_USB_STATE_DOWN) {
609b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "DBUS is down\n");
610b4c3e9b5SBjoern A. Zeeb 		brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);
611b4c3e9b5SBjoern A. Zeeb 	} else if (state == BRCMFMAC_USB_STATE_UP) {
612b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "DBUS is up\n");
613b4c3e9b5SBjoern A. Zeeb 		brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_UP);
614b4c3e9b5SBjoern A. Zeeb 	} else {
615b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "DBUS current state=%d\n", state);
616b4c3e9b5SBjoern A. Zeeb 	}
617b4c3e9b5SBjoern A. Zeeb }
618b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_tx(struct device * dev,struct sk_buff * skb)619b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
620b4c3e9b5SBjoern A. Zeeb {
621b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
622b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbreq  *req;
623b4c3e9b5SBjoern A. Zeeb 	int ret;
624b4c3e9b5SBjoern A. Zeeb 	unsigned long flags;
625b4c3e9b5SBjoern A. Zeeb 	struct usb_interface *intf = to_usb_interface(dev);
626b4c3e9b5SBjoern A. Zeeb 
627b4c3e9b5SBjoern A. Zeeb 	ret = usb_autopm_get_interface(intf);
628b4c3e9b5SBjoern A. Zeeb 	if (ret)
629b4c3e9b5SBjoern A. Zeeb 		goto out;
630b4c3e9b5SBjoern A. Zeeb 
631b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, skb=%p\n", skb);
632b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
633b4c3e9b5SBjoern A. Zeeb 		ret = -EIO;
634b4c3e9b5SBjoern A. Zeeb 		goto fail;
635b4c3e9b5SBjoern A. Zeeb 	}
636b4c3e9b5SBjoern A. Zeeb 
637b4c3e9b5SBjoern A. Zeeb 	req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq,
638b4c3e9b5SBjoern A. Zeeb 					&devinfo->tx_freecount);
639b4c3e9b5SBjoern A. Zeeb 	if (!req) {
640b4c3e9b5SBjoern A. Zeeb 		brcmf_err("no req to send\n");
641b4c3e9b5SBjoern A. Zeeb 		ret = -ENOMEM;
642b4c3e9b5SBjoern A. Zeeb 		goto fail;
643b4c3e9b5SBjoern A. Zeeb 	}
644b4c3e9b5SBjoern A. Zeeb 
645b4c3e9b5SBjoern A. Zeeb 	req->skb = skb;
646b4c3e9b5SBjoern A. Zeeb 	req->devinfo = devinfo;
647b4c3e9b5SBjoern A. Zeeb 	usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
648b4c3e9b5SBjoern A. Zeeb 			  skb->data, skb->len, brcmf_usb_tx_complete, req);
649b4c3e9b5SBjoern A. Zeeb 	req->urb->transfer_flags |= URB_ZERO_PACKET;
650b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_enq(devinfo, &devinfo->tx_postq, req, NULL);
651b4c3e9b5SBjoern A. Zeeb 	ret = usb_submit_urb(req->urb, GFP_ATOMIC);
652b4c3e9b5SBjoern A. Zeeb 	if (ret) {
653b4c3e9b5SBjoern A. Zeeb 		brcmf_err("brcmf_usb_tx usb_submit_urb FAILED\n");
654b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_del_fromq(devinfo, req);
655b4c3e9b5SBjoern A. Zeeb 		req->skb = NULL;
656b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req,
657b4c3e9b5SBjoern A. Zeeb 			      &devinfo->tx_freecount);
658b4c3e9b5SBjoern A. Zeeb 		goto fail;
659b4c3e9b5SBjoern A. Zeeb 	}
660b4c3e9b5SBjoern A. Zeeb 
661b4c3e9b5SBjoern A. Zeeb 	spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
662b4c3e9b5SBjoern A. Zeeb 	if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
663b4c3e9b5SBjoern A. Zeeb 	    !devinfo->tx_flowblock) {
664b4c3e9b5SBjoern A. Zeeb 		brcmf_proto_bcdc_txflowblock(dev, true);
665b4c3e9b5SBjoern A. Zeeb 		devinfo->tx_flowblock = true;
666b4c3e9b5SBjoern A. Zeeb 	}
667b4c3e9b5SBjoern A. Zeeb 	spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
668b4c3e9b5SBjoern A. Zeeb 
669b4c3e9b5SBjoern A. Zeeb fail:
670b4c3e9b5SBjoern A. Zeeb 	usb_autopm_put_interface(intf);
671b4c3e9b5SBjoern A. Zeeb out:
672b4c3e9b5SBjoern A. Zeeb 	return ret;
673b4c3e9b5SBjoern A. Zeeb }
674b4c3e9b5SBjoern A. Zeeb 
675b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_up(struct device * dev)676b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_up(struct device *dev)
677b4c3e9b5SBjoern A. Zeeb {
678b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
679b4c3e9b5SBjoern A. Zeeb 
680b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
681b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
682b4c3e9b5SBjoern A. Zeeb 		return 0;
683b4c3e9b5SBjoern A. Zeeb 
684b4c3e9b5SBjoern A. Zeeb 	/* Success, indicate devinfo is fully up */
685b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP);
686b4c3e9b5SBjoern A. Zeeb 
687b4c3e9b5SBjoern A. Zeeb 	if (devinfo->ctl_urb) {
688b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
689b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
690b4c3e9b5SBjoern A. Zeeb 
691b4c3e9b5SBjoern A. Zeeb 		/* CTL Write */
692b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_write.bRequestType =
693b4c3e9b5SBjoern A. Zeeb 			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
694b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_write.bRequest = 0;
695b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_write.wValue = cpu_to_le16(0);
696b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_write.wIndex = cpu_to_le16(devinfo->ifnum);
697b4c3e9b5SBjoern A. Zeeb 
698b4c3e9b5SBjoern A. Zeeb 		/* CTL Read */
699b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_read.bRequestType =
700b4c3e9b5SBjoern A. Zeeb 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
701b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_read.bRequest = 1;
702b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_read.wValue = cpu_to_le16(0);
703b4c3e9b5SBjoern A. Zeeb 		devinfo->ctl_read.wIndex = cpu_to_le16(devinfo->ifnum);
704b4c3e9b5SBjoern A. Zeeb 	}
705b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_rx_fill_all(devinfo);
706b4c3e9b5SBjoern A. Zeeb 	return 0;
707b4c3e9b5SBjoern A. Zeeb }
708b4c3e9b5SBjoern A. Zeeb 
brcmf_cancel_all_urbs(struct brcmf_usbdev_info * devinfo)709b4c3e9b5SBjoern A. Zeeb static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
710b4c3e9b5SBjoern A. Zeeb {
711b4c3e9b5SBjoern A. Zeeb 	int i;
712b4c3e9b5SBjoern A. Zeeb 
713b4c3e9b5SBjoern A. Zeeb 	if (devinfo->ctl_urb)
714b4c3e9b5SBjoern A. Zeeb 		usb_kill_urb(devinfo->ctl_urb);
715b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bulk_urb)
716b4c3e9b5SBjoern A. Zeeb 		usb_kill_urb(devinfo->bulk_urb);
717b4c3e9b5SBjoern A. Zeeb 	if (devinfo->tx_reqs)
718b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < devinfo->bus_pub.ntxq; i++)
719b4c3e9b5SBjoern A. Zeeb 			usb_kill_urb(devinfo->tx_reqs[i].urb);
720b4c3e9b5SBjoern A. Zeeb 	if (devinfo->rx_reqs)
721b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < devinfo->bus_pub.nrxq; i++)
722b4c3e9b5SBjoern A. Zeeb 			usb_kill_urb(devinfo->rx_reqs[i].urb);
723b4c3e9b5SBjoern A. Zeeb }
724b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_down(struct device * dev)725b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_down(struct device *dev)
726b4c3e9b5SBjoern A. Zeeb {
727b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
728b4c3e9b5SBjoern A. Zeeb 
729b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
730b4c3e9b5SBjoern A. Zeeb 	if (devinfo == NULL)
731b4c3e9b5SBjoern A. Zeeb 		return;
732b4c3e9b5SBjoern A. Zeeb 
733b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN)
734b4c3e9b5SBjoern A. Zeeb 		return;
735b4c3e9b5SBjoern A. Zeeb 
736b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
737b4c3e9b5SBjoern A. Zeeb 
738b4c3e9b5SBjoern A. Zeeb 	brcmf_cancel_all_urbs(devinfo);
739b4c3e9b5SBjoern A. Zeeb }
740b4c3e9b5SBjoern A. Zeeb 
741b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_sync_complete(struct urb * urb)742b4c3e9b5SBjoern A. Zeeb brcmf_usb_sync_complete(struct urb *urb)
743b4c3e9b5SBjoern A. Zeeb {
744b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo =
745b4c3e9b5SBjoern A. Zeeb 			(struct brcmf_usbdev_info *)urb->context;
746b4c3e9b5SBjoern A. Zeeb 
747b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_completed = true;
748b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_ioctl_resp_wake(devinfo);
749b4c3e9b5SBjoern A. Zeeb }
750b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_dl_cmd(struct brcmf_usbdev_info * devinfo,u8 cmd,void * buffer,int buflen)751b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
752b4c3e9b5SBjoern A. Zeeb 			    void *buffer, int buflen)
753b4c3e9b5SBjoern A. Zeeb {
754b4c3e9b5SBjoern A. Zeeb 	int ret;
755b4c3e9b5SBjoern A. Zeeb 	char *tmpbuf = NULL;
756b4c3e9b5SBjoern A. Zeeb 	u16 size;
757b4c3e9b5SBjoern A. Zeeb 
758b4c3e9b5SBjoern A. Zeeb 	if (!devinfo || !devinfo->ctl_urb) {
759b4c3e9b5SBjoern A. Zeeb 		ret = -EINVAL;
760b4c3e9b5SBjoern A. Zeeb 		goto err;
761b4c3e9b5SBjoern A. Zeeb 	}
762b4c3e9b5SBjoern A. Zeeb 
763b4c3e9b5SBjoern A. Zeeb 	tmpbuf = kmalloc(buflen, GFP_ATOMIC);
764b4c3e9b5SBjoern A. Zeeb 	if (!tmpbuf) {
765b4c3e9b5SBjoern A. Zeeb 		ret = -ENOMEM;
766b4c3e9b5SBjoern A. Zeeb 		goto err;
767b4c3e9b5SBjoern A. Zeeb 	}
768b4c3e9b5SBjoern A. Zeeb 
769b4c3e9b5SBjoern A. Zeeb 	size = buflen;
770b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb->transfer_buffer_length = size;
771b4c3e9b5SBjoern A. Zeeb 
772b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_read.wLength = cpu_to_le16p(&size);
773b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR |
774b4c3e9b5SBjoern A. Zeeb 		USB_RECIP_INTERFACE;
775b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_read.bRequest = cmd;
776b4c3e9b5SBjoern A. Zeeb 
777b4c3e9b5SBjoern A. Zeeb 	usb_fill_control_urb(devinfo->ctl_urb,
778b4c3e9b5SBjoern A. Zeeb 		devinfo->usbdev,
779b4c3e9b5SBjoern A. Zeeb 		usb_rcvctrlpipe(devinfo->usbdev, 0),
780b4c3e9b5SBjoern A. Zeeb 		(unsigned char *) &devinfo->ctl_read,
781b4c3e9b5SBjoern A. Zeeb 		(void *) tmpbuf, size,
782*22741535SBjoern A. Zeeb #if defined(__linux__)
783b4c3e9b5SBjoern A. Zeeb 		(usb_complete_t)brcmf_usb_sync_complete, devinfo);
784*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
785*22741535SBjoern A. Zeeb 		brcmf_usb_sync_complete, devinfo);
786*22741535SBjoern A. Zeeb #endif
787b4c3e9b5SBjoern A. Zeeb 
788b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_completed = false;
789b4c3e9b5SBjoern A. Zeeb 	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
790b4c3e9b5SBjoern A. Zeeb 	if (ret < 0) {
791b4c3e9b5SBjoern A. Zeeb 		brcmf_err("usb_submit_urb failed %d\n", ret);
792b4c3e9b5SBjoern A. Zeeb 		goto err;
793b4c3e9b5SBjoern A. Zeeb 	}
794b4c3e9b5SBjoern A. Zeeb 
795b4c3e9b5SBjoern A. Zeeb 	if (!brcmf_usb_ioctl_resp_wait(devinfo)) {
796b4c3e9b5SBjoern A. Zeeb 		usb_kill_urb(devinfo->ctl_urb);
797b4c3e9b5SBjoern A. Zeeb 		ret = -ETIMEDOUT;
798b4c3e9b5SBjoern A. Zeeb 		goto err;
799b4c3e9b5SBjoern A. Zeeb 	} else {
800b4c3e9b5SBjoern A. Zeeb 		memcpy(buffer, tmpbuf, buflen);
801b4c3e9b5SBjoern A. Zeeb 	}
802b4c3e9b5SBjoern A. Zeeb 
803b4c3e9b5SBjoern A. Zeeb 	kfree(tmpbuf);
804b4c3e9b5SBjoern A. Zeeb 	return 0;
805b4c3e9b5SBjoern A. Zeeb 
806b4c3e9b5SBjoern A. Zeeb err:
807b4c3e9b5SBjoern A. Zeeb 	kfree(tmpbuf);
808b4c3e9b5SBjoern A. Zeeb 	brcmf_err("dl cmd %u failed: err=%d\n", cmd, ret);
809b4c3e9b5SBjoern A. Zeeb 	return ret;
810b4c3e9b5SBjoern A. Zeeb }
811b4c3e9b5SBjoern A. Zeeb 
812b4c3e9b5SBjoern A. Zeeb static bool
brcmf_usb_dlneeded(struct brcmf_usbdev_info * devinfo)813b4c3e9b5SBjoern A. Zeeb brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)
814b4c3e9b5SBjoern A. Zeeb {
815b4c3e9b5SBjoern A. Zeeb 	struct bootrom_id_le id;
816b4c3e9b5SBjoern A. Zeeb 	u32 chipid, chiprev;
817b4c3e9b5SBjoern A. Zeeb 
818b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
819b4c3e9b5SBjoern A. Zeeb 
820b4c3e9b5SBjoern A. Zeeb 	if (devinfo == NULL)
821b4c3e9b5SBjoern A. Zeeb 		return false;
822b4c3e9b5SBjoern A. Zeeb 
823b4c3e9b5SBjoern A. Zeeb 	/* Check if firmware downloaded already by querying runtime ID */
824b4c3e9b5SBjoern A. Zeeb 	id.chip = cpu_to_le32(0xDEAD);
825b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
826b4c3e9b5SBjoern A. Zeeb 
827b4c3e9b5SBjoern A. Zeeb 	chipid = le32_to_cpu(id.chip);
828b4c3e9b5SBjoern A. Zeeb 	chiprev = le32_to_cpu(id.chiprev);
829b4c3e9b5SBjoern A. Zeeb 
830b4c3e9b5SBjoern A. Zeeb 	if ((chipid & 0x4300) == 0x4300)
831b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "chip %x rev 0x%x\n", chipid, chiprev);
832b4c3e9b5SBjoern A. Zeeb 	else
833b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "chip %d rev 0x%x\n", chipid, chiprev);
834b4c3e9b5SBjoern A. Zeeb 	if (chipid == BRCMF_POSTBOOT_ID) {
835b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "firmware already downloaded\n");
836b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id));
837b4c3e9b5SBjoern A. Zeeb 		return false;
838b4c3e9b5SBjoern A. Zeeb 	} else {
839b4c3e9b5SBjoern A. Zeeb 		devinfo->bus_pub.devid = chipid;
840b4c3e9b5SBjoern A. Zeeb 		devinfo->bus_pub.chiprev = chiprev;
841b4c3e9b5SBjoern A. Zeeb 	}
842b4c3e9b5SBjoern A. Zeeb 	return true;
843b4c3e9b5SBjoern A. Zeeb }
844b4c3e9b5SBjoern A. Zeeb 
845b4c3e9b5SBjoern A. Zeeb static int
brcmf_usb_resetcfg(struct brcmf_usbdev_info * devinfo)846b4c3e9b5SBjoern A. Zeeb brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
847b4c3e9b5SBjoern A. Zeeb {
848b4c3e9b5SBjoern A. Zeeb 	struct bootrom_id_le id;
849b4c3e9b5SBjoern A. Zeeb 	u32 loop_cnt;
850b4c3e9b5SBjoern A. Zeeb 	int err;
851b4c3e9b5SBjoern A. Zeeb 
852b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
853b4c3e9b5SBjoern A. Zeeb 
854b4c3e9b5SBjoern A. Zeeb 	loop_cnt = 0;
855b4c3e9b5SBjoern A. Zeeb 	do {
856b4c3e9b5SBjoern A. Zeeb 		mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT);
857b4c3e9b5SBjoern A. Zeeb 		loop_cnt++;
858b4c3e9b5SBjoern A. Zeeb 		id.chip = cpu_to_le32(0xDEAD);       /* Get the ID */
859b4c3e9b5SBjoern A. Zeeb 		err = brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
860b4c3e9b5SBjoern A. Zeeb 		if ((err) && (err != -ETIMEDOUT))
861b4c3e9b5SBjoern A. Zeeb 			return err;
862b4c3e9b5SBjoern A. Zeeb 		if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
863b4c3e9b5SBjoern A. Zeeb 			break;
864b4c3e9b5SBjoern A. Zeeb 	} while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT);
865b4c3e9b5SBjoern A. Zeeb 
866b4c3e9b5SBjoern A. Zeeb 	if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) {
867b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "postboot chip 0x%x/rev 0x%x\n",
868b4c3e9b5SBjoern A. Zeeb 			  le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
869b4c3e9b5SBjoern A. Zeeb 
870b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id));
871b4c3e9b5SBjoern A. Zeeb 		return 0;
872b4c3e9b5SBjoern A. Zeeb 	} else {
873b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Cannot talk to Dongle. Firmware is not UP, %d ms\n",
874b4c3e9b5SBjoern A. Zeeb 			  BRCMF_USB_RESET_GETVER_SPINWAIT * loop_cnt);
875b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
876b4c3e9b5SBjoern A. Zeeb 	}
877b4c3e9b5SBjoern A. Zeeb }
878b4c3e9b5SBjoern A. Zeeb 
879b4c3e9b5SBjoern A. Zeeb 
880b4c3e9b5SBjoern A. Zeeb static int
brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info * devinfo,void * buffer,int len)881b4c3e9b5SBjoern A. Zeeb brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len)
882b4c3e9b5SBjoern A. Zeeb {
883b4c3e9b5SBjoern A. Zeeb 	int ret;
884b4c3e9b5SBjoern A. Zeeb 
885b4c3e9b5SBjoern A. Zeeb 	if ((devinfo == NULL) || (devinfo->bulk_urb == NULL))
886b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
887b4c3e9b5SBjoern A. Zeeb 
888b4c3e9b5SBjoern A. Zeeb 	/* Prepare the URB */
889b4c3e9b5SBjoern A. Zeeb 	usb_fill_bulk_urb(devinfo->bulk_urb, devinfo->usbdev,
890b4c3e9b5SBjoern A. Zeeb 			  devinfo->tx_pipe, buffer, len,
891*22741535SBjoern A. Zeeb #if defined(__linux__)
892b4c3e9b5SBjoern A. Zeeb 			  (usb_complete_t)brcmf_usb_sync_complete, devinfo);
893*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
894*22741535SBjoern A. Zeeb 			  brcmf_usb_sync_complete, devinfo);
895*22741535SBjoern A. Zeeb #endif
896b4c3e9b5SBjoern A. Zeeb 
897b4c3e9b5SBjoern A. Zeeb 	devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET;
898b4c3e9b5SBjoern A. Zeeb 
899b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_completed = false;
900b4c3e9b5SBjoern A. Zeeb 	ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC);
901b4c3e9b5SBjoern A. Zeeb 	if (ret) {
902b4c3e9b5SBjoern A. Zeeb 		brcmf_err("usb_submit_urb failed %d\n", ret);
903b4c3e9b5SBjoern A. Zeeb 		return ret;
904b4c3e9b5SBjoern A. Zeeb 	}
905b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_usb_ioctl_resp_wait(devinfo);
906b4c3e9b5SBjoern A. Zeeb 	return (ret == 0);
907b4c3e9b5SBjoern A. Zeeb }
908b4c3e9b5SBjoern A. Zeeb 
909b4c3e9b5SBjoern A. Zeeb static int
910*22741535SBjoern A. Zeeb #if defined(__linux__)
brcmf_usb_dl_writeimage(struct brcmf_usbdev_info * devinfo,u8 * fw,int fwlen)911b4c3e9b5SBjoern A. Zeeb brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
912*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
913*22741535SBjoern A. Zeeb brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, const u8 *fw, int fwlen)
914*22741535SBjoern A. Zeeb #endif
915b4c3e9b5SBjoern A. Zeeb {
916b4c3e9b5SBjoern A. Zeeb 	unsigned int sendlen, sent, dllen;
917*22741535SBjoern A. Zeeb #if defined(__linux__)
918b4c3e9b5SBjoern A. Zeeb 	char *bulkchunk = NULL, *dlpos;
919*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
920*22741535SBjoern A. Zeeb 	char *bulkchunk = NULL;
921*22741535SBjoern A. Zeeb 	const u8 *dlpos;
922*22741535SBjoern A. Zeeb #endif
923b4c3e9b5SBjoern A. Zeeb 	struct rdl_state_le state;
924b4c3e9b5SBjoern A. Zeeb 	u32 rdlstate, rdlbytes;
925b4c3e9b5SBjoern A. Zeeb 	int err = 0;
926b4c3e9b5SBjoern A. Zeeb 
927b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);
928b4c3e9b5SBjoern A. Zeeb 
929b4c3e9b5SBjoern A. Zeeb 	bulkchunk = kmalloc(TRX_RDL_CHUNK, GFP_ATOMIC);
930b4c3e9b5SBjoern A. Zeeb 	if (bulkchunk == NULL) {
931b4c3e9b5SBjoern A. Zeeb 		err = -ENOMEM;
932b4c3e9b5SBjoern A. Zeeb 		goto fail;
933b4c3e9b5SBjoern A. Zeeb 	}
934b4c3e9b5SBjoern A. Zeeb 
935b4c3e9b5SBjoern A. Zeeb 	/* 1) Prepare USB boot loader for runtime image */
936b4c3e9b5SBjoern A. Zeeb 	err = brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
937b4c3e9b5SBjoern A. Zeeb 	if (err)
938b4c3e9b5SBjoern A. Zeeb 		goto fail;
939b4c3e9b5SBjoern A. Zeeb 
940b4c3e9b5SBjoern A. Zeeb 	rdlstate = le32_to_cpu(state.state);
941b4c3e9b5SBjoern A. Zeeb 	rdlbytes = le32_to_cpu(state.bytes);
942b4c3e9b5SBjoern A. Zeeb 
943b4c3e9b5SBjoern A. Zeeb 	/* 2) Check we are in the Waiting state */
944b4c3e9b5SBjoern A. Zeeb 	if (rdlstate != DL_WAITING) {
945b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Invalid DL state: %u\n", rdlstate);
946b4c3e9b5SBjoern A. Zeeb 		err = -EINVAL;
947b4c3e9b5SBjoern A. Zeeb 		goto fail;
948b4c3e9b5SBjoern A. Zeeb 	}
949b4c3e9b5SBjoern A. Zeeb 	sent = 0;
950b4c3e9b5SBjoern A. Zeeb 	dlpos = fw;
951b4c3e9b5SBjoern A. Zeeb 	dllen = fwlen;
952b4c3e9b5SBjoern A. Zeeb 
953b4c3e9b5SBjoern A. Zeeb 	/* Get chip id and rev */
954b4c3e9b5SBjoern A. Zeeb 	while (rdlbytes != dllen) {
955b4c3e9b5SBjoern A. Zeeb 		/* Wait until the usb device reports it received all
956b4c3e9b5SBjoern A. Zeeb 		 * the bytes we sent */
957b4c3e9b5SBjoern A. Zeeb 		if ((rdlbytes == sent) && (rdlbytes != dllen)) {
958b4c3e9b5SBjoern A. Zeeb 			sendlen = min(dllen - sent, TRX_RDL_CHUNK);
959b4c3e9b5SBjoern A. Zeeb 
960b4c3e9b5SBjoern A. Zeeb 			/* simply avoid having to send a ZLP by ensuring we
961b4c3e9b5SBjoern A. Zeeb 			 * never have an even
962b4c3e9b5SBjoern A. Zeeb 			 * multiple of 64
963b4c3e9b5SBjoern A. Zeeb 			 */
964b4c3e9b5SBjoern A. Zeeb 			if (!(sendlen % 64))
965b4c3e9b5SBjoern A. Zeeb 				sendlen -= 4;
966b4c3e9b5SBjoern A. Zeeb 
967b4c3e9b5SBjoern A. Zeeb 			/* send data */
968b4c3e9b5SBjoern A. Zeeb 			memcpy(bulkchunk, dlpos, sendlen);
969b4c3e9b5SBjoern A. Zeeb 			if (brcmf_usb_dl_send_bulk(devinfo, bulkchunk,
970b4c3e9b5SBjoern A. Zeeb 						   sendlen)) {
971b4c3e9b5SBjoern A. Zeeb 				brcmf_err("send_bulk failed\n");
972b4c3e9b5SBjoern A. Zeeb 				err = -EINVAL;
973b4c3e9b5SBjoern A. Zeeb 				goto fail;
974b4c3e9b5SBjoern A. Zeeb 			}
975b4c3e9b5SBjoern A. Zeeb 
976b4c3e9b5SBjoern A. Zeeb 			dlpos += sendlen;
977b4c3e9b5SBjoern A. Zeeb 			sent += sendlen;
978b4c3e9b5SBjoern A. Zeeb 		}
979b4c3e9b5SBjoern A. Zeeb 		err = brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
980b4c3e9b5SBjoern A. Zeeb 				       sizeof(state));
981b4c3e9b5SBjoern A. Zeeb 		if (err) {
982b4c3e9b5SBjoern A. Zeeb 			brcmf_err("DL_GETSTATE Failed\n");
983b4c3e9b5SBjoern A. Zeeb 			goto fail;
984b4c3e9b5SBjoern A. Zeeb 		}
985b4c3e9b5SBjoern A. Zeeb 
986b4c3e9b5SBjoern A. Zeeb 		rdlstate = le32_to_cpu(state.state);
987b4c3e9b5SBjoern A. Zeeb 		rdlbytes = le32_to_cpu(state.bytes);
988b4c3e9b5SBjoern A. Zeeb 
989b4c3e9b5SBjoern A. Zeeb 		/* restart if an error is reported */
990b4c3e9b5SBjoern A. Zeeb 		if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) {
991b4c3e9b5SBjoern A. Zeeb 			brcmf_err("Bad Hdr or Bad CRC state %d\n",
992b4c3e9b5SBjoern A. Zeeb 				  rdlstate);
993b4c3e9b5SBjoern A. Zeeb 			err = -EINVAL;
994b4c3e9b5SBjoern A. Zeeb 			goto fail;
995b4c3e9b5SBjoern A. Zeeb 		}
996b4c3e9b5SBjoern A. Zeeb 	}
997b4c3e9b5SBjoern A. Zeeb 
998b4c3e9b5SBjoern A. Zeeb fail:
999b4c3e9b5SBjoern A. Zeeb 	kfree(bulkchunk);
1000b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Exit, err=%d\n", err);
1001b4c3e9b5SBjoern A. Zeeb 	return err;
1002b4c3e9b5SBjoern A. Zeeb }
1003b4c3e9b5SBjoern A. Zeeb 
1004*22741535SBjoern A. Zeeb #if defined(__linux__)
brcmf_usb_dlstart(struct brcmf_usbdev_info * devinfo,u8 * fw,int len)1005b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
1006*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
1007*22741535SBjoern A. Zeeb static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, const u8 *fw, int len)
1008*22741535SBjoern A. Zeeb #endif
1009b4c3e9b5SBjoern A. Zeeb {
1010b4c3e9b5SBjoern A. Zeeb 	int err;
1011b4c3e9b5SBjoern A. Zeeb 
1012b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1013b4c3e9b5SBjoern A. Zeeb 
1014b4c3e9b5SBjoern A. Zeeb 	if (devinfo == NULL)
1015b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
1016b4c3e9b5SBjoern A. Zeeb 
1017b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.devid == 0xDEAD)
1018b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
1019b4c3e9b5SBjoern A. Zeeb 
1020b4c3e9b5SBjoern A. Zeeb 	err = brcmf_usb_dl_writeimage(devinfo, fw, len);
1021b4c3e9b5SBjoern A. Zeeb 	if (err == 0)
1022b4c3e9b5SBjoern A. Zeeb 		devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_DONE;
1023b4c3e9b5SBjoern A. Zeeb 	else
1024b4c3e9b5SBjoern A. Zeeb 		devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_FAIL;
1025b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Exit, err=%d\n", err);
1026b4c3e9b5SBjoern A. Zeeb 
1027b4c3e9b5SBjoern A. Zeeb 	return err;
1028b4c3e9b5SBjoern A. Zeeb }
1029b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_dlrun(struct brcmf_usbdev_info * devinfo)1030b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
1031b4c3e9b5SBjoern A. Zeeb {
1032b4c3e9b5SBjoern A. Zeeb 	struct rdl_state_le state;
1033b4c3e9b5SBjoern A. Zeeb 
1034b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1035b4c3e9b5SBjoern A. Zeeb 	if (!devinfo)
1036b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
1037b4c3e9b5SBjoern A. Zeeb 
1038b4c3e9b5SBjoern A. Zeeb 	if (devinfo->bus_pub.devid == 0xDEAD)
1039b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
1040b4c3e9b5SBjoern A. Zeeb 
1041b4c3e9b5SBjoern A. Zeeb 	/* Check we are runnable */
1042b4c3e9b5SBjoern A. Zeeb 	state.state = 0;
1043b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, sizeof(state));
1044b4c3e9b5SBjoern A. Zeeb 
1045b4c3e9b5SBjoern A. Zeeb 	/* Start the image */
1046b4c3e9b5SBjoern A. Zeeb 	if (state.state == cpu_to_le32(DL_RUNNABLE)) {
1047b4c3e9b5SBjoern A. Zeeb 		if (brcmf_usb_dl_cmd(devinfo, DL_GO, &state, sizeof(state)))
1048b4c3e9b5SBjoern A. Zeeb 			return -ENODEV;
1049b4c3e9b5SBjoern A. Zeeb 		if (brcmf_usb_resetcfg(devinfo))
1050b4c3e9b5SBjoern A. Zeeb 			return -ENODEV;
1051b4c3e9b5SBjoern A. Zeeb 		/* The Dongle may go for re-enumeration. */
1052b4c3e9b5SBjoern A. Zeeb 	} else {
1053b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Dongle not runnable\n");
1054b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
1055b4c3e9b5SBjoern A. Zeeb 	}
1056b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Exit\n");
1057b4c3e9b5SBjoern A. Zeeb 	return 0;
1058b4c3e9b5SBjoern A. Zeeb }
1059b4c3e9b5SBjoern A. Zeeb 
1060b4c3e9b5SBjoern A. Zeeb static int
brcmf_usb_fw_download(struct brcmf_usbdev_info * devinfo)1061b4c3e9b5SBjoern A. Zeeb brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
1062b4c3e9b5SBjoern A. Zeeb {
1063b4c3e9b5SBjoern A. Zeeb 	int err;
1064b4c3e9b5SBjoern A. Zeeb 	struct usb_interface *intf;
1065b4c3e9b5SBjoern A. Zeeb 
1066b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1067b4c3e9b5SBjoern A. Zeeb 	if (!devinfo) {
1068b4c3e9b5SBjoern A. Zeeb 		err = -ENODEV;
1069b4c3e9b5SBjoern A. Zeeb 		goto out;
1070b4c3e9b5SBjoern A. Zeeb 	}
1071b4c3e9b5SBjoern A. Zeeb 
1072b4c3e9b5SBjoern A. Zeeb 	if (!devinfo->image) {
1073b4c3e9b5SBjoern A. Zeeb 		brcmf_err("No firmware!\n");
1074b4c3e9b5SBjoern A. Zeeb 		err = -ENOENT;
1075b4c3e9b5SBjoern A. Zeeb 		goto out;
1076b4c3e9b5SBjoern A. Zeeb 	}
1077b4c3e9b5SBjoern A. Zeeb 
1078b4c3e9b5SBjoern A. Zeeb 	intf = to_usb_interface(devinfo->dev);
1079b4c3e9b5SBjoern A. Zeeb 	err = usb_autopm_get_interface(intf);
1080b4c3e9b5SBjoern A. Zeeb 	if (err)
1081b4c3e9b5SBjoern A. Zeeb 		goto out;
1082b4c3e9b5SBjoern A. Zeeb 
1083b4c3e9b5SBjoern A. Zeeb 	err = brcmf_usb_dlstart(devinfo,
1084*22741535SBjoern A. Zeeb #if defined(__linux__)
1085b4c3e9b5SBjoern A. Zeeb 		(u8 *)devinfo->image, devinfo->image_len);
1086*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
1087*22741535SBjoern A. Zeeb 		(const u8 *)devinfo->image, devinfo->image_len);
1088*22741535SBjoern A. Zeeb #endif
1089b4c3e9b5SBjoern A. Zeeb 	if (err == 0)
1090b4c3e9b5SBjoern A. Zeeb 		err = brcmf_usb_dlrun(devinfo);
1091b4c3e9b5SBjoern A. Zeeb 
1092b4c3e9b5SBjoern A. Zeeb 	usb_autopm_put_interface(intf);
1093b4c3e9b5SBjoern A. Zeeb out:
1094b4c3e9b5SBjoern A. Zeeb 	return err;
1095b4c3e9b5SBjoern A. Zeeb }
1096b4c3e9b5SBjoern A. Zeeb 
1097b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_detach(struct brcmf_usbdev_info * devinfo)1098b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
1099b4c3e9b5SBjoern A. Zeeb {
1100b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
1101b4c3e9b5SBjoern A. Zeeb 
1102b4c3e9b5SBjoern A. Zeeb 	/* free the URBS */
1103b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_free_q(&devinfo->rx_freeq);
1104b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_free_q(&devinfo->tx_freeq);
1105b4c3e9b5SBjoern A. Zeeb 
1106b4c3e9b5SBjoern A. Zeeb 	usb_free_urb(devinfo->ctl_urb);
1107b4c3e9b5SBjoern A. Zeeb 	usb_free_urb(devinfo->bulk_urb);
1108b4c3e9b5SBjoern A. Zeeb 
1109b4c3e9b5SBjoern A. Zeeb 	kfree(devinfo->tx_reqs);
1110b4c3e9b5SBjoern A. Zeeb 	kfree(devinfo->rx_reqs);
1111b4c3e9b5SBjoern A. Zeeb 
1112b4c3e9b5SBjoern A. Zeeb 	if (devinfo->settings)
1113b4c3e9b5SBjoern A. Zeeb 		brcmf_release_module_param(devinfo->settings);
1114b4c3e9b5SBjoern A. Zeeb }
1115b4c3e9b5SBjoern A. Zeeb 
1116b4c3e9b5SBjoern A. Zeeb 
check_file(const u8 * headers)1117b4c3e9b5SBjoern A. Zeeb static int check_file(const u8 *headers)
1118b4c3e9b5SBjoern A. Zeeb {
1119*22741535SBjoern A. Zeeb #if defined(__linux__)
1120b4c3e9b5SBjoern A. Zeeb 	struct trx_header_le *trx;
1121*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
1122*22741535SBjoern A. Zeeb 	const struct trx_header_le *trx;
1123*22741535SBjoern A. Zeeb #endif
1124b4c3e9b5SBjoern A. Zeeb 	int actual_len = -1;
1125b4c3e9b5SBjoern A. Zeeb 
1126b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1127b4c3e9b5SBjoern A. Zeeb 	/* Extract trx header */
1128*22741535SBjoern A. Zeeb #if defined(__linux__)
1129b4c3e9b5SBjoern A. Zeeb 	trx = (struct trx_header_le *) headers;
1130*22741535SBjoern A. Zeeb #elif defined(__FreeBSD__)
1131*22741535SBjoern A. Zeeb 	trx = (const struct trx_header_le *) headers;
1132*22741535SBjoern A. Zeeb #endif
1133b4c3e9b5SBjoern A. Zeeb 	if (trx->magic != cpu_to_le32(TRX_MAGIC))
1134b4c3e9b5SBjoern A. Zeeb 		return -1;
1135b4c3e9b5SBjoern A. Zeeb 
1136b4c3e9b5SBjoern A. Zeeb 	headers += sizeof(struct trx_header_le);
1137b4c3e9b5SBjoern A. Zeeb 
1138b4c3e9b5SBjoern A. Zeeb 	if (le32_to_cpu(trx->flag_version) & TRX_UNCOMP_IMAGE) {
1139b4c3e9b5SBjoern A. Zeeb 		actual_len = le32_to_cpu(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]);
1140b4c3e9b5SBjoern A. Zeeb 		return actual_len + sizeof(struct trx_header_le);
1141b4c3e9b5SBjoern A. Zeeb 	}
1142b4c3e9b5SBjoern A. Zeeb 	return -1;
1143b4c3e9b5SBjoern A. Zeeb }
1144b4c3e9b5SBjoern A. Zeeb 
1145b4c3e9b5SBjoern A. Zeeb 
1146b4c3e9b5SBjoern A. Zeeb static
brcmf_usb_attach(struct brcmf_usbdev_info * devinfo,int nrxq,int ntxq)1147b4c3e9b5SBjoern A. Zeeb struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
1148b4c3e9b5SBjoern A. Zeeb 				      int nrxq, int ntxq)
1149b4c3e9b5SBjoern A. Zeeb {
1150b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1151b4c3e9b5SBjoern A. Zeeb 
1152b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.nrxq = nrxq;
1153b4c3e9b5SBjoern A. Zeeb 	devinfo->rx_low_watermark = nrxq / 2;
1154b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.devinfo = devinfo;
1155b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.ntxq = ntxq;
1156b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DOWN;
1157b4c3e9b5SBjoern A. Zeeb 
1158b4c3e9b5SBjoern A. Zeeb 	/* flow control when too many tx urbs posted */
1159b4c3e9b5SBjoern A. Zeeb 	devinfo->tx_low_watermark = ntxq / 4;
1160b4c3e9b5SBjoern A. Zeeb 	devinfo->tx_high_watermark = devinfo->tx_low_watermark * 3;
1161b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.bus_mtu = BRCMF_USB_MAX_PKT_SIZE;
1162b4c3e9b5SBjoern A. Zeeb 
1163b4c3e9b5SBjoern A. Zeeb 	/* Initialize other structure content */
1164b4c3e9b5SBjoern A. Zeeb 	init_waitqueue_head(&devinfo->ioctl_resp_wait);
1165b4c3e9b5SBjoern A. Zeeb 
1166b4c3e9b5SBjoern A. Zeeb 	/* Initialize the spinlocks */
1167b4c3e9b5SBjoern A. Zeeb 	spin_lock_init(&devinfo->qlock);
1168b4c3e9b5SBjoern A. Zeeb 	spin_lock_init(&devinfo->tx_flowblock_lock);
1169b4c3e9b5SBjoern A. Zeeb 
1170b4c3e9b5SBjoern A. Zeeb 	INIT_LIST_HEAD(&devinfo->rx_freeq);
1171b4c3e9b5SBjoern A. Zeeb 	INIT_LIST_HEAD(&devinfo->rx_postq);
1172b4c3e9b5SBjoern A. Zeeb 
1173b4c3e9b5SBjoern A. Zeeb 	INIT_LIST_HEAD(&devinfo->tx_freeq);
1174b4c3e9b5SBjoern A. Zeeb 	INIT_LIST_HEAD(&devinfo->tx_postq);
1175b4c3e9b5SBjoern A. Zeeb 
1176b4c3e9b5SBjoern A. Zeeb 	devinfo->tx_flowblock = false;
1177b4c3e9b5SBjoern A. Zeeb 
1178b4c3e9b5SBjoern A. Zeeb 	devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq);
1179b4c3e9b5SBjoern A. Zeeb 	if (!devinfo->rx_reqs)
1180b4c3e9b5SBjoern A. Zeeb 		goto error;
1181b4c3e9b5SBjoern A. Zeeb 
1182b4c3e9b5SBjoern A. Zeeb 	devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq);
1183b4c3e9b5SBjoern A. Zeeb 	if (!devinfo->tx_reqs)
1184b4c3e9b5SBjoern A. Zeeb 		goto error;
1185b4c3e9b5SBjoern A. Zeeb 	devinfo->tx_freecount = ntxq;
1186b4c3e9b5SBjoern A. Zeeb 
1187b4c3e9b5SBjoern A. Zeeb 	devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);
1188b4c3e9b5SBjoern A. Zeeb 	if (!devinfo->ctl_urb)
1189b4c3e9b5SBjoern A. Zeeb 		goto error;
1190b4c3e9b5SBjoern A. Zeeb 	devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
1191b4c3e9b5SBjoern A. Zeeb 	if (!devinfo->bulk_urb)
1192b4c3e9b5SBjoern A. Zeeb 		goto error;
1193b4c3e9b5SBjoern A. Zeeb 
1194b4c3e9b5SBjoern A. Zeeb 	return &devinfo->bus_pub;
1195b4c3e9b5SBjoern A. Zeeb 
1196b4c3e9b5SBjoern A. Zeeb error:
1197b4c3e9b5SBjoern A. Zeeb 	brcmf_err("failed!\n");
1198b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_detach(devinfo);
1199b4c3e9b5SBjoern A. Zeeb 	return NULL;
1200b4c3e9b5SBjoern A. Zeeb }
1201b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_get_blob(struct device * dev,const struct firmware ** fw,enum brcmf_blob_type type)1202b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw,
1203b4c3e9b5SBjoern A. Zeeb 			      enum brcmf_blob_type type)
1204b4c3e9b5SBjoern A. Zeeb {
1205b4c3e9b5SBjoern A. Zeeb 	/* No blobs for USB devices... */
1206b4c3e9b5SBjoern A. Zeeb 	return -ENOENT;
1207b4c3e9b5SBjoern A. Zeeb }
1208b4c3e9b5SBjoern A. Zeeb 
1209b4c3e9b5SBjoern A. Zeeb static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
1210b4c3e9b5SBjoern A. Zeeb 	.preinit = brcmf_usb_up,
1211b4c3e9b5SBjoern A. Zeeb 	.stop = brcmf_usb_down,
1212b4c3e9b5SBjoern A. Zeeb 	.txdata = brcmf_usb_tx,
1213b4c3e9b5SBjoern A. Zeeb 	.txctl = brcmf_usb_tx_ctlpkt,
1214b4c3e9b5SBjoern A. Zeeb 	.rxctl = brcmf_usb_rx_ctlpkt,
1215b4c3e9b5SBjoern A. Zeeb 	.get_blob = brcmf_usb_get_blob,
1216b4c3e9b5SBjoern A. Zeeb };
1217b4c3e9b5SBjoern A. Zeeb 
1218b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_FW_CODE	0
1219b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_probe_phase2(struct device * dev,int ret,struct brcmf_fw_request * fwreq)1220b4c3e9b5SBjoern A. Zeeb static void brcmf_usb_probe_phase2(struct device *dev, int ret,
1221b4c3e9b5SBjoern A. Zeeb 				   struct brcmf_fw_request *fwreq)
1222b4c3e9b5SBjoern A. Zeeb {
1223b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus = dev_get_drvdata(dev);
1224b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo;
1225b4c3e9b5SBjoern A. Zeeb 	const struct firmware *fw;
1226b4c3e9b5SBjoern A. Zeeb 
1227b4c3e9b5SBjoern A. Zeeb 	if (ret)
1228b4c3e9b5SBjoern A. Zeeb 		goto error;
1229b4c3e9b5SBjoern A. Zeeb 
1230b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Start fw downloading\n");
1231b4c3e9b5SBjoern A. Zeeb 
1232b4c3e9b5SBjoern A. Zeeb 	fw = fwreq->items[BRCMF_USB_FW_CODE].binary;
1233b4c3e9b5SBjoern A. Zeeb 	kfree(fwreq);
1234*22741535SBjoern A. Zeeb #if defined(__FreeBSD__)
1235*22741535SBjoern A. Zeeb 	if (fw == NULL)
1236*22741535SBjoern A. Zeeb 		goto error;
1237*22741535SBjoern A. Zeeb #endif
1238b4c3e9b5SBjoern A. Zeeb 
1239b4c3e9b5SBjoern A. Zeeb 	ret = check_file(fw->data);
1240b4c3e9b5SBjoern A. Zeeb 	if (ret < 0) {
1241b4c3e9b5SBjoern A. Zeeb 		brcmf_err("invalid firmware\n");
1242b4c3e9b5SBjoern A. Zeeb 		release_firmware(fw);
1243b4c3e9b5SBjoern A. Zeeb 		goto error;
1244b4c3e9b5SBjoern A. Zeeb 	}
1245b4c3e9b5SBjoern A. Zeeb 
1246b4c3e9b5SBjoern A. Zeeb 	devinfo->image = fw->data;
1247b4c3e9b5SBjoern A. Zeeb 	devinfo->image_len = fw->size;
1248b4c3e9b5SBjoern A. Zeeb 
1249b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_usb_fw_download(devinfo);
1250b4c3e9b5SBjoern A. Zeeb 	release_firmware(fw);
1251b4c3e9b5SBjoern A. Zeeb 	if (ret)
1252b4c3e9b5SBjoern A. Zeeb 		goto error;
1253b4c3e9b5SBjoern A. Zeeb 
1254b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_alloc(devinfo->dev, devinfo->settings);
1255b4c3e9b5SBjoern A. Zeeb 	if (ret)
1256b4c3e9b5SBjoern A. Zeeb 		goto error;
1257b4c3e9b5SBjoern A. Zeeb 
1258b4c3e9b5SBjoern A. Zeeb 	/* Attach to the common driver interface */
1259b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_attach(devinfo->dev);
1260b4c3e9b5SBjoern A. Zeeb 	if (ret)
1261b4c3e9b5SBjoern A. Zeeb 		goto error;
1262b4c3e9b5SBjoern A. Zeeb 
1263b4c3e9b5SBjoern A. Zeeb 	complete(&devinfo->dev_init_done);
1264b4c3e9b5SBjoern A. Zeeb 	return;
1265b4c3e9b5SBjoern A. Zeeb error:
1266b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
1267b4c3e9b5SBjoern A. Zeeb 	complete(&devinfo->dev_init_done);
1268b4c3e9b5SBjoern A. Zeeb 	device_release_driver(dev);
1269b4c3e9b5SBjoern A. Zeeb }
1270b4c3e9b5SBjoern A. Zeeb 
1271b4c3e9b5SBjoern A. Zeeb static struct brcmf_fw_request *
brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info * devinfo)1272b4c3e9b5SBjoern A. Zeeb brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)
1273b4c3e9b5SBjoern A. Zeeb {
1274b4c3e9b5SBjoern A. Zeeb 	struct brcmf_fw_request *fwreq;
1275b4c3e9b5SBjoern A. Zeeb 	struct brcmf_fw_name fwnames[] = {
1276b4c3e9b5SBjoern A. Zeeb 		{ ".bin", devinfo->fw_name },
1277b4c3e9b5SBjoern A. Zeeb 	};
1278b4c3e9b5SBjoern A. Zeeb 
1279b4c3e9b5SBjoern A. Zeeb 	fwreq = brcmf_fw_alloc_request(devinfo->bus_pub.devid,
1280b4c3e9b5SBjoern A. Zeeb 				       devinfo->bus_pub.chiprev,
1281b4c3e9b5SBjoern A. Zeeb 				       brcmf_usb_fwnames,
1282b4c3e9b5SBjoern A. Zeeb 				       ARRAY_SIZE(brcmf_usb_fwnames),
1283b4c3e9b5SBjoern A. Zeeb 				       fwnames, ARRAY_SIZE(fwnames));
1284b4c3e9b5SBjoern A. Zeeb 	if (!fwreq)
1285b4c3e9b5SBjoern A. Zeeb 		return NULL;
1286b4c3e9b5SBjoern A. Zeeb 
1287b4c3e9b5SBjoern A. Zeeb 	fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
1288b4c3e9b5SBjoern A. Zeeb 
1289b4c3e9b5SBjoern A. Zeeb 	return fwreq;
1290b4c3e9b5SBjoern A. Zeeb }
1291b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_probe_cb(struct brcmf_usbdev_info * devinfo,enum brcmf_fwvendor fwvid)1292b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
1293b4c3e9b5SBjoern A. Zeeb 			      enum brcmf_fwvendor fwvid)
1294b4c3e9b5SBjoern A. Zeeb {
1295b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus;
1296b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev *bus_pub;
1297b4c3e9b5SBjoern A. Zeeb 	struct device *dev = devinfo->dev;
1298b4c3e9b5SBjoern A. Zeeb 	struct brcmf_fw_request *fwreq;
1299b4c3e9b5SBjoern A. Zeeb 	int ret;
1300b4c3e9b5SBjoern A. Zeeb 
1301b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1302b4c3e9b5SBjoern A. Zeeb 	bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);
1303b4c3e9b5SBjoern A. Zeeb 	if (!bus_pub)
1304b4c3e9b5SBjoern A. Zeeb 		return -ENODEV;
1305b4c3e9b5SBjoern A. Zeeb 
1306b4c3e9b5SBjoern A. Zeeb 	bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
1307b4c3e9b5SBjoern A. Zeeb 	if (!bus) {
1308b4c3e9b5SBjoern A. Zeeb 		ret = -ENOMEM;
1309b4c3e9b5SBjoern A. Zeeb 		goto fail;
1310b4c3e9b5SBjoern A. Zeeb 	}
1311b4c3e9b5SBjoern A. Zeeb 
1312b4c3e9b5SBjoern A. Zeeb 	bus->dev = dev;
1313b4c3e9b5SBjoern A. Zeeb 	bus_pub->bus = bus;
1314b4c3e9b5SBjoern A. Zeeb 	bus->bus_priv.usb = bus_pub;
1315b4c3e9b5SBjoern A. Zeeb 	dev_set_drvdata(dev, bus);
1316b4c3e9b5SBjoern A. Zeeb 	bus->ops = &brcmf_usb_bus_ops;
1317b4c3e9b5SBjoern A. Zeeb 	bus->proto_type = BRCMF_PROTO_BCDC;
1318b4c3e9b5SBjoern A. Zeeb 	bus->fwvid = fwvid;
1319b4c3e9b5SBjoern A. Zeeb 	bus->always_use_fws_queue = true;
1320b4c3e9b5SBjoern A. Zeeb #ifdef CONFIG_PM
1321b4c3e9b5SBjoern A. Zeeb 	bus->wowl_supported = true;
1322b4c3e9b5SBjoern A. Zeeb #endif
1323b4c3e9b5SBjoern A. Zeeb 
1324b4c3e9b5SBjoern A. Zeeb 	devinfo->settings = brcmf_get_module_param(bus->dev, BRCMF_BUSTYPE_USB,
1325b4c3e9b5SBjoern A. Zeeb 						   bus_pub->devid,
1326b4c3e9b5SBjoern A. Zeeb 						   bus_pub->chiprev);
1327b4c3e9b5SBjoern A. Zeeb 	if (!devinfo->settings) {
1328b4c3e9b5SBjoern A. Zeeb 		ret = -ENOMEM;
1329b4c3e9b5SBjoern A. Zeeb 		goto fail;
1330b4c3e9b5SBjoern A. Zeeb 	}
1331b4c3e9b5SBjoern A. Zeeb 	ret = PTR_ERR_OR_ZERO(devinfo->settings);
1332b4c3e9b5SBjoern A. Zeeb 	if (ret < 0)
1333b4c3e9b5SBjoern A. Zeeb 		goto fail;
1334b4c3e9b5SBjoern A. Zeeb 
1335b4c3e9b5SBjoern A. Zeeb 	if (!brcmf_usb_dlneeded(devinfo)) {
1336b4c3e9b5SBjoern A. Zeeb 		ret = brcmf_alloc(devinfo->dev, devinfo->settings);
1337b4c3e9b5SBjoern A. Zeeb 		if (ret)
1338b4c3e9b5SBjoern A. Zeeb 			goto fail;
1339b4c3e9b5SBjoern A. Zeeb 		ret = brcmf_attach(devinfo->dev);
1340b4c3e9b5SBjoern A. Zeeb 		if (ret)
1341b4c3e9b5SBjoern A. Zeeb 			goto fail;
1342b4c3e9b5SBjoern A. Zeeb 		/* we are done */
1343b4c3e9b5SBjoern A. Zeeb 		complete(&devinfo->dev_init_done);
1344b4c3e9b5SBjoern A. Zeeb 		return 0;
1345b4c3e9b5SBjoern A. Zeeb 	}
1346b4c3e9b5SBjoern A. Zeeb 	bus->chip = bus_pub->devid;
1347b4c3e9b5SBjoern A. Zeeb 	bus->chiprev = bus_pub->chiprev;
1348b4c3e9b5SBjoern A. Zeeb 
1349b4c3e9b5SBjoern A. Zeeb 	fwreq = brcmf_usb_prepare_fw_request(devinfo);
1350b4c3e9b5SBjoern A. Zeeb 	if (!fwreq) {
1351b4c3e9b5SBjoern A. Zeeb 		ret = -ENOMEM;
1352b4c3e9b5SBjoern A. Zeeb 		goto fail;
1353b4c3e9b5SBjoern A. Zeeb 	}
1354b4c3e9b5SBjoern A. Zeeb 
1355b4c3e9b5SBjoern A. Zeeb 	/* request firmware here */
1356b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);
1357b4c3e9b5SBjoern A. Zeeb 	if (ret) {
1358b4c3e9b5SBjoern A. Zeeb 		brcmf_err("firmware request failed: %d\n", ret);
1359b4c3e9b5SBjoern A. Zeeb 		kfree(fwreq);
1360b4c3e9b5SBjoern A. Zeeb 		goto fail;
1361b4c3e9b5SBjoern A. Zeeb 	}
1362b4c3e9b5SBjoern A. Zeeb 
1363b4c3e9b5SBjoern A. Zeeb 	return 0;
1364b4c3e9b5SBjoern A. Zeeb 
1365b4c3e9b5SBjoern A. Zeeb fail:
1366b4c3e9b5SBjoern A. Zeeb 	/* Release resources in reverse order */
1367b4c3e9b5SBjoern A. Zeeb 	brcmf_free(devinfo->dev);
1368b4c3e9b5SBjoern A. Zeeb 	kfree(bus);
1369b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_detach(devinfo);
1370b4c3e9b5SBjoern A. Zeeb 	return ret;
1371b4c3e9b5SBjoern A. Zeeb }
1372b4c3e9b5SBjoern A. Zeeb 
1373b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_disconnect_cb(struct brcmf_usbdev_info * devinfo)1374b4c3e9b5SBjoern A. Zeeb brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
1375b4c3e9b5SBjoern A. Zeeb {
1376b4c3e9b5SBjoern A. Zeeb 	if (!devinfo)
1377b4c3e9b5SBjoern A. Zeeb 		return;
1378b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
1379b4c3e9b5SBjoern A. Zeeb 
1380b4c3e9b5SBjoern A. Zeeb 	brcmf_detach(devinfo->dev);
1381b4c3e9b5SBjoern A. Zeeb 	brcmf_free(devinfo->dev);
1382b4c3e9b5SBjoern A. Zeeb 	kfree(devinfo->bus_pub.bus);
1383b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_detach(devinfo);
1384b4c3e9b5SBjoern A. Zeeb }
1385b4c3e9b5SBjoern A. Zeeb 
1386b4c3e9b5SBjoern A. Zeeb /* Forward declaration for usb_match_id() call */
1387b4c3e9b5SBjoern A. Zeeb static const struct usb_device_id brcmf_usb_devid_table[];
1388b4c3e9b5SBjoern A. Zeeb 
1389b4c3e9b5SBjoern A. Zeeb static int
brcmf_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)1390b4c3e9b5SBjoern A. Zeeb brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
1391b4c3e9b5SBjoern A. Zeeb {
1392b4c3e9b5SBjoern A. Zeeb 	struct usb_device *usb = interface_to_usbdev(intf);
1393b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo;
1394b4c3e9b5SBjoern A. Zeeb 	struct usb_interface_descriptor	*desc;
1395b4c3e9b5SBjoern A. Zeeb 	struct usb_endpoint_descriptor *endpoint;
1396b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
1397b4c3e9b5SBjoern A. Zeeb 	u32 num_of_eps;
1398b4c3e9b5SBjoern A. Zeeb 	u8 endpoint_num, ep;
1399b4c3e9b5SBjoern A. Zeeb 
1400b4c3e9b5SBjoern A. Zeeb 	if (!id) {
1401b4c3e9b5SBjoern A. Zeeb 		id = usb_match_id(intf, brcmf_usb_devid_table);
1402b4c3e9b5SBjoern A. Zeeb 		if (!id) {
1403b4c3e9b5SBjoern A. Zeeb 			dev_err(&intf->dev, "Error could not find matching usb_device_id\n");
1404b4c3e9b5SBjoern A. Zeeb 			return -ENODEV;
1405b4c3e9b5SBjoern A. Zeeb 		}
1406b4c3e9b5SBjoern A. Zeeb 	}
1407b4c3e9b5SBjoern A. Zeeb 
1408b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct);
1409b4c3e9b5SBjoern A. Zeeb 
1410b4c3e9b5SBjoern A. Zeeb 	devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
1411b4c3e9b5SBjoern A. Zeeb 	if (devinfo == NULL)
1412b4c3e9b5SBjoern A. Zeeb 		return -ENOMEM;
1413b4c3e9b5SBjoern A. Zeeb 
1414b4c3e9b5SBjoern A. Zeeb 	devinfo->usbdev = usb;
1415b4c3e9b5SBjoern A. Zeeb 	devinfo->dev = &usb->dev;
1416b4c3e9b5SBjoern A. Zeeb 	/* Init completion, to protect for disconnect while still loading.
1417b4c3e9b5SBjoern A. Zeeb 	 * Necessary because of the asynchronous firmware load construction
1418b4c3e9b5SBjoern A. Zeeb 	 */
1419b4c3e9b5SBjoern A. Zeeb 	init_completion(&devinfo->dev_init_done);
1420b4c3e9b5SBjoern A. Zeeb 
1421b4c3e9b5SBjoern A. Zeeb 	usb_set_intfdata(intf, devinfo);
1422b4c3e9b5SBjoern A. Zeeb 
1423b4c3e9b5SBjoern A. Zeeb 	intf->needs_remote_wakeup = 1;
1424b4c3e9b5SBjoern A. Zeeb 
1425b4c3e9b5SBjoern A. Zeeb 	/* Check that the device supports only one configuration */
1426b4c3e9b5SBjoern A. Zeeb 	if (usb->descriptor.bNumConfigurations != 1) {
1427b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Number of configurations: %d not supported\n",
1428b4c3e9b5SBjoern A. Zeeb 			  usb->descriptor.bNumConfigurations);
1429b4c3e9b5SBjoern A. Zeeb 		ret = -ENODEV;
1430b4c3e9b5SBjoern A. Zeeb 		goto fail;
1431b4c3e9b5SBjoern A. Zeeb 	}
1432b4c3e9b5SBjoern A. Zeeb 
1433b4c3e9b5SBjoern A. Zeeb 	if ((usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) &&
1434b4c3e9b5SBjoern A. Zeeb 	    (usb->descriptor.bDeviceClass != USB_CLASS_MISC) &&
1435b4c3e9b5SBjoern A. Zeeb 	    (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS_CONTROLLER)) {
1436b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Device class: 0x%x not supported\n",
1437b4c3e9b5SBjoern A. Zeeb 			  usb->descriptor.bDeviceClass);
1438b4c3e9b5SBjoern A. Zeeb 		ret = -ENODEV;
1439b4c3e9b5SBjoern A. Zeeb 		goto fail;
1440b4c3e9b5SBjoern A. Zeeb 	}
1441b4c3e9b5SBjoern A. Zeeb 
1442b4c3e9b5SBjoern A. Zeeb 	desc = &intf->cur_altsetting->desc;
1443b4c3e9b5SBjoern A. Zeeb 	if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
1444b4c3e9b5SBjoern A. Zeeb 	    (desc->bInterfaceSubClass != 2) ||
1445b4c3e9b5SBjoern A. Zeeb 	    (desc->bInterfaceProtocol != 0xff)) {
1446b4c3e9b5SBjoern A. Zeeb 		brcmf_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n",
1447b4c3e9b5SBjoern A. Zeeb 			  desc->bInterfaceNumber, desc->bInterfaceClass,
1448b4c3e9b5SBjoern A. Zeeb 			  desc->bInterfaceSubClass, desc->bInterfaceProtocol);
1449b4c3e9b5SBjoern A. Zeeb 		ret = -ENODEV;
1450b4c3e9b5SBjoern A. Zeeb 		goto fail;
1451b4c3e9b5SBjoern A. Zeeb 	}
1452b4c3e9b5SBjoern A. Zeeb 
1453b4c3e9b5SBjoern A. Zeeb 	num_of_eps = desc->bNumEndpoints;
1454b4c3e9b5SBjoern A. Zeeb 	for (ep = 0; ep < num_of_eps; ep++) {
1455b4c3e9b5SBjoern A. Zeeb 		endpoint = &intf->cur_altsetting->endpoint[ep].desc;
1456b4c3e9b5SBjoern A. Zeeb 		endpoint_num = usb_endpoint_num(endpoint);
1457b4c3e9b5SBjoern A. Zeeb 		if (!usb_endpoint_xfer_bulk(endpoint))
1458b4c3e9b5SBjoern A. Zeeb 			continue;
1459b4c3e9b5SBjoern A. Zeeb 		if (usb_endpoint_dir_in(endpoint)) {
1460b4c3e9b5SBjoern A. Zeeb 			if (!devinfo->rx_pipe)
1461b4c3e9b5SBjoern A. Zeeb 				devinfo->rx_pipe =
1462b4c3e9b5SBjoern A. Zeeb 					usb_rcvbulkpipe(usb, endpoint_num);
1463b4c3e9b5SBjoern A. Zeeb 		} else {
1464b4c3e9b5SBjoern A. Zeeb 			if (!devinfo->tx_pipe)
1465b4c3e9b5SBjoern A. Zeeb 				devinfo->tx_pipe =
1466b4c3e9b5SBjoern A. Zeeb 					usb_sndbulkpipe(usb, endpoint_num);
1467b4c3e9b5SBjoern A. Zeeb 		}
1468b4c3e9b5SBjoern A. Zeeb 	}
1469b4c3e9b5SBjoern A. Zeeb 	if (devinfo->rx_pipe == 0) {
1470b4c3e9b5SBjoern A. Zeeb 		brcmf_err("No RX (in) Bulk EP found\n");
1471b4c3e9b5SBjoern A. Zeeb 		ret = -ENODEV;
1472b4c3e9b5SBjoern A. Zeeb 		goto fail;
1473b4c3e9b5SBjoern A. Zeeb 	}
1474b4c3e9b5SBjoern A. Zeeb 	if (devinfo->tx_pipe == 0) {
1475b4c3e9b5SBjoern A. Zeeb 		brcmf_err("No TX (out) Bulk EP found\n");
1476b4c3e9b5SBjoern A. Zeeb 		ret = -ENODEV;
1477b4c3e9b5SBjoern A. Zeeb 		goto fail;
1478b4c3e9b5SBjoern A. Zeeb 	}
1479b4c3e9b5SBjoern A. Zeeb 
1480b4c3e9b5SBjoern A. Zeeb 	devinfo->ifnum = desc->bInterfaceNumber;
1481b4c3e9b5SBjoern A. Zeeb 
1482b4c3e9b5SBjoern A. Zeeb 	if (usb->speed == USB_SPEED_SUPER_PLUS)
1483b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "Broadcom super speed plus USB WLAN interface detected\n");
1484b4c3e9b5SBjoern A. Zeeb 	else if (usb->speed == USB_SPEED_SUPER)
1485b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "Broadcom super speed USB WLAN interface detected\n");
1486b4c3e9b5SBjoern A. Zeeb 	else if (usb->speed == USB_SPEED_HIGH)
1487b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "Broadcom high speed USB WLAN interface detected\n");
1488b4c3e9b5SBjoern A. Zeeb 	else
1489b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n");
1490b4c3e9b5SBjoern A. Zeeb 
1491b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_usb_probe_cb(devinfo, id->driver_info);
1492b4c3e9b5SBjoern A. Zeeb 	if (ret)
1493b4c3e9b5SBjoern A. Zeeb 		goto fail;
1494b4c3e9b5SBjoern A. Zeeb 
1495b4c3e9b5SBjoern A. Zeeb 	/* Success */
1496b4c3e9b5SBjoern A. Zeeb 	return 0;
1497b4c3e9b5SBjoern A. Zeeb 
1498b4c3e9b5SBjoern A. Zeeb fail:
1499b4c3e9b5SBjoern A. Zeeb 	complete(&devinfo->dev_init_done);
1500b4c3e9b5SBjoern A. Zeeb 	kfree(devinfo);
1501b4c3e9b5SBjoern A. Zeeb 	usb_set_intfdata(intf, NULL);
1502b4c3e9b5SBjoern A. Zeeb 	return ret;
1503b4c3e9b5SBjoern A. Zeeb }
1504b4c3e9b5SBjoern A. Zeeb 
1505b4c3e9b5SBjoern A. Zeeb static void
brcmf_usb_disconnect(struct usb_interface * intf)1506b4c3e9b5SBjoern A. Zeeb brcmf_usb_disconnect(struct usb_interface *intf)
1507b4c3e9b5SBjoern A. Zeeb {
1508b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo;
1509b4c3e9b5SBjoern A. Zeeb 
1510b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1511b4c3e9b5SBjoern A. Zeeb 	devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
1512b4c3e9b5SBjoern A. Zeeb 
1513b4c3e9b5SBjoern A. Zeeb 	if (devinfo) {
1514b4c3e9b5SBjoern A. Zeeb 		wait_for_completion(&devinfo->dev_init_done);
1515b4c3e9b5SBjoern A. Zeeb 		/* Make sure that devinfo still exists. Firmware probe routines
1516b4c3e9b5SBjoern A. Zeeb 		 * may have released the device and cleared the intfdata.
1517b4c3e9b5SBjoern A. Zeeb 		 */
1518b4c3e9b5SBjoern A. Zeeb 		if (!usb_get_intfdata(intf))
1519b4c3e9b5SBjoern A. Zeeb 			goto done;
1520b4c3e9b5SBjoern A. Zeeb 
1521b4c3e9b5SBjoern A. Zeeb 		brcmf_usb_disconnect_cb(devinfo);
1522b4c3e9b5SBjoern A. Zeeb 		kfree(devinfo);
1523b4c3e9b5SBjoern A. Zeeb 	}
1524b4c3e9b5SBjoern A. Zeeb done:
1525b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Exit\n");
1526b4c3e9b5SBjoern A. Zeeb }
1527b4c3e9b5SBjoern A. Zeeb 
1528b4c3e9b5SBjoern A. Zeeb /*
1529b4c3e9b5SBjoern A. Zeeb  * only need to signal the bus being down and update the state.
1530b4c3e9b5SBjoern A. Zeeb  */
brcmf_usb_suspend(struct usb_interface * intf,pm_message_t state)1531b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
1532b4c3e9b5SBjoern A. Zeeb {
1533b4c3e9b5SBjoern A. Zeeb 	struct usb_device *usb = interface_to_usbdev(intf);
1534b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
1535b4c3e9b5SBjoern A. Zeeb 
1536b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1537b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
1538b4c3e9b5SBjoern A. Zeeb 	brcmf_cancel_all_urbs(devinfo);
1539b4c3e9b5SBjoern A. Zeeb 	device_set_wakeup_enable(devinfo->dev, true);
1540b4c3e9b5SBjoern A. Zeeb 	return 0;
1541b4c3e9b5SBjoern A. Zeeb }
1542b4c3e9b5SBjoern A. Zeeb 
1543b4c3e9b5SBjoern A. Zeeb /*
1544b4c3e9b5SBjoern A. Zeeb  * (re-) start the bus.
1545b4c3e9b5SBjoern A. Zeeb  */
brcmf_usb_resume(struct usb_interface * intf)1546b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_resume(struct usb_interface *intf)
1547b4c3e9b5SBjoern A. Zeeb {
1548b4c3e9b5SBjoern A. Zeeb 	struct usb_device *usb = interface_to_usbdev(intf);
1549b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
1550b4c3e9b5SBjoern A. Zeeb 
1551b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1552b4c3e9b5SBjoern A. Zeeb 
1553b4c3e9b5SBjoern A. Zeeb 	devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
1554b4c3e9b5SBjoern A. Zeeb 	brcmf_usb_rx_fill_all(devinfo);
1555b4c3e9b5SBjoern A. Zeeb 	device_set_wakeup_enable(devinfo->dev, false);
1556b4c3e9b5SBjoern A. Zeeb 	return 0;
1557b4c3e9b5SBjoern A. Zeeb }
1558b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_reset_resume(struct usb_interface * intf)1559b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_reset_resume(struct usb_interface *intf)
1560b4c3e9b5SBjoern A. Zeeb {
1561b4c3e9b5SBjoern A. Zeeb 	struct usb_device *usb = interface_to_usbdev(intf);
1562b4c3e9b5SBjoern A. Zeeb 	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
1563b4c3e9b5SBjoern A. Zeeb 	struct brcmf_fw_request *fwreq;
1564b4c3e9b5SBjoern A. Zeeb 	int ret;
1565b4c3e9b5SBjoern A. Zeeb 
1566b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1567b4c3e9b5SBjoern A. Zeeb 
1568b4c3e9b5SBjoern A. Zeeb 	fwreq = brcmf_usb_prepare_fw_request(devinfo);
1569b4c3e9b5SBjoern A. Zeeb 	if (!fwreq)
1570b4c3e9b5SBjoern A. Zeeb 		return -ENOMEM;
1571b4c3e9b5SBjoern A. Zeeb 
1572b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_fw_get_firmwares(&usb->dev, fwreq, brcmf_usb_probe_phase2);
1573b4c3e9b5SBjoern A. Zeeb 	if (ret < 0)
1574b4c3e9b5SBjoern A. Zeeb 		kfree(fwreq);
1575b4c3e9b5SBjoern A. Zeeb 
1576b4c3e9b5SBjoern A. Zeeb 	return ret;
1577b4c3e9b5SBjoern A. Zeeb }
1578b4c3e9b5SBjoern A. Zeeb 
1579b4c3e9b5SBjoern A. Zeeb #define BRCMF_USB_DEVICE(dev_id) \
1580b4c3e9b5SBjoern A. Zeeb 	{ \
1581b4c3e9b5SBjoern A. Zeeb 		USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id), \
1582b4c3e9b5SBjoern A. Zeeb 		.driver_info = BRCMF_FWVENDOR_WCC \
1583b4c3e9b5SBjoern A. Zeeb 	}
1584b4c3e9b5SBjoern A. Zeeb 
1585b4c3e9b5SBjoern A. Zeeb #define LINKSYS_USB_DEVICE(dev_id) \
1586b4c3e9b5SBjoern A. Zeeb 	{ \
1587b4c3e9b5SBjoern A. Zeeb 		USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id), \
1588b4c3e9b5SBjoern A. Zeeb 		.driver_info = BRCMF_FWVENDOR_WCC \
1589b4c3e9b5SBjoern A. Zeeb 	}
1590b4c3e9b5SBjoern A. Zeeb 
1591b4c3e9b5SBjoern A. Zeeb #define CYPRESS_USB_DEVICE(dev_id) \
1592b4c3e9b5SBjoern A. Zeeb 	{ \
1593b4c3e9b5SBjoern A. Zeeb 		USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, dev_id), \
1594b4c3e9b5SBjoern A. Zeeb 		.driver_info = BRCMF_FWVENDOR_WCC \
1595b4c3e9b5SBjoern A. Zeeb 	}
1596b4c3e9b5SBjoern A. Zeeb 
1597b4c3e9b5SBjoern A. Zeeb static const struct usb_device_id brcmf_usb_devid_table[] = {
1598b4c3e9b5SBjoern A. Zeeb 	BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),
1599b4c3e9b5SBjoern A. Zeeb 	BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID),
1600b4c3e9b5SBjoern A. Zeeb 	BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID),
1601b4c3e9b5SBjoern A. Zeeb 	BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID),
1602b4c3e9b5SBjoern A. Zeeb 	LINKSYS_USB_DEVICE(BRCM_USB_43235_LINKSYS_DEVICE_ID),
1603b4c3e9b5SBjoern A. Zeeb 	CYPRESS_USB_DEVICE(CY_USB_4373_DEVICE_ID),
1604b4c3e9b5SBjoern A. Zeeb 	{ USB_DEVICE(BRCM_USB_VENDOR_ID_LG, BRCM_USB_43242_LG_DEVICE_ID) },
1605b4c3e9b5SBjoern A. Zeeb 	/* special entry for device with firmware loaded and running */
1606b4c3e9b5SBjoern A. Zeeb 	BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID),
1607b4c3e9b5SBjoern A. Zeeb 	CYPRESS_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID),
1608b4c3e9b5SBjoern A. Zeeb 	{ /* end: all zeroes */ }
1609b4c3e9b5SBjoern A. Zeeb };
1610b4c3e9b5SBjoern A. Zeeb 
1611b4c3e9b5SBjoern A. Zeeb MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
1612b4c3e9b5SBjoern A. Zeeb 
1613b4c3e9b5SBjoern A. Zeeb static struct usb_driver brcmf_usbdrvr = {
1614b4c3e9b5SBjoern A. Zeeb 	.name = KBUILD_MODNAME,
1615b4c3e9b5SBjoern A. Zeeb 	.probe = brcmf_usb_probe,
1616b4c3e9b5SBjoern A. Zeeb 	.disconnect = brcmf_usb_disconnect,
1617b4c3e9b5SBjoern A. Zeeb 	.id_table = brcmf_usb_devid_table,
1618b4c3e9b5SBjoern A. Zeeb 	.suspend = brcmf_usb_suspend,
1619b4c3e9b5SBjoern A. Zeeb 	.resume = brcmf_usb_resume,
1620b4c3e9b5SBjoern A. Zeeb 	.reset_resume = brcmf_usb_reset_resume,
1621b4c3e9b5SBjoern A. Zeeb 	.supports_autosuspend = true,
1622b4c3e9b5SBjoern A. Zeeb 	.disable_hub_initiated_lpm = 1,
1623b4c3e9b5SBjoern A. Zeeb };
1624b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_reset_device(struct device * dev,void * notused)1625b4c3e9b5SBjoern A. Zeeb static int brcmf_usb_reset_device(struct device *dev, void *notused)
1626b4c3e9b5SBjoern A. Zeeb {
1627b4c3e9b5SBjoern A. Zeeb 	/* device past is the usb interface so we
1628b4c3e9b5SBjoern A. Zeeb 	 * need to use parent here.
1629b4c3e9b5SBjoern A. Zeeb 	 */
1630b4c3e9b5SBjoern A. Zeeb 	brcmf_dev_reset(dev->parent);
1631b4c3e9b5SBjoern A. Zeeb 	return 0;
1632b4c3e9b5SBjoern A. Zeeb }
1633b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_exit(void)1634b4c3e9b5SBjoern A. Zeeb void brcmf_usb_exit(void)
1635b4c3e9b5SBjoern A. Zeeb {
1636b4c3e9b5SBjoern A. Zeeb 	struct device_driver *drv = &brcmf_usbdrvr.driver;
1637b4c3e9b5SBjoern A. Zeeb 	int ret;
1638b4c3e9b5SBjoern A. Zeeb 
1639b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1640b4c3e9b5SBjoern A. Zeeb 	ret = driver_for_each_device(drv, NULL, NULL,
1641b4c3e9b5SBjoern A. Zeeb 				     brcmf_usb_reset_device);
1642b4c3e9b5SBjoern A. Zeeb 	if (ret)
1643b4c3e9b5SBjoern A. Zeeb 		brcmf_err("failed to reset all usb devices %d\n", ret);
1644b4c3e9b5SBjoern A. Zeeb 
1645b4c3e9b5SBjoern A. Zeeb 	usb_deregister(&brcmf_usbdrvr);
1646b4c3e9b5SBjoern A. Zeeb }
1647b4c3e9b5SBjoern A. Zeeb 
brcmf_usb_register(void)1648b4c3e9b5SBjoern A. Zeeb int brcmf_usb_register(void)
1649b4c3e9b5SBjoern A. Zeeb {
1650b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(USB, "Enter\n");
1651b4c3e9b5SBjoern A. Zeeb 	return usb_register(&brcmf_usbdrvr);
1652b4c3e9b5SBjoern A. Zeeb }
1653*22741535SBjoern A. Zeeb 
1654*22741535SBjoern A. Zeeb #if defined(__FreeBSD__)
1655*22741535SBjoern A. Zeeb MODULE_DEPEND(brcmfmac, linuxkpi_usb, 1, 1, 1);
1656*22741535SBjoern A. Zeeb #endif
1657