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