uboot/drivers/usb/gadget/f_dfu.c
<<
>>
Prefs
   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
  41struct 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
  57typedef int (*dfu_state_fn) (struct f_dfu *,
  58                             const struct usb_ctrlrequest *,
  59                             struct usb_gadget *,
  60                             struct usb_request *);
  61
  62static inline struct f_dfu *func_to_dfu(struct usb_function *f)
  63{
  64        return container_of(f, struct f_dfu, usb_function);
  65}
  66
  67static 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
  79static 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
  89static struct usb_descriptor_header *dfu_runtime_descs[] = {
  90        (struct usb_descriptor_header *) &dfu_intf_runtime,
  91        NULL,
  92};
  93
  94static 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
 102static const char dfu_name[] = "Device Firmware Upgrade";
 103
 104/*
 105 * static strings, in UTF-8
 106 *
 107 * dfu_generic configuration
 108 */
 109static struct usb_string strings_dfu_generic[] = {
 110        [0].s = dfu_name,
 111        {  }                    /* end of list */
 112};
 113
 114static struct usb_gadget_strings stringtab_dfu_generic = {
 115        .language       = 0x0409,       /* en-us */
 116        .strings        = strings_dfu_generic,
 117};
 118
 119static struct usb_gadget_strings *dfu_generic_strings[] = {
 120        &stringtab_dfu_generic,
 121        NULL,
 122};
 123
 124/*
 125 * usb_function specific
 126 */
 127static 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
 138static struct usb_gadget_strings *dfu_strings[] = {
 139        &stringtab_dfu,
 140        NULL,
 141};
 142
 143/*-------------------------------------------------------------------------*/
 144
 145static 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
 156static 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
 181static 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
 189static 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
 196static 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
 202static 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
 210static 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  */
 226static 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
 254static 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
 278static 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
 337static 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
 361static 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
 382static 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
 417static 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
 444static 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
 482static 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
 512static 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
 526static int
 527dfu_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
 565static int
 566dfu_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
 585enomem:
 586        while (i)
 587                f_dfu->strings[--i].s = NULL;
 588
 589        free(f_dfu->strings);
 590
 591        return -ENOMEM;
 592}
 593
 594static 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
 622enomem:
 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
 632static 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
 669error:
 670        return rv;
 671}
 672
 673static 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
 699static 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? */
 711static 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
 722static 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
 746int 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