xref: /linux/drivers/net/wireless/zydas/zd1211rw/zd_usb.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
266bb42fdSDaniel Drake /* ZD1211 USB-WLAN driver for Linux
366bb42fdSDaniel Drake  *
466bb42fdSDaniel Drake  * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
566bb42fdSDaniel Drake  * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
666bb42fdSDaniel Drake  * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net>
7e85d0918SDaniel Drake  */
8e85d0918SDaniel Drake 
9d066c219SDaniel Drake #include <linux/kernel.h>
10e85d0918SDaniel Drake #include <linux/init.h>
11e85d0918SDaniel Drake #include <linux/firmware.h>
12e85d0918SDaniel Drake #include <linux/device.h>
13e85d0918SDaniel Drake #include <linux/errno.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
15e85d0918SDaniel Drake #include <linux/skbuff.h>
16e85d0918SDaniel Drake #include <linux/usb.h>
17bc5f06a8SUlrich Kunitz #include <linux/workqueue.h>
189d9779e7SPaul Gortmaker #include <linux/module.h>
19459c51adSDaniel Drake #include <net/mac80211.h>
205f60d5f6SAl Viro #include <linux/unaligned.h>
21e85d0918SDaniel Drake 
22e85d0918SDaniel Drake #include "zd_def.h"
23e85d0918SDaniel Drake #include "zd_mac.h"
24e85d0918SDaniel Drake #include "zd_usb.h"
25e85d0918SDaniel Drake 
26ecf23a78SArvind Yadav static const struct usb_device_id usb_ids[] = {
27e85d0918SDaniel Drake 	/* ZD1211 */
283bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
293bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
303bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
313bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
323bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
333bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
343bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
35e85d0918SDaniel Drake 	{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
3614990c69SHin-Tak Leung 	{ USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
373bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
383bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
393bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
40e85d0918SDaniel Drake 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
41aa1d3a18SMatthew Davidson 	{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
423bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
43ababda03SUlrich Kunitz 	{ USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
443bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
453bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
468cecc90eSmaximilian attems 	{ USB_DEVICE(0x14ea, 0xab10), .driver_info = DEVICE_ZD1211 },
473bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
48269fca0eSDaniel Drake 	{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
493bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
503bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
519011cd25STõnu Samuel 	{ USB_DEVICE(0x157e, 0x3207), .driver_info = DEVICE_ZD1211 },
523bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
533bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
54e85d0918SDaniel Drake 	/* ZD1211B */
55019a6755SUlrich Kunitz 	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
56ad580db5SHin-Tak Leung 	{ USB_DEVICE(0x0409, 0x0248), .driver_info = DEVICE_ZD1211B },
5793f510bbSDaniel Drake 	{ USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
583bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
5961ef6062SDaniel Drake 	{ USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
603bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
613bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
623bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
633bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
643bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
653bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
663bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
673bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
683bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
693bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
708f75e07aSHin-Tak Leung 	{ USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
713bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
723bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
733bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
743bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
753bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
763bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
773bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
783bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
793bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
803bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
813bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
823bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
833bfbe80eSHin-Tak Leung 	{ USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
848cecc90eSmaximilian attems 	{ USB_DEVICE(0x2019, 0xed01), .driver_info = DEVICE_ZD1211B },
85a1030e92SDaniel Drake 	/* "Driverless" devices that need ejecting */
86a1030e92SDaniel Drake 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
87aa1d3a18SMatthew Davidson 	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
88e85d0918SDaniel Drake 	{}
89e85d0918SDaniel Drake };
90e85d0918SDaniel Drake 
91e85d0918SDaniel Drake MODULE_LICENSE("GPL");
92e85d0918SDaniel Drake MODULE_DESCRIPTION("USB driver for devices with the ZD1211 chip.");
93e85d0918SDaniel Drake MODULE_AUTHOR("Ulrich Kunitz");
94e85d0918SDaniel Drake MODULE_AUTHOR("Daniel Drake");
95e85d0918SDaniel Drake MODULE_VERSION("1.0");
96e85d0918SDaniel Drake MODULE_DEVICE_TABLE(usb, usb_ids);
97e85d0918SDaniel Drake 
98e85d0918SDaniel Drake #define FW_ZD1211_PREFIX	"zd1211/zd1211_"
99e85d0918SDaniel Drake #define FW_ZD1211B_PREFIX	"zd1211/zd1211b_"
100e85d0918SDaniel Drake 
101c900eff3SJussi Kivilinna static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req,
102c900eff3SJussi Kivilinna 			    unsigned int count);
103c900eff3SJussi Kivilinna 
104e85d0918SDaniel Drake /* USB device initialization */
10572e77a8aSLuis Carlos Cobo static void int_urb_complete(struct urb *urb);
106e85d0918SDaniel Drake 
request_fw_file(const struct firmware ** fw,const char * name,struct device * device)107e85d0918SDaniel Drake static int request_fw_file(
108e85d0918SDaniel Drake 	const struct firmware **fw, const char *name, struct device *device)
109e85d0918SDaniel Drake {
110e85d0918SDaniel Drake 	int r;
111e85d0918SDaniel Drake 
112e85d0918SDaniel Drake 	dev_dbg_f(device, "fw name %s\n", name);
113e85d0918SDaniel Drake 
114e85d0918SDaniel Drake 	r = request_firmware(fw, name, device);
115e85d0918SDaniel Drake 	if (r)
116e85d0918SDaniel Drake 		dev_err(device,
117e85d0918SDaniel Drake 		       "Could not load firmware file %s. Error number %d\n",
118e85d0918SDaniel Drake 		       name, r);
119e85d0918SDaniel Drake 	return r;
120e85d0918SDaniel Drake }
121e85d0918SDaniel Drake 
get_bcdDevice(const struct usb_device * udev)122e85d0918SDaniel Drake static inline u16 get_bcdDevice(const struct usb_device *udev)
123e85d0918SDaniel Drake {
124e85d0918SDaniel Drake 	return le16_to_cpu(udev->descriptor.bcdDevice);
125e85d0918SDaniel Drake }
126e85d0918SDaniel Drake 
127e85d0918SDaniel Drake enum upload_code_flags {
128e85d0918SDaniel Drake 	REBOOT = 1,
129e85d0918SDaniel Drake };
130e85d0918SDaniel Drake 
131e85d0918SDaniel Drake /* Ensures that MAX_TRANSFER_SIZE is even. */
132e85d0918SDaniel Drake #define MAX_TRANSFER_SIZE (USB_MAX_TRANSFER_SIZE & ~1)
133e85d0918SDaniel Drake 
upload_code(struct usb_device * udev,const u8 * data,size_t size,u16 code_offset,int flags)134e85d0918SDaniel Drake static int upload_code(struct usb_device *udev,
135e85d0918SDaniel Drake 	const u8 *data, size_t size, u16 code_offset, int flags)
136e85d0918SDaniel Drake {
137e85d0918SDaniel Drake 	u8 *p;
138e85d0918SDaniel Drake 	int r;
139e85d0918SDaniel Drake 
140e85d0918SDaniel Drake 	/* USB request blocks need "kmalloced" buffers.
141e85d0918SDaniel Drake 	 */
142e85d0918SDaniel Drake 	p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
143e85d0918SDaniel Drake 	if (!p) {
144e85d0918SDaniel Drake 		r = -ENOMEM;
145e85d0918SDaniel Drake 		goto error;
146e85d0918SDaniel Drake 	}
147e85d0918SDaniel Drake 
148e85d0918SDaniel Drake 	size &= ~1;
149e85d0918SDaniel Drake 	while (size > 0) {
150e85d0918SDaniel Drake 		size_t transfer_size = size <= MAX_TRANSFER_SIZE ?
151e85d0918SDaniel Drake 			size : MAX_TRANSFER_SIZE;
152e85d0918SDaniel Drake 
153e85d0918SDaniel Drake 		dev_dbg_f(&udev->dev, "transfer size %zu\n", transfer_size);
154e85d0918SDaniel Drake 
155e85d0918SDaniel Drake 		memcpy(p, data, transfer_size);
156e85d0918SDaniel Drake 		r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
157e85d0918SDaniel Drake 			USB_REQ_FIRMWARE_DOWNLOAD,
158e85d0918SDaniel Drake 			USB_DIR_OUT | USB_TYPE_VENDOR,
159e85d0918SDaniel Drake 			code_offset, 0, p, transfer_size, 1000 /* ms */);
160e85d0918SDaniel Drake 		if (r < 0) {
161e85d0918SDaniel Drake 			dev_err(&udev->dev,
162e85d0918SDaniel Drake 			       "USB control request for firmware upload"
163e85d0918SDaniel Drake 			       " failed. Error number %d\n", r);
164e85d0918SDaniel Drake 			goto error;
165e85d0918SDaniel Drake 		}
166e85d0918SDaniel Drake 		transfer_size = r & ~1;
167e85d0918SDaniel Drake 
168e85d0918SDaniel Drake 		size -= transfer_size;
169e85d0918SDaniel Drake 		data += transfer_size;
170e85d0918SDaniel Drake 		code_offset += transfer_size/sizeof(u16);
171e85d0918SDaniel Drake 	}
172e85d0918SDaniel Drake 
173e85d0918SDaniel Drake 	if (flags & REBOOT) {
174e85d0918SDaniel Drake 		u8 ret;
175e85d0918SDaniel Drake 
176a8c4ea7aSAtsushi Nemoto 		/* Use "DMA-aware" buffer. */
177e85d0918SDaniel Drake 		r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
178e85d0918SDaniel Drake 			USB_REQ_FIRMWARE_CONFIRM,
179e85d0918SDaniel Drake 			USB_DIR_IN | USB_TYPE_VENDOR,
180a8c4ea7aSAtsushi Nemoto 			0, 0, p, sizeof(ret), 5000 /* ms */);
181e85d0918SDaniel Drake 		if (r != sizeof(ret)) {
182e85d0918SDaniel Drake 			dev_err(&udev->dev,
183b46b5993SColin Ian King 				"control request firmware confirmation failed."
184e85d0918SDaniel Drake 				" Return value %d\n", r);
185e85d0918SDaniel Drake 			if (r >= 0)
186e85d0918SDaniel Drake 				r = -ENODEV;
187e85d0918SDaniel Drake 			goto error;
188e85d0918SDaniel Drake 		}
189a8c4ea7aSAtsushi Nemoto 		ret = p[0];
190e85d0918SDaniel Drake 		if (ret & 0x80) {
191e85d0918SDaniel Drake 			dev_err(&udev->dev,
192e85d0918SDaniel Drake 				"Internal error while downloading."
193e85d0918SDaniel Drake 				" Firmware confirm return value %#04x\n",
194e85d0918SDaniel Drake 				(unsigned int)ret);
195e85d0918SDaniel Drake 			r = -ENODEV;
196e85d0918SDaniel Drake 			goto error;
197e85d0918SDaniel Drake 		}
198e85d0918SDaniel Drake 		dev_dbg_f(&udev->dev, "firmware confirm return value %#04x\n",
199e85d0918SDaniel Drake 			(unsigned int)ret);
200e85d0918SDaniel Drake 	}
201e85d0918SDaniel Drake 
202e85d0918SDaniel Drake 	r = 0;
203e85d0918SDaniel Drake error:
204e85d0918SDaniel Drake 	kfree(p);
205e85d0918SDaniel Drake 	return r;
206e85d0918SDaniel Drake }
207e85d0918SDaniel Drake 
get_word(const void * data,u16 offset)208e85d0918SDaniel Drake static u16 get_word(const void *data, u16 offset)
209e85d0918SDaniel Drake {
210e85d0918SDaniel Drake 	const __le16 *p = data;
211e85d0918SDaniel Drake 	return le16_to_cpu(p[offset]);
212e85d0918SDaniel Drake }
213e85d0918SDaniel Drake 
get_fw_name(struct zd_usb * usb,char * buffer,size_t size,const char * postfix)21474553aedSDaniel Drake static char *get_fw_name(struct zd_usb *usb, char *buffer, size_t size,
215e85d0918SDaniel Drake 	               const char* postfix)
216e85d0918SDaniel Drake {
217e85d0918SDaniel Drake 	scnprintf(buffer, size, "%s%s",
21874553aedSDaniel Drake 		usb->is_zd1211b ?
219e85d0918SDaniel Drake 			FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
220e85d0918SDaniel Drake 		postfix);
221e85d0918SDaniel Drake 	return buffer;
222e85d0918SDaniel Drake }
223e85d0918SDaniel Drake 
handle_version_mismatch(struct zd_usb * usb,const struct firmware * ub_fw)22474553aedSDaniel Drake static int handle_version_mismatch(struct zd_usb *usb,
225d066c219SDaniel Drake 	const struct firmware *ub_fw)
226d066c219SDaniel Drake {
22774553aedSDaniel Drake 	struct usb_device *udev = zd_usb_to_usbdev(usb);
228d066c219SDaniel Drake 	const struct firmware *ur_fw = NULL;
229d066c219SDaniel Drake 	int offset;
230d066c219SDaniel Drake 	int r = 0;
231d066c219SDaniel Drake 	char fw_name[128];
232d066c219SDaniel Drake 
233d066c219SDaniel Drake 	r = request_fw_file(&ur_fw,
23474553aedSDaniel Drake 		get_fw_name(usb, fw_name, sizeof(fw_name), "ur"),
235d066c219SDaniel Drake 		&udev->dev);
236d066c219SDaniel Drake 	if (r)
237d066c219SDaniel Drake 		goto error;
238d066c219SDaniel Drake 
239ee302767SDaniel Drake 	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
240d066c219SDaniel Drake 	if (r)
241d066c219SDaniel Drake 		goto error;
242d066c219SDaniel Drake 
243ee302767SDaniel Drake 	offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
244d066c219SDaniel Drake 	r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
245ee302767SDaniel Drake 		E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
246d066c219SDaniel Drake 
247d066c219SDaniel Drake 	/* At this point, the vendor driver downloads the whole firmware
248d066c219SDaniel Drake 	 * image, hacks around with version IDs, and uploads it again,
249d066c219SDaniel Drake 	 * completely overwriting the boot code. We do not do this here as
250d066c219SDaniel Drake 	 * it is not required on any tested devices, and it is suspected to
251d066c219SDaniel Drake 	 * cause problems. */
252d066c219SDaniel Drake error:
253d066c219SDaniel Drake 	release_firmware(ur_fw);
254d066c219SDaniel Drake 	return r;
255d066c219SDaniel Drake }
256d066c219SDaniel Drake 
upload_firmware(struct zd_usb * usb)25774553aedSDaniel Drake static int upload_firmware(struct zd_usb *usb)
258e85d0918SDaniel Drake {
259e85d0918SDaniel Drake 	int r;
260e85d0918SDaniel Drake 	u16 fw_bcdDevice;
261e85d0918SDaniel Drake 	u16 bcdDevice;
26274553aedSDaniel Drake 	struct usb_device *udev = zd_usb_to_usbdev(usb);
263e85d0918SDaniel Drake 	const struct firmware *ub_fw = NULL;
264e85d0918SDaniel Drake 	const struct firmware *uph_fw = NULL;
265e85d0918SDaniel Drake 	char fw_name[128];
266e85d0918SDaniel Drake 
267e85d0918SDaniel Drake 	bcdDevice = get_bcdDevice(udev);
268e85d0918SDaniel Drake 
269e85d0918SDaniel Drake 	r = request_fw_file(&ub_fw,
27074553aedSDaniel Drake 		get_fw_name(usb, fw_name, sizeof(fw_name), "ub"),
271e85d0918SDaniel Drake 		&udev->dev);
272e85d0918SDaniel Drake 	if (r)
273e85d0918SDaniel Drake 		goto error;
274e85d0918SDaniel Drake 
275ee302767SDaniel Drake 	fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
276e85d0918SDaniel Drake 
277e85d0918SDaniel Drake 	if (fw_bcdDevice != bcdDevice) {
278e85d0918SDaniel Drake 		dev_info(&udev->dev,
279d066c219SDaniel Drake 			"firmware version %#06x and device bootcode version "
280d066c219SDaniel Drake 			"%#06x differ\n", fw_bcdDevice, bcdDevice);
281d066c219SDaniel Drake 		if (bcdDevice <= 0x4313)
282d066c219SDaniel Drake 			dev_warn(&udev->dev, "device has old bootcode, please "
283d066c219SDaniel Drake 				"report success or failure\n");
284d066c219SDaniel Drake 
28574553aedSDaniel Drake 		r = handle_version_mismatch(usb, ub_fw);
286d066c219SDaniel Drake 		if (r)
287d066c219SDaniel Drake 			goto error;
288e85d0918SDaniel Drake 	} else {
289e85d0918SDaniel Drake 		dev_dbg_f(&udev->dev,
290e85d0918SDaniel Drake 			"firmware device id %#06x is equal to the "
291e85d0918SDaniel Drake 			"actual device id\n", fw_bcdDevice);
292e85d0918SDaniel Drake 	}
293e85d0918SDaniel Drake 
294e85d0918SDaniel Drake 
295e85d0918SDaniel Drake 	r = request_fw_file(&uph_fw,
29674553aedSDaniel Drake 		get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"),
297e85d0918SDaniel Drake 		&udev->dev);
298e85d0918SDaniel Drake 	if (r)
299e85d0918SDaniel Drake 		goto error;
300e85d0918SDaniel Drake 
301ee302767SDaniel Drake 	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
302e85d0918SDaniel Drake 	if (r) {
303e85d0918SDaniel Drake 		dev_err(&udev->dev,
304e85d0918SDaniel Drake 			"Could not upload firmware code uph. Error number %d\n",
305e85d0918SDaniel Drake 			r);
306e85d0918SDaniel Drake 	}
307e85d0918SDaniel Drake 
308e85d0918SDaniel Drake 	/* FALL-THROUGH */
309e85d0918SDaniel Drake error:
310e85d0918SDaniel Drake 	release_firmware(ub_fw);
311e85d0918SDaniel Drake 	release_firmware(uph_fw);
312e85d0918SDaniel Drake 	return r;
313e85d0918SDaniel Drake }
314e85d0918SDaniel Drake 
3153e8b4d00SBen Hutchings MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur");
3163e8b4d00SBen Hutchings MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur");
3173e8b4d00SBen Hutchings MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub");
3183e8b4d00SBen Hutchings MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub");
3193e8b4d00SBen Hutchings MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr");
3203e8b4d00SBen Hutchings MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr");
3213e8b4d00SBen Hutchings 
32274553aedSDaniel Drake /* Read data from device address space using "firmware interface" which does
32374553aedSDaniel Drake  * not require firmware to be loaded. */
zd_usb_read_fw(struct zd_usb * usb,zd_addr_t addr,u8 * data,u16 len)32474553aedSDaniel Drake int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)
32574553aedSDaniel Drake {
32674553aedSDaniel Drake 	int r;
32774553aedSDaniel Drake 	struct usb_device *udev = zd_usb_to_usbdev(usb);
328a8c4ea7aSAtsushi Nemoto 	u8 *buf;
32974553aedSDaniel Drake 
330a8c4ea7aSAtsushi Nemoto 	/* Use "DMA-aware" buffer. */
331a8c4ea7aSAtsushi Nemoto 	buf = kmalloc(len, GFP_KERNEL);
332a8c4ea7aSAtsushi Nemoto 	if (!buf)
333a8c4ea7aSAtsushi Nemoto 		return -ENOMEM;
33474553aedSDaniel Drake 	r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
33574553aedSDaniel Drake 		USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
336a8c4ea7aSAtsushi Nemoto 		buf, len, 5000);
33774553aedSDaniel Drake 	if (r < 0) {
33874553aedSDaniel Drake 		dev_err(&udev->dev,
33974553aedSDaniel Drake 			"read over firmware interface failed: %d\n", r);
340a8c4ea7aSAtsushi Nemoto 		goto exit;
34174553aedSDaniel Drake 	} else if (r != len) {
34274553aedSDaniel Drake 		dev_err(&udev->dev,
34374553aedSDaniel Drake 			"incomplete read over firmware interface: %d/%d\n",
34474553aedSDaniel Drake 			r, len);
345a8c4ea7aSAtsushi Nemoto 		r = -EIO;
346a8c4ea7aSAtsushi Nemoto 		goto exit;
34774553aedSDaniel Drake 	}
348a8c4ea7aSAtsushi Nemoto 	r = 0;
349a8c4ea7aSAtsushi Nemoto 	memcpy(data, buf, len);
350a8c4ea7aSAtsushi Nemoto exit:
351a8c4ea7aSAtsushi Nemoto 	kfree(buf);
352a8c4ea7aSAtsushi Nemoto 	return r;
35374553aedSDaniel Drake }
35474553aedSDaniel Drake 
355e85d0918SDaniel Drake #define urb_dev(urb) (&(urb)->dev->dev)
356e85d0918SDaniel Drake 
handle_regs_int_override(struct urb * urb)357c900eff3SJussi Kivilinna static inline void handle_regs_int_override(struct urb *urb)
358c900eff3SJussi Kivilinna {
359c900eff3SJussi Kivilinna 	struct zd_usb *usb = urb->context;
360c900eff3SJussi Kivilinna 	struct zd_usb_interrupt *intr = &usb->intr;
36181454b84SSebastian Andrzej Siewior 	unsigned long flags;
362c900eff3SJussi Kivilinna 
36381454b84SSebastian Andrzej Siewior 	spin_lock_irqsave(&intr->lock, flags);
364c900eff3SJussi Kivilinna 	if (atomic_read(&intr->read_regs_enabled)) {
365c900eff3SJussi Kivilinna 		atomic_set(&intr->read_regs_enabled, 0);
366c900eff3SJussi Kivilinna 		intr->read_regs_int_overridden = 1;
367c900eff3SJussi Kivilinna 		complete(&intr->read_regs.completion);
368c900eff3SJussi Kivilinna 	}
36981454b84SSebastian Andrzej Siewior 	spin_unlock_irqrestore(&intr->lock, flags);
370c900eff3SJussi Kivilinna }
371c900eff3SJussi Kivilinna 
handle_regs_int(struct urb * urb)372e85d0918SDaniel Drake static inline void handle_regs_int(struct urb *urb)
373e85d0918SDaniel Drake {
374e85d0918SDaniel Drake 	struct zd_usb *usb = urb->context;
375e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
37681454b84SSebastian Andrzej Siewior 	unsigned long flags;
377e85d0918SDaniel Drake 	int len;
37872e77a8aSLuis Carlos Cobo 	u16 int_num;
379e85d0918SDaniel Drake 
38081454b84SSebastian Andrzej Siewior 	spin_lock_irqsave(&intr->lock, flags);
381e85d0918SDaniel Drake 
382d63ddcecSAl Viro 	int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2));
3835a391813SJohannes Berg 	if (int_num == (u16)CR_INTERRUPT) {
38472e77a8aSLuis Carlos Cobo 		struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context));
3858b17f75cSJussi Kivilinna 		spin_lock(&mac->lock);
38672e77a8aSLuis Carlos Cobo 		memcpy(&mac->intr_buffer, urb->transfer_buffer,
38772e77a8aSLuis Carlos Cobo 				USB_MAX_EP_INT_BUFFER);
3888b17f75cSJussi Kivilinna 		spin_unlock(&mac->lock);
38972e77a8aSLuis Carlos Cobo 		schedule_work(&mac->process_intr);
390c900eff3SJussi Kivilinna 	} else if (atomic_read(&intr->read_regs_enabled)) {
391c900eff3SJussi Kivilinna 		len = urb->actual_length;
392c900eff3SJussi Kivilinna 		intr->read_regs.length = urb->actual_length;
393e85d0918SDaniel Drake 		if (len > sizeof(intr->read_regs.buffer))
394e85d0918SDaniel Drake 			len = sizeof(intr->read_regs.buffer);
395c900eff3SJussi Kivilinna 
396e85d0918SDaniel Drake 		memcpy(intr->read_regs.buffer, urb->transfer_buffer, len);
397c900eff3SJussi Kivilinna 
398c900eff3SJussi Kivilinna 		/* Sometimes USB_INT_ID_REGS is not overridden, but comes after
399c900eff3SJussi Kivilinna 		 * USB_INT_ID_RETRY_FAILED. Read-reg retry then gets this
400c900eff3SJussi Kivilinna 		 * delayed USB_INT_ID_REGS, but leaves USB_INT_ID_REGS of
401c900eff3SJussi Kivilinna 		 * retry unhandled. Next read-reg command then might catch
402c900eff3SJussi Kivilinna 		 * this wrong USB_INT_ID_REGS. Fix by ignoring wrong reads.
403c900eff3SJussi Kivilinna 		 */
404c900eff3SJussi Kivilinna 		if (!check_read_regs(usb, intr->read_regs.req,
405c900eff3SJussi Kivilinna 						intr->read_regs.req_count))
406c900eff3SJussi Kivilinna 			goto out;
407c900eff3SJussi Kivilinna 
408c900eff3SJussi Kivilinna 		atomic_set(&intr->read_regs_enabled, 0);
409c900eff3SJussi Kivilinna 		intr->read_regs_int_overridden = 0;
410e85d0918SDaniel Drake 		complete(&intr->read_regs.completion);
411c900eff3SJussi Kivilinna 
412e85d0918SDaniel Drake 		goto out;
413e85d0918SDaniel Drake 	}
414e85d0918SDaniel Drake 
415e85d0918SDaniel Drake out:
41681454b84SSebastian Andrzej Siewior 	spin_unlock_irqrestore(&intr->lock, flags);
417c900eff3SJussi Kivilinna 
418c900eff3SJussi Kivilinna 	/* CR_INTERRUPT might override read_reg too. */
4195a391813SJohannes Berg 	if (int_num == (u16)CR_INTERRUPT &&
4205a391813SJohannes Berg 	    atomic_read(&intr->read_regs_enabled))
421c900eff3SJussi Kivilinna 		handle_regs_int_override(urb);
422e85d0918SDaniel Drake }
423e85d0918SDaniel Drake 
int_urb_complete(struct urb * urb)4247d12e780SDavid Howells static void int_urb_complete(struct urb *urb)
425e85d0918SDaniel Drake {
426e85d0918SDaniel Drake 	int r;
427e85d0918SDaniel Drake 	struct usb_int_header *hdr;
428c900eff3SJussi Kivilinna 	struct zd_usb *usb;
429c900eff3SJussi Kivilinna 	struct zd_usb_interrupt *intr;
430e85d0918SDaniel Drake 
431e85d0918SDaniel Drake 	switch (urb->status) {
432e85d0918SDaniel Drake 	case 0:
433e85d0918SDaniel Drake 		break;
434e85d0918SDaniel Drake 	case -ESHUTDOWN:
435e85d0918SDaniel Drake 	case -EINVAL:
436e85d0918SDaniel Drake 	case -ENODEV:
437e85d0918SDaniel Drake 	case -ENOENT:
438e85d0918SDaniel Drake 	case -ECONNRESET:
439e85d0918SDaniel Drake 	case -EPIPE:
44024d24c62SJussi Kivilinna 		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
4414a3b0874SJussi Kivilinna 		return;
442e85d0918SDaniel Drake 	default:
44324d24c62SJussi Kivilinna 		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
444e85d0918SDaniel Drake 		goto resubmit;
445e85d0918SDaniel Drake 	}
446e85d0918SDaniel Drake 
447e85d0918SDaniel Drake 	if (urb->actual_length < sizeof(hdr)) {
448*41469ff9SBjorn Helgaas 		dev_dbg_f(urb_dev(urb), "error: urb %p too small\n", urb);
449e85d0918SDaniel Drake 		goto resubmit;
450e85d0918SDaniel Drake 	}
451e85d0918SDaniel Drake 
452e85d0918SDaniel Drake 	hdr = urb->transfer_buffer;
453e85d0918SDaniel Drake 	if (hdr->type != USB_INT_TYPE) {
454e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb);
455e85d0918SDaniel Drake 		goto resubmit;
456e85d0918SDaniel Drake 	}
457e85d0918SDaniel Drake 
458c900eff3SJussi Kivilinna 	/* USB_INT_ID_RETRY_FAILED triggered by tx-urb submit can override
459c900eff3SJussi Kivilinna 	 * pending USB_INT_ID_REGS causing read command timeout.
460c900eff3SJussi Kivilinna 	 */
461c900eff3SJussi Kivilinna 	usb = urb->context;
462c900eff3SJussi Kivilinna 	intr = &usb->intr;
463c900eff3SJussi Kivilinna 	if (hdr->id != USB_INT_ID_REGS && atomic_read(&intr->read_regs_enabled))
464c900eff3SJussi Kivilinna 		handle_regs_int_override(urb);
465c900eff3SJussi Kivilinna 
466e85d0918SDaniel Drake 	switch (hdr->id) {
467e85d0918SDaniel Drake 	case USB_INT_ID_REGS:
468e85d0918SDaniel Drake 		handle_regs_int(urb);
469e85d0918SDaniel Drake 		break;
470e85d0918SDaniel Drake 	case USB_INT_ID_RETRY_FAILED:
4717f4013f0SBenoit PAPILLAULT 		zd_mac_tx_failed(urb);
472e85d0918SDaniel Drake 		break;
473e85d0918SDaniel Drake 	default:
474e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
475e85d0918SDaniel Drake 			(unsigned int)hdr->id);
476e85d0918SDaniel Drake 		goto resubmit;
477e85d0918SDaniel Drake 	}
478e85d0918SDaniel Drake 
479e85d0918SDaniel Drake resubmit:
480e85d0918SDaniel Drake 	r = usb_submit_urb(urb, GFP_ATOMIC);
481e85d0918SDaniel Drake 	if (r) {
4824a3b0874SJussi Kivilinna 		dev_dbg_f(urb_dev(urb), "error: resubmit urb %p err code %d\n",
4834a3b0874SJussi Kivilinna 			  urb, r);
4844a3b0874SJussi Kivilinna 		/* TODO: add worker to reset intr->urb */
485e85d0918SDaniel Drake 	}
486e85d0918SDaniel Drake 	return;
487e85d0918SDaniel Drake }
488e85d0918SDaniel Drake 
int_urb_interval(struct usb_device * udev)489e85d0918SDaniel Drake static inline int int_urb_interval(struct usb_device *udev)
490e85d0918SDaniel Drake {
491e85d0918SDaniel Drake 	switch (udev->speed) {
492e85d0918SDaniel Drake 	case USB_SPEED_HIGH:
493e85d0918SDaniel Drake 		return 4;
494e85d0918SDaniel Drake 	case USB_SPEED_LOW:
495e85d0918SDaniel Drake 		return 10;
496e85d0918SDaniel Drake 	case USB_SPEED_FULL:
497e85d0918SDaniel Drake 	default:
498e85d0918SDaniel Drake 		return 1;
499e85d0918SDaniel Drake 	}
500e85d0918SDaniel Drake }
501e85d0918SDaniel Drake 
usb_int_enabled(struct zd_usb * usb)502e85d0918SDaniel Drake static inline int usb_int_enabled(struct zd_usb *usb)
503e85d0918SDaniel Drake {
504e85d0918SDaniel Drake 	unsigned long flags;
505e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
506e85d0918SDaniel Drake 	struct urb *urb;
507e85d0918SDaniel Drake 
508e85d0918SDaniel Drake 	spin_lock_irqsave(&intr->lock, flags);
509e85d0918SDaniel Drake 	urb = intr->urb;
510e85d0918SDaniel Drake 	spin_unlock_irqrestore(&intr->lock, flags);
511e85d0918SDaniel Drake 	return urb != NULL;
512e85d0918SDaniel Drake }
513e85d0918SDaniel Drake 
zd_usb_enable_int(struct zd_usb * usb)514e85d0918SDaniel Drake int zd_usb_enable_int(struct zd_usb *usb)
515e85d0918SDaniel Drake {
516e85d0918SDaniel Drake 	int r;
5174a3b0874SJussi Kivilinna 	struct usb_device *udev = zd_usb_to_usbdev(usb);
518e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
519e85d0918SDaniel Drake 	struct urb *urb;
520e85d0918SDaniel Drake 
521e85d0918SDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "\n");
522e85d0918SDaniel Drake 
52335c3404eSUlrich Kunitz 	urb = usb_alloc_urb(0, GFP_KERNEL);
524e85d0918SDaniel Drake 	if (!urb) {
525e85d0918SDaniel Drake 		r = -ENOMEM;
526e85d0918SDaniel Drake 		goto out;
527e85d0918SDaniel Drake 	}
528e85d0918SDaniel Drake 
529e85d0918SDaniel Drake 	ZD_ASSERT(!irqs_disabled());
530e85d0918SDaniel Drake 	spin_lock_irq(&intr->lock);
531e85d0918SDaniel Drake 	if (intr->urb) {
532e85d0918SDaniel Drake 		spin_unlock_irq(&intr->lock);
533e85d0918SDaniel Drake 		r = 0;
534e85d0918SDaniel Drake 		goto error_free_urb;
535e85d0918SDaniel Drake 	}
536e85d0918SDaniel Drake 	intr->urb = urb;
537e85d0918SDaniel Drake 	spin_unlock_irq(&intr->lock);
538e85d0918SDaniel Drake 
539e85d0918SDaniel Drake 	r = -ENOMEM;
5404a3b0874SJussi Kivilinna 	intr->buffer = usb_alloc_coherent(udev, USB_MAX_EP_INT_BUFFER,
5414a3b0874SJussi Kivilinna 					  GFP_KERNEL, &intr->buffer_dma);
5424a3b0874SJussi Kivilinna 	if (!intr->buffer) {
543e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
544e85d0918SDaniel Drake 			"couldn't allocate transfer_buffer\n");
545e85d0918SDaniel Drake 		goto error_set_urb_null;
546e85d0918SDaniel Drake 	}
547e85d0918SDaniel Drake 
548e85d0918SDaniel Drake 	usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
5494a3b0874SJussi Kivilinna 			 intr->buffer, USB_MAX_EP_INT_BUFFER,
550e85d0918SDaniel Drake 			 int_urb_complete, usb,
551e85d0918SDaniel Drake 			 intr->interval);
5524a3b0874SJussi Kivilinna 	urb->transfer_dma = intr->buffer_dma;
5534a3b0874SJussi Kivilinna 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
554e85d0918SDaniel Drake 
555e85d0918SDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
55635c3404eSUlrich Kunitz 	r = usb_submit_urb(urb, GFP_KERNEL);
557e85d0918SDaniel Drake 	if (r) {
558e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
559e85d0918SDaniel Drake 			 "Couldn't submit urb. Error number %d\n", r);
560e85d0918SDaniel Drake 		goto error;
561e85d0918SDaniel Drake 	}
562e85d0918SDaniel Drake 
563e85d0918SDaniel Drake 	return 0;
564e85d0918SDaniel Drake error:
5654a3b0874SJussi Kivilinna 	usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER,
5664a3b0874SJussi Kivilinna 			  intr->buffer, intr->buffer_dma);
567e85d0918SDaniel Drake error_set_urb_null:
568e85d0918SDaniel Drake 	spin_lock_irq(&intr->lock);
569e85d0918SDaniel Drake 	intr->urb = NULL;
570e85d0918SDaniel Drake 	spin_unlock_irq(&intr->lock);
571e85d0918SDaniel Drake error_free_urb:
572e85d0918SDaniel Drake 	usb_free_urb(urb);
573e85d0918SDaniel Drake out:
574e85d0918SDaniel Drake 	return r;
575e85d0918SDaniel Drake }
576e85d0918SDaniel Drake 
zd_usb_disable_int(struct zd_usb * usb)577e85d0918SDaniel Drake void zd_usb_disable_int(struct zd_usb *usb)
578e85d0918SDaniel Drake {
579e85d0918SDaniel Drake 	unsigned long flags;
5804a3b0874SJussi Kivilinna 	struct usb_device *udev = zd_usb_to_usbdev(usb);
581e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
582e85d0918SDaniel Drake 	struct urb *urb;
5834a3b0874SJussi Kivilinna 	void *buffer;
5844a3b0874SJussi Kivilinna 	dma_addr_t buffer_dma;
585e85d0918SDaniel Drake 
586e85d0918SDaniel Drake 	spin_lock_irqsave(&intr->lock, flags);
587e85d0918SDaniel Drake 	urb = intr->urb;
588e85d0918SDaniel Drake 	if (!urb) {
589e85d0918SDaniel Drake 		spin_unlock_irqrestore(&intr->lock, flags);
590e85d0918SDaniel Drake 		return;
591e85d0918SDaniel Drake 	}
592e85d0918SDaniel Drake 	intr->urb = NULL;
5934a3b0874SJussi Kivilinna 	buffer = intr->buffer;
5944a3b0874SJussi Kivilinna 	buffer_dma = intr->buffer_dma;
5954a3b0874SJussi Kivilinna 	intr->buffer = NULL;
596e85d0918SDaniel Drake 	spin_unlock_irqrestore(&intr->lock, flags);
597e85d0918SDaniel Drake 
598e85d0918SDaniel Drake 	usb_kill_urb(urb);
599e85d0918SDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb);
600e85d0918SDaniel Drake 	usb_free_urb(urb);
6014a3b0874SJussi Kivilinna 
6024f3ebd6fSXu Wang 	usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, buffer, buffer_dma);
603e85d0918SDaniel Drake }
604e85d0918SDaniel Drake 
handle_rx_packet(struct zd_usb * usb,const u8 * buffer,unsigned int length)605e85d0918SDaniel Drake static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
606e85d0918SDaniel Drake 			     unsigned int length)
607e85d0918SDaniel Drake {
608e85d0918SDaniel Drake 	int i;
609e85d0918SDaniel Drake 	const struct rx_length_info *length_info;
610e85d0918SDaniel Drake 
611e85d0918SDaniel Drake 	if (length < sizeof(struct rx_length_info)) {
612e85d0918SDaniel Drake 		/* It's not a complete packet anyhow. */
613b405e1b8SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "invalid, small RX packet : %d\n",
614b405e1b8SJussi Kivilinna 					   length);
615e85d0918SDaniel Drake 		return;
616e85d0918SDaniel Drake 	}
617e85d0918SDaniel Drake 	length_info = (struct rx_length_info *)
618e85d0918SDaniel Drake 		(buffer + length - sizeof(struct rx_length_info));
619e85d0918SDaniel Drake 
620e85d0918SDaniel Drake 	/* It might be that three frames are merged into a single URB
621e85d0918SDaniel Drake 	 * transaction. We have to check for the length info tag.
622e85d0918SDaniel Drake 	 *
623e85d0918SDaniel Drake 	 * While testing we discovered that length_info might be unaligned,
624e85d0918SDaniel Drake 	 * because if USB transactions are merged, the last packet will not
625e85d0918SDaniel Drake 	 * be padded. Unaligned access might also happen if the length_info
626e85d0918SDaniel Drake 	 * structure is not present.
627e85d0918SDaniel Drake 	 */
628533dd1b0SHarvey Harrison 	if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG)
629b269825bSUlrich Kunitz 	{
630e85d0918SDaniel Drake 		unsigned int l, k, n;
631e85d0918SDaniel Drake 		for (i = 0, l = 0;; i++) {
632533dd1b0SHarvey Harrison 			k = get_unaligned_le16(&length_info->length[i]);
633850c211cSUlrich Kunitz 			if (k == 0)
634850c211cSUlrich Kunitz 				return;
635e85d0918SDaniel Drake 			n = l+k;
636e85d0918SDaniel Drake 			if (n > length)
637e85d0918SDaniel Drake 				return;
638459c51adSDaniel Drake 			zd_mac_rx(zd_usb_to_hw(usb), buffer+l, k);
639e85d0918SDaniel Drake 			if (i >= 2)
640e85d0918SDaniel Drake 				return;
641e85d0918SDaniel Drake 			l = (n+3) & ~3;
642e85d0918SDaniel Drake 		}
643e85d0918SDaniel Drake 	} else {
644459c51adSDaniel Drake 		zd_mac_rx(zd_usb_to_hw(usb), buffer, length);
645e85d0918SDaniel Drake 	}
646e85d0918SDaniel Drake }
647e85d0918SDaniel Drake 
rx_urb_complete(struct urb * urb)6487d12e780SDavid Howells static void rx_urb_complete(struct urb *urb)
649e85d0918SDaniel Drake {
65024d24c62SJussi Kivilinna 	int r;
651e85d0918SDaniel Drake 	struct zd_usb *usb;
652e85d0918SDaniel Drake 	struct zd_usb_rx *rx;
653e85d0918SDaniel Drake 	const u8 *buffer;
654e85d0918SDaniel Drake 	unsigned int length;
65581454b84SSebastian Andrzej Siewior 	unsigned long flags;
656e85d0918SDaniel Drake 
657e85d0918SDaniel Drake 	switch (urb->status) {
658e85d0918SDaniel Drake 	case 0:
659e85d0918SDaniel Drake 		break;
660e85d0918SDaniel Drake 	case -ESHUTDOWN:
661e85d0918SDaniel Drake 	case -EINVAL:
662e85d0918SDaniel Drake 	case -ENODEV:
663e85d0918SDaniel Drake 	case -ENOENT:
664e85d0918SDaniel Drake 	case -ECONNRESET:
665e85d0918SDaniel Drake 	case -EPIPE:
66624d24c62SJussi Kivilinna 		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
667b312d799SDaniel Drake 		return;
668e85d0918SDaniel Drake 	default:
669e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
670e85d0918SDaniel Drake 		goto resubmit;
671e85d0918SDaniel Drake 	}
672e85d0918SDaniel Drake 
673e85d0918SDaniel Drake 	buffer = urb->transfer_buffer;
674e85d0918SDaniel Drake 	length = urb->actual_length;
675e85d0918SDaniel Drake 	usb = urb->context;
676e85d0918SDaniel Drake 	rx = &usb->rx;
677e85d0918SDaniel Drake 
67802353573SJussi Kivilinna 	tasklet_schedule(&rx->reset_timer_tasklet);
6791f6cccccSJussi Kivilinna 
680e85d0918SDaniel Drake 	if (length%rx->usb_packet_size > rx->usb_packet_size-4) {
681e85d0918SDaniel Drake 		/* If there is an old first fragment, we don't care. */
682e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
683e85d0918SDaniel Drake 		ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
68481454b84SSebastian Andrzej Siewior 		spin_lock_irqsave(&rx->lock, flags);
685e85d0918SDaniel Drake 		memcpy(rx->fragment, buffer, length);
686e85d0918SDaniel Drake 		rx->fragment_length = length;
68781454b84SSebastian Andrzej Siewior 		spin_unlock_irqrestore(&rx->lock, flags);
688e85d0918SDaniel Drake 		goto resubmit;
689e85d0918SDaniel Drake 	}
690e85d0918SDaniel Drake 
69181454b84SSebastian Andrzej Siewior 	spin_lock_irqsave(&rx->lock, flags);
692e85d0918SDaniel Drake 	if (rx->fragment_length > 0) {
693e85d0918SDaniel Drake 		/* We are on a second fragment, we believe */
694e85d0918SDaniel Drake 		ZD_ASSERT(length + rx->fragment_length <=
695e85d0918SDaniel Drake 			  ARRAY_SIZE(rx->fragment));
696e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "*** second fragment ***\n");
697e85d0918SDaniel Drake 		memcpy(rx->fragment+rx->fragment_length, buffer, length);
698e85d0918SDaniel Drake 		handle_rx_packet(usb, rx->fragment,
699e85d0918SDaniel Drake 			         rx->fragment_length + length);
700e85d0918SDaniel Drake 		rx->fragment_length = 0;
70181454b84SSebastian Andrzej Siewior 		spin_unlock_irqrestore(&rx->lock, flags);
702e85d0918SDaniel Drake 	} else {
70381454b84SSebastian Andrzej Siewior 		spin_unlock_irqrestore(&rx->lock, flags);
704e85d0918SDaniel Drake 		handle_rx_packet(usb, buffer, length);
705e85d0918SDaniel Drake 	}
706e85d0918SDaniel Drake 
707e85d0918SDaniel Drake resubmit:
70824d24c62SJussi Kivilinna 	r = usb_submit_urb(urb, GFP_ATOMIC);
70924d24c62SJussi Kivilinna 	if (r)
71024d24c62SJussi Kivilinna 		dev_dbg_f(urb_dev(urb), "urb %p resubmit error %d\n", urb, r);
711e85d0918SDaniel Drake }
712e85d0918SDaniel Drake 
alloc_rx_urb(struct zd_usb * usb)713459c51adSDaniel Drake static struct urb *alloc_rx_urb(struct zd_usb *usb)
714e85d0918SDaniel Drake {
715e85d0918SDaniel Drake 	struct usb_device *udev = zd_usb_to_usbdev(usb);
716e85d0918SDaniel Drake 	struct urb *urb;
717e85d0918SDaniel Drake 	void *buffer;
718e85d0918SDaniel Drake 
71935c3404eSUlrich Kunitz 	urb = usb_alloc_urb(0, GFP_KERNEL);
720e85d0918SDaniel Drake 	if (!urb)
721e85d0918SDaniel Drake 		return NULL;
722997ea58eSDaniel Mack 	buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
723e85d0918SDaniel Drake 				    &urb->transfer_dma);
724e85d0918SDaniel Drake 	if (!buffer) {
725e85d0918SDaniel Drake 		usb_free_urb(urb);
726e85d0918SDaniel Drake 		return NULL;
727e85d0918SDaniel Drake 	}
728e85d0918SDaniel Drake 
729e85d0918SDaniel Drake 	usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
730e85d0918SDaniel Drake 			  buffer, USB_MAX_RX_SIZE,
731e85d0918SDaniel Drake 			  rx_urb_complete, usb);
732e85d0918SDaniel Drake 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
733e85d0918SDaniel Drake 
734e85d0918SDaniel Drake 	return urb;
735e85d0918SDaniel Drake }
736e85d0918SDaniel Drake 
free_rx_urb(struct urb * urb)737459c51adSDaniel Drake static void free_rx_urb(struct urb *urb)
738e85d0918SDaniel Drake {
739e85d0918SDaniel Drake 	if (!urb)
740e85d0918SDaniel Drake 		return;
741997ea58eSDaniel Mack 	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
742e85d0918SDaniel Drake 			  urb->transfer_buffer, urb->transfer_dma);
743e85d0918SDaniel Drake 	usb_free_urb(urb);
744e85d0918SDaniel Drake }
745e85d0918SDaniel Drake 
__zd_usb_enable_rx(struct zd_usb * usb)7461f6cccccSJussi Kivilinna static int __zd_usb_enable_rx(struct zd_usb *usb)
747e85d0918SDaniel Drake {
748e85d0918SDaniel Drake 	int i, r;
749e85d0918SDaniel Drake 	struct zd_usb_rx *rx = &usb->rx;
750e85d0918SDaniel Drake 	struct urb **urbs;
751e85d0918SDaniel Drake 
752e85d0918SDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "\n");
753e85d0918SDaniel Drake 
754e85d0918SDaniel Drake 	r = -ENOMEM;
755459c51adSDaniel Drake 	urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
756e85d0918SDaniel Drake 	if (!urbs)
757e85d0918SDaniel Drake 		goto error;
758459c51adSDaniel Drake 	for (i = 0; i < RX_URBS_COUNT; i++) {
759459c51adSDaniel Drake 		urbs[i] = alloc_rx_urb(usb);
760e85d0918SDaniel Drake 		if (!urbs[i])
761e85d0918SDaniel Drake 			goto error;
762e85d0918SDaniel Drake 	}
763e85d0918SDaniel Drake 
764e85d0918SDaniel Drake 	ZD_ASSERT(!irqs_disabled());
765e85d0918SDaniel Drake 	spin_lock_irq(&rx->lock);
766e85d0918SDaniel Drake 	if (rx->urbs) {
767e85d0918SDaniel Drake 		spin_unlock_irq(&rx->lock);
768e85d0918SDaniel Drake 		r = 0;
769e85d0918SDaniel Drake 		goto error;
770e85d0918SDaniel Drake 	}
771e85d0918SDaniel Drake 	rx->urbs = urbs;
772459c51adSDaniel Drake 	rx->urbs_count = RX_URBS_COUNT;
773e85d0918SDaniel Drake 	spin_unlock_irq(&rx->lock);
774e85d0918SDaniel Drake 
775459c51adSDaniel Drake 	for (i = 0; i < RX_URBS_COUNT; i++) {
77635c3404eSUlrich Kunitz 		r = usb_submit_urb(urbs[i], GFP_KERNEL);
777e85d0918SDaniel Drake 		if (r)
778e85d0918SDaniel Drake 			goto error_submit;
779e85d0918SDaniel Drake 	}
780e85d0918SDaniel Drake 
781e85d0918SDaniel Drake 	return 0;
782e85d0918SDaniel Drake error_submit:
783459c51adSDaniel Drake 	for (i = 0; i < RX_URBS_COUNT; i++) {
784e85d0918SDaniel Drake 		usb_kill_urb(urbs[i]);
785e85d0918SDaniel Drake 	}
786e85d0918SDaniel Drake 	spin_lock_irq(&rx->lock);
787e85d0918SDaniel Drake 	rx->urbs = NULL;
788e85d0918SDaniel Drake 	rx->urbs_count = 0;
789e85d0918SDaniel Drake 	spin_unlock_irq(&rx->lock);
790e85d0918SDaniel Drake error:
791e85d0918SDaniel Drake 	if (urbs) {
792459c51adSDaniel Drake 		for (i = 0; i < RX_URBS_COUNT; i++)
793459c51adSDaniel Drake 			free_rx_urb(urbs[i]);
794e85d0918SDaniel Drake 	}
795e85d0918SDaniel Drake 	return r;
796e85d0918SDaniel Drake }
797e85d0918SDaniel Drake 
zd_usb_enable_rx(struct zd_usb * usb)7981f6cccccSJussi Kivilinna int zd_usb_enable_rx(struct zd_usb *usb)
7991f6cccccSJussi Kivilinna {
8001f6cccccSJussi Kivilinna 	int r;
8011f6cccccSJussi Kivilinna 	struct zd_usb_rx *rx = &usb->rx;
8021f6cccccSJussi Kivilinna 
8031f6cccccSJussi Kivilinna 	mutex_lock(&rx->setup_mutex);
8041f6cccccSJussi Kivilinna 	r = __zd_usb_enable_rx(usb);
8051f6cccccSJussi Kivilinna 	mutex_unlock(&rx->setup_mutex);
8061f6cccccSJussi Kivilinna 
8071f6cccccSJussi Kivilinna 	zd_usb_reset_rx_idle_timer(usb);
8081f6cccccSJussi Kivilinna 
8091f6cccccSJussi Kivilinna 	return r;
8101f6cccccSJussi Kivilinna }
8111f6cccccSJussi Kivilinna 
__zd_usb_disable_rx(struct zd_usb * usb)8121f6cccccSJussi Kivilinna static void __zd_usb_disable_rx(struct zd_usb *usb)
813e85d0918SDaniel Drake {
814e85d0918SDaniel Drake 	int i;
815e85d0918SDaniel Drake 	unsigned long flags;
816e85d0918SDaniel Drake 	struct urb **urbs;
817e85d0918SDaniel Drake 	unsigned int count;
818e85d0918SDaniel Drake 	struct zd_usb_rx *rx = &usb->rx;
819e85d0918SDaniel Drake 
820e85d0918SDaniel Drake 	spin_lock_irqsave(&rx->lock, flags);
821e85d0918SDaniel Drake 	urbs = rx->urbs;
822e85d0918SDaniel Drake 	count = rx->urbs_count;
823e85d0918SDaniel Drake 	spin_unlock_irqrestore(&rx->lock, flags);
824e85d0918SDaniel Drake 	if (!urbs)
825e85d0918SDaniel Drake 		return;
826e85d0918SDaniel Drake 
827e85d0918SDaniel Drake 	for (i = 0; i < count; i++) {
828e85d0918SDaniel Drake 		usb_kill_urb(urbs[i]);
829459c51adSDaniel Drake 		free_rx_urb(urbs[i]);
830e85d0918SDaniel Drake 	}
831e85d0918SDaniel Drake 	kfree(urbs);
832e85d0918SDaniel Drake 
833e85d0918SDaniel Drake 	spin_lock_irqsave(&rx->lock, flags);
834e85d0918SDaniel Drake 	rx->urbs = NULL;
835e85d0918SDaniel Drake 	rx->urbs_count = 0;
836e85d0918SDaniel Drake 	spin_unlock_irqrestore(&rx->lock, flags);
837e85d0918SDaniel Drake }
838e85d0918SDaniel Drake 
zd_usb_disable_rx(struct zd_usb * usb)8391f6cccccSJussi Kivilinna void zd_usb_disable_rx(struct zd_usb *usb)
8401f6cccccSJussi Kivilinna {
8411f6cccccSJussi Kivilinna 	struct zd_usb_rx *rx = &usb->rx;
8421f6cccccSJussi Kivilinna 
8431f6cccccSJussi Kivilinna 	mutex_lock(&rx->setup_mutex);
8441f6cccccSJussi Kivilinna 	__zd_usb_disable_rx(usb);
8451f6cccccSJussi Kivilinna 	mutex_unlock(&rx->setup_mutex);
8461f6cccccSJussi Kivilinna 
84702353573SJussi Kivilinna 	tasklet_kill(&rx->reset_timer_tasklet);
8481f6cccccSJussi Kivilinna 	cancel_delayed_work_sync(&rx->idle_work);
8491f6cccccSJussi Kivilinna }
8501f6cccccSJussi Kivilinna 
zd_usb_reset_rx(struct zd_usb * usb)8511f6cccccSJussi Kivilinna static void zd_usb_reset_rx(struct zd_usb *usb)
8521f6cccccSJussi Kivilinna {
8531f6cccccSJussi Kivilinna 	bool do_reset;
8541f6cccccSJussi Kivilinna 	struct zd_usb_rx *rx = &usb->rx;
8551f6cccccSJussi Kivilinna 	unsigned long flags;
8561f6cccccSJussi Kivilinna 
8571f6cccccSJussi Kivilinna 	mutex_lock(&rx->setup_mutex);
8581f6cccccSJussi Kivilinna 
8591f6cccccSJussi Kivilinna 	spin_lock_irqsave(&rx->lock, flags);
8601f6cccccSJussi Kivilinna 	do_reset = rx->urbs != NULL;
8611f6cccccSJussi Kivilinna 	spin_unlock_irqrestore(&rx->lock, flags);
8621f6cccccSJussi Kivilinna 
8631f6cccccSJussi Kivilinna 	if (do_reset) {
8641f6cccccSJussi Kivilinna 		__zd_usb_disable_rx(usb);
8651f6cccccSJussi Kivilinna 		__zd_usb_enable_rx(usb);
8661f6cccccSJussi Kivilinna 	}
8671f6cccccSJussi Kivilinna 
8681f6cccccSJussi Kivilinna 	mutex_unlock(&rx->setup_mutex);
8691f6cccccSJussi Kivilinna 
8701f6cccccSJussi Kivilinna 	if (do_reset)
8711f6cccccSJussi Kivilinna 		zd_usb_reset_rx_idle_timer(usb);
8721f6cccccSJussi Kivilinna }
8731f6cccccSJussi Kivilinna 
874459c51adSDaniel Drake /**
875459c51adSDaniel Drake  * zd_usb_disable_tx - disable transmission
876459c51adSDaniel Drake  * @usb: the zd1211rw-private USB structure
877459c51adSDaniel Drake  *
878459c51adSDaniel Drake  * Frees all URBs in the free list and marks the transmission as disabled.
879459c51adSDaniel Drake  */
zd_usb_disable_tx(struct zd_usb * usb)880459c51adSDaniel Drake void zd_usb_disable_tx(struct zd_usb *usb)
881459c51adSDaniel Drake {
882459c51adSDaniel Drake 	struct zd_usb_tx *tx = &usb->tx;
883459c51adSDaniel Drake 	unsigned long flags;
88478fc800fSJussi Kivilinna 
88578fc800fSJussi Kivilinna 	atomic_set(&tx->enabled, 0);
88678fc800fSJussi Kivilinna 
88778fc800fSJussi Kivilinna 	/* kill all submitted tx-urbs */
88878fc800fSJussi Kivilinna 	usb_kill_anchored_urbs(&tx->submitted);
889459c51adSDaniel Drake 
890459c51adSDaniel Drake 	spin_lock_irqsave(&tx->lock, flags);
891a0fd751fSJussi Kivilinna 	WARN_ON(!skb_queue_empty(&tx->submitted_skbs));
89278fc800fSJussi Kivilinna 	WARN_ON(tx->submitted_urbs != 0);
893459c51adSDaniel Drake 	tx->submitted_urbs = 0;
89478fc800fSJussi Kivilinna 	spin_unlock_irqrestore(&tx->lock, flags);
89578fc800fSJussi Kivilinna 
896459c51adSDaniel Drake 	/* The stopped state is ignored, relying on ieee80211_wake_queues()
897459c51adSDaniel Drake 	 * in a potentionally following zd_usb_enable_tx().
898459c51adSDaniel Drake 	 */
899459c51adSDaniel Drake }
900459c51adSDaniel Drake 
901459c51adSDaniel Drake /**
902459c51adSDaniel Drake  * zd_usb_enable_tx - enables transmission
903459c51adSDaniel Drake  * @usb: a &struct zd_usb pointer
904459c51adSDaniel Drake  *
905459c51adSDaniel Drake  * This function enables transmission and prepares the &zd_usb_tx data
906459c51adSDaniel Drake  * structure.
907459c51adSDaniel Drake  */
zd_usb_enable_tx(struct zd_usb * usb)908459c51adSDaniel Drake void zd_usb_enable_tx(struct zd_usb *usb)
909459c51adSDaniel Drake {
910459c51adSDaniel Drake 	unsigned long flags;
911459c51adSDaniel Drake 	struct zd_usb_tx *tx = &usb->tx;
912459c51adSDaniel Drake 
913459c51adSDaniel Drake 	spin_lock_irqsave(&tx->lock, flags);
91478fc800fSJussi Kivilinna 	atomic_set(&tx->enabled, 1);
915459c51adSDaniel Drake 	tx->submitted_urbs = 0;
916459c51adSDaniel Drake 	ieee80211_wake_queues(zd_usb_to_hw(usb));
917459c51adSDaniel Drake 	tx->stopped = 0;
918459c51adSDaniel Drake 	spin_unlock_irqrestore(&tx->lock, flags);
919459c51adSDaniel Drake }
920459c51adSDaniel Drake 
tx_dec_submitted_urbs(struct zd_usb * usb)921459c51adSDaniel Drake static void tx_dec_submitted_urbs(struct zd_usb *usb)
922459c51adSDaniel Drake {
923459c51adSDaniel Drake 	struct zd_usb_tx *tx = &usb->tx;
924459c51adSDaniel Drake 	unsigned long flags;
925459c51adSDaniel Drake 
926459c51adSDaniel Drake 	spin_lock_irqsave(&tx->lock, flags);
927459c51adSDaniel Drake 	--tx->submitted_urbs;
928459c51adSDaniel Drake 	if (tx->stopped && tx->submitted_urbs <= ZD_USB_TX_LOW) {
929459c51adSDaniel Drake 		ieee80211_wake_queues(zd_usb_to_hw(usb));
930459c51adSDaniel Drake 		tx->stopped = 0;
931459c51adSDaniel Drake 	}
932459c51adSDaniel Drake 	spin_unlock_irqrestore(&tx->lock, flags);
933459c51adSDaniel Drake }
934459c51adSDaniel Drake 
tx_inc_submitted_urbs(struct zd_usb * usb)935459c51adSDaniel Drake static void tx_inc_submitted_urbs(struct zd_usb *usb)
936459c51adSDaniel Drake {
937459c51adSDaniel Drake 	struct zd_usb_tx *tx = &usb->tx;
938459c51adSDaniel Drake 	unsigned long flags;
939459c51adSDaniel Drake 
940459c51adSDaniel Drake 	spin_lock_irqsave(&tx->lock, flags);
941459c51adSDaniel Drake 	++tx->submitted_urbs;
942459c51adSDaniel Drake 	if (!tx->stopped && tx->submitted_urbs > ZD_USB_TX_HIGH) {
943459c51adSDaniel Drake 		ieee80211_stop_queues(zd_usb_to_hw(usb));
944459c51adSDaniel Drake 		tx->stopped = 1;
945459c51adSDaniel Drake 	}
946459c51adSDaniel Drake 	spin_unlock_irqrestore(&tx->lock, flags);
947459c51adSDaniel Drake }
948459c51adSDaniel Drake 
949459c51adSDaniel Drake /**
950459c51adSDaniel Drake  * tx_urb_complete - completes the execution of an URB
951459c51adSDaniel Drake  * @urb: a URB
952459c51adSDaniel Drake  *
953459c51adSDaniel Drake  * This function is called if the URB has been transferred to a device or an
954459c51adSDaniel Drake  * error has happened.
955459c51adSDaniel Drake  */
tx_urb_complete(struct urb * urb)9567d12e780SDavid Howells static void tx_urb_complete(struct urb *urb)
957e85d0918SDaniel Drake {
958e85d0918SDaniel Drake 	int r;
959459c51adSDaniel Drake 	struct sk_buff *skb;
960e039fa4aSJohannes Berg 	struct ieee80211_tx_info *info;
961459c51adSDaniel Drake 	struct zd_usb *usb;
96278fc800fSJussi Kivilinna 	struct zd_usb_tx *tx;
96378fc800fSJussi Kivilinna 
96478fc800fSJussi Kivilinna 	skb = (struct sk_buff *)urb->context;
96578fc800fSJussi Kivilinna 	info = IEEE80211_SKB_CB(skb);
96678fc800fSJussi Kivilinna 	/*
96778fc800fSJussi Kivilinna 	 * grab 'usb' pointer before handing off the skb (since
96878fc800fSJussi Kivilinna 	 * it might be freed by zd_mac_tx_to_dev or mac80211)
96978fc800fSJussi Kivilinna 	 */
97078fc800fSJussi Kivilinna 	usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
97178fc800fSJussi Kivilinna 	tx = &usb->tx;
972e85d0918SDaniel Drake 
973e85d0918SDaniel Drake 	switch (urb->status) {
974e85d0918SDaniel Drake 	case 0:
975e85d0918SDaniel Drake 		break;
976e85d0918SDaniel Drake 	case -ESHUTDOWN:
977e85d0918SDaniel Drake 	case -EINVAL:
978e85d0918SDaniel Drake 	case -ENODEV:
979e85d0918SDaniel Drake 	case -ENOENT:
980e85d0918SDaniel Drake 	case -ECONNRESET:
981b312d799SDaniel Drake 	case -EPIPE:
982e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
983e85d0918SDaniel Drake 		break;
984e85d0918SDaniel Drake 	default:
985e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
986e85d0918SDaniel Drake 		goto resubmit;
987e85d0918SDaniel Drake 	}
988e85d0918SDaniel Drake free_urb:
989a0fd751fSJussi Kivilinna 	skb_unlink(skb, &usb->tx.submitted_skbs);
990dbabad0cSJohannes Berg 	zd_mac_tx_to_dev(skb, urb->status);
99178fc800fSJussi Kivilinna 	usb_free_urb(urb);
992459c51adSDaniel Drake 	tx_dec_submitted_urbs(usb);
993e85d0918SDaniel Drake 	return;
994e85d0918SDaniel Drake resubmit:
99578fc800fSJussi Kivilinna 	usb_anchor_urb(urb, &tx->submitted);
996e85d0918SDaniel Drake 	r = usb_submit_urb(urb, GFP_ATOMIC);
997e85d0918SDaniel Drake 	if (r) {
99878fc800fSJussi Kivilinna 		usb_unanchor_urb(urb);
999e85d0918SDaniel Drake 		dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);
1000e85d0918SDaniel Drake 		goto free_urb;
1001e85d0918SDaniel Drake 	}
1002e85d0918SDaniel Drake }
1003e85d0918SDaniel Drake 
1004459c51adSDaniel Drake /**
1005459c51adSDaniel Drake  * zd_usb_tx: initiates transfer of a frame of the device
1006459c51adSDaniel Drake  *
1007459c51adSDaniel Drake  * @usb: the zd1211rw-private USB structure
1008459c51adSDaniel Drake  * @skb: a &struct sk_buff pointer
1009459c51adSDaniel Drake  *
10102d594783SYueh-Shun Li  * This function transmits a frame to the device. It doesn't wait for
1011459c51adSDaniel Drake  * completion. The frame must contain the control set and have all the
1012459c51adSDaniel Drake  * control set information available.
1013459c51adSDaniel Drake  *
1014459c51adSDaniel Drake  * The function returns 0 if the transfer has been successfully initiated.
1015e85d0918SDaniel Drake  */
zd_usb_tx(struct zd_usb * usb,struct sk_buff * skb)1016459c51adSDaniel Drake int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb)
1017e85d0918SDaniel Drake {
1018e85d0918SDaniel Drake 	int r;
1019a0fd751fSJussi Kivilinna 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1020e85d0918SDaniel Drake 	struct usb_device *udev = zd_usb_to_usbdev(usb);
1021e85d0918SDaniel Drake 	struct urb *urb;
102278fc800fSJussi Kivilinna 	struct zd_usb_tx *tx = &usb->tx;
1023e85d0918SDaniel Drake 
102478fc800fSJussi Kivilinna 	if (!atomic_read(&tx->enabled)) {
102578fc800fSJussi Kivilinna 		r = -ENOENT;
102678fc800fSJussi Kivilinna 		goto out;
102778fc800fSJussi Kivilinna 	}
102878fc800fSJussi Kivilinna 
102978fc800fSJussi Kivilinna 	urb = usb_alloc_urb(0, GFP_ATOMIC);
1030e85d0918SDaniel Drake 	if (!urb) {
1031e85d0918SDaniel Drake 		r = -ENOMEM;
1032e85d0918SDaniel Drake 		goto out;
1033e85d0918SDaniel Drake 	}
1034e85d0918SDaniel Drake 
1035e85d0918SDaniel Drake 	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
1036459c51adSDaniel Drake 		          skb->data, skb->len, tx_urb_complete, skb);
1037e85d0918SDaniel Drake 
1038a0fd751fSJussi Kivilinna 	info->rate_driver_data[1] = (void *)jiffies;
1039a0fd751fSJussi Kivilinna 	skb_queue_tail(&tx->submitted_skbs, skb);
104078fc800fSJussi Kivilinna 	usb_anchor_urb(urb, &tx->submitted);
1041a0fd751fSJussi Kivilinna 
1042e85d0918SDaniel Drake 	r = usb_submit_urb(urb, GFP_ATOMIC);
104378fc800fSJussi Kivilinna 	if (r) {
104424d24c62SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "error submit urb %p %d\n", urb, r);
104578fc800fSJussi Kivilinna 		usb_unanchor_urb(urb);
1046a0fd751fSJussi Kivilinna 		skb_unlink(skb, &tx->submitted_skbs);
1047e85d0918SDaniel Drake 		goto error;
104878fc800fSJussi Kivilinna 	}
1049459c51adSDaniel Drake 	tx_inc_submitted_urbs(usb);
1050e85d0918SDaniel Drake 	return 0;
1051e85d0918SDaniel Drake error:
105278fc800fSJussi Kivilinna 	usb_free_urb(urb);
1053e85d0918SDaniel Drake out:
1054e85d0918SDaniel Drake 	return r;
1055e85d0918SDaniel Drake }
1056e85d0918SDaniel Drake 
zd_tx_timeout(struct zd_usb * usb)1057a0fd751fSJussi Kivilinna static bool zd_tx_timeout(struct zd_usb *usb)
1058a0fd751fSJussi Kivilinna {
1059a0fd751fSJussi Kivilinna 	struct zd_usb_tx *tx = &usb->tx;
1060a0fd751fSJussi Kivilinna 	struct sk_buff_head *q = &tx->submitted_skbs;
1061a0fd751fSJussi Kivilinna 	struct sk_buff *skb, *skbnext;
1062a0fd751fSJussi Kivilinna 	struct ieee80211_tx_info *info;
1063a0fd751fSJussi Kivilinna 	unsigned long flags, trans_start;
1064a0fd751fSJussi Kivilinna 	bool have_timedout = false;
1065a0fd751fSJussi Kivilinna 
1066a0fd751fSJussi Kivilinna 	spin_lock_irqsave(&q->lock, flags);
1067a0fd751fSJussi Kivilinna 	skb_queue_walk_safe(q, skb, skbnext) {
1068a0fd751fSJussi Kivilinna 		info = IEEE80211_SKB_CB(skb);
1069a0fd751fSJussi Kivilinna 		trans_start = (unsigned long)info->rate_driver_data[1];
1070a0fd751fSJussi Kivilinna 
1071a0fd751fSJussi Kivilinna 		if (time_is_before_jiffies(trans_start + ZD_TX_TIMEOUT)) {
1072a0fd751fSJussi Kivilinna 			have_timedout = true;
1073a0fd751fSJussi Kivilinna 			break;
1074a0fd751fSJussi Kivilinna 		}
1075a0fd751fSJussi Kivilinna 	}
1076a0fd751fSJussi Kivilinna 	spin_unlock_irqrestore(&q->lock, flags);
1077a0fd751fSJussi Kivilinna 
1078a0fd751fSJussi Kivilinna 	return have_timedout;
1079a0fd751fSJussi Kivilinna }
1080a0fd751fSJussi Kivilinna 
zd_tx_watchdog_handler(struct work_struct * work)1081a0fd751fSJussi Kivilinna static void zd_tx_watchdog_handler(struct work_struct *work)
1082a0fd751fSJussi Kivilinna {
1083a0fd751fSJussi Kivilinna 	struct zd_usb *usb =
1084a0fd751fSJussi Kivilinna 		container_of(work, struct zd_usb, tx.watchdog_work.work);
1085a0fd751fSJussi Kivilinna 	struct zd_usb_tx *tx = &usb->tx;
1086a0fd751fSJussi Kivilinna 
1087a0fd751fSJussi Kivilinna 	if (!atomic_read(&tx->enabled) || !tx->watchdog_enabled)
1088a0fd751fSJussi Kivilinna 		goto out;
1089a0fd751fSJussi Kivilinna 	if (!zd_tx_timeout(usb))
1090a0fd751fSJussi Kivilinna 		goto out;
1091a0fd751fSJussi Kivilinna 
1092a0fd751fSJussi Kivilinna 	/* TX halted, try reset */
109350db7fa3SMasanari Iida 	dev_warn(zd_usb_dev(usb), "TX-stall detected, resetting device...");
1094a0fd751fSJussi Kivilinna 
1095a0fd751fSJussi Kivilinna 	usb_queue_reset_device(usb->intf);
1096a0fd751fSJussi Kivilinna 
1097a0fd751fSJussi Kivilinna 	/* reset will stop this worker, don't rearm */
1098a0fd751fSJussi Kivilinna 	return;
1099a0fd751fSJussi Kivilinna out:
1100a0fd751fSJussi Kivilinna 	queue_delayed_work(zd_workqueue, &tx->watchdog_work,
1101a0fd751fSJussi Kivilinna 			   ZD_TX_WATCHDOG_INTERVAL);
1102a0fd751fSJussi Kivilinna }
1103a0fd751fSJussi Kivilinna 
zd_tx_watchdog_enable(struct zd_usb * usb)1104a0fd751fSJussi Kivilinna void zd_tx_watchdog_enable(struct zd_usb *usb)
1105a0fd751fSJussi Kivilinna {
1106a0fd751fSJussi Kivilinna 	struct zd_usb_tx *tx = &usb->tx;
1107a0fd751fSJussi Kivilinna 
1108a0fd751fSJussi Kivilinna 	if (!tx->watchdog_enabled) {
1109a0fd751fSJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "\n");
1110a0fd751fSJussi Kivilinna 		queue_delayed_work(zd_workqueue, &tx->watchdog_work,
1111a0fd751fSJussi Kivilinna 				   ZD_TX_WATCHDOG_INTERVAL);
1112a0fd751fSJussi Kivilinna 		tx->watchdog_enabled = 1;
1113a0fd751fSJussi Kivilinna 	}
1114a0fd751fSJussi Kivilinna }
1115a0fd751fSJussi Kivilinna 
zd_tx_watchdog_disable(struct zd_usb * usb)1116a0fd751fSJussi Kivilinna void zd_tx_watchdog_disable(struct zd_usb *usb)
1117a0fd751fSJussi Kivilinna {
1118a0fd751fSJussi Kivilinna 	struct zd_usb_tx *tx = &usb->tx;
1119a0fd751fSJussi Kivilinna 
1120a0fd751fSJussi Kivilinna 	if (tx->watchdog_enabled) {
1121a0fd751fSJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "\n");
1122a0fd751fSJussi Kivilinna 		tx->watchdog_enabled = 0;
1123a0fd751fSJussi Kivilinna 		cancel_delayed_work_sync(&tx->watchdog_work);
1124a0fd751fSJussi Kivilinna 	}
1125a0fd751fSJussi Kivilinna }
1126a0fd751fSJussi Kivilinna 
zd_rx_idle_timer_handler(struct work_struct * work)11271f6cccccSJussi Kivilinna static void zd_rx_idle_timer_handler(struct work_struct *work)
11281f6cccccSJussi Kivilinna {
11291f6cccccSJussi Kivilinna 	struct zd_usb *usb =
11301f6cccccSJussi Kivilinna 		container_of(work, struct zd_usb, rx.idle_work.work);
11311f6cccccSJussi Kivilinna 	struct zd_mac *mac = zd_usb_to_mac(usb);
11321f6cccccSJussi Kivilinna 
11331f6cccccSJussi Kivilinna 	if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags))
11341f6cccccSJussi Kivilinna 		return;
11351f6cccccSJussi Kivilinna 
11361f6cccccSJussi Kivilinna 	dev_dbg_f(zd_usb_dev(usb), "\n");
11371f6cccccSJussi Kivilinna 
11381f6cccccSJussi Kivilinna 	/* 30 seconds since last rx, reset rx */
11391f6cccccSJussi Kivilinna 	zd_usb_reset_rx(usb);
11401f6cccccSJussi Kivilinna }
11411f6cccccSJussi Kivilinna 
zd_usb_reset_rx_idle_timer_tasklet(struct tasklet_struct * t)114226721b02SAllen Pais static void zd_usb_reset_rx_idle_timer_tasklet(struct tasklet_struct *t)
114302353573SJussi Kivilinna {
114426721b02SAllen Pais 	struct zd_usb *usb = from_tasklet(usb, t, rx.reset_timer_tasklet);
114502353573SJussi Kivilinna 
114602353573SJussi Kivilinna 	zd_usb_reset_rx_idle_timer(usb);
114702353573SJussi Kivilinna }
114802353573SJussi Kivilinna 
zd_usb_reset_rx_idle_timer(struct zd_usb * usb)11491f6cccccSJussi Kivilinna void zd_usb_reset_rx_idle_timer(struct zd_usb *usb)
11501f6cccccSJussi Kivilinna {
11511f6cccccSJussi Kivilinna 	struct zd_usb_rx *rx = &usb->rx;
11521f6cccccSJussi Kivilinna 
115341f63c53STejun Heo 	mod_delayed_work(zd_workqueue, &rx->idle_work, ZD_RX_IDLE_INTERVAL);
11541f6cccccSJussi Kivilinna }
11551f6cccccSJussi Kivilinna 
init_usb_interrupt(struct zd_usb * usb)1156e85d0918SDaniel Drake static inline void init_usb_interrupt(struct zd_usb *usb)
1157e85d0918SDaniel Drake {
1158e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
1159e85d0918SDaniel Drake 
1160e85d0918SDaniel Drake 	spin_lock_init(&intr->lock);
1161e85d0918SDaniel Drake 	intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
1162e85d0918SDaniel Drake 	init_completion(&intr->read_regs.completion);
1163c900eff3SJussi Kivilinna 	atomic_set(&intr->read_regs_enabled, 0);
11640ce34bc8SDaniel Drake 	intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
1165e85d0918SDaniel Drake }
1166e85d0918SDaniel Drake 
init_usb_rx(struct zd_usb * usb)1167e85d0918SDaniel Drake static inline void init_usb_rx(struct zd_usb *usb)
1168e85d0918SDaniel Drake {
1169e85d0918SDaniel Drake 	struct zd_usb_rx *rx = &usb->rx;
117002353573SJussi Kivilinna 
1171e85d0918SDaniel Drake 	spin_lock_init(&rx->lock);
11721f6cccccSJussi Kivilinna 	mutex_init(&rx->setup_mutex);
1173e85d0918SDaniel Drake 	if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) {
1174e85d0918SDaniel Drake 		rx->usb_packet_size = 512;
1175e85d0918SDaniel Drake 	} else {
1176e85d0918SDaniel Drake 		rx->usb_packet_size = 64;
1177e85d0918SDaniel Drake 	}
1178e85d0918SDaniel Drake 	ZD_ASSERT(rx->fragment_length == 0);
11791f6cccccSJussi Kivilinna 	INIT_DELAYED_WORK(&rx->idle_work, zd_rx_idle_timer_handler);
11805d4650aeSAllen Pais 	rx->reset_timer_tasklet.func = (void (*))
118126721b02SAllen Pais 					zd_usb_reset_rx_idle_timer_tasklet;
11825d4650aeSAllen Pais 	rx->reset_timer_tasklet.data = (unsigned long)&rx->reset_timer_tasklet;
1183e85d0918SDaniel Drake }
1184e85d0918SDaniel Drake 
init_usb_tx(struct zd_usb * usb)1185e85d0918SDaniel Drake static inline void init_usb_tx(struct zd_usb *usb)
1186e85d0918SDaniel Drake {
1187459c51adSDaniel Drake 	struct zd_usb_tx *tx = &usb->tx;
118802353573SJussi Kivilinna 
1189459c51adSDaniel Drake 	spin_lock_init(&tx->lock);
119078fc800fSJussi Kivilinna 	atomic_set(&tx->enabled, 0);
1191459c51adSDaniel Drake 	tx->stopped = 0;
1192a0fd751fSJussi Kivilinna 	skb_queue_head_init(&tx->submitted_skbs);
119378fc800fSJussi Kivilinna 	init_usb_anchor(&tx->submitted);
1194459c51adSDaniel Drake 	tx->submitted_urbs = 0;
1195a0fd751fSJussi Kivilinna 	tx->watchdog_enabled = 0;
1196a0fd751fSJussi Kivilinna 	INIT_DELAYED_WORK(&tx->watchdog_work, zd_tx_watchdog_handler);
1197e85d0918SDaniel Drake }
1198e85d0918SDaniel Drake 
zd_usb_init(struct zd_usb * usb,struct ieee80211_hw * hw,struct usb_interface * intf)1199459c51adSDaniel Drake void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw,
1200e85d0918SDaniel Drake 	         struct usb_interface *intf)
1201e85d0918SDaniel Drake {
1202e85d0918SDaniel Drake 	memset(usb, 0, sizeof(*usb));
1203e85d0918SDaniel Drake 	usb->intf = usb_get_intf(intf);
1204459c51adSDaniel Drake 	usb_set_intfdata(usb->intf, hw);
1205eefdbec1SJussi Kivilinna 	init_usb_anchor(&usb->submitted_cmds);
1206e85d0918SDaniel Drake 	init_usb_interrupt(usb);
1207e85d0918SDaniel Drake 	init_usb_tx(usb);
1208e85d0918SDaniel Drake 	init_usb_rx(usb);
1209e85d0918SDaniel Drake }
1210e85d0918SDaniel Drake 
zd_usb_clear(struct zd_usb * usb)1211e85d0918SDaniel Drake void zd_usb_clear(struct zd_usb *usb)
1212e85d0918SDaniel Drake {
1213e85d0918SDaniel Drake 	usb_set_intfdata(usb->intf, NULL);
1214e85d0918SDaniel Drake 	usb_put_intf(usb->intf);
1215c48cf125SUlrich Kunitz 	ZD_MEMCLEAR(usb, sizeof(*usb));
1216e85d0918SDaniel Drake 	/* FIXME: usb_interrupt, usb_tx, usb_rx? */
1217e85d0918SDaniel Drake }
1218e85d0918SDaniel Drake 
speed(enum usb_device_speed speed)1219e85d0918SDaniel Drake static const char *speed(enum usb_device_speed speed)
1220e85d0918SDaniel Drake {
1221e85d0918SDaniel Drake 	switch (speed) {
1222e85d0918SDaniel Drake 	case USB_SPEED_LOW:
1223e85d0918SDaniel Drake 		return "low";
1224e85d0918SDaniel Drake 	case USB_SPEED_FULL:
1225e85d0918SDaniel Drake 		return "full";
1226e85d0918SDaniel Drake 	case USB_SPEED_HIGH:
1227e85d0918SDaniel Drake 		return "high";
1228e85d0918SDaniel Drake 	default:
1229e85d0918SDaniel Drake 		return "unknown speed";
1230e85d0918SDaniel Drake 	}
1231e85d0918SDaniel Drake }
1232e85d0918SDaniel Drake 
scnprint_id(struct usb_device * udev,char * buffer,size_t size)1233e85d0918SDaniel Drake static int scnprint_id(struct usb_device *udev, char *buffer, size_t size)
1234e85d0918SDaniel Drake {
1235e85d0918SDaniel Drake 	return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s",
1236e85d0918SDaniel Drake 		le16_to_cpu(udev->descriptor.idVendor),
1237e85d0918SDaniel Drake 		le16_to_cpu(udev->descriptor.idProduct),
1238e85d0918SDaniel Drake 		get_bcdDevice(udev),
1239e85d0918SDaniel Drake 		speed(udev->speed));
1240e85d0918SDaniel Drake }
1241e85d0918SDaniel Drake 
zd_usb_scnprint_id(struct zd_usb * usb,char * buffer,size_t size)1242e85d0918SDaniel Drake int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size)
1243e85d0918SDaniel Drake {
1244e85d0918SDaniel Drake 	struct usb_device *udev = interface_to_usbdev(usb->intf);
1245e85d0918SDaniel Drake 	return scnprint_id(udev, buffer, size);
1246e85d0918SDaniel Drake }
1247e85d0918SDaniel Drake 
1248e85d0918SDaniel Drake #ifdef DEBUG
print_id(struct usb_device * udev)1249e85d0918SDaniel Drake static void print_id(struct usb_device *udev)
1250e85d0918SDaniel Drake {
1251e85d0918SDaniel Drake 	char buffer[40];
1252e85d0918SDaniel Drake 
1253e85d0918SDaniel Drake 	scnprint_id(udev, buffer, sizeof(buffer));
1254e85d0918SDaniel Drake 	buffer[sizeof(buffer)-1] = 0;
1255e85d0918SDaniel Drake 	dev_dbg_f(&udev->dev, "%s\n", buffer);
1256e85d0918SDaniel Drake }
1257e85d0918SDaniel Drake #else
1258e85d0918SDaniel Drake #define print_id(udev) do { } while (0)
1259e85d0918SDaniel Drake #endif
1260e85d0918SDaniel Drake 
eject_installer(struct usb_interface * intf)1261a1030e92SDaniel Drake static int eject_installer(struct usb_interface *intf)
1262a1030e92SDaniel Drake {
1263a1030e92SDaniel Drake 	struct usb_device *udev = interface_to_usbdev(intf);
12642d68bb26SJohan Hovold 	struct usb_host_interface *iface_desc = intf->cur_altsetting;
1265a1030e92SDaniel Drake 	struct usb_endpoint_descriptor *endpoint;
1266a1030e92SDaniel Drake 	unsigned char *cmd;
1267a1030e92SDaniel Drake 	u8 bulk_out_ep;
1268a1030e92SDaniel Drake 	int r;
1269a1030e92SDaniel Drake 
1270ca260eceSJohan Hovold 	if (iface_desc->desc.bNumEndpoints < 2)
1271ca260eceSJohan Hovold 		return -ENODEV;
1272ca260eceSJohan Hovold 
1273a1030e92SDaniel Drake 	/* Find bulk out endpoint */
127411466f13SStefan Seyfried 	for (r = 1; r >= 0; r--) {
127511466f13SStefan Seyfried 		endpoint = &iface_desc->endpoint[r].desc;
127633e2fb2fSJulia Lawall 		if (usb_endpoint_dir_out(endpoint) &&
1277f201a8a4SJulia Lawall 		    usb_endpoint_xfer_bulk(endpoint)) {
1278a1030e92SDaniel Drake 			bulk_out_ep = endpoint->bEndpointAddress;
127911466f13SStefan Seyfried 			break;
128011466f13SStefan Seyfried 		}
128111466f13SStefan Seyfried 	}
128211466f13SStefan Seyfried 	if (r == -1) {
1283a1030e92SDaniel Drake 		dev_err(&udev->dev,
1284a1030e92SDaniel Drake 			"zd1211rw: Could not find bulk out endpoint\n");
1285a1030e92SDaniel Drake 		return -ENODEV;
1286a1030e92SDaniel Drake 	}
1287a1030e92SDaniel Drake 
1288a1030e92SDaniel Drake 	cmd = kzalloc(31, GFP_KERNEL);
1289a1030e92SDaniel Drake 	if (cmd == NULL)
1290a1030e92SDaniel Drake 		return -ENODEV;
1291a1030e92SDaniel Drake 
1292a1030e92SDaniel Drake 	/* USB bulk command block */
1293a1030e92SDaniel Drake 	cmd[0] = 0x55;	/* bulk command signature */
1294a1030e92SDaniel Drake 	cmd[1] = 0x53;	/* bulk command signature */
1295a1030e92SDaniel Drake 	cmd[2] = 0x42;	/* bulk command signature */
1296a1030e92SDaniel Drake 	cmd[3] = 0x43;	/* bulk command signature */
1297a1030e92SDaniel Drake 	cmd[14] = 6;	/* command length */
1298a1030e92SDaniel Drake 
1299a1030e92SDaniel Drake 	cmd[15] = 0x1b;	/* SCSI command: START STOP UNIT */
1300a1030e92SDaniel Drake 	cmd[19] = 0x2;	/* eject disc */
1301a1030e92SDaniel Drake 
1302a1030e92SDaniel Drake 	dev_info(&udev->dev, "Ejecting virtual installer media...\n");
1303a1030e92SDaniel Drake 	r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
1304a1030e92SDaniel Drake 		cmd, 31, NULL, 2000);
1305a1030e92SDaniel Drake 	kfree(cmd);
1306a1030e92SDaniel Drake 	if (r)
1307a1030e92SDaniel Drake 		return r;
1308a1030e92SDaniel Drake 
1309a1030e92SDaniel Drake 	/* At this point, the device disconnects and reconnects with the real
1310a1030e92SDaniel Drake 	 * ID numbers. */
1311a1030e92SDaniel Drake 
1312a1030e92SDaniel Drake 	usb_set_intfdata(intf, NULL);
1313a1030e92SDaniel Drake 	return 0;
1314a1030e92SDaniel Drake }
1315a1030e92SDaniel Drake 
zd_usb_init_hw(struct zd_usb * usb)131674553aedSDaniel Drake int zd_usb_init_hw(struct zd_usb *usb)
131774553aedSDaniel Drake {
131874553aedSDaniel Drake 	int r;
131974553aedSDaniel Drake 	struct zd_mac *mac = zd_usb_to_mac(usb);
132074553aedSDaniel Drake 
132174553aedSDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "\n");
132274553aedSDaniel Drake 
132374553aedSDaniel Drake 	r = upload_firmware(usb);
132474553aedSDaniel Drake 	if (r) {
132574553aedSDaniel Drake 		dev_err(zd_usb_dev(usb),
132674553aedSDaniel Drake 		       "couldn't load firmware. Error number %d\n", r);
132774553aedSDaniel Drake 		return r;
132874553aedSDaniel Drake 	}
132974553aedSDaniel Drake 
133074553aedSDaniel Drake 	r = usb_reset_configuration(zd_usb_to_usbdev(usb));
133174553aedSDaniel Drake 	if (r) {
133274553aedSDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
133374553aedSDaniel Drake 			"couldn't reset configuration. Error number %d\n", r);
133474553aedSDaniel Drake 		return r;
133574553aedSDaniel Drake 	}
133674553aedSDaniel Drake 
1337459c51adSDaniel Drake 	r = zd_mac_init_hw(mac->hw);
133874553aedSDaniel Drake 	if (r) {
133974553aedSDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
134074553aedSDaniel Drake 		         "couldn't initialize mac. Error number %d\n", r);
134174553aedSDaniel Drake 		return r;
134274553aedSDaniel Drake 	}
134374553aedSDaniel Drake 
134474553aedSDaniel Drake 	usb->initialized = 1;
134574553aedSDaniel Drake 	return 0;
134674553aedSDaniel Drake }
134774553aedSDaniel Drake 
probe(struct usb_interface * intf,const struct usb_device_id * id)1348e85d0918SDaniel Drake static int probe(struct usb_interface *intf, const struct usb_device_id *id)
1349e85d0918SDaniel Drake {
1350e85d0918SDaniel Drake 	int r;
1351e85d0918SDaniel Drake 	struct usb_device *udev = interface_to_usbdev(intf);
1352459c51adSDaniel Drake 	struct zd_usb *usb;
1353459c51adSDaniel Drake 	struct ieee80211_hw *hw = NULL;
1354e85d0918SDaniel Drake 
1355e85d0918SDaniel Drake 	print_id(udev);
1356e85d0918SDaniel Drake 
1357a1030e92SDaniel Drake 	if (id->driver_info & DEVICE_INSTALLER)
1358a1030e92SDaniel Drake 		return eject_installer(intf);
1359a1030e92SDaniel Drake 
1360e85d0918SDaniel Drake 	switch (udev->speed) {
1361e85d0918SDaniel Drake 	case USB_SPEED_LOW:
1362e85d0918SDaniel Drake 	case USB_SPEED_FULL:
1363e85d0918SDaniel Drake 	case USB_SPEED_HIGH:
1364e85d0918SDaniel Drake 		break;
1365e85d0918SDaniel Drake 	default:
1366e85d0918SDaniel Drake 		dev_dbg_f(&intf->dev, "Unknown USB speed\n");
1367e85d0918SDaniel Drake 		r = -ENODEV;
1368e85d0918SDaniel Drake 		goto error;
1369e85d0918SDaniel Drake 	}
1370e85d0918SDaniel Drake 
1371459c51adSDaniel Drake 	r = usb_reset_device(udev);
1372459c51adSDaniel Drake 	if (r) {
1373459c51adSDaniel Drake 		dev_err(&intf->dev,
1374459c51adSDaniel Drake 			"couldn't reset usb device. Error number %d\n", r);
1375459c51adSDaniel Drake 		goto error;
1376459c51adSDaniel Drake 	}
13776e3632f6SUlrich Kunitz 
1378459c51adSDaniel Drake 	hw = zd_mac_alloc_hw(intf);
1379459c51adSDaniel Drake 	if (hw == NULL) {
1380e85d0918SDaniel Drake 		r = -ENOMEM;
1381e85d0918SDaniel Drake 		goto error;
1382e85d0918SDaniel Drake 	}
1383e85d0918SDaniel Drake 
1384459c51adSDaniel Drake 	usb = &zd_hw_mac(hw)->chip.usb;
138574553aedSDaniel Drake 	usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0;
1386e85d0918SDaniel Drake 
1387459c51adSDaniel Drake 	r = zd_mac_preinit_hw(hw);
1388e85d0918SDaniel Drake 	if (r) {
1389e85d0918SDaniel Drake 		dev_dbg_f(&intf->dev,
1390e85d0918SDaniel Drake 		         "couldn't initialize mac. Error number %d\n", r);
1391e85d0918SDaniel Drake 		goto error;
1392e85d0918SDaniel Drake 	}
1393e85d0918SDaniel Drake 
1394459c51adSDaniel Drake 	r = ieee80211_register_hw(hw);
1395e85d0918SDaniel Drake 	if (r) {
1396e85d0918SDaniel Drake 		dev_dbg_f(&intf->dev,
1397459c51adSDaniel Drake 			 "couldn't register device. Error number %d\n", r);
1398e85d0918SDaniel Drake 		goto error;
1399e85d0918SDaniel Drake 	}
1400e85d0918SDaniel Drake 
1401e85d0918SDaniel Drake 	dev_dbg_f(&intf->dev, "successful\n");
1402459c51adSDaniel Drake 	dev_info(&intf->dev, "%s\n", wiphy_name(hw->wiphy));
1403e85d0918SDaniel Drake 	return 0;
1404e85d0918SDaniel Drake error:
1405e85d0918SDaniel Drake 	usb_reset_device(interface_to_usbdev(intf));
1406459c51adSDaniel Drake 	if (hw) {
1407459c51adSDaniel Drake 		zd_mac_clear(zd_hw_mac(hw));
1408459c51adSDaniel Drake 		ieee80211_free_hw(hw);
1409459c51adSDaniel Drake 	}
1410e85d0918SDaniel Drake 	return r;
1411e85d0918SDaniel Drake }
1412e85d0918SDaniel Drake 
disconnect(struct usb_interface * intf)1413e85d0918SDaniel Drake static void disconnect(struct usb_interface *intf)
1414e85d0918SDaniel Drake {
1415459c51adSDaniel Drake 	struct ieee80211_hw *hw = zd_intf_to_hw(intf);
1416e0579d57SMarc Pignat 	struct zd_mac *mac;
1417e0579d57SMarc Pignat 	struct zd_usb *usb;
1418e85d0918SDaniel Drake 
1419a1030e92SDaniel Drake 	/* Either something really bad happened, or we're just dealing with
1420a1030e92SDaniel Drake 	 * a DEVICE_INSTALLER. */
1421459c51adSDaniel Drake 	if (hw == NULL)
1422a1030e92SDaniel Drake 		return;
1423a1030e92SDaniel Drake 
1424459c51adSDaniel Drake 	mac = zd_hw_mac(hw);
1425e0579d57SMarc Pignat 	usb = &mac->chip.usb;
1426e0579d57SMarc Pignat 
1427e85d0918SDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "\n");
1428e85d0918SDaniel Drake 
1429459c51adSDaniel Drake 	ieee80211_unregister_hw(hw);
1430e85d0918SDaniel Drake 
1431e85d0918SDaniel Drake 	/* Just in case something has gone wrong! */
143278fc800fSJussi Kivilinna 	zd_usb_disable_tx(usb);
1433e85d0918SDaniel Drake 	zd_usb_disable_rx(usb);
1434e85d0918SDaniel Drake 	zd_usb_disable_int(usb);
1435e85d0918SDaniel Drake 
1436e85d0918SDaniel Drake 	/* If the disconnect has been caused by a removal of the
1437e85d0918SDaniel Drake 	 * driver module, the reset allows reloading of the driver. If the
1438e85d0918SDaniel Drake 	 * reset will not be executed here, the upload of the firmware in the
1439e85d0918SDaniel Drake 	 * probe function caused by the reloading of the driver will fail.
1440e85d0918SDaniel Drake 	 */
1441e85d0918SDaniel Drake 	usb_reset_device(interface_to_usbdev(intf));
1442e85d0918SDaniel Drake 
1443459c51adSDaniel Drake 	zd_mac_clear(mac);
1444459c51adSDaniel Drake 	ieee80211_free_hw(hw);
1445e85d0918SDaniel Drake 	dev_dbg(&intf->dev, "disconnected\n");
1446e85d0918SDaniel Drake }
1447e85d0918SDaniel Drake 
zd_usb_resume(struct zd_usb * usb)1448a0fd751fSJussi Kivilinna static void zd_usb_resume(struct zd_usb *usb)
1449a0fd751fSJussi Kivilinna {
1450a0fd751fSJussi Kivilinna 	struct zd_mac *mac = zd_usb_to_mac(usb);
1451a0fd751fSJussi Kivilinna 	int r;
1452a0fd751fSJussi Kivilinna 
1453a0fd751fSJussi Kivilinna 	dev_dbg_f(zd_usb_dev(usb), "\n");
1454a0fd751fSJussi Kivilinna 
1455a0fd751fSJussi Kivilinna 	r = zd_op_start(zd_usb_to_hw(usb));
1456a0fd751fSJussi Kivilinna 	if (r < 0) {
1457a0fd751fSJussi Kivilinna 		dev_warn(zd_usb_dev(usb), "Device resume failed "
1458a0fd751fSJussi Kivilinna 			 "with error code %d. Retrying...\n", r);
1459a0fd751fSJussi Kivilinna 		if (usb->was_running)
1460a0fd751fSJussi Kivilinna 			set_bit(ZD_DEVICE_RUNNING, &mac->flags);
1461a0fd751fSJussi Kivilinna 		usb_queue_reset_device(usb->intf);
1462a0fd751fSJussi Kivilinna 		return;
1463a0fd751fSJussi Kivilinna 	}
1464a0fd751fSJussi Kivilinna 
1465a0fd751fSJussi Kivilinna 	if (mac->type != NL80211_IFTYPE_UNSPECIFIED) {
1466a0fd751fSJussi Kivilinna 		r = zd_restore_settings(mac);
1467a0fd751fSJussi Kivilinna 		if (r < 0) {
1468a0fd751fSJussi Kivilinna 			dev_dbg(zd_usb_dev(usb),
1469a0fd751fSJussi Kivilinna 				"failed to restore settings, %d\n", r);
1470a0fd751fSJussi Kivilinna 			return;
1471a0fd751fSJussi Kivilinna 		}
1472a0fd751fSJussi Kivilinna 	}
1473a0fd751fSJussi Kivilinna }
1474a0fd751fSJussi Kivilinna 
zd_usb_stop(struct zd_usb * usb)1475a0fd751fSJussi Kivilinna static void zd_usb_stop(struct zd_usb *usb)
1476a0fd751fSJussi Kivilinna {
1477a0fd751fSJussi Kivilinna 	dev_dbg_f(zd_usb_dev(usb), "\n");
1478a0fd751fSJussi Kivilinna 
14791decf05dSEmmanuel Grumbach 	zd_op_stop(zd_usb_to_hw(usb), false);
1480a0fd751fSJussi Kivilinna 
1481a0fd751fSJussi Kivilinna 	zd_usb_disable_tx(usb);
1482a0fd751fSJussi Kivilinna 	zd_usb_disable_rx(usb);
1483a0fd751fSJussi Kivilinna 	zd_usb_disable_int(usb);
1484a0fd751fSJussi Kivilinna 
1485a0fd751fSJussi Kivilinna 	usb->initialized = 0;
1486a0fd751fSJussi Kivilinna }
1487a0fd751fSJussi Kivilinna 
pre_reset(struct usb_interface * intf)1488a0fd751fSJussi Kivilinna static int pre_reset(struct usb_interface *intf)
1489a0fd751fSJussi Kivilinna {
1490a0fd751fSJussi Kivilinna 	struct ieee80211_hw *hw = usb_get_intfdata(intf);
1491a0fd751fSJussi Kivilinna 	struct zd_mac *mac;
1492a0fd751fSJussi Kivilinna 	struct zd_usb *usb;
1493a0fd751fSJussi Kivilinna 
1494a0fd751fSJussi Kivilinna 	if (!hw || intf->condition != USB_INTERFACE_BOUND)
1495a0fd751fSJussi Kivilinna 		return 0;
1496a0fd751fSJussi Kivilinna 
1497a0fd751fSJussi Kivilinna 	mac = zd_hw_mac(hw);
1498a0fd751fSJussi Kivilinna 	usb = &mac->chip.usb;
1499a0fd751fSJussi Kivilinna 
1500a0fd751fSJussi Kivilinna 	usb->was_running = test_bit(ZD_DEVICE_RUNNING, &mac->flags);
1501a0fd751fSJussi Kivilinna 
1502a0fd751fSJussi Kivilinna 	zd_usb_stop(usb);
1503a0fd751fSJussi Kivilinna 
1504a0fd751fSJussi Kivilinna 	mutex_lock(&mac->chip.mutex);
1505a0fd751fSJussi Kivilinna 	return 0;
1506a0fd751fSJussi Kivilinna }
1507a0fd751fSJussi Kivilinna 
post_reset(struct usb_interface * intf)1508a0fd751fSJussi Kivilinna static int post_reset(struct usb_interface *intf)
1509a0fd751fSJussi Kivilinna {
1510a0fd751fSJussi Kivilinna 	struct ieee80211_hw *hw = usb_get_intfdata(intf);
1511a0fd751fSJussi Kivilinna 	struct zd_mac *mac;
1512a0fd751fSJussi Kivilinna 	struct zd_usb *usb;
1513a0fd751fSJussi Kivilinna 
1514a0fd751fSJussi Kivilinna 	if (!hw || intf->condition != USB_INTERFACE_BOUND)
1515a0fd751fSJussi Kivilinna 		return 0;
1516a0fd751fSJussi Kivilinna 
1517a0fd751fSJussi Kivilinna 	mac = zd_hw_mac(hw);
1518a0fd751fSJussi Kivilinna 	usb = &mac->chip.usb;
1519a0fd751fSJussi Kivilinna 
1520a0fd751fSJussi Kivilinna 	mutex_unlock(&mac->chip.mutex);
1521a0fd751fSJussi Kivilinna 
1522a0fd751fSJussi Kivilinna 	if (usb->was_running)
1523a0fd751fSJussi Kivilinna 		zd_usb_resume(usb);
1524a0fd751fSJussi Kivilinna 	return 0;
1525a0fd751fSJussi Kivilinna }
1526a0fd751fSJussi Kivilinna 
1527e85d0918SDaniel Drake static struct usb_driver driver = {
1528459c51adSDaniel Drake 	.name		= KBUILD_MODNAME,
1529e85d0918SDaniel Drake 	.id_table	= usb_ids,
1530e85d0918SDaniel Drake 	.probe		= probe,
1531e85d0918SDaniel Drake 	.disconnect	= disconnect,
1532a0fd751fSJussi Kivilinna 	.pre_reset	= pre_reset,
1533a0fd751fSJussi Kivilinna 	.post_reset	= post_reset,
1534e1f12eb6SSarah Sharp 	.disable_hub_initiated_lpm = 1,
1535e85d0918SDaniel Drake };
1536e85d0918SDaniel Drake 
1537bc5f06a8SUlrich Kunitz struct workqueue_struct *zd_workqueue;
1538bc5f06a8SUlrich Kunitz 
usb_init(void)1539e85d0918SDaniel Drake static int __init usb_init(void)
1540e85d0918SDaniel Drake {
1541e85d0918SDaniel Drake 	int r;
1542e85d0918SDaniel Drake 
1543741fec53SUlrich Kunitz 	pr_debug("%s usb_init()\n", driver.name);
1544e85d0918SDaniel Drake 
1545bc5f06a8SUlrich Kunitz 	zd_workqueue = create_singlethread_workqueue(driver.name);
1546bc5f06a8SUlrich Kunitz 	if (zd_workqueue == NULL) {
154729d97219SSaurav Girepunje 		pr_err("%s couldn't create workqueue\n", driver.name);
1548bc5f06a8SUlrich Kunitz 		return -ENOMEM;
1549bc5f06a8SUlrich Kunitz 	}
1550bc5f06a8SUlrich Kunitz 
1551e85d0918SDaniel Drake 	r = usb_register(&driver);
1552e85d0918SDaniel Drake 	if (r) {
1553192b775cSMaxime Austruy 		destroy_workqueue(zd_workqueue);
155429d97219SSaurav Girepunje 		pr_err("%s usb_register() failed. Error number %d\n",
1555741fec53SUlrich Kunitz 		       driver.name, r);
1556e85d0918SDaniel Drake 		return r;
1557e85d0918SDaniel Drake 	}
1558e85d0918SDaniel Drake 
1559741fec53SUlrich Kunitz 	pr_debug("%s initialized\n", driver.name);
1560e85d0918SDaniel Drake 	return 0;
1561e85d0918SDaniel Drake }
1562e85d0918SDaniel Drake 
usb_exit(void)1563e85d0918SDaniel Drake static void __exit usb_exit(void)
1564e85d0918SDaniel Drake {
1565741fec53SUlrich Kunitz 	pr_debug("%s usb_exit()\n", driver.name);
1566e85d0918SDaniel Drake 	usb_deregister(&driver);
1567bc5f06a8SUlrich Kunitz 	destroy_workqueue(zd_workqueue);
1568e85d0918SDaniel Drake }
1569e85d0918SDaniel Drake 
1570e85d0918SDaniel Drake module_init(usb_init);
1571e85d0918SDaniel Drake module_exit(usb_exit);
1572e85d0918SDaniel Drake 
zd_ep_regs_out_msg(struct usb_device * udev,void * data,int len,int * actual_length,int timeout)157359342f6aSJussi Kivilinna static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len,
157459342f6aSJussi Kivilinna 			      int *actual_length, int timeout)
157559342f6aSJussi Kivilinna {
157659342f6aSJussi Kivilinna 	/* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in
157759342f6aSJussi Kivilinna 	 * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint
157859342f6aSJussi Kivilinna 	 * descriptor.
157959342f6aSJussi Kivilinna 	 */
158059342f6aSJussi Kivilinna 	struct usb_host_endpoint *ep;
158159342f6aSJussi Kivilinna 	unsigned int pipe;
158259342f6aSJussi Kivilinna 
158359342f6aSJussi Kivilinna 	pipe = usb_sndintpipe(udev, EP_REGS_OUT);
158459342f6aSJussi Kivilinna 	ep = usb_pipe_endpoint(udev, pipe);
158559342f6aSJussi Kivilinna 	if (!ep)
158659342f6aSJussi Kivilinna 		return -EINVAL;
158759342f6aSJussi Kivilinna 
158859342f6aSJussi Kivilinna 	if (usb_endpoint_xfer_int(&ep->desc)) {
158959342f6aSJussi Kivilinna 		return usb_interrupt_msg(udev, pipe, data, len,
159059342f6aSJussi Kivilinna 					 actual_length, timeout);
159159342f6aSJussi Kivilinna 	} else {
159259342f6aSJussi Kivilinna 		pipe = usb_sndbulkpipe(udev, EP_REGS_OUT);
159359342f6aSJussi Kivilinna 		return usb_bulk_msg(udev, pipe, data, len, actual_length,
159459342f6aSJussi Kivilinna 				    timeout);
159559342f6aSJussi Kivilinna 	}
159659342f6aSJussi Kivilinna }
159759342f6aSJussi Kivilinna 
prepare_read_regs_int(struct zd_usb * usb,struct usb_req_read_regs * req,unsigned int count)1598c900eff3SJussi Kivilinna static void prepare_read_regs_int(struct zd_usb *usb,
1599c900eff3SJussi Kivilinna 				  struct usb_req_read_regs *req,
1600c900eff3SJussi Kivilinna 				  unsigned int count)
1601e85d0918SDaniel Drake {
1602e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
1603e85d0918SDaniel Drake 
1604a68077deSUlrich Kunitz 	spin_lock_irq(&intr->lock);
1605c900eff3SJussi Kivilinna 	atomic_set(&intr->read_regs_enabled, 1);
1606c900eff3SJussi Kivilinna 	intr->read_regs.req = req;
1607c900eff3SJussi Kivilinna 	intr->read_regs.req_count = count;
160816735d02SWolfram Sang 	reinit_completion(&intr->read_regs.completion);
1609a68077deSUlrich Kunitz 	spin_unlock_irq(&intr->lock);
1610a68077deSUlrich Kunitz }
1611a68077deSUlrich Kunitz 
disable_read_regs_int(struct zd_usb * usb)1612a68077deSUlrich Kunitz static void disable_read_regs_int(struct zd_usb *usb)
1613a68077deSUlrich Kunitz {
1614a68077deSUlrich Kunitz 	struct zd_usb_interrupt *intr = &usb->intr;
1615a68077deSUlrich Kunitz 
1616a68077deSUlrich Kunitz 	spin_lock_irq(&intr->lock);
1617c900eff3SJussi Kivilinna 	atomic_set(&intr->read_regs_enabled, 0);
1618a68077deSUlrich Kunitz 	spin_unlock_irq(&intr->lock);
1619e85d0918SDaniel Drake }
1620e85d0918SDaniel Drake 
check_read_regs(struct zd_usb * usb,struct usb_req_read_regs * req,unsigned int count)1621c900eff3SJussi Kivilinna static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req,
1622c900eff3SJussi Kivilinna 			    unsigned int count)
1623c900eff3SJussi Kivilinna {
1624c900eff3SJussi Kivilinna 	int i;
1625c900eff3SJussi Kivilinna 	struct zd_usb_interrupt *intr = &usb->intr;
1626c900eff3SJussi Kivilinna 	struct read_regs_int *rr = &intr->read_regs;
1627c900eff3SJussi Kivilinna 	struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;
1628c900eff3SJussi Kivilinna 
1629c900eff3SJussi Kivilinna 	/* The created block size seems to be larger than expected.
1630c900eff3SJussi Kivilinna 	 * However results appear to be correct.
1631c900eff3SJussi Kivilinna 	 */
163284b0b663SGustavo A. R. Silva 	if (rr->length < struct_size(regs, regs, count)) {
1633c900eff3SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb),
16346355592eSGeert Uytterhoeven 			 "error: actual length %d less than expected %zu\n",
163584b0b663SGustavo A. R. Silva 			 rr->length, struct_size(regs, regs, count));
1636c900eff3SJussi Kivilinna 		return false;
1637c900eff3SJussi Kivilinna 	}
1638c900eff3SJussi Kivilinna 
1639c900eff3SJussi Kivilinna 	if (rr->length > sizeof(rr->buffer)) {
1640c900eff3SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb),
1641c900eff3SJussi Kivilinna 			 "error: actual length %d exceeds buffer size %zu\n",
1642c900eff3SJussi Kivilinna 			 rr->length, sizeof(rr->buffer));
1643c900eff3SJussi Kivilinna 		return false;
1644c900eff3SJussi Kivilinna 	}
1645c900eff3SJussi Kivilinna 
1646c900eff3SJussi Kivilinna 	for (i = 0; i < count; i++) {
1647c900eff3SJussi Kivilinna 		struct reg_data *rd = &regs->regs[i];
1648c900eff3SJussi Kivilinna 		if (rd->addr != req->addr[i]) {
1649c900eff3SJussi Kivilinna 			dev_dbg_f(zd_usb_dev(usb),
1650c900eff3SJussi Kivilinna 				 "rd[%d] addr %#06hx expected %#06hx\n", i,
1651c900eff3SJussi Kivilinna 				 le16_to_cpu(rd->addr),
1652c900eff3SJussi Kivilinna 				 le16_to_cpu(req->addr[i]));
1653c900eff3SJussi Kivilinna 			return false;
1654c900eff3SJussi Kivilinna 		}
1655c900eff3SJussi Kivilinna 	}
1656c900eff3SJussi Kivilinna 
1657c900eff3SJussi Kivilinna 	return true;
1658c900eff3SJussi Kivilinna }
1659c900eff3SJussi Kivilinna 
get_results(struct zd_usb * usb,u16 * values,struct usb_req_read_regs * req,unsigned int count,bool * retry)1660e85d0918SDaniel Drake static int get_results(struct zd_usb *usb, u16 *values,
1661c900eff3SJussi Kivilinna 		       struct usb_req_read_regs *req, unsigned int count,
1662c900eff3SJussi Kivilinna 		       bool *retry)
1663e85d0918SDaniel Drake {
1664e85d0918SDaniel Drake 	int r;
1665e85d0918SDaniel Drake 	int i;
1666e85d0918SDaniel Drake 	struct zd_usb_interrupt *intr = &usb->intr;
1667e85d0918SDaniel Drake 	struct read_regs_int *rr = &intr->read_regs;
1668e85d0918SDaniel Drake 	struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;
1669e85d0918SDaniel Drake 
1670a68077deSUlrich Kunitz 	spin_lock_irq(&intr->lock);
1671e85d0918SDaniel Drake 
1672e85d0918SDaniel Drake 	r = -EIO;
1673c900eff3SJussi Kivilinna 
1674c900eff3SJussi Kivilinna 	/* Read failed because firmware bug? */
1675c900eff3SJussi Kivilinna 	*retry = !!intr->read_regs_int_overridden;
1676c900eff3SJussi Kivilinna 	if (*retry)
1677e85d0918SDaniel Drake 		goto error_unlock;
1678c900eff3SJussi Kivilinna 
1679c900eff3SJussi Kivilinna 	if (!check_read_regs(usb, req, count)) {
1680c900eff3SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "error: invalid read regs\n");
1681e85d0918SDaniel Drake 		goto error_unlock;
1682e85d0918SDaniel Drake 	}
1683e85d0918SDaniel Drake 
1684e85d0918SDaniel Drake 	for (i = 0; i < count; i++) {
1685e85d0918SDaniel Drake 		struct reg_data *rd = &regs->regs[i];
1686e85d0918SDaniel Drake 		values[i] = le16_to_cpu(rd->value);
1687e85d0918SDaniel Drake 	}
1688e85d0918SDaniel Drake 
1689e85d0918SDaniel Drake 	r = 0;
1690e85d0918SDaniel Drake error_unlock:
1691a68077deSUlrich Kunitz 	spin_unlock_irq(&intr->lock);
1692e85d0918SDaniel Drake 	return r;
1693e85d0918SDaniel Drake }
1694e85d0918SDaniel Drake 
zd_usb_ioread16v(struct zd_usb * usb,u16 * values,const zd_addr_t * addresses,unsigned int count)1695e85d0918SDaniel Drake int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
1696e85d0918SDaniel Drake 	             const zd_addr_t *addresses, unsigned int count)
1697e85d0918SDaniel Drake {
1698c900eff3SJussi Kivilinna 	int r, i, req_len, actual_req_len, try_count = 0;
1699e85d0918SDaniel Drake 	struct usb_device *udev;
1700e85d0918SDaniel Drake 	struct usb_req_read_regs *req = NULL;
1701a2ead344SWolfram Sang 	unsigned long time_left;
1702c900eff3SJussi Kivilinna 	bool retry = false;
1703e85d0918SDaniel Drake 
1704e85d0918SDaniel Drake 	if (count < 1) {
1705e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");
1706e85d0918SDaniel Drake 		return -EINVAL;
1707e85d0918SDaniel Drake 	}
1708e85d0918SDaniel Drake 	if (count > USB_MAX_IOREAD16_COUNT) {
1709e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1710e85d0918SDaniel Drake 			 "error: count %u exceeds possible max %u\n",
1711e85d0918SDaniel Drake 			 count, USB_MAX_IOREAD16_COUNT);
1712e85d0918SDaniel Drake 		return -EINVAL;
1713e85d0918SDaniel Drake 	}
1714e85d0918SDaniel Drake 	if (!usb_int_enabled(usb)) {
1715e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1716e85d0918SDaniel Drake 			  "error: usb interrupt not enabled\n");
1717e85d0918SDaniel Drake 		return -EWOULDBLOCK;
1718e85d0918SDaniel Drake 	}
1719e85d0918SDaniel Drake 
17209bca0c3bSJussi Kivilinna 	ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
17219bca0c3bSJussi Kivilinna 	BUILD_BUG_ON(sizeof(struct usb_req_read_regs) + USB_MAX_IOREAD16_COUNT *
17229bca0c3bSJussi Kivilinna 		     sizeof(__le16) > sizeof(usb->req_buf));
17239bca0c3bSJussi Kivilinna 	BUG_ON(sizeof(struct usb_req_read_regs) + count * sizeof(__le16) >
17249bca0c3bSJussi Kivilinna 	       sizeof(usb->req_buf));
17259bca0c3bSJussi Kivilinna 
1726e85d0918SDaniel Drake 	req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
17279bca0c3bSJussi Kivilinna 	req = (void *)usb->req_buf;
17289bca0c3bSJussi Kivilinna 
1729e85d0918SDaniel Drake 	req->id = cpu_to_le16(USB_REQ_READ_REGS);
1730e85d0918SDaniel Drake 	for (i = 0; i < count; i++)
17310ce34bc8SDaniel Drake 		req->addr[i] = cpu_to_le16((u16)addresses[i]);
1732e85d0918SDaniel Drake 
1733c900eff3SJussi Kivilinna retry_read:
1734c900eff3SJussi Kivilinna 	try_count++;
1735e85d0918SDaniel Drake 	udev = zd_usb_to_usbdev(usb);
1736c900eff3SJussi Kivilinna 	prepare_read_regs_int(usb, req, count);
173759342f6aSJussi Kivilinna 	r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/);
1738e85d0918SDaniel Drake 	if (r) {
1739e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
174059342f6aSJussi Kivilinna 			"error in zd_ep_regs_out_msg(). Error number %d\n", r);
1741e85d0918SDaniel Drake 		goto error;
1742e85d0918SDaniel Drake 	}
1743e85d0918SDaniel Drake 	if (req_len != actual_req_len) {
174459342f6aSJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n"
1745e85d0918SDaniel Drake 			" req_len %d != actual_req_len %d\n",
1746e85d0918SDaniel Drake 			req_len, actual_req_len);
1747e85d0918SDaniel Drake 		r = -EIO;
1748e85d0918SDaniel Drake 		goto error;
1749e85d0918SDaniel Drake 	}
1750e85d0918SDaniel Drake 
1751a2ead344SWolfram Sang 	time_left = wait_for_completion_timeout(&usb->intr.read_regs.completion,
17528f2d8f86SJussi Kivilinna 						msecs_to_jiffies(50));
1753a2ead344SWolfram Sang 	if (!time_left) {
1754e85d0918SDaniel Drake 		disable_read_regs_int(usb);
1755e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb), "read timed out\n");
1756e85d0918SDaniel Drake 		r = -ETIMEDOUT;
1757e85d0918SDaniel Drake 		goto error;
1758e85d0918SDaniel Drake 	}
1759e85d0918SDaniel Drake 
1760c900eff3SJussi Kivilinna 	r = get_results(usb, values, req, count, &retry);
1761c900eff3SJussi Kivilinna 	if (retry && try_count < 20) {
1762c900eff3SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "read retry, tries so far: %d\n",
1763c900eff3SJussi Kivilinna 				try_count);
1764c900eff3SJussi Kivilinna 		goto retry_read;
1765c900eff3SJussi Kivilinna 	}
1766e85d0918SDaniel Drake error:
1767e85d0918SDaniel Drake 	return r;
1768e85d0918SDaniel Drake }
1769e85d0918SDaniel Drake 
iowrite16v_urb_complete(struct urb * urb)1770eefdbec1SJussi Kivilinna static void iowrite16v_urb_complete(struct urb *urb)
1771eefdbec1SJussi Kivilinna {
1772eefdbec1SJussi Kivilinna 	struct zd_usb *usb = urb->context;
1773eefdbec1SJussi Kivilinna 
1774eefdbec1SJussi Kivilinna 	if (urb->status && !usb->cmd_error)
1775eefdbec1SJussi Kivilinna 		usb->cmd_error = urb->status;
17762fc713b2SJussi Kivilinna 
17772fc713b2SJussi Kivilinna 	if (!usb->cmd_error &&
17782fc713b2SJussi Kivilinna 			urb->actual_length != urb->transfer_buffer_length)
17792fc713b2SJussi Kivilinna 		usb->cmd_error = -EIO;
1780eefdbec1SJussi Kivilinna }
1781eefdbec1SJussi Kivilinna 
zd_submit_waiting_urb(struct zd_usb * usb,bool last)1782eefdbec1SJussi Kivilinna static int zd_submit_waiting_urb(struct zd_usb *usb, bool last)
1783eefdbec1SJussi Kivilinna {
17848662b251SJussi Kivilinna 	int r = 0;
1785eefdbec1SJussi Kivilinna 	struct urb *urb = usb->urb_async_waiting;
1786eefdbec1SJussi Kivilinna 
1787eefdbec1SJussi Kivilinna 	if (!urb)
1788eefdbec1SJussi Kivilinna 		return 0;
1789eefdbec1SJussi Kivilinna 
1790eefdbec1SJussi Kivilinna 	usb->urb_async_waiting = NULL;
1791eefdbec1SJussi Kivilinna 
1792eefdbec1SJussi Kivilinna 	if (!last)
1793eefdbec1SJussi Kivilinna 		urb->transfer_flags |= URB_NO_INTERRUPT;
1794eefdbec1SJussi Kivilinna 
1795eefdbec1SJussi Kivilinna 	usb_anchor_urb(urb, &usb->submitted_cmds);
1796eefdbec1SJussi Kivilinna 	r = usb_submit_urb(urb, GFP_KERNEL);
1797eefdbec1SJussi Kivilinna 	if (r) {
1798eefdbec1SJussi Kivilinna 		usb_unanchor_urb(urb);
1799eefdbec1SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb),
1800eefdbec1SJussi Kivilinna 			"error in usb_submit_urb(). Error number %d\n", r);
1801eefdbec1SJussi Kivilinna 		goto error;
1802eefdbec1SJussi Kivilinna 	}
1803eefdbec1SJussi Kivilinna 
1804eefdbec1SJussi Kivilinna 	/* fall-through with r == 0 */
1805eefdbec1SJussi Kivilinna error:
1806eefdbec1SJussi Kivilinna 	usb_free_urb(urb);
1807eefdbec1SJussi Kivilinna 	return r;
1808eefdbec1SJussi Kivilinna }
1809eefdbec1SJussi Kivilinna 
zd_usb_iowrite16v_async_start(struct zd_usb * usb)18108662b251SJussi Kivilinna void zd_usb_iowrite16v_async_start(struct zd_usb *usb)
1811eefdbec1SJussi Kivilinna {
1812eefdbec1SJussi Kivilinna 	ZD_ASSERT(usb_anchor_empty(&usb->submitted_cmds));
1813eefdbec1SJussi Kivilinna 	ZD_ASSERT(usb->urb_async_waiting == NULL);
1814eefdbec1SJussi Kivilinna 	ZD_ASSERT(!usb->in_async);
1815eefdbec1SJussi Kivilinna 
1816eefdbec1SJussi Kivilinna 	ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
1817eefdbec1SJussi Kivilinna 
1818eefdbec1SJussi Kivilinna 	usb->in_async = 1;
1819eefdbec1SJussi Kivilinna 	usb->cmd_error = 0;
1820eefdbec1SJussi Kivilinna 	usb->urb_async_waiting = NULL;
1821eefdbec1SJussi Kivilinna }
1822eefdbec1SJussi Kivilinna 
zd_usb_iowrite16v_async_end(struct zd_usb * usb,unsigned int timeout)18238662b251SJussi Kivilinna int zd_usb_iowrite16v_async_end(struct zd_usb *usb, unsigned int timeout)
1824eefdbec1SJussi Kivilinna {
1825eefdbec1SJussi Kivilinna 	int r;
1826eefdbec1SJussi Kivilinna 
1827eefdbec1SJussi Kivilinna 	ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
1828eefdbec1SJussi Kivilinna 	ZD_ASSERT(usb->in_async);
1829eefdbec1SJussi Kivilinna 
1830eefdbec1SJussi Kivilinna 	/* Submit last iowrite16v URB */
1831eefdbec1SJussi Kivilinna 	r = zd_submit_waiting_urb(usb, true);
1832eefdbec1SJussi Kivilinna 	if (r) {
1833eefdbec1SJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb),
1834eefdbec1SJussi Kivilinna 			"error in zd_submit_waiting_usb(). "
1835eefdbec1SJussi Kivilinna 			"Error number %d\n", r);
1836eefdbec1SJussi Kivilinna 
1837eefdbec1SJussi Kivilinna 		usb_kill_anchored_urbs(&usb->submitted_cmds);
1838eefdbec1SJussi Kivilinna 		goto error;
1839eefdbec1SJussi Kivilinna 	}
1840eefdbec1SJussi Kivilinna 
1841eefdbec1SJussi Kivilinna 	if (timeout)
1842eefdbec1SJussi Kivilinna 		timeout = usb_wait_anchor_empty_timeout(&usb->submitted_cmds,
1843eefdbec1SJussi Kivilinna 							timeout);
1844eefdbec1SJussi Kivilinna 	if (!timeout) {
1845eefdbec1SJussi Kivilinna 		usb_kill_anchored_urbs(&usb->submitted_cmds);
1846eefdbec1SJussi Kivilinna 		if (usb->cmd_error == -ENOENT) {
1847eefdbec1SJussi Kivilinna 			dev_dbg_f(zd_usb_dev(usb), "timed out");
1848eefdbec1SJussi Kivilinna 			r = -ETIMEDOUT;
1849eefdbec1SJussi Kivilinna 			goto error;
1850eefdbec1SJussi Kivilinna 		}
1851eefdbec1SJussi Kivilinna 	}
1852eefdbec1SJussi Kivilinna 
1853eefdbec1SJussi Kivilinna 	r = usb->cmd_error;
1854eefdbec1SJussi Kivilinna error:
1855eefdbec1SJussi Kivilinna 	usb->in_async = 0;
1856eefdbec1SJussi Kivilinna 	return r;
1857eefdbec1SJussi Kivilinna }
1858eefdbec1SJussi Kivilinna 
zd_usb_iowrite16v_async(struct zd_usb * usb,const struct zd_ioreq16 * ioreqs,unsigned int count)18598662b251SJussi Kivilinna int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
1860e85d0918SDaniel Drake 			    unsigned int count)
1861e85d0918SDaniel Drake {
1862e85d0918SDaniel Drake 	int r;
1863e85d0918SDaniel Drake 	struct usb_device *udev;
1864e85d0918SDaniel Drake 	struct usb_req_write_regs *req = NULL;
1865eefdbec1SJussi Kivilinna 	int i, req_len;
1866eefdbec1SJussi Kivilinna 	struct urb *urb;
1867eefdbec1SJussi Kivilinna 	struct usb_host_endpoint *ep;
1868eefdbec1SJussi Kivilinna 
1869eefdbec1SJussi Kivilinna 	ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
1870eefdbec1SJussi Kivilinna 	ZD_ASSERT(usb->in_async);
1871e85d0918SDaniel Drake 
1872e85d0918SDaniel Drake 	if (count == 0)
1873e85d0918SDaniel Drake 		return 0;
1874e85d0918SDaniel Drake 	if (count > USB_MAX_IOWRITE16_COUNT) {
1875e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1876e85d0918SDaniel Drake 			"error: count %u exceeds possible max %u\n",
1877e85d0918SDaniel Drake 			count, USB_MAX_IOWRITE16_COUNT);
1878e85d0918SDaniel Drake 		return -EINVAL;
1879e85d0918SDaniel Drake 	}
1880e85d0918SDaniel Drake 
1881eefdbec1SJussi Kivilinna 	udev = zd_usb_to_usbdev(usb);
1882eefdbec1SJussi Kivilinna 
1883eefdbec1SJussi Kivilinna 	ep = usb_pipe_endpoint(udev, usb_sndintpipe(udev, EP_REGS_OUT));
1884eefdbec1SJussi Kivilinna 	if (!ep)
1885eefdbec1SJussi Kivilinna 		return -ENOENT;
1886eefdbec1SJussi Kivilinna 
1887eefdbec1SJussi Kivilinna 	urb = usb_alloc_urb(0, GFP_KERNEL);
1888eefdbec1SJussi Kivilinna 	if (!urb)
1889eefdbec1SJussi Kivilinna 		return -ENOMEM;
18909bca0c3bSJussi Kivilinna 
18910c7beb2dSGustavo A. R. Silva 	req_len = struct_size(req, reg_writes, count);
1892eefdbec1SJussi Kivilinna 	req = kmalloc(req_len, GFP_KERNEL);
1893eefdbec1SJussi Kivilinna 	if (!req) {
1894eefdbec1SJussi Kivilinna 		r = -ENOMEM;
1895eefdbec1SJussi Kivilinna 		goto error;
1896eefdbec1SJussi Kivilinna 	}
1897e85d0918SDaniel Drake 
1898e85d0918SDaniel Drake 	req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
1899e85d0918SDaniel Drake 	for (i = 0; i < count; i++) {
1900e85d0918SDaniel Drake 		struct reg_data *rw  = &req->reg_writes[i];
19010ce34bc8SDaniel Drake 		rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
1902e85d0918SDaniel Drake 		rw->value = cpu_to_le16(ioreqs[i].value);
1903e85d0918SDaniel Drake 	}
1904e85d0918SDaniel Drake 
190559342f6aSJussi Kivilinna 	/* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode
190659342f6aSJussi Kivilinna 	 * endpoint is bulk. Select correct type URB by endpoint descriptor.
190759342f6aSJussi Kivilinna 	 */
190859342f6aSJussi Kivilinna 	if (usb_endpoint_xfer_int(&ep->desc))
1909eefdbec1SJussi Kivilinna 		usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT),
1910eefdbec1SJussi Kivilinna 				 req, req_len, iowrite16v_urb_complete, usb,
1911eefdbec1SJussi Kivilinna 				 ep->desc.bInterval);
191259342f6aSJussi Kivilinna 	else
191359342f6aSJussi Kivilinna 		usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
191459342f6aSJussi Kivilinna 				  req, req_len, iowrite16v_urb_complete, usb);
191559342f6aSJussi Kivilinna 
19162fc713b2SJussi Kivilinna 	urb->transfer_flags |= URB_FREE_BUFFER;
1917eefdbec1SJussi Kivilinna 
1918eefdbec1SJussi Kivilinna 	/* Submit previous URB */
1919eefdbec1SJussi Kivilinna 	r = zd_submit_waiting_urb(usb, false);
1920e85d0918SDaniel Drake 	if (r) {
1921e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1922eefdbec1SJussi Kivilinna 			"error in zd_submit_waiting_usb(). "
1923eefdbec1SJussi Kivilinna 			"Error number %d\n", r);
1924e85d0918SDaniel Drake 		goto error;
1925e85d0918SDaniel Drake 	}
1926e85d0918SDaniel Drake 
1927eefdbec1SJussi Kivilinna 	/* Delay submit so that URB_NO_INTERRUPT flag can be set for all URBs
1928eefdbec1SJussi Kivilinna 	 * of currect batch except for very last.
1929eefdbec1SJussi Kivilinna 	 */
1930eefdbec1SJussi Kivilinna 	usb->urb_async_waiting = urb;
1931eefdbec1SJussi Kivilinna 	return 0;
1932e85d0918SDaniel Drake error:
1933eefdbec1SJussi Kivilinna 	usb_free_urb(urb);
1934e85d0918SDaniel Drake 	return r;
1935e85d0918SDaniel Drake }
1936e85d0918SDaniel Drake 
zd_usb_iowrite16v(struct zd_usb * usb,const struct zd_ioreq16 * ioreqs,unsigned int count)1937eefdbec1SJussi Kivilinna int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
1938eefdbec1SJussi Kivilinna 			unsigned int count)
1939eefdbec1SJussi Kivilinna {
1940eefdbec1SJussi Kivilinna 	int r;
1941eefdbec1SJussi Kivilinna 
1942eefdbec1SJussi Kivilinna 	zd_usb_iowrite16v_async_start(usb);
1943eefdbec1SJussi Kivilinna 	r = zd_usb_iowrite16v_async(usb, ioreqs, count);
1944eefdbec1SJussi Kivilinna 	if (r) {
1945eefdbec1SJussi Kivilinna 		zd_usb_iowrite16v_async_end(usb, 0);
1946eefdbec1SJussi Kivilinna 		return r;
1947eefdbec1SJussi Kivilinna 	}
1948eefdbec1SJussi Kivilinna 	return zd_usb_iowrite16v_async_end(usb, 50 /* ms */);
1949eefdbec1SJussi Kivilinna }
1950eefdbec1SJussi Kivilinna 
zd_usb_rfwrite(struct zd_usb * usb,u32 value,u8 bits)1951e85d0918SDaniel Drake int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
1952e85d0918SDaniel Drake {
1953e85d0918SDaniel Drake 	int r;
1954e85d0918SDaniel Drake 	struct usb_device *udev;
1955e85d0918SDaniel Drake 	struct usb_req_rfwrite *req = NULL;
1956e85d0918SDaniel Drake 	int i, req_len, actual_req_len;
1957e85d0918SDaniel Drake 	u16 bit_value_template;
1958e85d0918SDaniel Drake 
1959e85d0918SDaniel Drake 	if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
1960e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1961e85d0918SDaniel Drake 			"error: bits %d are smaller than"
1962e85d0918SDaniel Drake 			" USB_MIN_RFWRITE_BIT_COUNT %d\n",
1963e85d0918SDaniel Drake 			bits, USB_MIN_RFWRITE_BIT_COUNT);
1964e85d0918SDaniel Drake 		return -EINVAL;
1965e85d0918SDaniel Drake 	}
1966e85d0918SDaniel Drake 	if (bits > USB_MAX_RFWRITE_BIT_COUNT) {
1967e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1968e85d0918SDaniel Drake 			"error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",
1969e85d0918SDaniel Drake 			bits, USB_MAX_RFWRITE_BIT_COUNT);
1970e85d0918SDaniel Drake 		return -EINVAL;
1971e85d0918SDaniel Drake 	}
1972e85d0918SDaniel Drake #ifdef DEBUG
1973e85d0918SDaniel Drake 	if (value & (~0UL << bits)) {
1974e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1975e85d0918SDaniel Drake 			"error: value %#09x has bits >= %d set\n",
1976e85d0918SDaniel Drake 			value, bits);
1977e85d0918SDaniel Drake 		return -EINVAL;
1978e85d0918SDaniel Drake 	}
1979e85d0918SDaniel Drake #endif /* DEBUG */
1980e85d0918SDaniel Drake 
1981e85d0918SDaniel Drake 	dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
1982e85d0918SDaniel Drake 
1983fbd5d17bSJussi Kivilinna 	r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203);
1984e85d0918SDaniel Drake 	if (r) {
1985e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
1986fbd5d17bSJussi Kivilinna 			"error %d: Couldn't read ZD_CR203\n", r);
19879bca0c3bSJussi Kivilinna 		return r;
1988e85d0918SDaniel Drake 	}
1989e85d0918SDaniel Drake 	bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
1990e85d0918SDaniel Drake 
19919bca0c3bSJussi Kivilinna 	ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex));
19929bca0c3bSJussi Kivilinna 	BUILD_BUG_ON(sizeof(struct usb_req_rfwrite) +
19939bca0c3bSJussi Kivilinna 		     USB_MAX_RFWRITE_BIT_COUNT * sizeof(__le16) >
19949bca0c3bSJussi Kivilinna 		     sizeof(usb->req_buf));
19959bca0c3bSJussi Kivilinna 	BUG_ON(sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16) >
19969bca0c3bSJussi Kivilinna 	       sizeof(usb->req_buf));
19979bca0c3bSJussi Kivilinna 
1998e85d0918SDaniel Drake 	req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
19999bca0c3bSJussi Kivilinna 	req = (void *)usb->req_buf;
2000e85d0918SDaniel Drake 
2001e85d0918SDaniel Drake 	req->id = cpu_to_le16(USB_REQ_WRITE_RF);
2002e85d0918SDaniel Drake 	/* 1: 3683a, but not used in ZYDAS driver */
2003e85d0918SDaniel Drake 	req->value = cpu_to_le16(2);
2004e85d0918SDaniel Drake 	req->bits = cpu_to_le16(bits);
2005e85d0918SDaniel Drake 
2006e85d0918SDaniel Drake 	for (i = 0; i < bits; i++) {
2007e85d0918SDaniel Drake 		u16 bv = bit_value_template;
2008e85d0918SDaniel Drake 		if (value & (1 << (bits-1-i)))
2009e85d0918SDaniel Drake 			bv |= RF_DATA;
2010e85d0918SDaniel Drake 		req->bit_values[i] = cpu_to_le16(bv);
2011e85d0918SDaniel Drake 	}
2012e85d0918SDaniel Drake 
2013e85d0918SDaniel Drake 	udev = zd_usb_to_usbdev(usb);
201459342f6aSJussi Kivilinna 	r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/);
2015e85d0918SDaniel Drake 	if (r) {
2016e85d0918SDaniel Drake 		dev_dbg_f(zd_usb_dev(usb),
201759342f6aSJussi Kivilinna 			"error in zd_ep_regs_out_msg(). Error number %d\n", r);
2018e85d0918SDaniel Drake 		goto out;
2019e85d0918SDaniel Drake 	}
2020e85d0918SDaniel Drake 	if (req_len != actual_req_len) {
202159342f6aSJussi Kivilinna 		dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()"
2022e85d0918SDaniel Drake 			" req_len %d != actual_req_len %d\n",
2023e85d0918SDaniel Drake 			req_len, actual_req_len);
2024e85d0918SDaniel Drake 		r = -EIO;
2025e85d0918SDaniel Drake 		goto out;
2026e85d0918SDaniel Drake 	}
2027e85d0918SDaniel Drake 
2028e85d0918SDaniel Drake 	/* FALL-THROUGH with r == 0 */
2029e85d0918SDaniel Drake out:
2030e85d0918SDaniel Drake 	return r;
2031e85d0918SDaniel Drake }
2032