xref: /OK3568_Linux_fs/kernel/drivers/net/wimax/i2400m/usb-fw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Intel Wireless WiMAX Connection 2400m
3*4882a593Smuzhiyun  * Firmware uploader's USB specifics
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
9*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions
10*4882a593Smuzhiyun  * are met:
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *   * Redistributions of source code must retain the above copyright
13*4882a593Smuzhiyun  *     notice, this list of conditions and the following disclaimer.
14*4882a593Smuzhiyun  *   * Redistributions in binary form must reproduce the above copyright
15*4882a593Smuzhiyun  *     notice, this list of conditions and the following disclaimer in
16*4882a593Smuzhiyun  *     the documentation and/or other materials provided with the
17*4882a593Smuzhiyun  *     distribution.
18*4882a593Smuzhiyun  *   * Neither the name of Intel Corporation nor the names of its
19*4882a593Smuzhiyun  *     contributors may be used to endorse or promote products derived
20*4882a593Smuzhiyun  *     from this software without specific prior written permission.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23*4882a593Smuzhiyun  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24*4882a593Smuzhiyun  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25*4882a593Smuzhiyun  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26*4882a593Smuzhiyun  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27*4882a593Smuzhiyun  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28*4882a593Smuzhiyun  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29*4882a593Smuzhiyun  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30*4882a593Smuzhiyun  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32*4882a593Smuzhiyun  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * Intel Corporation <linux-wimax@intel.com>
36*4882a593Smuzhiyun  * Yanir Lubetkin <yanirx.lubetkin@intel.com>
37*4882a593Smuzhiyun  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
38*4882a593Smuzhiyun  *  - Initial implementation
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
41*4882a593Smuzhiyun  *  - bus generic/specific split
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * THE PROCEDURE
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * See fw.c for the generic description of this procedure.
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  * This file implements only the USB specifics. It boils down to how
48*4882a593Smuzhiyun  * to send a command and waiting for an acknowledgement from the
49*4882a593Smuzhiyun  * device.
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  * This code (and process) is single threaded. It assumes it is the
52*4882a593Smuzhiyun  * only thread poking around (guaranteed by fw.c).
53*4882a593Smuzhiyun  *
54*4882a593Smuzhiyun  * COMMAND EXECUTION
55*4882a593Smuzhiyun  *
56*4882a593Smuzhiyun  * A write URB is posted with the buffer to the bulk output endpoint.
57*4882a593Smuzhiyun  *
58*4882a593Smuzhiyun  * ACK RECEPTION
59*4882a593Smuzhiyun  *
60*4882a593Smuzhiyun  * We just post a URB to the notification endpoint and wait for
61*4882a593Smuzhiyun  * data. We repeat until we get all the data we expect (as indicated
62*4882a593Smuzhiyun  * by the call from the bus generic code).
63*4882a593Smuzhiyun  *
64*4882a593Smuzhiyun  * The data is not read from the bulk in endpoint for boot mode.
65*4882a593Smuzhiyun  *
66*4882a593Smuzhiyun  * ROADMAP
67*4882a593Smuzhiyun  *
68*4882a593Smuzhiyun  * i2400mu_bus_bm_cmd_send
69*4882a593Smuzhiyun  *   i2400m_bm_cmd_prepare...
70*4882a593Smuzhiyun  *   i2400mu_tx_bulk_out
71*4882a593Smuzhiyun  *
72*4882a593Smuzhiyun  * i2400mu_bus_bm_wait_for_ack
73*4882a593Smuzhiyun  *   i2400m_notif_submit
74*4882a593Smuzhiyun  */
75*4882a593Smuzhiyun #include <linux/usb.h>
76*4882a593Smuzhiyun #include <linux/gfp.h>
77*4882a593Smuzhiyun #include "i2400m-usb.h"
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun #define D_SUBMODULE fw
81*4882a593Smuzhiyun #include "usb-debug-levels.h"
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /*
85*4882a593Smuzhiyun  * Synchronous write to the device
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun  * Takes care of updating EDC counts and thus, handle device errors.
88*4882a593Smuzhiyun  */
89*4882a593Smuzhiyun static
i2400mu_tx_bulk_out(struct i2400mu * i2400mu,void * buf,size_t buf_size)90*4882a593Smuzhiyun ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	int result;
93*4882a593Smuzhiyun 	struct device *dev = &i2400mu->usb_iface->dev;
94*4882a593Smuzhiyun 	int len;
95*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *epd;
96*4882a593Smuzhiyun 	int pipe, do_autopm = 1;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	result = usb_autopm_get_interface(i2400mu->usb_iface);
99*4882a593Smuzhiyun 	if (result < 0) {
100*4882a593Smuzhiyun 		dev_err(dev, "BM-CMD: can't get autopm: %d\n", result);
101*4882a593Smuzhiyun 		do_autopm = 0;
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun 	epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out);
104*4882a593Smuzhiyun 	pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
105*4882a593Smuzhiyun retry:
106*4882a593Smuzhiyun 	result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, 200);
107*4882a593Smuzhiyun 	switch (result) {
108*4882a593Smuzhiyun 	case 0:
109*4882a593Smuzhiyun 		if (len != buf_size) {
110*4882a593Smuzhiyun 			dev_err(dev, "BM-CMD: short write (%u B vs %zu "
111*4882a593Smuzhiyun 				"expected)\n", len, buf_size);
112*4882a593Smuzhiyun 			result = -EIO;
113*4882a593Smuzhiyun 			break;
114*4882a593Smuzhiyun 		}
115*4882a593Smuzhiyun 		result = len;
116*4882a593Smuzhiyun 		break;
117*4882a593Smuzhiyun 	case -EPIPE:
118*4882a593Smuzhiyun 		/*
119*4882a593Smuzhiyun 		 * Stall -- maybe the device is choking with our
120*4882a593Smuzhiyun 		 * requests. Clear it and give it some time. If they
121*4882a593Smuzhiyun 		 * happen to often, it might be another symptom, so we
122*4882a593Smuzhiyun 		 * reset.
123*4882a593Smuzhiyun 		 *
124*4882a593Smuzhiyun 		 * No error handling for usb_clear_halt(0; if it
125*4882a593Smuzhiyun 		 * works, the retry works; if it fails, this switch
126*4882a593Smuzhiyun 		 * does the error handling for us.
127*4882a593Smuzhiyun 		 */
128*4882a593Smuzhiyun 		if (edc_inc(&i2400mu->urb_edc,
129*4882a593Smuzhiyun 			    10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
130*4882a593Smuzhiyun 			dev_err(dev, "BM-CMD: too many stalls in "
131*4882a593Smuzhiyun 				"URB; resetting device\n");
132*4882a593Smuzhiyun 			usb_queue_reset_device(i2400mu->usb_iface);
133*4882a593Smuzhiyun 		} else {
134*4882a593Smuzhiyun 			usb_clear_halt(i2400mu->usb_dev, pipe);
135*4882a593Smuzhiyun 			msleep(10);	/* give the device some time */
136*4882a593Smuzhiyun 			goto retry;
137*4882a593Smuzhiyun 		}
138*4882a593Smuzhiyun 		fallthrough;
139*4882a593Smuzhiyun 	case -EINVAL:			/* while removing driver */
140*4882a593Smuzhiyun 	case -ENODEV:			/* dev disconnect ... */
141*4882a593Smuzhiyun 	case -ENOENT:			/* just ignore it */
142*4882a593Smuzhiyun 	case -ESHUTDOWN:		/* and exit */
143*4882a593Smuzhiyun 	case -ECONNRESET:
144*4882a593Smuzhiyun 		result = -ESHUTDOWN;
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	case -ETIMEDOUT:			/* bah... */
147*4882a593Smuzhiyun 		break;
148*4882a593Smuzhiyun 	default:				/* any other? */
149*4882a593Smuzhiyun 		if (edc_inc(&i2400mu->urb_edc,
150*4882a593Smuzhiyun 			    EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
151*4882a593Smuzhiyun 				dev_err(dev, "BM-CMD: maximum errors in "
152*4882a593Smuzhiyun 					"URB exceeded; resetting device\n");
153*4882a593Smuzhiyun 				usb_queue_reset_device(i2400mu->usb_iface);
154*4882a593Smuzhiyun 				result = -ENODEV;
155*4882a593Smuzhiyun 				break;
156*4882a593Smuzhiyun 		}
157*4882a593Smuzhiyun 		dev_err(dev, "BM-CMD: URB error %d, retrying\n",
158*4882a593Smuzhiyun 			result);
159*4882a593Smuzhiyun 		goto retry;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 	if (do_autopm)
162*4882a593Smuzhiyun 		usb_autopm_put_interface(i2400mu->usb_iface);
163*4882a593Smuzhiyun 	return result;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun  * Send a boot-mode command over the bulk-out pipe
169*4882a593Smuzhiyun  *
170*4882a593Smuzhiyun  * Command can be a raw command, which requires no preparation (and
171*4882a593Smuzhiyun  * which might not even be following the command format). Checks that
172*4882a593Smuzhiyun  * the right amount of data was transferred.
173*4882a593Smuzhiyun  *
174*4882a593Smuzhiyun  * To satisfy USB requirements (no onstack, vmalloc or in data segment
175*4882a593Smuzhiyun  * buffers), we copy the command to i2400m->bm_cmd_buf and send it from
176*4882a593Smuzhiyun  * there.
177*4882a593Smuzhiyun  *
178*4882a593Smuzhiyun  * @flags: pass thru from i2400m_bm_cmd()
179*4882a593Smuzhiyun  * @return: cmd_size if ok, < 0 errno code on error.
180*4882a593Smuzhiyun  */
i2400mu_bus_bm_cmd_send(struct i2400m * i2400m,const struct i2400m_bootrom_header * _cmd,size_t cmd_size,int flags)181*4882a593Smuzhiyun ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m,
182*4882a593Smuzhiyun 				const struct i2400m_bootrom_header *_cmd,
183*4882a593Smuzhiyun 				size_t cmd_size, int flags)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	ssize_t result;
186*4882a593Smuzhiyun 	struct device *dev = i2400m_dev(i2400m);
187*4882a593Smuzhiyun 	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
188*4882a593Smuzhiyun 	int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
189*4882a593Smuzhiyun 	struct i2400m_bootrom_header *cmd;
190*4882a593Smuzhiyun 	size_t cmd_size_a = ALIGN(cmd_size, 16);	/* USB restriction */
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	d_fnstart(8, dev, "(i2400m %p cmd %p size %zu)\n",
193*4882a593Smuzhiyun 		  i2400m, _cmd, cmd_size);
194*4882a593Smuzhiyun 	result = -E2BIG;
195*4882a593Smuzhiyun 	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
196*4882a593Smuzhiyun 		goto error_too_big;
197*4882a593Smuzhiyun 	if (_cmd != i2400m->bm_cmd_buf)
198*4882a593Smuzhiyun 		memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
199*4882a593Smuzhiyun 	cmd = i2400m->bm_cmd_buf;
200*4882a593Smuzhiyun 	if (cmd_size_a > cmd_size)			/* Zero pad space */
201*4882a593Smuzhiyun 		memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
202*4882a593Smuzhiyun 	if ((flags & I2400M_BM_CMD_RAW) == 0) {
203*4882a593Smuzhiyun 		if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
204*4882a593Smuzhiyun 			dev_warn(dev, "SW BUG: response_required == 0\n");
205*4882a593Smuzhiyun 		i2400m_bm_cmd_prepare(cmd);
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 	result = i2400mu_tx_bulk_out(i2400mu, i2400m->bm_cmd_buf, cmd_size);
208*4882a593Smuzhiyun 	if (result < 0) {
209*4882a593Smuzhiyun 		dev_err(dev, "boot-mode cmd %d: cannot send: %zd\n",
210*4882a593Smuzhiyun 			opcode, result);
211*4882a593Smuzhiyun 		goto error_cmd_send;
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun 	if (result != cmd_size) {		/* all was transferred? */
214*4882a593Smuzhiyun 		dev_err(dev, "boot-mode cmd %d: incomplete transfer "
215*4882a593Smuzhiyun 			"(%zd vs %zu submitted)\n",  opcode, result, cmd_size);
216*4882a593Smuzhiyun 		result = -EIO;
217*4882a593Smuzhiyun 		goto error_cmd_size;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun error_cmd_size:
220*4882a593Smuzhiyun error_cmd_send:
221*4882a593Smuzhiyun error_too_big:
222*4882a593Smuzhiyun 	d_fnend(8, dev, "(i2400m %p cmd %p size %zu) = %zd\n",
223*4882a593Smuzhiyun 		i2400m, _cmd, cmd_size, result);
224*4882a593Smuzhiyun 	return result;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun static
__i2400mu_bm_notif_cb(struct urb * urb)229*4882a593Smuzhiyun void __i2400mu_bm_notif_cb(struct urb *urb)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	complete(urb->context);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun /*
236*4882a593Smuzhiyun  * submit a read to the notification endpoint
237*4882a593Smuzhiyun  *
238*4882a593Smuzhiyun  * @i2400m: device descriptor
239*4882a593Smuzhiyun  * @urb: urb to use
240*4882a593Smuzhiyun  * @completion: completion variable to complete when done
241*4882a593Smuzhiyun  *
242*4882a593Smuzhiyun  * Data is always read to i2400m->bm_ack_buf
243*4882a593Smuzhiyun  */
244*4882a593Smuzhiyun static
i2400mu_notif_submit(struct i2400mu * i2400mu,struct urb * urb,struct completion * completion)245*4882a593Smuzhiyun int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb,
246*4882a593Smuzhiyun 			 struct completion *completion)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct i2400m *i2400m = &i2400mu->i2400m;
249*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *epd;
250*4882a593Smuzhiyun 	int pipe;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	epd = usb_get_epd(i2400mu->usb_iface,
253*4882a593Smuzhiyun 			  i2400mu->endpoint_cfg.notification);
254*4882a593Smuzhiyun 	pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
255*4882a593Smuzhiyun 	usb_fill_int_urb(urb, i2400mu->usb_dev, pipe,
256*4882a593Smuzhiyun 			 i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE,
257*4882a593Smuzhiyun 			 __i2400mu_bm_notif_cb, completion,
258*4882a593Smuzhiyun 			 epd->bInterval);
259*4882a593Smuzhiyun 	return usb_submit_urb(urb, GFP_KERNEL);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun /*
264*4882a593Smuzhiyun  * Read an ack from  the notification endpoint
265*4882a593Smuzhiyun  *
266*4882a593Smuzhiyun  * @i2400m:
267*4882a593Smuzhiyun  * @_ack: pointer to where to store the read data
268*4882a593Smuzhiyun  * @ack_size: how many bytes we should read
269*4882a593Smuzhiyun  *
270*4882a593Smuzhiyun  * Returns: < 0 errno code on error; otherwise, amount of received bytes.
271*4882a593Smuzhiyun  *
272*4882a593Smuzhiyun  * Submits a notification read, appends the read data to the given ack
273*4882a593Smuzhiyun  * buffer and then repeats (until @ack_size bytes have been
274*4882a593Smuzhiyun  * received).
275*4882a593Smuzhiyun  */
i2400mu_bus_bm_wait_for_ack(struct i2400m * i2400m,struct i2400m_bootrom_header * _ack,size_t ack_size)276*4882a593Smuzhiyun ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m,
277*4882a593Smuzhiyun 				    struct i2400m_bootrom_header *_ack,
278*4882a593Smuzhiyun 				    size_t ack_size)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	ssize_t result = -ENOMEM;
281*4882a593Smuzhiyun 	struct device *dev = i2400m_dev(i2400m);
282*4882a593Smuzhiyun 	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
283*4882a593Smuzhiyun 	struct urb notif_urb;
284*4882a593Smuzhiyun 	void *ack = _ack;
285*4882a593Smuzhiyun 	size_t offset, len;
286*4882a593Smuzhiyun 	long val;
287*4882a593Smuzhiyun 	int do_autopm = 1;
288*4882a593Smuzhiyun 	DECLARE_COMPLETION_ONSTACK(notif_completion);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	d_fnstart(8, dev, "(i2400m %p ack %p size %zu)\n",
291*4882a593Smuzhiyun 		  i2400m, ack, ack_size);
292*4882a593Smuzhiyun 	BUG_ON(_ack == i2400m->bm_ack_buf);
293*4882a593Smuzhiyun 	result = usb_autopm_get_interface(i2400mu->usb_iface);
294*4882a593Smuzhiyun 	if (result < 0) {
295*4882a593Smuzhiyun 		dev_err(dev, "BM-ACK: can't get autopm: %d\n", (int) result);
296*4882a593Smuzhiyun 		do_autopm = 0;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 	usb_init_urb(&notif_urb);	/* ready notifications */
299*4882a593Smuzhiyun 	usb_get_urb(&notif_urb);
300*4882a593Smuzhiyun 	offset = 0;
301*4882a593Smuzhiyun 	while (offset < ack_size) {
302*4882a593Smuzhiyun 		init_completion(&notif_completion);
303*4882a593Smuzhiyun 		result = i2400mu_notif_submit(i2400mu, &notif_urb,
304*4882a593Smuzhiyun 					      &notif_completion);
305*4882a593Smuzhiyun 		if (result < 0)
306*4882a593Smuzhiyun 			goto error_notif_urb_submit;
307*4882a593Smuzhiyun 		val = wait_for_completion_interruptible_timeout(
308*4882a593Smuzhiyun 			&notif_completion, HZ);
309*4882a593Smuzhiyun 		if (val == 0) {
310*4882a593Smuzhiyun 			result = -ETIMEDOUT;
311*4882a593Smuzhiyun 			usb_kill_urb(&notif_urb);	/* Timedout */
312*4882a593Smuzhiyun 			goto error_notif_wait;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 		if (val == -ERESTARTSYS) {
315*4882a593Smuzhiyun 			result = -EINTR;		/* Interrupted */
316*4882a593Smuzhiyun 			usb_kill_urb(&notif_urb);
317*4882a593Smuzhiyun 			goto error_notif_wait;
318*4882a593Smuzhiyun 		}
319*4882a593Smuzhiyun 		result = notif_urb.status;		/* How was the ack? */
320*4882a593Smuzhiyun 		switch (result) {
321*4882a593Smuzhiyun 		case 0:
322*4882a593Smuzhiyun 			break;
323*4882a593Smuzhiyun 		case -EINVAL:			/* while removing driver */
324*4882a593Smuzhiyun 		case -ENODEV:			/* dev disconnect ... */
325*4882a593Smuzhiyun 		case -ENOENT:			/* just ignore it */
326*4882a593Smuzhiyun 		case -ESHUTDOWN:		/* and exit */
327*4882a593Smuzhiyun 		case -ECONNRESET:
328*4882a593Smuzhiyun 			result = -ESHUTDOWN;
329*4882a593Smuzhiyun 			goto error_dev_gone;
330*4882a593Smuzhiyun 		default:				/* any other? */
331*4882a593Smuzhiyun 			usb_kill_urb(&notif_urb);	/* Timedout */
332*4882a593Smuzhiyun 			if (edc_inc(&i2400mu->urb_edc,
333*4882a593Smuzhiyun 				    EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME))
334*4882a593Smuzhiyun 				goto error_exceeded;
335*4882a593Smuzhiyun 			dev_err(dev, "BM-ACK: URB error %d, "
336*4882a593Smuzhiyun 				"retrying\n", notif_urb.status);
337*4882a593Smuzhiyun 			continue;	/* retry */
338*4882a593Smuzhiyun 		}
339*4882a593Smuzhiyun 		if (notif_urb.actual_length == 0) {
340*4882a593Smuzhiyun 			d_printf(6, dev, "ZLP received, retrying\n");
341*4882a593Smuzhiyun 			continue;
342*4882a593Smuzhiyun 		}
343*4882a593Smuzhiyun 		/* Got data, append it to the buffer */
344*4882a593Smuzhiyun 		len = min(ack_size - offset, (size_t) notif_urb.actual_length);
345*4882a593Smuzhiyun 		memcpy(ack + offset, i2400m->bm_ack_buf, len);
346*4882a593Smuzhiyun 		offset += len;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 	result = offset;
349*4882a593Smuzhiyun error_notif_urb_submit:
350*4882a593Smuzhiyun error_notif_wait:
351*4882a593Smuzhiyun error_dev_gone:
352*4882a593Smuzhiyun out:
353*4882a593Smuzhiyun 	if (do_autopm)
354*4882a593Smuzhiyun 		usb_autopm_put_interface(i2400mu->usb_iface);
355*4882a593Smuzhiyun 	d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n",
356*4882a593Smuzhiyun 		i2400m, ack, ack_size, (long) result);
357*4882a593Smuzhiyun 	usb_put_urb(&notif_urb);
358*4882a593Smuzhiyun 	return result;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun error_exceeded:
361*4882a593Smuzhiyun 	dev_err(dev, "bm: maximum errors in notification URB exceeded; "
362*4882a593Smuzhiyun 		"resetting device\n");
363*4882a593Smuzhiyun 	usb_queue_reset_device(i2400mu->usb_iface);
364*4882a593Smuzhiyun 	goto out;
365*4882a593Smuzhiyun }
366