xref: /OK3568_Linux_fs/u-boot/drivers/usb/gadget/f_dfu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * f_dfu.c -- Device Firmware Update USB function
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2012 Samsung Electronics
5*4882a593Smuzhiyun  * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
6*4882a593Smuzhiyun  *          Lukasz Majewski <l.majewski@samsung.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Based on OpenMoko u-boot: drivers/usb/usbdfu.c
9*4882a593Smuzhiyun  * (C) 2007 by OpenMoko, Inc.
10*4882a593Smuzhiyun  * Author: Harald Welte <laforge@openmoko.org>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * based on existing SAM7DFU code from OpenPCD:
13*4882a593Smuzhiyun  * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de>
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <errno.h>
19*4882a593Smuzhiyun #include <common.h>
20*4882a593Smuzhiyun #include <malloc.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <linux/usb/ch9.h>
23*4882a593Smuzhiyun #include <linux/usb/gadget.h>
24*4882a593Smuzhiyun #include <linux/usb/composite.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <dfu.h>
27*4882a593Smuzhiyun #include <g_dnl.h>
28*4882a593Smuzhiyun #include "f_dfu.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun struct f_dfu {
31*4882a593Smuzhiyun 	struct usb_function		usb_function;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	struct usb_descriptor_header	**function;
34*4882a593Smuzhiyun 	struct usb_string		*strings;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	/* when configured, we have one config */
37*4882a593Smuzhiyun 	u8				config;
38*4882a593Smuzhiyun 	u8				altsetting;
39*4882a593Smuzhiyun 	enum dfu_state			dfu_state;
40*4882a593Smuzhiyun 	unsigned int			dfu_status;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	/* Send/received block number is handy for data integrity check */
43*4882a593Smuzhiyun 	int                             blk_seq_num;
44*4882a593Smuzhiyun 	unsigned int                    poll_timeout;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun struct dfu_entity *dfu_defer_flush;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun typedef int (*dfu_state_fn) (struct f_dfu *,
50*4882a593Smuzhiyun 			     const struct usb_ctrlrequest *,
51*4882a593Smuzhiyun 			     struct usb_gadget *,
52*4882a593Smuzhiyun 			     struct usb_request *);
53*4882a593Smuzhiyun 
func_to_dfu(struct usb_function * f)54*4882a593Smuzhiyun static inline struct f_dfu *func_to_dfu(struct usb_function *f)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	return container_of(f, struct f_dfu, usb_function);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun static const struct dfu_function_descriptor dfu_func = {
60*4882a593Smuzhiyun 	.bLength =		sizeof dfu_func,
61*4882a593Smuzhiyun 	.bDescriptorType =	DFU_DT_FUNC,
62*4882a593Smuzhiyun 	.bmAttributes =		DFU_BIT_WILL_DETACH |
63*4882a593Smuzhiyun 				DFU_BIT_MANIFESTATION_TOLERANT |
64*4882a593Smuzhiyun 				DFU_BIT_CAN_UPLOAD |
65*4882a593Smuzhiyun 				DFU_BIT_CAN_DNLOAD,
66*4882a593Smuzhiyun 	.wDetachTimeOut =	0,
67*4882a593Smuzhiyun 	.wTransferSize =	DFU_USB_BUFSIZ,
68*4882a593Smuzhiyun 	.bcdDFUVersion =	__constant_cpu_to_le16(0x0110),
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static struct usb_interface_descriptor dfu_intf_runtime = {
72*4882a593Smuzhiyun 	.bLength =		sizeof dfu_intf_runtime,
73*4882a593Smuzhiyun 	.bDescriptorType =	USB_DT_INTERFACE,
74*4882a593Smuzhiyun 	.bNumEndpoints =	0,
75*4882a593Smuzhiyun 	.bInterfaceClass =	USB_CLASS_APP_SPEC,
76*4882a593Smuzhiyun 	.bInterfaceSubClass =	1,
77*4882a593Smuzhiyun 	.bInterfaceProtocol =	1,
78*4882a593Smuzhiyun 	/* .iInterface = DYNAMIC */
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static struct usb_descriptor_header *dfu_runtime_descs[] = {
82*4882a593Smuzhiyun 	(struct usb_descriptor_header *) &dfu_intf_runtime,
83*4882a593Smuzhiyun 	NULL,
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun static const char dfu_name[] = "Device Firmware Upgrade";
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun  * static strings, in UTF-8
90*4882a593Smuzhiyun  *
91*4882a593Smuzhiyun  * dfu_generic configuration
92*4882a593Smuzhiyun  */
93*4882a593Smuzhiyun static struct usb_string strings_dfu_generic[] = {
94*4882a593Smuzhiyun 	[0].s = dfu_name,
95*4882a593Smuzhiyun 	{  }			/* end of list */
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun static struct usb_gadget_strings stringtab_dfu_generic = {
99*4882a593Smuzhiyun 	.language	= 0x0409,	/* en-us */
100*4882a593Smuzhiyun 	.strings	= strings_dfu_generic,
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun static struct usb_gadget_strings *dfu_generic_strings[] = {
104*4882a593Smuzhiyun 	&stringtab_dfu_generic,
105*4882a593Smuzhiyun 	NULL,
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun  * usb_function specific
110*4882a593Smuzhiyun  */
111*4882a593Smuzhiyun static struct usb_gadget_strings stringtab_dfu = {
112*4882a593Smuzhiyun 	.language	= 0x0409,	/* en-us */
113*4882a593Smuzhiyun 	/*
114*4882a593Smuzhiyun 	 * .strings
115*4882a593Smuzhiyun 	 *
116*4882a593Smuzhiyun 	 * assigned during initialization,
117*4882a593Smuzhiyun 	 * depends on number of flash entities
118*4882a593Smuzhiyun 	 *
119*4882a593Smuzhiyun 	 */
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun static struct usb_gadget_strings *dfu_strings[] = {
123*4882a593Smuzhiyun 	&stringtab_dfu,
124*4882a593Smuzhiyun 	NULL,
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun 
dfu_set_poll_timeout(struct dfu_status * dstat,unsigned int ms)127*4882a593Smuzhiyun static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	/*
130*4882a593Smuzhiyun 	 * The bwPollTimeout DFU_GETSTATUS request payload provides information
131*4882a593Smuzhiyun 	 * about minimum time, in milliseconds, that the host should wait before
132*4882a593Smuzhiyun 	 * sending a subsequent DFU_GETSTATUS request
133*4882a593Smuzhiyun 	 *
134*4882a593Smuzhiyun 	 * This permits the device to vary the delay depending on its need to
135*4882a593Smuzhiyun 	 * erase or program the memory
136*4882a593Smuzhiyun 	 *
137*4882a593Smuzhiyun 	 */
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	unsigned char *p = (unsigned char *)&ms;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) {
142*4882a593Smuzhiyun 		dstat->bwPollTimeout[0] = 0;
143*4882a593Smuzhiyun 		dstat->bwPollTimeout[1] = 0;
144*4882a593Smuzhiyun 		dstat->bwPollTimeout[2] = 0;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		return;
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	dstat->bwPollTimeout[0] = *p++;
150*4882a593Smuzhiyun 	dstat->bwPollTimeout[1] = *p++;
151*4882a593Smuzhiyun 	dstat->bwPollTimeout[2] = *p;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
155*4882a593Smuzhiyun 
dnload_request_complete(struct usb_ep * ep,struct usb_request * req)156*4882a593Smuzhiyun static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct f_dfu *f_dfu = req->context;
159*4882a593Smuzhiyun 	int ret;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	ret = dfu_write(dfu_get_entity(f_dfu->altsetting), req->buf,
162*4882a593Smuzhiyun 			req->actual, f_dfu->blk_seq_num);
163*4882a593Smuzhiyun 	if (ret) {
164*4882a593Smuzhiyun 		f_dfu->dfu_status = DFU_STATUS_errUNKNOWN;
165*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
dnload_request_flush(struct usb_ep * ep,struct usb_request * req)169*4882a593Smuzhiyun static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct f_dfu *f_dfu = req->context;
172*4882a593Smuzhiyun 	dfu_set_defer_flush(dfu_get_entity(f_dfu->altsetting));
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
dfu_get_manifest_timeout(struct dfu_entity * dfu)175*4882a593Smuzhiyun static inline int dfu_get_manifest_timeout(struct dfu_entity *dfu)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	return dfu->poll_timeout ? dfu->poll_timeout(dfu) :
178*4882a593Smuzhiyun 		DFU_MANIFEST_POLL_TIMEOUT;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
handle_getstatus(struct usb_request * req)181*4882a593Smuzhiyun static int handle_getstatus(struct usb_request *req)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct dfu_status *dstat = (struct dfu_status *)req->buf;
184*4882a593Smuzhiyun 	struct f_dfu *f_dfu = req->context;
185*4882a593Smuzhiyun 	struct dfu_entity *dfu = dfu_get_entity(f_dfu->altsetting);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	dfu_set_poll_timeout(dstat, 0);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	switch (f_dfu->dfu_state) {
190*4882a593Smuzhiyun 	case DFU_STATE_dfuDNLOAD_SYNC:
191*4882a593Smuzhiyun 	case DFU_STATE_dfuDNBUSY:
192*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
193*4882a593Smuzhiyun 		break;
194*4882a593Smuzhiyun 	case DFU_STATE_dfuMANIFEST_SYNC:
195*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
196*4882a593Smuzhiyun 		break;
197*4882a593Smuzhiyun 	case DFU_STATE_dfuMANIFEST:
198*4882a593Smuzhiyun 		dfu_set_poll_timeout(dstat, dfu_get_manifest_timeout(dfu));
199*4882a593Smuzhiyun 		break;
200*4882a593Smuzhiyun 	default:
201*4882a593Smuzhiyun 		break;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	if (f_dfu->poll_timeout)
205*4882a593Smuzhiyun 		if (!(f_dfu->blk_seq_num %
206*4882a593Smuzhiyun 		      (dfu_get_buf_size() / DFU_USB_BUFSIZ)))
207*4882a593Smuzhiyun 			dfu_set_poll_timeout(dstat, f_dfu->poll_timeout);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	/* send status response */
210*4882a593Smuzhiyun 	dstat->bStatus = f_dfu->dfu_status;
211*4882a593Smuzhiyun 	dstat->bState = f_dfu->dfu_state;
212*4882a593Smuzhiyun 	dstat->iString = 0;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	return sizeof(struct dfu_status);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
handle_getstate(struct usb_request * req)217*4882a593Smuzhiyun static int handle_getstate(struct usb_request *req)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct f_dfu *f_dfu = req->context;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	((u8 *)req->buf)[0] = f_dfu->dfu_state;
222*4882a593Smuzhiyun 	return sizeof(u8);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
to_dfu_mode(struct f_dfu * f_dfu)225*4882a593Smuzhiyun static inline void to_dfu_mode(struct f_dfu *f_dfu)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	f_dfu->usb_function.strings = dfu_strings;
228*4882a593Smuzhiyun 	f_dfu->usb_function.hs_descriptors = f_dfu->function;
229*4882a593Smuzhiyun 	f_dfu->usb_function.descriptors = f_dfu->function;
230*4882a593Smuzhiyun 	f_dfu->dfu_state = DFU_STATE_dfuIDLE;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
to_runtime_mode(struct f_dfu * f_dfu)233*4882a593Smuzhiyun static inline void to_runtime_mode(struct f_dfu *f_dfu)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	f_dfu->usb_function.strings = NULL;
236*4882a593Smuzhiyun 	f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
237*4882a593Smuzhiyun 	f_dfu->usb_function.descriptors = dfu_runtime_descs;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
handle_upload(struct usb_request * req,u16 len)240*4882a593Smuzhiyun static int handle_upload(struct usb_request *req, u16 len)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	struct f_dfu *f_dfu = req->context;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return dfu_read(dfu_get_entity(f_dfu->altsetting), req->buf,
245*4882a593Smuzhiyun 			req->length, f_dfu->blk_seq_num);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
handle_dnload(struct usb_gadget * gadget,u16 len)248*4882a593Smuzhiyun static int handle_dnload(struct usb_gadget *gadget, u16 len)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct usb_composite_dev *cdev = get_gadget_data(gadget);
251*4882a593Smuzhiyun 	struct usb_request *req = cdev->req;
252*4882a593Smuzhiyun 	struct f_dfu *f_dfu = req->context;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	if (len == 0)
255*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	req->complete = dnload_request_complete;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	return len;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
263*4882a593Smuzhiyun /* DFU state machine  */
state_app_idle(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)264*4882a593Smuzhiyun static int state_app_idle(struct f_dfu *f_dfu,
265*4882a593Smuzhiyun 			  const struct usb_ctrlrequest *ctrl,
266*4882a593Smuzhiyun 			  struct usb_gadget *gadget,
267*4882a593Smuzhiyun 			  struct usb_request *req)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int value = 0;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
272*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
273*4882a593Smuzhiyun 		value = handle_getstatus(req);
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
276*4882a593Smuzhiyun 		value = handle_getstate(req);
277*4882a593Smuzhiyun 		break;
278*4882a593Smuzhiyun 	case USB_REQ_DFU_DETACH:
279*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_appDETACH;
280*4882a593Smuzhiyun 		to_dfu_mode(f_dfu);
281*4882a593Smuzhiyun 		value = RET_ZLP;
282*4882a593Smuzhiyun 		break;
283*4882a593Smuzhiyun 	default:
284*4882a593Smuzhiyun 		value = RET_STALL;
285*4882a593Smuzhiyun 		break;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	return value;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
state_app_detach(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)291*4882a593Smuzhiyun static int state_app_detach(struct f_dfu *f_dfu,
292*4882a593Smuzhiyun 			    const struct usb_ctrlrequest *ctrl,
293*4882a593Smuzhiyun 			    struct usb_gadget *gadget,
294*4882a593Smuzhiyun 			    struct usb_request *req)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	int value = 0;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
299*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
300*4882a593Smuzhiyun 		value = handle_getstatus(req);
301*4882a593Smuzhiyun 		break;
302*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
303*4882a593Smuzhiyun 		value = handle_getstate(req);
304*4882a593Smuzhiyun 		break;
305*4882a593Smuzhiyun 	default:
306*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_appIDLE;
307*4882a593Smuzhiyun 		value = RET_STALL;
308*4882a593Smuzhiyun 		break;
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return value;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
state_dfu_idle(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)314*4882a593Smuzhiyun static int state_dfu_idle(struct f_dfu *f_dfu,
315*4882a593Smuzhiyun 			  const struct usb_ctrlrequest *ctrl,
316*4882a593Smuzhiyun 			  struct usb_gadget *gadget,
317*4882a593Smuzhiyun 			  struct usb_request *req)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	u16 w_value = le16_to_cpu(ctrl->wValue);
320*4882a593Smuzhiyun 	u16 len = le16_to_cpu(ctrl->wLength);
321*4882a593Smuzhiyun 	int value = 0;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
324*4882a593Smuzhiyun 	case USB_REQ_DFU_DNLOAD:
325*4882a593Smuzhiyun 		if (len == 0) {
326*4882a593Smuzhiyun 			f_dfu->dfu_state = DFU_STATE_dfuERROR;
327*4882a593Smuzhiyun 			value = RET_STALL;
328*4882a593Smuzhiyun 			break;
329*4882a593Smuzhiyun 		}
330*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
331*4882a593Smuzhiyun 		f_dfu->blk_seq_num = w_value;
332*4882a593Smuzhiyun 		value = handle_dnload(gadget, len);
333*4882a593Smuzhiyun 		break;
334*4882a593Smuzhiyun 	case USB_REQ_DFU_UPLOAD:
335*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
336*4882a593Smuzhiyun 		f_dfu->blk_seq_num = 0;
337*4882a593Smuzhiyun 		value = handle_upload(req, len);
338*4882a593Smuzhiyun 		break;
339*4882a593Smuzhiyun 	case USB_REQ_DFU_ABORT:
340*4882a593Smuzhiyun 		/* no zlp? */
341*4882a593Smuzhiyun 		value = RET_ZLP;
342*4882a593Smuzhiyun 		break;
343*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
344*4882a593Smuzhiyun 		value = handle_getstatus(req);
345*4882a593Smuzhiyun 		break;
346*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
347*4882a593Smuzhiyun 		value = handle_getstate(req);
348*4882a593Smuzhiyun 		break;
349*4882a593Smuzhiyun 	case USB_REQ_DFU_DETACH:
350*4882a593Smuzhiyun 		/*
351*4882a593Smuzhiyun 		 * Proprietary extension: 'detach' from idle mode and
352*4882a593Smuzhiyun 		 * get back to runtime mode in case of USB Reset.  As
353*4882a593Smuzhiyun 		 * much as I dislike this, we just can't use every USB
354*4882a593Smuzhiyun 		 * bus reset to switch back to runtime mode, since at
355*4882a593Smuzhiyun 		 * least the Linux USB stack likes to send a number of
356*4882a593Smuzhiyun 		 * resets in a row :(
357*4882a593Smuzhiyun 		 */
358*4882a593Smuzhiyun 		f_dfu->dfu_state =
359*4882a593Smuzhiyun 			DFU_STATE_dfuMANIFEST_WAIT_RST;
360*4882a593Smuzhiyun 		to_runtime_mode(f_dfu);
361*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_appIDLE;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 		g_dnl_trigger_detach();
364*4882a593Smuzhiyun 		break;
365*4882a593Smuzhiyun 	default:
366*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
367*4882a593Smuzhiyun 		value = RET_STALL;
368*4882a593Smuzhiyun 		break;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	return value;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
state_dfu_dnload_sync(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)374*4882a593Smuzhiyun static int state_dfu_dnload_sync(struct f_dfu *f_dfu,
375*4882a593Smuzhiyun 				 const struct usb_ctrlrequest *ctrl,
376*4882a593Smuzhiyun 				 struct usb_gadget *gadget,
377*4882a593Smuzhiyun 				 struct usb_request *req)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	int value = 0;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
382*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
383*4882a593Smuzhiyun 		value = handle_getstatus(req);
384*4882a593Smuzhiyun 		break;
385*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
386*4882a593Smuzhiyun 		value = handle_getstate(req);
387*4882a593Smuzhiyun 		break;
388*4882a593Smuzhiyun 	default:
389*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
390*4882a593Smuzhiyun 		value = RET_STALL;
391*4882a593Smuzhiyun 		break;
392*4882a593Smuzhiyun 	}
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	return value;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
state_dfu_dnbusy(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)397*4882a593Smuzhiyun static int state_dfu_dnbusy(struct f_dfu *f_dfu,
398*4882a593Smuzhiyun 			    const struct usb_ctrlrequest *ctrl,
399*4882a593Smuzhiyun 			    struct usb_gadget *gadget,
400*4882a593Smuzhiyun 			    struct usb_request *req)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	int value = 0;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
405*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
406*4882a593Smuzhiyun 		value = handle_getstatus(req);
407*4882a593Smuzhiyun 		break;
408*4882a593Smuzhiyun 	default:
409*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
410*4882a593Smuzhiyun 		value = RET_STALL;
411*4882a593Smuzhiyun 		break;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	return value;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
state_dfu_dnload_idle(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)417*4882a593Smuzhiyun static int state_dfu_dnload_idle(struct f_dfu *f_dfu,
418*4882a593Smuzhiyun 				 const struct usb_ctrlrequest *ctrl,
419*4882a593Smuzhiyun 				 struct usb_gadget *gadget,
420*4882a593Smuzhiyun 				 struct usb_request *req)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	u16 w_value = le16_to_cpu(ctrl->wValue);
423*4882a593Smuzhiyun 	u16 len = le16_to_cpu(ctrl->wLength);
424*4882a593Smuzhiyun 	int value = 0;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
427*4882a593Smuzhiyun 	case USB_REQ_DFU_DNLOAD:
428*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
429*4882a593Smuzhiyun 		f_dfu->blk_seq_num = w_value;
430*4882a593Smuzhiyun 		value = handle_dnload(gadget, len);
431*4882a593Smuzhiyun 		break;
432*4882a593Smuzhiyun 	case USB_REQ_DFU_ABORT:
433*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
434*4882a593Smuzhiyun 		value = RET_ZLP;
435*4882a593Smuzhiyun 		break;
436*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
437*4882a593Smuzhiyun 		value = handle_getstatus(req);
438*4882a593Smuzhiyun 		break;
439*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
440*4882a593Smuzhiyun 		value = handle_getstate(req);
441*4882a593Smuzhiyun 		break;
442*4882a593Smuzhiyun 	default:
443*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
444*4882a593Smuzhiyun 		value = RET_STALL;
445*4882a593Smuzhiyun 		break;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return value;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
state_dfu_manifest_sync(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)451*4882a593Smuzhiyun static int state_dfu_manifest_sync(struct f_dfu *f_dfu,
452*4882a593Smuzhiyun 				   const struct usb_ctrlrequest *ctrl,
453*4882a593Smuzhiyun 				   struct usb_gadget *gadget,
454*4882a593Smuzhiyun 				   struct usb_request *req)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	int value = 0;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
459*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
460*4882a593Smuzhiyun 		/* We're MainfestationTolerant */
461*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
462*4882a593Smuzhiyun 		value = handle_getstatus(req);
463*4882a593Smuzhiyun 		f_dfu->blk_seq_num = 0;
464*4882a593Smuzhiyun 		req->complete = dnload_request_flush;
465*4882a593Smuzhiyun 		break;
466*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
467*4882a593Smuzhiyun 		value = handle_getstate(req);
468*4882a593Smuzhiyun 		break;
469*4882a593Smuzhiyun 	default:
470*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
471*4882a593Smuzhiyun 		value = RET_STALL;
472*4882a593Smuzhiyun 		break;
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	return value;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
state_dfu_manifest(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)478*4882a593Smuzhiyun static int state_dfu_manifest(struct f_dfu *f_dfu,
479*4882a593Smuzhiyun 			      const struct usb_ctrlrequest *ctrl,
480*4882a593Smuzhiyun 			      struct usb_gadget *gadget,
481*4882a593Smuzhiyun 			      struct usb_request *req)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun 	int value = 0;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
486*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
487*4882a593Smuzhiyun 		/* We're MainfestationTolerant */
488*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
489*4882a593Smuzhiyun 		value = handle_getstatus(req);
490*4882a593Smuzhiyun 		f_dfu->blk_seq_num = 0;
491*4882a593Smuzhiyun 		puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
492*4882a593Smuzhiyun 		break;
493*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
494*4882a593Smuzhiyun 		value = handle_getstate(req);
495*4882a593Smuzhiyun 		break;
496*4882a593Smuzhiyun 	default:
497*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
498*4882a593Smuzhiyun 		value = RET_STALL;
499*4882a593Smuzhiyun 		break;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 	return value;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
state_dfu_upload_idle(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)504*4882a593Smuzhiyun static int state_dfu_upload_idle(struct f_dfu *f_dfu,
505*4882a593Smuzhiyun 				 const struct usb_ctrlrequest *ctrl,
506*4882a593Smuzhiyun 				 struct usb_gadget *gadget,
507*4882a593Smuzhiyun 				 struct usb_request *req)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	u16 w_value = le16_to_cpu(ctrl->wValue);
510*4882a593Smuzhiyun 	u16 len = le16_to_cpu(ctrl->wLength);
511*4882a593Smuzhiyun 	int value = 0;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
514*4882a593Smuzhiyun 	case USB_REQ_DFU_UPLOAD:
515*4882a593Smuzhiyun 		/* state transition if less data then requested */
516*4882a593Smuzhiyun 		f_dfu->blk_seq_num = w_value;
517*4882a593Smuzhiyun 		value = handle_upload(req, len);
518*4882a593Smuzhiyun 		if (value >= 0 && value < len)
519*4882a593Smuzhiyun 			f_dfu->dfu_state = DFU_STATE_dfuIDLE;
520*4882a593Smuzhiyun 		break;
521*4882a593Smuzhiyun 	case USB_REQ_DFU_ABORT:
522*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
523*4882a593Smuzhiyun 		/* no zlp? */
524*4882a593Smuzhiyun 		value = RET_ZLP;
525*4882a593Smuzhiyun 		break;
526*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
527*4882a593Smuzhiyun 		value = handle_getstatus(req);
528*4882a593Smuzhiyun 		break;
529*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
530*4882a593Smuzhiyun 		value = handle_getstate(req);
531*4882a593Smuzhiyun 		break;
532*4882a593Smuzhiyun 	default:
533*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
534*4882a593Smuzhiyun 		value = RET_STALL;
535*4882a593Smuzhiyun 		break;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	return value;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
state_dfu_error(struct f_dfu * f_dfu,const struct usb_ctrlrequest * ctrl,struct usb_gadget * gadget,struct usb_request * req)541*4882a593Smuzhiyun static int state_dfu_error(struct f_dfu *f_dfu,
542*4882a593Smuzhiyun 				 const struct usb_ctrlrequest *ctrl,
543*4882a593Smuzhiyun 				 struct usb_gadget *gadget,
544*4882a593Smuzhiyun 				 struct usb_request *req)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	int value = 0;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	switch (ctrl->bRequest) {
549*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATUS:
550*4882a593Smuzhiyun 		value = handle_getstatus(req);
551*4882a593Smuzhiyun 		break;
552*4882a593Smuzhiyun 	case USB_REQ_DFU_GETSTATE:
553*4882a593Smuzhiyun 		value = handle_getstate(req);
554*4882a593Smuzhiyun 		break;
555*4882a593Smuzhiyun 	case USB_REQ_DFU_CLRSTATUS:
556*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
557*4882a593Smuzhiyun 		f_dfu->dfu_status = DFU_STATUS_OK;
558*4882a593Smuzhiyun 		/* no zlp? */
559*4882a593Smuzhiyun 		value = RET_ZLP;
560*4882a593Smuzhiyun 		break;
561*4882a593Smuzhiyun 	default:
562*4882a593Smuzhiyun 		f_dfu->dfu_state = DFU_STATE_dfuERROR;
563*4882a593Smuzhiyun 		value = RET_STALL;
564*4882a593Smuzhiyun 		break;
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	return value;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun static dfu_state_fn dfu_state[] = {
571*4882a593Smuzhiyun 	state_app_idle,          /* DFU_STATE_appIDLE */
572*4882a593Smuzhiyun 	state_app_detach,        /* DFU_STATE_appDETACH */
573*4882a593Smuzhiyun 	state_dfu_idle,          /* DFU_STATE_dfuIDLE */
574*4882a593Smuzhiyun 	state_dfu_dnload_sync,   /* DFU_STATE_dfuDNLOAD_SYNC */
575*4882a593Smuzhiyun 	state_dfu_dnbusy,        /* DFU_STATE_dfuDNBUSY */
576*4882a593Smuzhiyun 	state_dfu_dnload_idle,   /* DFU_STATE_dfuDNLOAD_IDLE */
577*4882a593Smuzhiyun 	state_dfu_manifest_sync, /* DFU_STATE_dfuMANIFEST_SYNC */
578*4882a593Smuzhiyun 	state_dfu_manifest,	 /* DFU_STATE_dfuMANIFEST */
579*4882a593Smuzhiyun 	NULL,                    /* DFU_STATE_dfuMANIFEST_WAIT_RST */
580*4882a593Smuzhiyun 	state_dfu_upload_idle,   /* DFU_STATE_dfuUPLOAD_IDLE */
581*4882a593Smuzhiyun 	state_dfu_error          /* DFU_STATE_dfuERROR */
582*4882a593Smuzhiyun };
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun static int
dfu_handle(struct usb_function * f,const struct usb_ctrlrequest * ctrl)585*4882a593Smuzhiyun dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	struct usb_gadget *gadget = f->config->cdev->gadget;
588*4882a593Smuzhiyun 	struct usb_request *req = f->config->cdev->req;
589*4882a593Smuzhiyun 	struct f_dfu *f_dfu = f->config->cdev->req->context;
590*4882a593Smuzhiyun 	u16 len = le16_to_cpu(ctrl->wLength);
591*4882a593Smuzhiyun 	u16 w_value = le16_to_cpu(ctrl->wValue);
592*4882a593Smuzhiyun 	int value = 0;
593*4882a593Smuzhiyun 	u8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	debug("w_value: 0x%x len: 0x%x\n", w_value, len);
596*4882a593Smuzhiyun 	debug("req_type: 0x%x ctrl->bRequest: 0x%x f_dfu->dfu_state: 0x%x\n",
597*4882a593Smuzhiyun 	       req_type, ctrl->bRequest, f_dfu->dfu_state);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	if (req_type == USB_TYPE_STANDARD) {
600*4882a593Smuzhiyun 		if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR &&
601*4882a593Smuzhiyun 		    (w_value >> 8) == DFU_DT_FUNC) {
602*4882a593Smuzhiyun 			value = min(len, (u16) sizeof(dfu_func));
603*4882a593Smuzhiyun 			memcpy(req->buf, &dfu_func, value);
604*4882a593Smuzhiyun 		}
605*4882a593Smuzhiyun 	} else /* DFU specific request */
606*4882a593Smuzhiyun 		value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	if (value >= 0) {
609*4882a593Smuzhiyun 		req->length = value;
610*4882a593Smuzhiyun 		req->zero = value < len;
611*4882a593Smuzhiyun 		value = usb_ep_queue(gadget->ep0, req, 0);
612*4882a593Smuzhiyun 		if (value < 0) {
613*4882a593Smuzhiyun 			debug("ep_queue --> %d\n", value);
614*4882a593Smuzhiyun 			req->status = 0;
615*4882a593Smuzhiyun 		}
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return value;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun static int
dfu_prepare_strings(struct f_dfu * f_dfu,int n)624*4882a593Smuzhiyun dfu_prepare_strings(struct f_dfu *f_dfu, int n)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun 	struct dfu_entity *de = NULL;
627*4882a593Smuzhiyun 	int i = 0;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	f_dfu->strings = calloc(sizeof(struct usb_string), n + 1);
630*4882a593Smuzhiyun 	if (!f_dfu->strings)
631*4882a593Smuzhiyun 		return -ENOMEM;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	for (i = 0; i < n; ++i) {
634*4882a593Smuzhiyun 		de = dfu_get_entity(i);
635*4882a593Smuzhiyun 		f_dfu->strings[i].s = de->name;
636*4882a593Smuzhiyun 	}
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	f_dfu->strings[i].id = 0;
639*4882a593Smuzhiyun 	f_dfu->strings[i].s = NULL;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return 0;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
dfu_prepare_function(struct f_dfu * f_dfu,int n)644*4882a593Smuzhiyun static int dfu_prepare_function(struct f_dfu *f_dfu, int n)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	struct usb_interface_descriptor *d;
647*4882a593Smuzhiyun 	int i = 0;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 2);
650*4882a593Smuzhiyun 	if (!f_dfu->function)
651*4882a593Smuzhiyun 		goto enomem;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	for (i = 0; i < n; ++i) {
654*4882a593Smuzhiyun 		d = calloc(sizeof(*d), 1);
655*4882a593Smuzhiyun 		if (!d)
656*4882a593Smuzhiyun 			goto enomem;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 		d->bLength =		sizeof(*d);
659*4882a593Smuzhiyun 		d->bDescriptorType =	USB_DT_INTERFACE;
660*4882a593Smuzhiyun 		d->bAlternateSetting =	i;
661*4882a593Smuzhiyun 		d->bNumEndpoints =	0;
662*4882a593Smuzhiyun 		d->bInterfaceClass =	USB_CLASS_APP_SPEC;
663*4882a593Smuzhiyun 		d->bInterfaceSubClass =	1;
664*4882a593Smuzhiyun 		d->bInterfaceProtocol =	2;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 		f_dfu->function[i] = (struct usb_descriptor_header *)d;
667*4882a593Smuzhiyun 	}
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	/* add DFU Functional Descriptor */
670*4882a593Smuzhiyun 	f_dfu->function[i] = calloc(sizeof(dfu_func), 1);
671*4882a593Smuzhiyun 	if (!f_dfu->function[i])
672*4882a593Smuzhiyun 		goto enomem;
673*4882a593Smuzhiyun 	memcpy(f_dfu->function[i], &dfu_func, sizeof(dfu_func));
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	i++;
676*4882a593Smuzhiyun 	f_dfu->function[i] = NULL;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	return 0;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun enomem:
681*4882a593Smuzhiyun 	while (i) {
682*4882a593Smuzhiyun 		free(f_dfu->function[--i]);
683*4882a593Smuzhiyun 		f_dfu->function[i] = NULL;
684*4882a593Smuzhiyun 	}
685*4882a593Smuzhiyun 	free(f_dfu->function);
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	return -ENOMEM;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun 
dfu_bind(struct usb_configuration * c,struct usb_function * f)690*4882a593Smuzhiyun static int dfu_bind(struct usb_configuration *c, struct usb_function *f)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	struct usb_composite_dev *cdev = c->cdev;
693*4882a593Smuzhiyun 	struct f_dfu *f_dfu = func_to_dfu(f);
694*4882a593Smuzhiyun 	const char *s;
695*4882a593Smuzhiyun 	int alt_num = dfu_get_alt_number();
696*4882a593Smuzhiyun 	int rv, id, i;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	id = usb_interface_id(c, f);
699*4882a593Smuzhiyun 	if (id < 0)
700*4882a593Smuzhiyun 		return id;
701*4882a593Smuzhiyun 	dfu_intf_runtime.bInterfaceNumber = id;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	f_dfu->dfu_state = DFU_STATE_appIDLE;
704*4882a593Smuzhiyun 	f_dfu->dfu_status = DFU_STATUS_OK;
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	rv = dfu_prepare_function(f_dfu, alt_num);
707*4882a593Smuzhiyun 	if (rv)
708*4882a593Smuzhiyun 		goto error;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	rv = dfu_prepare_strings(f_dfu, alt_num);
711*4882a593Smuzhiyun 	if (rv)
712*4882a593Smuzhiyun 		goto error;
713*4882a593Smuzhiyun 	for (i = 0; i < alt_num; i++) {
714*4882a593Smuzhiyun 		id = usb_string_id(cdev);
715*4882a593Smuzhiyun 		if (id < 0)
716*4882a593Smuzhiyun 			return id;
717*4882a593Smuzhiyun 		f_dfu->strings[i].id = id;
718*4882a593Smuzhiyun 		((struct usb_interface_descriptor *)f_dfu->function[i])
719*4882a593Smuzhiyun 			->iInterface = id;
720*4882a593Smuzhiyun 	}
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	to_dfu_mode(f_dfu);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	stringtab_dfu.strings = f_dfu->strings;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	cdev->req->context = f_dfu;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	s = env_get("serial#");
729*4882a593Smuzhiyun 	if (s)
730*4882a593Smuzhiyun 		g_dnl_set_serialnumber((char *)s);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun error:
733*4882a593Smuzhiyun 	return rv;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
dfu_unbind(struct usb_configuration * c,struct usb_function * f)736*4882a593Smuzhiyun static void dfu_unbind(struct usb_configuration *c, struct usb_function *f)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	struct f_dfu *f_dfu = func_to_dfu(f);
739*4882a593Smuzhiyun 	int alt_num = dfu_get_alt_number();
740*4882a593Smuzhiyun 	int i;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	if (f_dfu->strings) {
743*4882a593Smuzhiyun 		i = alt_num;
744*4882a593Smuzhiyun 		while (i)
745*4882a593Smuzhiyun 			f_dfu->strings[--i].s = NULL;
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		free(f_dfu->strings);
748*4882a593Smuzhiyun 	}
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	if (f_dfu->function) {
751*4882a593Smuzhiyun 		i = alt_num;
752*4882a593Smuzhiyun 		i++; /* free DFU Functional Descriptor */
753*4882a593Smuzhiyun 		while (i) {
754*4882a593Smuzhiyun 			free(f_dfu->function[--i]);
755*4882a593Smuzhiyun 			f_dfu->function[i] = NULL;
756*4882a593Smuzhiyun 		}
757*4882a593Smuzhiyun 		free(f_dfu->function);
758*4882a593Smuzhiyun 	}
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	free(f_dfu);
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
dfu_set_alt(struct usb_function * f,unsigned intf,unsigned alt)763*4882a593Smuzhiyun static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun 	struct f_dfu *f_dfu = func_to_dfu(f);
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	debug("%s: intf:%d alt:%d\n", __func__, intf, alt);
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	f_dfu->altsetting = alt;
770*4882a593Smuzhiyun 	f_dfu->dfu_state = DFU_STATE_dfuIDLE;
771*4882a593Smuzhiyun 	f_dfu->dfu_status = DFU_STATUS_OK;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	return 0;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
__dfu_get_alt(struct usb_function * f,unsigned intf)776*4882a593Smuzhiyun static int __dfu_get_alt(struct usb_function *f, unsigned intf)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun 	struct f_dfu *f_dfu = func_to_dfu(f);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	return f_dfu->altsetting;
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun /* TODO: is this really what we need here? */
dfu_disable(struct usb_function * f)784*4882a593Smuzhiyun static void dfu_disable(struct usb_function *f)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	struct f_dfu *f_dfu = func_to_dfu(f);
787*4882a593Smuzhiyun 	if (f_dfu->config == 0)
788*4882a593Smuzhiyun 		return;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	debug("%s: reset config\n", __func__);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	f_dfu->config = 0;
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun 
dfu_bind_config(struct usb_configuration * c)795*4882a593Smuzhiyun static int dfu_bind_config(struct usb_configuration *c)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun 	struct f_dfu *f_dfu;
798*4882a593Smuzhiyun 	int status;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	f_dfu = calloc(sizeof(*f_dfu), 1);
801*4882a593Smuzhiyun 	if (!f_dfu)
802*4882a593Smuzhiyun 		return -ENOMEM;
803*4882a593Smuzhiyun 	f_dfu->usb_function.name = "dfu";
804*4882a593Smuzhiyun 	f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
805*4882a593Smuzhiyun 	f_dfu->usb_function.descriptors = dfu_runtime_descs;
806*4882a593Smuzhiyun 	f_dfu->usb_function.bind = dfu_bind;
807*4882a593Smuzhiyun 	f_dfu->usb_function.unbind = dfu_unbind;
808*4882a593Smuzhiyun 	f_dfu->usb_function.set_alt = dfu_set_alt;
809*4882a593Smuzhiyun 	f_dfu->usb_function.get_alt = __dfu_get_alt;
810*4882a593Smuzhiyun 	f_dfu->usb_function.disable = dfu_disable;
811*4882a593Smuzhiyun 	f_dfu->usb_function.strings = dfu_generic_strings;
812*4882a593Smuzhiyun 	f_dfu->usb_function.setup = dfu_handle;
813*4882a593Smuzhiyun 	f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	status = usb_add_function(c, &f_dfu->usb_function);
816*4882a593Smuzhiyun 	if (status)
817*4882a593Smuzhiyun 		free(f_dfu);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	return status;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun 
dfu_add(struct usb_configuration * c)822*4882a593Smuzhiyun int dfu_add(struct usb_configuration *c)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	int id;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	id = usb_string_id(c->cdev);
827*4882a593Smuzhiyun 	if (id < 0)
828*4882a593Smuzhiyun 		return id;
829*4882a593Smuzhiyun 	strings_dfu_generic[0].id = id;
830*4882a593Smuzhiyun 	dfu_intf_runtime.iInterface = id;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	debug("%s: cdev: 0x%p gadget:0x%p gadget->ep0: 0x%p\n", __func__,
833*4882a593Smuzhiyun 	       c->cdev, c->cdev->gadget, c->cdev->gadget->ep0);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	return dfu_bind_config(c);
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun DECLARE_GADGET_BIND_CALLBACK(usb_dnl_dfu, dfu_add);
839