2 * f_dfu.c -- Device Firmware Update USB function
4 * Copyright (C) 2012 Samsung Electronics
5 * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
6 * Lukasz Majewski <l.majewski@samsung.com>
8 * Based on OpenMoko u-boot: drivers/usb/usbdfu.c
9 * (C) 2007 by OpenMoko, Inc.
10 * Author: Harald Welte <laforge@openmoko.org>
12 * based on existing SAM7DFU code from OpenPCD:
13 * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de>
15 * SPDX-License-Identifier: GPL-2.0+
22 #include <linux/usb/ch9.h>
23 #include <linux/usb/gadget.h>
24 #include <linux/usb/composite.h>
31 struct usb_function usb_function
;
33 struct usb_descriptor_header
**function
;
34 struct usb_string
*strings
;
36 /* when configured, we have one config */
39 enum dfu_state dfu_state
;
40 unsigned int dfu_status
;
42 /* Send/received block number is handy for data integrity check */
44 unsigned int poll_timeout
;
47 struct dfu_entity
*dfu_defer_flush
;
49 typedef int (*dfu_state_fn
) (struct f_dfu
*,
50 const struct usb_ctrlrequest
*,
52 struct usb_request
*);
54 static inline struct f_dfu
*func_to_dfu(struct usb_function
*f
)
56 return container_of(f
, struct f_dfu
, usb_function
);
59 static const struct dfu_function_descriptor dfu_func
= {
60 .bLength
= sizeof dfu_func
,
61 .bDescriptorType
= DFU_DT_FUNC
,
62 .bmAttributes
= DFU_BIT_WILL_DETACH
|
63 DFU_BIT_MANIFESTATION_TOLERANT
|
67 .wTransferSize
= DFU_USB_BUFSIZ
,
68 .bcdDFUVersion
= __constant_cpu_to_le16(0x0110),
71 static struct usb_interface_descriptor dfu_intf_runtime
= {
72 .bLength
= sizeof dfu_intf_runtime
,
73 .bDescriptorType
= USB_DT_INTERFACE
,
75 .bInterfaceClass
= USB_CLASS_APP_SPEC
,
76 .bInterfaceSubClass
= 1,
77 .bInterfaceProtocol
= 1,
78 /* .iInterface = DYNAMIC */
81 static struct usb_descriptor_header
*dfu_runtime_descs
[] = {
82 (struct usb_descriptor_header
*) &dfu_intf_runtime
,
86 static const char dfu_name
[] = "Device Firmware Upgrade";
89 * static strings, in UTF-8
91 * dfu_generic configuration
93 static struct usb_string strings_dfu_generic
[] = {
98 static struct usb_gadget_strings stringtab_dfu_generic
= {
99 .language
= 0x0409, /* en-us */
100 .strings
= strings_dfu_generic
,
103 static struct usb_gadget_strings
*dfu_generic_strings
[] = {
104 &stringtab_dfu_generic
,
109 * usb_function specific
111 static struct usb_gadget_strings stringtab_dfu
= {
112 .language
= 0x0409, /* en-us */
116 * assigned during initialization,
117 * depends on number of flash entities
122 static struct usb_gadget_strings
*dfu_strings
[] = {
127 static void dfu_set_poll_timeout(struct dfu_status
*dstat
, unsigned int ms
)
130 * The bwPollTimeout DFU_GETSTATUS request payload provides information
131 * about minimum time, in milliseconds, that the host should wait before
132 * sending a subsequent DFU_GETSTATUS request
134 * This permits the device to vary the delay depending on its need to
135 * erase or program the memory
139 unsigned char *p
= (unsigned char *)&ms
;
141 if (!ms
|| (ms
& ~DFU_POLL_TIMEOUT_MASK
)) {
142 dstat
->bwPollTimeout
[0] = 0;
143 dstat
->bwPollTimeout
[1] = 0;
144 dstat
->bwPollTimeout
[2] = 0;
149 dstat
->bwPollTimeout
[0] = *p
++;
150 dstat
->bwPollTimeout
[1] = *p
++;
151 dstat
->bwPollTimeout
[2] = *p
;
154 /*-------------------------------------------------------------------------*/
156 static void dnload_request_complete(struct usb_ep
*ep
, struct usb_request
*req
)
158 struct f_dfu
*f_dfu
= req
->context
;
161 ret
= dfu_write(dfu_get_entity(f_dfu
->altsetting
), req
->buf
,
162 req
->actual
, f_dfu
->blk_seq_num
);
164 f_dfu
->dfu_status
= DFU_STATUS_errUNKNOWN
;
165 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
169 static void dnload_request_flush(struct usb_ep
*ep
, struct usb_request
*req
)
171 struct f_dfu
*f_dfu
= req
->context
;
172 dfu_set_defer_flush(dfu_get_entity(f_dfu
->altsetting
));
175 static inline int dfu_get_manifest_timeout(struct dfu_entity
*dfu
)
177 return dfu
->poll_timeout
? dfu
->poll_timeout(dfu
) :
178 DFU_MANIFEST_POLL_TIMEOUT
;
181 static int handle_getstatus(struct usb_request
*req
)
183 struct dfu_status
*dstat
= (struct dfu_status
*)req
->buf
;
184 struct f_dfu
*f_dfu
= req
->context
;
185 struct dfu_entity
*dfu
= dfu_get_entity(f_dfu
->altsetting
);
187 dfu_set_poll_timeout(dstat
, 0);
189 switch (f_dfu
->dfu_state
) {
190 case DFU_STATE_dfuDNLOAD_SYNC
:
191 case DFU_STATE_dfuDNBUSY
:
192 f_dfu
->dfu_state
= DFU_STATE_dfuDNLOAD_IDLE
;
194 case DFU_STATE_dfuMANIFEST_SYNC
:
195 f_dfu
->dfu_state
= DFU_STATE_dfuMANIFEST
;
197 case DFU_STATE_dfuMANIFEST
:
198 dfu_set_poll_timeout(dstat
, dfu_get_manifest_timeout(dfu
));
204 if (f_dfu
->poll_timeout
)
205 if (!(f_dfu
->blk_seq_num
%
206 (dfu_get_buf_size() / DFU_USB_BUFSIZ
)))
207 dfu_set_poll_timeout(dstat
, f_dfu
->poll_timeout
);
209 /* send status response */
210 dstat
->bStatus
= f_dfu
->dfu_status
;
211 dstat
->bState
= f_dfu
->dfu_state
;
214 return sizeof(struct dfu_status
);
217 static int handle_getstate(struct usb_request
*req
)
219 struct f_dfu
*f_dfu
= req
->context
;
221 ((u8
*)req
->buf
)[0] = f_dfu
->dfu_state
;
225 static inline void to_dfu_mode(struct f_dfu
*f_dfu
)
227 f_dfu
->usb_function
.strings
= dfu_strings
;
228 f_dfu
->usb_function
.hs_descriptors
= f_dfu
->function
;
229 f_dfu
->usb_function
.descriptors
= f_dfu
->function
;
230 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
233 static inline void to_runtime_mode(struct f_dfu
*f_dfu
)
235 f_dfu
->usb_function
.strings
= NULL
;
236 f_dfu
->usb_function
.hs_descriptors
= dfu_runtime_descs
;
237 f_dfu
->usb_function
.descriptors
= dfu_runtime_descs
;
240 static int handle_upload(struct usb_request
*req
, u16 len
)
242 struct f_dfu
*f_dfu
= req
->context
;
244 return dfu_read(dfu_get_entity(f_dfu
->altsetting
), req
->buf
,
245 req
->length
, f_dfu
->blk_seq_num
);
248 static int handle_dnload(struct usb_gadget
*gadget
, u16 len
)
250 struct usb_composite_dev
*cdev
= get_gadget_data(gadget
);
251 struct usb_request
*req
= cdev
->req
;
252 struct f_dfu
*f_dfu
= req
->context
;
255 f_dfu
->dfu_state
= DFU_STATE_dfuMANIFEST_SYNC
;
257 req
->complete
= dnload_request_complete
;
262 /*-------------------------------------------------------------------------*/
263 /* DFU state machine */
264 static int state_app_idle(struct f_dfu
*f_dfu
,
265 const struct usb_ctrlrequest
*ctrl
,
266 struct usb_gadget
*gadget
,
267 struct usb_request
*req
)
271 switch (ctrl
->bRequest
) {
272 case USB_REQ_DFU_GETSTATUS
:
273 value
= handle_getstatus(req
);
275 case USB_REQ_DFU_GETSTATE
:
276 value
= handle_getstate(req
);
278 case USB_REQ_DFU_DETACH
:
279 f_dfu
->dfu_state
= DFU_STATE_appDETACH
;
291 static int state_app_detach(struct f_dfu
*f_dfu
,
292 const struct usb_ctrlrequest
*ctrl
,
293 struct usb_gadget
*gadget
,
294 struct usb_request
*req
)
298 switch (ctrl
->bRequest
) {
299 case USB_REQ_DFU_GETSTATUS
:
300 value
= handle_getstatus(req
);
302 case USB_REQ_DFU_GETSTATE
:
303 value
= handle_getstate(req
);
306 f_dfu
->dfu_state
= DFU_STATE_appIDLE
;
314 static int state_dfu_idle(struct f_dfu
*f_dfu
,
315 const struct usb_ctrlrequest
*ctrl
,
316 struct usb_gadget
*gadget
,
317 struct usb_request
*req
)
319 u16 w_value
= le16_to_cpu(ctrl
->wValue
);
320 u16 len
= le16_to_cpu(ctrl
->wLength
);
323 switch (ctrl
->bRequest
) {
324 case USB_REQ_DFU_DNLOAD
:
326 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
330 f_dfu
->dfu_state
= DFU_STATE_dfuDNLOAD_SYNC
;
331 f_dfu
->blk_seq_num
= w_value
;
332 value
= handle_dnload(gadget
, len
);
334 case USB_REQ_DFU_UPLOAD
:
335 f_dfu
->dfu_state
= DFU_STATE_dfuUPLOAD_IDLE
;
336 f_dfu
->blk_seq_num
= 0;
337 value
= handle_upload(req
, len
);
339 case USB_REQ_DFU_ABORT
:
343 case USB_REQ_DFU_GETSTATUS
:
344 value
= handle_getstatus(req
);
346 case USB_REQ_DFU_GETSTATE
:
347 value
= handle_getstate(req
);
349 case USB_REQ_DFU_DETACH
:
351 * Proprietary extension: 'detach' from idle mode and
352 * get back to runtime mode in case of USB Reset. As
353 * much as I dislike this, we just can't use every USB
354 * bus reset to switch back to runtime mode, since at
355 * least the Linux USB stack likes to send a number of
359 DFU_STATE_dfuMANIFEST_WAIT_RST
;
360 to_runtime_mode(f_dfu
);
361 f_dfu
->dfu_state
= DFU_STATE_appIDLE
;
363 g_dnl_trigger_detach();
366 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
374 static int state_dfu_dnload_sync(struct f_dfu
*f_dfu
,
375 const struct usb_ctrlrequest
*ctrl
,
376 struct usb_gadget
*gadget
,
377 struct usb_request
*req
)
381 switch (ctrl
->bRequest
) {
382 case USB_REQ_DFU_GETSTATUS
:
383 value
= handle_getstatus(req
);
385 case USB_REQ_DFU_GETSTATE
:
386 value
= handle_getstate(req
);
389 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
397 static int state_dfu_dnbusy(struct f_dfu
*f_dfu
,
398 const struct usb_ctrlrequest
*ctrl
,
399 struct usb_gadget
*gadget
,
400 struct usb_request
*req
)
404 switch (ctrl
->bRequest
) {
405 case USB_REQ_DFU_GETSTATUS
:
406 value
= handle_getstatus(req
);
409 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
417 static int state_dfu_dnload_idle(struct f_dfu
*f_dfu
,
418 const struct usb_ctrlrequest
*ctrl
,
419 struct usb_gadget
*gadget
,
420 struct usb_request
*req
)
422 u16 w_value
= le16_to_cpu(ctrl
->wValue
);
423 u16 len
= le16_to_cpu(ctrl
->wLength
);
426 switch (ctrl
->bRequest
) {
427 case USB_REQ_DFU_DNLOAD
:
428 f_dfu
->dfu_state
= DFU_STATE_dfuDNLOAD_SYNC
;
429 f_dfu
->blk_seq_num
= w_value
;
430 value
= handle_dnload(gadget
, len
);
432 case USB_REQ_DFU_ABORT
:
433 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
436 case USB_REQ_DFU_GETSTATUS
:
437 value
= handle_getstatus(req
);
439 case USB_REQ_DFU_GETSTATE
:
440 value
= handle_getstate(req
);
443 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
451 static int state_dfu_manifest_sync(struct f_dfu
*f_dfu
,
452 const struct usb_ctrlrequest
*ctrl
,
453 struct usb_gadget
*gadget
,
454 struct usb_request
*req
)
458 switch (ctrl
->bRequest
) {
459 case USB_REQ_DFU_GETSTATUS
:
460 /* We're MainfestationTolerant */
461 f_dfu
->dfu_state
= DFU_STATE_dfuMANIFEST
;
462 value
= handle_getstatus(req
);
463 f_dfu
->blk_seq_num
= 0;
464 req
->complete
= dnload_request_flush
;
466 case USB_REQ_DFU_GETSTATE
:
467 value
= handle_getstate(req
);
470 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
478 static int state_dfu_manifest(struct f_dfu
*f_dfu
,
479 const struct usb_ctrlrequest
*ctrl
,
480 struct usb_gadget
*gadget
,
481 struct usb_request
*req
)
485 switch (ctrl
->bRequest
) {
486 case USB_REQ_DFU_GETSTATUS
:
487 /* We're MainfestationTolerant */
488 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
489 value
= handle_getstatus(req
);
490 f_dfu
->blk_seq_num
= 0;
491 puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
493 case USB_REQ_DFU_GETSTATE
:
494 value
= handle_getstate(req
);
497 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
504 static int state_dfu_upload_idle(struct f_dfu
*f_dfu
,
505 const struct usb_ctrlrequest
*ctrl
,
506 struct usb_gadget
*gadget
,
507 struct usb_request
*req
)
509 u16 w_value
= le16_to_cpu(ctrl
->wValue
);
510 u16 len
= le16_to_cpu(ctrl
->wLength
);
513 switch (ctrl
->bRequest
) {
514 case USB_REQ_DFU_UPLOAD
:
515 /* state transition if less data then requested */
516 f_dfu
->blk_seq_num
= w_value
;
517 value
= handle_upload(req
, len
);
518 if (value
>= 0 && value
< len
)
519 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
521 case USB_REQ_DFU_ABORT
:
522 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
526 case USB_REQ_DFU_GETSTATUS
:
527 value
= handle_getstatus(req
);
529 case USB_REQ_DFU_GETSTATE
:
530 value
= handle_getstate(req
);
533 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
541 static int state_dfu_error(struct f_dfu
*f_dfu
,
542 const struct usb_ctrlrequest
*ctrl
,
543 struct usb_gadget
*gadget
,
544 struct usb_request
*req
)
548 switch (ctrl
->bRequest
) {
549 case USB_REQ_DFU_GETSTATUS
:
550 value
= handle_getstatus(req
);
552 case USB_REQ_DFU_GETSTATE
:
553 value
= handle_getstate(req
);
555 case USB_REQ_DFU_CLRSTATUS
:
556 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
557 f_dfu
->dfu_status
= DFU_STATUS_OK
;
562 f_dfu
->dfu_state
= DFU_STATE_dfuERROR
;
570 static dfu_state_fn dfu_state
[] = {
571 state_app_idle
, /* DFU_STATE_appIDLE */
572 state_app_detach
, /* DFU_STATE_appDETACH */
573 state_dfu_idle
, /* DFU_STATE_dfuIDLE */
574 state_dfu_dnload_sync
, /* DFU_STATE_dfuDNLOAD_SYNC */
575 state_dfu_dnbusy
, /* DFU_STATE_dfuDNBUSY */
576 state_dfu_dnload_idle
, /* DFU_STATE_dfuDNLOAD_IDLE */
577 state_dfu_manifest_sync
, /* DFU_STATE_dfuMANIFEST_SYNC */
578 state_dfu_manifest
, /* DFU_STATE_dfuMANIFEST */
579 NULL
, /* DFU_STATE_dfuMANIFEST_WAIT_RST */
580 state_dfu_upload_idle
, /* DFU_STATE_dfuUPLOAD_IDLE */
581 state_dfu_error
/* DFU_STATE_dfuERROR */
585 dfu_handle(struct usb_function
*f
, const struct usb_ctrlrequest
*ctrl
)
587 struct usb_gadget
*gadget
= f
->config
->cdev
->gadget
;
588 struct usb_request
*req
= f
->config
->cdev
->req
;
589 struct f_dfu
*f_dfu
= f
->config
->cdev
->req
->context
;
590 u16 len
= le16_to_cpu(ctrl
->wLength
);
591 u16 w_value
= le16_to_cpu(ctrl
->wValue
);
593 u8 req_type
= ctrl
->bRequestType
& USB_TYPE_MASK
;
595 debug("w_value: 0x%x len: 0x%x\n", w_value
, len
);
596 debug("req_type: 0x%x ctrl->bRequest: 0x%x f_dfu->dfu_state: 0x%x\n",
597 req_type
, ctrl
->bRequest
, f_dfu
->dfu_state
);
599 if (req_type
== USB_TYPE_STANDARD
) {
600 if (ctrl
->bRequest
== USB_REQ_GET_DESCRIPTOR
&&
601 (w_value
>> 8) == DFU_DT_FUNC
) {
602 value
= min(len
, (u16
) sizeof(dfu_func
));
603 memcpy(req
->buf
, &dfu_func
, value
);
605 } else /* DFU specific request */
606 value
= dfu_state
[f_dfu
->dfu_state
] (f_dfu
, ctrl
, gadget
, req
);
610 req
->zero
= value
< len
;
611 value
= usb_ep_queue(gadget
->ep0
, req
, 0);
613 debug("ep_queue --> %d\n", value
);
621 /*-------------------------------------------------------------------------*/
624 dfu_prepare_strings(struct f_dfu
*f_dfu
, int n
)
626 struct dfu_entity
*de
= NULL
;
629 f_dfu
->strings
= calloc(sizeof(struct usb_string
), n
+ 1);
633 for (i
= 0; i
< n
; ++i
) {
634 de
= dfu_get_entity(i
);
635 f_dfu
->strings
[i
].s
= de
->name
;
638 f_dfu
->strings
[i
].id
= 0;
639 f_dfu
->strings
[i
].s
= NULL
;
644 static int dfu_prepare_function(struct f_dfu
*f_dfu
, int n
)
646 struct usb_interface_descriptor
*d
;
649 f_dfu
->function
= calloc(sizeof(struct usb_descriptor_header
*), n
+ 2);
650 if (!f_dfu
->function
)
653 for (i
= 0; i
< n
; ++i
) {
654 d
= calloc(sizeof(*d
), 1);
658 d
->bLength
= sizeof(*d
);
659 d
->bDescriptorType
= USB_DT_INTERFACE
;
660 d
->bAlternateSetting
= i
;
661 d
->bNumEndpoints
= 0;
662 d
->bInterfaceClass
= USB_CLASS_APP_SPEC
;
663 d
->bInterfaceSubClass
= 1;
664 d
->bInterfaceProtocol
= 2;
666 f_dfu
->function
[i
] = (struct usb_descriptor_header
*)d
;
669 /* add DFU Functional Descriptor */
670 f_dfu
->function
[i
] = calloc(sizeof(dfu_func
), 1);
671 if (!f_dfu
->function
[i
])
673 memcpy(f_dfu
->function
[i
], &dfu_func
, sizeof(dfu_func
));
676 f_dfu
->function
[i
] = NULL
;
682 free(f_dfu
->function
[--i
]);
683 f_dfu
->function
[i
] = NULL
;
685 free(f_dfu
->function
);
690 static int dfu_bind(struct usb_configuration
*c
, struct usb_function
*f
)
692 struct usb_composite_dev
*cdev
= c
->cdev
;
693 struct f_dfu
*f_dfu
= func_to_dfu(f
);
695 int alt_num
= dfu_get_alt_number();
698 id
= usb_interface_id(c
, f
);
701 dfu_intf_runtime
.bInterfaceNumber
= id
;
703 f_dfu
->dfu_state
= DFU_STATE_appIDLE
;
704 f_dfu
->dfu_status
= DFU_STATUS_OK
;
706 rv
= dfu_prepare_function(f_dfu
, alt_num
);
710 rv
= dfu_prepare_strings(f_dfu
, alt_num
);
713 for (i
= 0; i
< alt_num
; i
++) {
714 id
= usb_string_id(cdev
);
717 f_dfu
->strings
[i
].id
= id
;
718 ((struct usb_interface_descriptor
*)f_dfu
->function
[i
])
724 stringtab_dfu
.strings
= f_dfu
->strings
;
726 cdev
->req
->context
= f_dfu
;
728 s
= env_get("serial#");
730 g_dnl_set_serialnumber((char *)s
);
736 static void dfu_unbind(struct usb_configuration
*c
, struct usb_function
*f
)
738 struct f_dfu
*f_dfu
= func_to_dfu(f
);
739 int alt_num
= dfu_get_alt_number();
742 if (f_dfu
->strings
) {
745 f_dfu
->strings
[--i
].s
= NULL
;
747 free(f_dfu
->strings
);
750 if (f_dfu
->function
) {
753 free(f_dfu
->function
[--i
]);
754 f_dfu
->function
[i
] = NULL
;
756 free(f_dfu
->function
);
762 static int dfu_set_alt(struct usb_function
*f
, unsigned intf
, unsigned alt
)
764 struct f_dfu
*f_dfu
= func_to_dfu(f
);
766 debug("%s: intf:%d alt:%d\n", __func__
, intf
, alt
);
768 f_dfu
->altsetting
= alt
;
769 f_dfu
->dfu_state
= DFU_STATE_dfuIDLE
;
770 f_dfu
->dfu_status
= DFU_STATUS_OK
;
775 static int __dfu_get_alt(struct usb_function
*f
, unsigned intf
)
777 struct f_dfu
*f_dfu
= func_to_dfu(f
);
779 return f_dfu
->altsetting
;
782 /* TODO: is this really what we need here? */
783 static void dfu_disable(struct usb_function
*f
)
785 struct f_dfu
*f_dfu
= func_to_dfu(f
);
786 if (f_dfu
->config
== 0)
789 debug("%s: reset config\n", __func__
);
794 static int dfu_bind_config(struct usb_configuration
*c
)
799 f_dfu
= calloc(sizeof(*f_dfu
), 1);
802 f_dfu
->usb_function
.name
= "dfu";
803 f_dfu
->usb_function
.hs_descriptors
= dfu_runtime_descs
;
804 f_dfu
->usb_function
.descriptors
= dfu_runtime_descs
;
805 f_dfu
->usb_function
.bind
= dfu_bind
;
806 f_dfu
->usb_function
.unbind
= dfu_unbind
;
807 f_dfu
->usb_function
.set_alt
= dfu_set_alt
;
808 f_dfu
->usb_function
.get_alt
= __dfu_get_alt
;
809 f_dfu
->usb_function
.disable
= dfu_disable
;
810 f_dfu
->usb_function
.strings
= dfu_generic_strings
;
811 f_dfu
->usb_function
.setup
= dfu_handle
;
812 f_dfu
->poll_timeout
= DFU_DEFAULT_POLL_TIMEOUT
;
814 status
= usb_add_function(c
, &f_dfu
->usb_function
);
821 int dfu_add(struct usb_configuration
*c
)
825 id
= usb_string_id(c
->cdev
);
828 strings_dfu_generic
[0].id
= id
;
829 dfu_intf_runtime
.iInterface
= id
;
831 debug("%s: cdev: 0x%p gadget:0x%p gadget->ep0: 0x%p\n", __func__
,
832 c
->cdev
, c
->cdev
->gadget
, c
->cdev
->gadget
->ep0
);
834 return dfu_bind_config(c
);
837 DECLARE_GADGET_BIND_CALLBACK(usb_dnl_dfu
, dfu_add
);