]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/usb/gadget/f_dfu.c
mxc_ipuv3: fix memory alignment of framebuffer
[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  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29
30 #include <errno.h>
31 #include <common.h>
32 #include <malloc.h>
33
34 #include <linux/usb/ch9.h>
35 #include <linux/usb/gadget.h>
36 #include <linux/usb/composite.h>
37
38 #include <dfu.h>
39 #include "f_dfu.h"
40
41 struct f_dfu {
42         struct usb_function             usb_function;
43
44         struct usb_descriptor_header    **function;
45         struct usb_string               *strings;
46
47         /* when configured, we have one config */
48         u8                              config;
49         u8                              altsetting;
50         enum dfu_state                  dfu_state;
51         unsigned int                    dfu_status;
52
53         /* Send/received block number is handy for data integrity check */
54         int                             blk_seq_num;
55 };
56
57 typedef int (*dfu_state_fn) (struct f_dfu *,
58                              const struct usb_ctrlrequest *,
59                              struct usb_gadget *,
60                              struct usb_request *);
61
62 static inline struct f_dfu *func_to_dfu(struct usb_function *f)
63 {
64         return container_of(f, struct f_dfu, usb_function);
65 }
66
67 static const struct dfu_function_descriptor dfu_func = {
68         .bLength =              sizeof dfu_func,
69         .bDescriptorType =      DFU_DT_FUNC,
70         .bmAttributes =         DFU_BIT_WILL_DETACH |
71                                 DFU_BIT_MANIFESTATION_TOLERANT |
72                                 DFU_BIT_CAN_UPLOAD |
73                                 DFU_BIT_CAN_DNLOAD,
74         .wDetachTimeOut =       0,
75         .wTransferSize =        DFU_USB_BUFSIZ,
76         .bcdDFUVersion =        __constant_cpu_to_le16(0x0110),
77 };
78
79 static struct usb_interface_descriptor dfu_intf_runtime = {
80         .bLength =              sizeof dfu_intf_runtime,
81         .bDescriptorType =      USB_DT_INTERFACE,
82         .bNumEndpoints =        0,
83         .bInterfaceClass =      USB_CLASS_APP_SPEC,
84         .bInterfaceSubClass =   1,
85         .bInterfaceProtocol =   1,
86         /* .iInterface = DYNAMIC */
87 };
88
89 static struct usb_descriptor_header *dfu_runtime_descs[] = {
90         (struct usb_descriptor_header *) &dfu_intf_runtime,
91         NULL,
92 };
93
94 static const struct usb_qualifier_descriptor dev_qualifier = {
95         .bLength =              sizeof dev_qualifier,
96         .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
97         .bcdUSB =               __constant_cpu_to_le16(0x0200),
98         .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
99         .bNumConfigurations =   1,
100 };
101
102 static const char dfu_name[] = "Device Firmware Upgrade";
103
104 /*
105  * static strings, in UTF-8
106  *
107  * dfu_generic configuration
108  */
109 static struct usb_string strings_dfu_generic[] = {
110         [0].s = dfu_name,
111         {  }                    /* end of list */
112 };
113
114 static struct usb_gadget_strings stringtab_dfu_generic = {
115         .language       = 0x0409,       /* en-us */
116         .strings        = strings_dfu_generic,
117 };
118
119 static struct usb_gadget_strings *dfu_generic_strings[] = {
120         &stringtab_dfu_generic,
121         NULL,
122 };
123
124 /*
125  * usb_function specific
126  */
127 static struct usb_gadget_strings stringtab_dfu = {
128         .language       = 0x0409,       /* en-us */
129         /*
130          * .strings
131          *
132          * assigned during initialization,
133          * depends on number of flash entities
134          *
135          */
136 };
137
138 static struct usb_gadget_strings *dfu_strings[] = {
139         &stringtab_dfu,
140         NULL,
141 };
142
143 /*-------------------------------------------------------------------------*/
144
145 static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req)
146 {
147         struct f_dfu *f_dfu = req->context;
148
149         dfu_write(dfu_get_entity(f_dfu->altsetting), req->buf,
150                   req->length, f_dfu->blk_seq_num);
151
152         if (req->length == 0)
153                 puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
154 }
155
156 static void handle_getstatus(struct usb_request *req)
157 {
158         struct dfu_status *dstat = (struct dfu_status *)req->buf;
159         struct f_dfu *f_dfu = req->context;
160
161         switch (f_dfu->dfu_state) {
162         case DFU_STATE_dfuDNLOAD_SYNC:
163         case DFU_STATE_dfuDNBUSY:
164                 f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
165                 break;
166         case DFU_STATE_dfuMANIFEST_SYNC:
167                 break;
168         default:
169                 break;
170         }
171
172         /* send status response */
173         dstat->bStatus = f_dfu->dfu_status;
174         dstat->bwPollTimeout[0] = 0;
175         dstat->bwPollTimeout[1] = 0;
176         dstat->bwPollTimeout[2] = 0;
177         dstat->bState = f_dfu->dfu_state;
178         dstat->iString = 0;
179 }
180
181 static void handle_getstate(struct usb_request *req)
182 {
183         struct f_dfu *f_dfu = req->context;
184
185         ((u8 *)req->buf)[0] = f_dfu->dfu_state;
186         req->actual = sizeof(u8);
187 }
188
189 static inline void to_dfu_mode(struct f_dfu *f_dfu)
190 {
191         f_dfu->usb_function.strings = dfu_strings;
192         f_dfu->usb_function.hs_descriptors = f_dfu->function;
193         f_dfu->dfu_state = DFU_STATE_dfuIDLE;
194 }
195
196 static inline void to_runtime_mode(struct f_dfu *f_dfu)
197 {
198         f_dfu->usb_function.strings = NULL;
199         f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
200 }
201
202 static int handle_upload(struct usb_request *req, u16 len)
203 {
204         struct f_dfu *f_dfu = req->context;
205
206         return dfu_read(dfu_get_entity(f_dfu->altsetting), req->buf,
207                         req->length, f_dfu->blk_seq_num);
208 }
209
210 static int handle_dnload(struct usb_gadget *gadget, u16 len)
211 {
212         struct usb_composite_dev *cdev = get_gadget_data(gadget);
213         struct usb_request *req = cdev->req;
214         struct f_dfu *f_dfu = req->context;
215
216         if (len == 0)
217                 f_dfu->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
218
219         req->complete = dnload_request_complete;
220
221         return len;
222 }
223
224 /*-------------------------------------------------------------------------*/
225 /* DFU state machine  */
226 static int state_app_idle(struct f_dfu *f_dfu,
227                           const struct usb_ctrlrequest *ctrl,
228                           struct usb_gadget *gadget,
229                           struct usb_request *req)
230 {
231         int value = 0;
232
233         switch (ctrl->bRequest) {
234         case USB_REQ_DFU_GETSTATUS:
235                 handle_getstatus(req);
236                 value = RET_STAT_LEN;
237                 break;
238         case USB_REQ_DFU_GETSTATE:
239                 handle_getstate(req);
240                 break;
241         case USB_REQ_DFU_DETACH:
242                 f_dfu->dfu_state = DFU_STATE_appDETACH;
243                 to_dfu_mode(f_dfu);
244                 value = RET_ZLP;
245                 break;
246         default:
247                 value = RET_STALL;
248                 break;
249         }
250
251         return value;
252 }
253
254 static int state_app_detach(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         default:
270                 f_dfu->dfu_state = DFU_STATE_appIDLE;
271                 value = RET_STALL;
272                 break;
273         }
274
275         return value;
276 }
277
278 static int state_dfu_idle(struct f_dfu *f_dfu,
279                           const struct usb_ctrlrequest *ctrl,
280                           struct usb_gadget *gadget,
281                           struct usb_request *req)
282 {
283         u16 w_value = le16_to_cpu(ctrl->wValue);
284         u16 len = le16_to_cpu(ctrl->wLength);
285         int value = 0;
286
287         switch (ctrl->bRequest) {
288         case USB_REQ_DFU_DNLOAD:
289                 if (len == 0) {
290                         f_dfu->dfu_state = DFU_STATE_dfuERROR;
291                         value = RET_STALL;
292                         break;
293                 }
294                 f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
295                 f_dfu->blk_seq_num = w_value;
296                 value = handle_dnload(gadget, len);
297                 break;
298         case USB_REQ_DFU_UPLOAD:
299                 f_dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
300                 f_dfu->blk_seq_num = 0;
301                 value = handle_upload(req, len);
302                 break;
303         case USB_REQ_DFU_ABORT:
304                 /* no zlp? */
305                 value = RET_ZLP;
306                 break;
307         case USB_REQ_DFU_GETSTATUS:
308                 handle_getstatus(req);
309                 value = RET_STAT_LEN;
310                 break;
311         case USB_REQ_DFU_GETSTATE:
312                 handle_getstate(req);
313                 break;
314         case USB_REQ_DFU_DETACH:
315                 /*
316                  * Proprietary extension: 'detach' from idle mode and
317                  * get back to runtime mode in case of USB Reset.  As
318                  * much as I dislike this, we just can't use every USB
319                  * bus reset to switch back to runtime mode, since at
320                  * least the Linux USB stack likes to send a number of
321                  * resets in a row :(
322                  */
323                 f_dfu->dfu_state =
324                         DFU_STATE_dfuMANIFEST_WAIT_RST;
325                 to_runtime_mode(f_dfu);
326                 f_dfu->dfu_state = DFU_STATE_appIDLE;
327                 break;
328         default:
329                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
330                 value = RET_STALL;
331                 break;
332         }
333
334         return value;
335 }
336
337 static int state_dfu_dnload_sync(struct f_dfu *f_dfu,
338                                  const struct usb_ctrlrequest *ctrl,
339                                  struct usb_gadget *gadget,
340                                  struct usb_request *req)
341 {
342         int value = 0;
343
344         switch (ctrl->bRequest) {
345         case USB_REQ_DFU_GETSTATUS:
346                 handle_getstatus(req);
347                 value = RET_STAT_LEN;
348                 break;
349         case USB_REQ_DFU_GETSTATE:
350                 handle_getstate(req);
351                 break;
352         default:
353                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
354                 value = RET_STALL;
355                 break;
356         }
357
358         return value;
359 }
360
361 static int state_dfu_dnbusy(struct f_dfu *f_dfu,
362                             const struct usb_ctrlrequest *ctrl,
363                             struct usb_gadget *gadget,
364                             struct usb_request *req)
365 {
366         int value = 0;
367
368         switch (ctrl->bRequest) {
369         case USB_REQ_DFU_GETSTATUS:
370                 handle_getstatus(req);
371                 value = RET_STAT_LEN;
372                 break;
373         default:
374                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
375                 value = RET_STALL;
376                 break;
377         }
378
379         return value;
380 }
381
382 static int state_dfu_dnload_idle(struct f_dfu *f_dfu,
383                                  const struct usb_ctrlrequest *ctrl,
384                                  struct usb_gadget *gadget,
385                                  struct usb_request *req)
386 {
387         u16 w_value = le16_to_cpu(ctrl->wValue);
388         u16 len = le16_to_cpu(ctrl->wLength);
389         int value = 0;
390
391         switch (ctrl->bRequest) {
392         case USB_REQ_DFU_DNLOAD:
393                 f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
394                 f_dfu->blk_seq_num = w_value;
395                 value = handle_dnload(gadget, len);
396                 break;
397         case USB_REQ_DFU_ABORT:
398                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
399                 value = RET_ZLP;
400                 break;
401         case USB_REQ_DFU_GETSTATUS:
402                 handle_getstatus(req);
403                 value = RET_STAT_LEN;
404                 break;
405         case USB_REQ_DFU_GETSTATE:
406                 handle_getstate(req);
407                 break;
408         default:
409                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
410                 value = RET_STALL;
411                 break;
412         }
413
414         return value;
415 }
416
417 static int state_dfu_manifest_sync(struct f_dfu *f_dfu,
418                                    const struct usb_ctrlrequest *ctrl,
419                                    struct usb_gadget *gadget,
420                                    struct usb_request *req)
421 {
422         int value = 0;
423
424         switch (ctrl->bRequest) {
425         case USB_REQ_DFU_GETSTATUS:
426                 /* We're MainfestationTolerant */
427                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
428                 handle_getstatus(req);
429                 f_dfu->blk_seq_num = 0;
430                 value = RET_STAT_LEN;
431                 break;
432         case USB_REQ_DFU_GETSTATE:
433                 handle_getstate(req);
434                 break;
435         default:
436                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
437                 value = RET_STALL;
438                 break;
439         }
440
441         return value;
442 }
443
444 static int state_dfu_upload_idle(struct f_dfu *f_dfu,
445                                  const struct usb_ctrlrequest *ctrl,
446                                  struct usb_gadget *gadget,
447                                  struct usb_request *req)
448 {
449         u16 w_value = le16_to_cpu(ctrl->wValue);
450         u16 len = le16_to_cpu(ctrl->wLength);
451         int value = 0;
452
453         switch (ctrl->bRequest) {
454         case USB_REQ_DFU_UPLOAD:
455                 /* state transition if less data then requested */
456                 f_dfu->blk_seq_num = w_value;
457                 value = handle_upload(req, len);
458                 if (value >= 0 && value < len)
459                         f_dfu->dfu_state = DFU_STATE_dfuIDLE;
460                 break;
461         case USB_REQ_DFU_ABORT:
462                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
463                 /* no zlp? */
464                 value = RET_ZLP;
465                 break;
466         case USB_REQ_DFU_GETSTATUS:
467                 handle_getstatus(req);
468                 value = RET_STAT_LEN;
469                 break;
470         case USB_REQ_DFU_GETSTATE:
471                 handle_getstate(req);
472                 break;
473         default:
474                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
475                 value = RET_STALL;
476                 break;
477         }
478
479         return value;
480 }
481
482 static int state_dfu_error(struct f_dfu *f_dfu,
483                                  const struct usb_ctrlrequest *ctrl,
484                                  struct usb_gadget *gadget,
485                                  struct usb_request *req)
486 {
487         int value = 0;
488
489         switch (ctrl->bRequest) {
490         case USB_REQ_DFU_GETSTATUS:
491                 handle_getstatus(req);
492                 value = RET_STAT_LEN;
493                 break;
494         case USB_REQ_DFU_GETSTATE:
495                 handle_getstate(req);
496                 break;
497         case USB_REQ_DFU_CLRSTATUS:
498                 f_dfu->dfu_state = DFU_STATE_dfuIDLE;
499                 f_dfu->dfu_status = DFU_STATUS_OK;
500                 /* no zlp? */
501                 value = RET_ZLP;
502                 break;
503         default:
504                 f_dfu->dfu_state = DFU_STATE_dfuERROR;
505                 value = RET_STALL;
506                 break;
507         }
508
509         return value;
510 }
511
512 static dfu_state_fn dfu_state[] = {
513         state_app_idle,          /* DFU_STATE_appIDLE */
514         state_app_detach,        /* DFU_STATE_appDETACH */
515         state_dfu_idle,          /* DFU_STATE_dfuIDLE */
516         state_dfu_dnload_sync,   /* DFU_STATE_dfuDNLOAD_SYNC */
517         state_dfu_dnbusy,        /* DFU_STATE_dfuDNBUSY */
518         state_dfu_dnload_idle,   /* DFU_STATE_dfuDNLOAD_IDLE */
519         state_dfu_manifest_sync, /* DFU_STATE_dfuMANIFEST_SYNC */
520         NULL,                    /* DFU_STATE_dfuMANIFEST */
521         NULL,                    /* DFU_STATE_dfuMANIFEST_WAIT_RST */
522         state_dfu_upload_idle,   /* DFU_STATE_dfuUPLOAD_IDLE */
523         state_dfu_error          /* DFU_STATE_dfuERROR */
524 };
525
526 static int
527 dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
528 {
529         struct usb_gadget *gadget = f->config->cdev->gadget;
530         struct usb_request *req = f->config->cdev->req;
531         struct f_dfu *f_dfu = f->config->cdev->req->context;
532         u16 len = le16_to_cpu(ctrl->wLength);
533         u16 w_value = le16_to_cpu(ctrl->wValue);
534         int value = 0;
535         u8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
536
537         debug("w_value: 0x%x len: 0x%x\n", w_value, len);
538         debug("req_type: 0x%x ctrl->bRequest: 0x%x f_dfu->dfu_state: 0x%x\n",
539                req_type, ctrl->bRequest, f_dfu->dfu_state);
540
541         if (req_type == USB_TYPE_STANDARD) {
542                 if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR &&
543                     (w_value >> 8) == DFU_DT_FUNC) {
544                         value = min(len, (u16) sizeof(dfu_func));
545                         memcpy(req->buf, &dfu_func, value);
546                 }
547         } else /* DFU specific request */
548                 value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req);
549
550         if (value >= 0) {
551                 req->length = value;
552                 req->zero = value < len;
553                 value = usb_ep_queue(gadget->ep0, req, 0);
554                 if (value < 0) {
555                         debug("ep_queue --> %d\n", value);
556                         req->status = 0;
557                 }
558         }
559
560         return value;
561 }
562
563 /*-------------------------------------------------------------------------*/
564
565 static int
566 dfu_prepare_strings(struct f_dfu *f_dfu, int n)
567 {
568         struct dfu_entity *de = NULL;
569         int i = 0;
570
571         f_dfu->strings = calloc(sizeof(struct usb_string), n + 1);
572         if (!f_dfu->strings)
573                 goto enomem;
574
575         for (i = 0; i < n; ++i) {
576                 de = dfu_get_entity(i);
577                 f_dfu->strings[i].s = de->name;
578         }
579
580         f_dfu->strings[i].id = 0;
581         f_dfu->strings[i].s = NULL;
582
583         return 0;
584
585 enomem:
586         while (i)
587                 f_dfu->strings[--i].s = NULL;
588
589         free(f_dfu->strings);
590
591         return -ENOMEM;
592 }
593
594 static int dfu_prepare_function(struct f_dfu *f_dfu, int n)
595 {
596         struct usb_interface_descriptor *d;
597         int i = 0;
598
599         f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 1);
600         if (!f_dfu->function)
601                 goto enomem;
602
603         for (i = 0; i < n; ++i) {
604                 d = calloc(sizeof(*d), 1);
605                 if (!d)
606                         goto enomem;
607
608                 d->bLength =            sizeof(*d);
609                 d->bDescriptorType =    USB_DT_INTERFACE;
610                 d->bAlternateSetting =  i;
611                 d->bNumEndpoints =      0;
612                 d->bInterfaceClass =    USB_CLASS_APP_SPEC;
613                 d->bInterfaceSubClass = 1;
614                 d->bInterfaceProtocol = 2;
615
616                 f_dfu->function[i] = (struct usb_descriptor_header *)d;
617         }
618         f_dfu->function[i] = NULL;
619
620         return 0;
621
622 enomem:
623         while (i) {
624                 free(f_dfu->function[--i]);
625                 f_dfu->function[i] = NULL;
626         }
627         free(f_dfu->function);
628
629         return -ENOMEM;
630 }
631
632 static int dfu_bind(struct usb_configuration *c, struct usb_function *f)
633 {
634         struct usb_composite_dev *cdev = c->cdev;
635         struct f_dfu *f_dfu = func_to_dfu(f);
636         int alt_num = dfu_get_alt_number();
637         int rv, id, i;
638
639         id = usb_interface_id(c, f);
640         if (id < 0)
641                 return id;
642         dfu_intf_runtime.bInterfaceNumber = id;
643
644         f_dfu->dfu_state = DFU_STATE_appIDLE;
645         f_dfu->dfu_status = DFU_STATUS_OK;
646
647         rv = dfu_prepare_function(f_dfu, alt_num);
648         if (rv)
649                 goto error;
650
651         rv = dfu_prepare_strings(f_dfu, alt_num);
652         if (rv)
653                 goto error;
654         for (i = 0; i < alt_num; i++) {
655                 id = usb_string_id(cdev);
656                 if (id < 0)
657                         return id;
658                 f_dfu->strings[i].id = id;
659                 ((struct usb_interface_descriptor *)f_dfu->function[i])
660                         ->iInterface = id;
661         }
662
663         to_dfu_mode(f_dfu);
664
665         stringtab_dfu.strings = f_dfu->strings;
666
667         cdev->req->context = f_dfu;
668
669 error:
670         return rv;
671 }
672
673 static void dfu_unbind(struct usb_configuration *c, struct usb_function *f)
674 {
675         struct f_dfu *f_dfu = func_to_dfu(f);
676         int alt_num = dfu_get_alt_number();
677         int i;
678
679         if (f_dfu->strings) {
680                 i = alt_num;
681                 while (i)
682                         f_dfu->strings[--i].s = NULL;
683
684                 free(f_dfu->strings);
685         }
686
687         if (f_dfu->function) {
688                 i = alt_num;
689                 while (i) {
690                         free(f_dfu->function[--i]);
691                         f_dfu->function[i] = NULL;
692                 }
693                 free(f_dfu->function);
694         }
695
696         free(f_dfu);
697 }
698
699 static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
700 {
701         struct f_dfu *f_dfu = func_to_dfu(f);
702
703         debug("%s: intf:%d alt:%d\n", __func__, intf, alt);
704
705         f_dfu->altsetting = alt;
706
707         return 0;
708 }
709
710 /* TODO: is this really what we need here? */
711 static void dfu_disable(struct usb_function *f)
712 {
713         struct f_dfu *f_dfu = func_to_dfu(f);
714         if (f_dfu->config == 0)
715                 return;
716
717         debug("%s: reset config\n", __func__);
718
719         f_dfu->config = 0;
720 }
721
722 static int dfu_bind_config(struct usb_configuration *c)
723 {
724         struct f_dfu *f_dfu;
725         int status;
726
727         f_dfu = calloc(sizeof(*f_dfu), 1);
728         if (!f_dfu)
729                 return -ENOMEM;
730         f_dfu->usb_function.name = "dfu";
731         f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
732         f_dfu->usb_function.bind = dfu_bind;
733         f_dfu->usb_function.unbind = dfu_unbind;
734         f_dfu->usb_function.set_alt = dfu_set_alt;
735         f_dfu->usb_function.disable = dfu_disable;
736         f_dfu->usb_function.strings = dfu_generic_strings,
737         f_dfu->usb_function.setup = dfu_handle,
738
739         status = usb_add_function(c, &f_dfu->usb_function);
740         if (status)
741                 free(f_dfu);
742
743         return status;
744 }
745
746 int dfu_add(struct usb_configuration *c)
747 {
748         int id;
749
750         id = usb_string_id(c->cdev);
751         if (id < 0)
752                 return id;
753         strings_dfu_generic[0].id = id;
754         dfu_intf_runtime.iInterface = id;
755
756         debug("%s: cdev: 0x%p gadget:0x%p gadget->ep0: 0x%p\n", __func__,
757                c->cdev, c->cdev->gadget, c->cdev->gadget->ep0);
758
759         return dfu_bind_config(c);
760 }