]> 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-usb
[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 inline int dfu_get_manifest_timeout(struct dfu_entity *dfu)
179 {
180         return dfu->poll_timeout ? dfu->poll_timeout(dfu) :
181                 DFU_MANIFEST_POLL_TIMEOUT;
182 }
183
184 static void handle_getstatus(struct usb_request *req)
185 {
186         struct dfu_status *dstat = (struct dfu_status *)req->buf;
187         struct f_dfu *f_dfu = req->context;
188         struct dfu_entity *dfu = dfu_get_entity(f_dfu->altsetting);
189
190         dfu_set_poll_timeout(dstat, 0);
191
192         switch (f_dfu->dfu_state) {
193         case DFU_STATE_dfuDNLOAD_SYNC:
194         case DFU_STATE_dfuDNBUSY:
195                 f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
196                 break;
197         case DFU_STATE_dfuMANIFEST_SYNC:
198                 f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
199                 break;
200         case DFU_STATE_dfuMANIFEST:
201                 dfu_set_poll_timeout(dstat, dfu_get_manifest_timeout(dfu));
202                 break;
203         default:
204                 break;
205         }
206
207         if (f_dfu->poll_timeout)
208                 if (!(f_dfu->blk_seq_num %
209                       (dfu_get_buf_size() / DFU_USB_BUFSIZ)))
210                         dfu_set_poll_timeout(dstat, f_dfu->poll_timeout);
211
212         /* send status response */
213         dstat->bStatus = f_dfu->dfu_status;
214         dstat->bState = f_dfu->dfu_state;
215         dstat->iString = 0;
216 }
217
218 static void handle_getstate(struct usb_request *req)
219 {
220         struct f_dfu *f_dfu = req->context;
221
222         ((u8 *)req->buf)[0] = f_dfu->dfu_state;
223         req->actual = sizeof(u8);
224 }
225
226 static inline void to_dfu_mode(struct f_dfu *f_dfu)
227 {
228         f_dfu->usb_function.strings = dfu_strings;
229         f_dfu->usb_function.hs_descriptors = f_dfu->function;
230         f_dfu->dfu_state = DFU_STATE_dfuIDLE;
231 }
232
233 static inline void to_runtime_mode(struct f_dfu *f_dfu)
234 {
235         f_dfu->usb_function.strings = NULL;
236         f_dfu->usb_function.hs_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                 handle_getstatus(req);
273                 value = RET_STAT_LEN;
274                 break;
275         case USB_REQ_DFU_GETSTATE:
276                 handle_getstate(req);
277                 break;
278         case USB_REQ_DFU_DETACH:
279                 f_dfu->dfu_state = DFU_STATE_appDETACH;
280                 to_dfu_mode(f_dfu);
281                 value = RET_ZLP;
282                 break;
283         default:
284                 value = RET_STALL;
285                 break;
286         }
287
288         return value;
289 }
290
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)
295 {
296         int value = 0;
297
298         switch (ctrl->bRequest) {
299         case USB_REQ_DFU_GETSTATUS:
300                 handle_getstatus(req);
301                 value = RET_STAT_LEN;
302                 break;
303         case USB_REQ_DFU_GETSTATE:
304                 handle_getstate(req);
305                 break;
306         default:
307                 f_dfu->dfu_state = DFU_STATE_appIDLE;
308                 value = RET_STALL;
309                 break;
310         }
311
312         return value;
313 }
314
315 static int state_dfu_idle(struct f_dfu *f_dfu,
316                           const struct usb_ctrlrequest *ctrl,
317                           struct usb_gadget *gadget,
318                           struct usb_request *req)
319 {
320         u16 w_value = le16_to_cpu(ctrl->wValue);
321         u16 len = le16_to_cpu(ctrl->wLength);
322         int value = 0;
323
324         switch (ctrl->bRequest) {
325         case USB_REQ_DFU_DNLOAD:
326                 if (len == 0) {
327                         f_dfu->dfu_state = DFU_STATE_dfuERROR;
328                         value = RET_STALL;
329                         break;
330                 }
331                 f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
332                 f_dfu->blk_seq_num = w_value;
333                 value = handle_dnload(gadget, len);
334                 break;
335         case USB_REQ_DFU_UPLOAD:
336                 f_dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
337                 f_dfu->blk_seq_num = 0;
338                 value = handle_upload(req, len);
339                 break;
340         case USB_REQ_DFU_ABORT:
341                 /* no zlp? */
342                 value = RET_ZLP;
343                 break;
344         case USB_REQ_DFU_GETSTATUS:
345                 handle_getstatus(req);
346                 value = RET_STAT_LEN;
347                 break;
348         case USB_REQ_DFU_GETSTATE:
349                 handle_getstate(req);
350                 break;
351         case USB_REQ_DFU_DETACH:
352                 /*
353                  * Proprietary extension: 'detach' from idle mode and
354                  * get back to runtime mode in case of USB Reset.  As
355                  * much as I dislike this, we just can't use every USB
356                  * bus reset to switch back to runtime mode, since at
357                  * least the Linux USB stack likes to send a number of
358                  * resets in a row :(
359                  */
360                 f_dfu->dfu_state =
361                         DFU_STATE_dfuMANIFEST_WAIT_RST;
362                 to_runtime_mode(f_dfu);
363                 f_dfu->dfu_state = DFU_STATE_appIDLE;
364
365                 dfu_trigger_reset();
366                 break;
367         default:
368                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
369                 value = RET_STALL;
370                 break;
371         }
372
373         return value;
374 }
375
376 static int state_dfu_dnload_sync(struct f_dfu *f_dfu,
377                                  const struct usb_ctrlrequest *ctrl,
378                                  struct usb_gadget *gadget,
379                                  struct usb_request *req)
380 {
381         int value = 0;
382
383         switch (ctrl->bRequest) {
384         case USB_REQ_DFU_GETSTATUS:
385                 handle_getstatus(req);
386                 value = RET_STAT_LEN;
387                 break;
388         case USB_REQ_DFU_GETSTATE:
389                 handle_getstate(req);
390                 break;
391         default:
392                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
393                 value = RET_STALL;
394                 break;
395         }
396
397         return value;
398 }
399
400 static int state_dfu_dnbusy(struct f_dfu *f_dfu,
401                             const struct usb_ctrlrequest *ctrl,
402                             struct usb_gadget *gadget,
403                             struct usb_request *req)
404 {
405         int value = 0;
406
407         switch (ctrl->bRequest) {
408         case USB_REQ_DFU_GETSTATUS:
409                 handle_getstatus(req);
410                 value = RET_STAT_LEN;
411                 break;
412         default:
413                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
414                 value = RET_STALL;
415                 break;
416         }
417
418         return value;
419 }
420
421 static int state_dfu_dnload_idle(struct f_dfu *f_dfu,
422                                  const struct usb_ctrlrequest *ctrl,
423                                  struct usb_gadget *gadget,
424                                  struct usb_request *req)
425 {
426         u16 w_value = le16_to_cpu(ctrl->wValue);
427         u16 len = le16_to_cpu(ctrl->wLength);
428         int value = 0;
429
430         switch (ctrl->bRequest) {
431         case USB_REQ_DFU_DNLOAD:
432                 f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
433                 f_dfu->blk_seq_num = w_value;
434                 value = handle_dnload(gadget, len);
435                 break;
436         case USB_REQ_DFU_ABORT:
437                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
438                 value = RET_ZLP;
439                 break;
440         case USB_REQ_DFU_GETSTATUS:
441                 handle_getstatus(req);
442                 value = RET_STAT_LEN;
443                 break;
444         case USB_REQ_DFU_GETSTATE:
445                 handle_getstate(req);
446                 break;
447         default:
448                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
449                 value = RET_STALL;
450                 break;
451         }
452
453         return value;
454 }
455
456 static int state_dfu_manifest_sync(struct f_dfu *f_dfu,
457                                    const struct usb_ctrlrequest *ctrl,
458                                    struct usb_gadget *gadget,
459                                    struct usb_request *req)
460 {
461         int value = 0;
462
463         switch (ctrl->bRequest) {
464         case USB_REQ_DFU_GETSTATUS:
465                 /* We're MainfestationTolerant */
466                 f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
467                 handle_getstatus(req);
468                 f_dfu->blk_seq_num = 0;
469                 value = RET_STAT_LEN;
470                 req->complete = dnload_request_flush;
471                 break;
472         case USB_REQ_DFU_GETSTATE:
473                 handle_getstate(req);
474                 break;
475         default:
476                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
477                 value = RET_STALL;
478                 break;
479         }
480
481         return value;
482 }
483
484 static int state_dfu_manifest(struct f_dfu *f_dfu,
485                               const struct usb_ctrlrequest *ctrl,
486                               struct usb_gadget *gadget,
487                               struct usb_request *req)
488 {
489         int value = 0;
490
491         switch (ctrl->bRequest) {
492         case USB_REQ_DFU_GETSTATUS:
493                 /* We're MainfestationTolerant */
494                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
495                 handle_getstatus(req);
496                 f_dfu->blk_seq_num = 0;
497                 value = RET_STAT_LEN;
498                 puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
499                 break;
500         case USB_REQ_DFU_GETSTATE:
501                 handle_getstate(req);
502                 break;
503         default:
504                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
505                 value = RET_STALL;
506                 break;
507         }
508         return value;
509 }
510
511 static int state_dfu_upload_idle(struct f_dfu *f_dfu,
512                                  const struct usb_ctrlrequest *ctrl,
513                                  struct usb_gadget *gadget,
514                                  struct usb_request *req)
515 {
516         u16 w_value = le16_to_cpu(ctrl->wValue);
517         u16 len = le16_to_cpu(ctrl->wLength);
518         int value = 0;
519
520         switch (ctrl->bRequest) {
521         case USB_REQ_DFU_UPLOAD:
522                 /* state transition if less data then requested */
523                 f_dfu->blk_seq_num = w_value;
524                 value = handle_upload(req, len);
525                 if (value >= 0 && value < len)
526                         f_dfu->dfu_state = DFU_STATE_dfuIDLE;
527                 break;
528         case USB_REQ_DFU_ABORT:
529                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
530                 /* no zlp? */
531                 value = RET_ZLP;
532                 break;
533         case USB_REQ_DFU_GETSTATUS:
534                 handle_getstatus(req);
535                 value = RET_STAT_LEN;
536                 break;
537         case USB_REQ_DFU_GETSTATE:
538                 handle_getstate(req);
539                 break;
540         default:
541                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
542                 value = RET_STALL;
543                 break;
544         }
545
546         return value;
547 }
548
549 static int state_dfu_error(struct f_dfu *f_dfu,
550                                  const struct usb_ctrlrequest *ctrl,
551                                  struct usb_gadget *gadget,
552                                  struct usb_request *req)
553 {
554         int value = 0;
555
556         switch (ctrl->bRequest) {
557         case USB_REQ_DFU_GETSTATUS:
558                 handle_getstatus(req);
559                 value = RET_STAT_LEN;
560                 break;
561         case USB_REQ_DFU_GETSTATE:
562                 handle_getstate(req);
563                 break;
564         case USB_REQ_DFU_CLRSTATUS:
565                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
566                 f_dfu->dfu_status = DFU_STATUS_OK;
567                 /* no zlp? */
568                 value = RET_ZLP;
569                 break;
570         default:
571                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
572                 value = RET_STALL;
573                 break;
574         }
575
576         return value;
577 }
578
579 static dfu_state_fn dfu_state[] = {
580         state_app_idle,          /* DFU_STATE_appIDLE */
581         state_app_detach,        /* DFU_STATE_appDETACH */
582         state_dfu_idle,          /* DFU_STATE_dfuIDLE */
583         state_dfu_dnload_sync,   /* DFU_STATE_dfuDNLOAD_SYNC */
584         state_dfu_dnbusy,        /* DFU_STATE_dfuDNBUSY */
585         state_dfu_dnload_idle,   /* DFU_STATE_dfuDNLOAD_IDLE */
586         state_dfu_manifest_sync, /* DFU_STATE_dfuMANIFEST_SYNC */
587         state_dfu_manifest,      /* DFU_STATE_dfuMANIFEST */
588         NULL,                    /* DFU_STATE_dfuMANIFEST_WAIT_RST */
589         state_dfu_upload_idle,   /* DFU_STATE_dfuUPLOAD_IDLE */
590         state_dfu_error          /* DFU_STATE_dfuERROR */
591 };
592
593 static int
594 dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
595 {
596         struct usb_gadget *gadget = f->config->cdev->gadget;
597         struct usb_request *req = f->config->cdev->req;
598         struct f_dfu *f_dfu = f->config->cdev->req->context;
599         u16 len = le16_to_cpu(ctrl->wLength);
600         u16 w_value = le16_to_cpu(ctrl->wValue);
601         int value = 0;
602         u8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
603
604         debug("w_value: 0x%x len: 0x%x\n", w_value, len);
605         debug("req_type: 0x%x ctrl->bRequest: 0x%x f_dfu->dfu_state: 0x%x\n",
606                req_type, ctrl->bRequest, f_dfu->dfu_state);
607
608         if (req_type == USB_TYPE_STANDARD) {
609                 if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR &&
610                     (w_value >> 8) == DFU_DT_FUNC) {
611                         value = min(len, (u16) sizeof(dfu_func));
612                         memcpy(req->buf, &dfu_func, value);
613                 }
614         } else /* DFU specific request */
615                 value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req);
616
617         if (value >= 0) {
618                 req->length = value;
619                 req->zero = value < len;
620                 value = usb_ep_queue(gadget->ep0, req, 0);
621                 if (value < 0) {
622                         debug("ep_queue --> %d\n", value);
623                         req->status = 0;
624                 }
625         }
626
627         return value;
628 }
629
630 /*-------------------------------------------------------------------------*/
631
632 static int
633 dfu_prepare_strings(struct f_dfu *f_dfu, int n)
634 {
635         struct dfu_entity *de = NULL;
636         int i = 0;
637
638         f_dfu->strings = calloc(sizeof(struct usb_string), n + 1);
639         if (!f_dfu->strings)
640                 goto enomem;
641
642         for (i = 0; i < n; ++i) {
643                 de = dfu_get_entity(i);
644                 f_dfu->strings[i].s = de->name;
645         }
646
647         f_dfu->strings[i].id = 0;
648         f_dfu->strings[i].s = NULL;
649
650         return 0;
651
652 enomem:
653         while (i)
654                 f_dfu->strings[--i].s = NULL;
655
656         free(f_dfu->strings);
657
658         return -ENOMEM;
659 }
660
661 static int dfu_prepare_function(struct f_dfu *f_dfu, int n)
662 {
663         struct usb_interface_descriptor *d;
664         int i = 0;
665
666         f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 1);
667         if (!f_dfu->function)
668                 goto enomem;
669
670         for (i = 0; i < n; ++i) {
671                 d = calloc(sizeof(*d), 1);
672                 if (!d)
673                         goto enomem;
674
675                 d->bLength =            sizeof(*d);
676                 d->bDescriptorType =    USB_DT_INTERFACE;
677                 d->bAlternateSetting =  i;
678                 d->bNumEndpoints =      0;
679                 d->bInterfaceClass =    USB_CLASS_APP_SPEC;
680                 d->bInterfaceSubClass = 1;
681                 d->bInterfaceProtocol = 2;
682
683                 f_dfu->function[i] = (struct usb_descriptor_header *)d;
684         }
685         f_dfu->function[i] = NULL;
686
687         return 0;
688
689 enomem:
690         while (i) {
691                 free(f_dfu->function[--i]);
692                 f_dfu->function[i] = NULL;
693         }
694         free(f_dfu->function);
695
696         return -ENOMEM;
697 }
698
699 static int dfu_bind(struct usb_configuration *c, struct usb_function *f)
700 {
701         struct usb_composite_dev *cdev = c->cdev;
702         struct f_dfu *f_dfu = func_to_dfu(f);
703         int alt_num = dfu_get_alt_number();
704         int rv, id, i;
705
706         id = usb_interface_id(c, f);
707         if (id < 0)
708                 return id;
709         dfu_intf_runtime.bInterfaceNumber = id;
710
711         f_dfu->dfu_state = DFU_STATE_appIDLE;
712         f_dfu->dfu_status = DFU_STATUS_OK;
713
714         rv = dfu_prepare_function(f_dfu, alt_num);
715         if (rv)
716                 goto error;
717
718         rv = dfu_prepare_strings(f_dfu, alt_num);
719         if (rv)
720                 goto error;
721         for (i = 0; i < alt_num; i++) {
722                 id = usb_string_id(cdev);
723                 if (id < 0)
724                         return id;
725                 f_dfu->strings[i].id = id;
726                 ((struct usb_interface_descriptor *)f_dfu->function[i])
727                         ->iInterface = id;
728         }
729
730         to_dfu_mode(f_dfu);
731
732         stringtab_dfu.strings = f_dfu->strings;
733
734         cdev->req->context = f_dfu;
735
736 error:
737         return rv;
738 }
739
740 static void dfu_unbind(struct usb_configuration *c, struct usb_function *f)
741 {
742         struct f_dfu *f_dfu = func_to_dfu(f);
743         int alt_num = dfu_get_alt_number();
744         int i;
745
746         if (f_dfu->strings) {
747                 i = alt_num;
748                 while (i)
749                         f_dfu->strings[--i].s = NULL;
750
751                 free(f_dfu->strings);
752         }
753
754         if (f_dfu->function) {
755                 i = alt_num;
756                 while (i) {
757                         free(f_dfu->function[--i]);
758                         f_dfu->function[i] = NULL;
759                 }
760                 free(f_dfu->function);
761         }
762
763         free(f_dfu);
764 }
765
766 static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
767 {
768         struct f_dfu *f_dfu = func_to_dfu(f);
769
770         debug("%s: intf:%d alt:%d\n", __func__, intf, alt);
771
772         f_dfu->altsetting = alt;
773
774         return 0;
775 }
776
777 /* TODO: is this really what we need here? */
778 static void dfu_disable(struct usb_function *f)
779 {
780         struct f_dfu *f_dfu = func_to_dfu(f);
781         if (f_dfu->config == 0)
782                 return;
783
784         debug("%s: reset config\n", __func__);
785
786         f_dfu->config = 0;
787 }
788
789 static int dfu_bind_config(struct usb_configuration *c)
790 {
791         struct f_dfu *f_dfu;
792         int status;
793
794         f_dfu = calloc(sizeof(*f_dfu), 1);
795         if (!f_dfu)
796                 return -ENOMEM;
797         f_dfu->usb_function.name = "dfu";
798         f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
799         f_dfu->usb_function.bind = dfu_bind;
800         f_dfu->usb_function.unbind = dfu_unbind;
801         f_dfu->usb_function.set_alt = dfu_set_alt;
802         f_dfu->usb_function.disable = dfu_disable;
803         f_dfu->usb_function.strings = dfu_generic_strings;
804         f_dfu->usb_function.setup = dfu_handle;
805         f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT;
806
807         status = usb_add_function(c, &f_dfu->usb_function);
808         if (status)
809                 free(f_dfu);
810
811         return status;
812 }
813
814 int dfu_add(struct usb_configuration *c)
815 {
816         int id;
817
818         id = usb_string_id(c->cdev);
819         if (id < 0)
820                 return id;
821         strings_dfu_generic[0].id = id;
822         dfu_intf_runtime.iInterface = id;
823
824         debug("%s: cdev: 0x%p gadget:0x%p gadget->ep0: 0x%p\n", __func__,
825                c->cdev, c->cdev->gadget, c->cdev->gadget->ep0);
826
827         return dfu_bind_config(c);
828 }
829
830 DECLARE_GADGET_BIND_CALLBACK(usb_dnl_dfu, dfu_add);