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