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