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