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 } 761