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