uboot/drivers/usb/gadget/f_thor.c
<<
>>
Prefs
   1/*
   2 * f_thor.c -- USB TIZEN THOR Downloader gadget function
   3 *
   4 * Copyright (C) 2013 Samsung Electronics
   5 * Lukasz Majewski <l.majewski@samsung.com>
   6 *
   7 * Based on code from:
   8 * git://review.tizen.org/kernel/u-boot
   9 *
  10 * Developed by:
  11 * Copyright (C) 2009 Samsung Electronics
  12 * Minkyu Kang <mk7.kang@samsung.com>
  13 * Sanghee Kim <sh0130.kim@samsung.com>
  14 *
  15 * SPDX-License-Identifier:     GPL-2.0+
  16 */
  17
  18#include <errno.h>
  19#include <common.h>
  20#include <console.h>
  21#include <malloc.h>
  22#include <memalign.h>
  23#include <version.h>
  24#include <linux/usb/ch9.h>
  25#include <linux/usb/gadget.h>
  26#include <linux/usb/composite.h>
  27#include <linux/usb/cdc.h>
  28#include <g_dnl.h>
  29#include <dfu.h>
  30
  31#include "f_thor.h"
  32
  33static void thor_tx_data(unsigned char *data, int len);
  34static void thor_set_dma(void *addr, int len);
  35static int thor_rx_data(void);
  36
  37static struct f_thor *thor_func;
  38static inline struct f_thor *func_to_thor(struct usb_function *f)
  39{
  40        return container_of(f, struct f_thor, usb_function);
  41}
  42
  43DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_tx_data_buf,
  44                          sizeof(struct rsp_box));
  45DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_rx_data_buf,
  46                          sizeof(struct rqt_box));
  47
  48/* ********************************************************** */
  49/*         THOR protocol - transmission handling              */
  50/* ********************************************************** */
  51DEFINE_CACHE_ALIGN_BUFFER(char, f_name, F_NAME_BUF_SIZE);
  52static unsigned long long int thor_file_size;
  53static int alt_setting_num;
  54
  55static void send_rsp(const struct rsp_box *rsp)
  56{
  57        memcpy(thor_tx_data_buf, rsp, sizeof(struct rsp_box));
  58        thor_tx_data(thor_tx_data_buf, sizeof(struct rsp_box));
  59
  60        debug("-RSP: %d, %d\n", rsp->rsp, rsp->rsp_data);
  61}
  62
  63static void send_data_rsp(s32 ack, s32 count)
  64{
  65        ALLOC_CACHE_ALIGN_BUFFER(struct data_rsp_box, rsp,
  66                                 sizeof(struct data_rsp_box));
  67
  68        rsp->ack = ack;
  69        rsp->count = count;
  70
  71        memcpy(thor_tx_data_buf, rsp, sizeof(struct data_rsp_box));
  72        thor_tx_data(thor_tx_data_buf, sizeof(struct data_rsp_box));
  73
  74        debug("-DATA RSP: %d, %d\n", ack, count);
  75}
  76
  77static int process_rqt_info(const struct rqt_box *rqt)
  78{
  79        ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
  80        memset(rsp, 0, sizeof(struct rsp_box));
  81
  82        rsp->rsp = rqt->rqt;
  83        rsp->rsp_data = rqt->rqt_data;
  84
  85        switch (rqt->rqt_data) {
  86        case RQT_INFO_VER_PROTOCOL:
  87                rsp->int_data[0] = VER_PROTOCOL_MAJOR;
  88                rsp->int_data[1] = VER_PROTOCOL_MINOR;
  89                break;
  90        case RQT_INIT_VER_HW:
  91                snprintf(rsp->str_data[0], sizeof(rsp->str_data[0]),
  92                         "%x", checkboard());
  93                break;
  94        case RQT_INIT_VER_BOOT:
  95                sprintf(rsp->str_data[0], "%s", U_BOOT_VERSION);
  96                break;
  97        case RQT_INIT_VER_KERNEL:
  98                sprintf(rsp->str_data[0], "%s", "k unknown");
  99                break;
 100        case RQT_INIT_VER_PLATFORM:
 101                sprintf(rsp->str_data[0], "%s", "p unknown");
 102                break;
 103        case RQT_INIT_VER_CSC:
 104                sprintf(rsp->str_data[0], "%s", "c unknown");
 105                break;
 106        default:
 107                return -EINVAL;
 108        }
 109
 110        send_rsp(rsp);
 111        return true;
 112}
 113
 114static int process_rqt_cmd(const struct rqt_box *rqt)
 115{
 116        ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
 117        memset(rsp, 0, sizeof(struct rsp_box));
 118
 119        rsp->rsp = rqt->rqt;
 120        rsp->rsp_data = rqt->rqt_data;
 121
 122        switch (rqt->rqt_data) {
 123        case RQT_CMD_REBOOT:
 124                debug("TARGET RESET\n");
 125                send_rsp(rsp);
 126                g_dnl_unregister();
 127                dfu_free_entities();
 128#ifdef CONFIG_THOR_RESET_OFF
 129                return RESET_DONE;
 130#endif
 131                run_command("reset", 0);
 132                break;
 133        case RQT_CMD_POWEROFF:
 134        case RQT_CMD_EFSCLEAR:
 135                send_rsp(rsp);
 136        default:
 137                printf("Command not supported -> cmd: %d\n", rqt->rqt_data);
 138                return -EINVAL;
 139        }
 140
 141        return true;
 142}
 143
 144static long long int download_head(unsigned long long total,
 145                                   unsigned int packet_size,
 146                                   long long int *left,
 147                                   int *cnt)
 148{
 149        long long int rcv_cnt = 0, left_to_rcv, ret_rcv;
 150        struct dfu_entity *dfu_entity = dfu_get_entity(alt_setting_num);
 151        void *transfer_buffer = dfu_get_buf(dfu_entity);
 152        void *buf = transfer_buffer;
 153        int usb_pkt_cnt = 0, ret;
 154
 155        /*
 156         * Files smaller than THOR_STORE_UNIT_SIZE (now 32 MiB) are stored on
 157         * the medium.
 158         * The packet response is sent on the purpose after successful data
 159         * chunk write. There is a room for improvement when asynchronous write
 160         * is performed.
 161         */
 162        while (total - rcv_cnt >= packet_size) {
 163                thor_set_dma(buf, packet_size);
 164                buf += packet_size;
 165                ret_rcv = thor_rx_data();
 166                if (ret_rcv < 0)
 167                        return ret_rcv;
 168                rcv_cnt += ret_rcv;
 169                debug("%d: RCV data count: %llu cnt: %d\n", usb_pkt_cnt,
 170                      rcv_cnt, *cnt);
 171
 172                if ((rcv_cnt % THOR_STORE_UNIT_SIZE) == 0) {
 173                        ret = dfu_write(dfu_get_entity(alt_setting_num),
 174                                        transfer_buffer, THOR_STORE_UNIT_SIZE,
 175                                        (*cnt)++);
 176                        if (ret) {
 177                                error("DFU write failed [%d] cnt: %d",
 178                                      ret, *cnt);
 179                                return ret;
 180                        }
 181                        buf = transfer_buffer;
 182                }
 183                send_data_rsp(0, ++usb_pkt_cnt);
 184        }
 185
 186        /* Calculate the amount of data to arrive from PC (in bytes) */
 187        left_to_rcv = total - rcv_cnt;
 188
 189        /*
 190         * Calculate number of data already received. but not yet stored
 191         * on the medium (they are smaller than THOR_STORE_UNIT_SIZE)
 192         */
 193        *left = left_to_rcv + buf - transfer_buffer;
 194        debug("%s: left: %llu left_to_rcv: %llu buf: 0x%p\n", __func__,
 195              *left, left_to_rcv, buf);
 196
 197        if (left_to_rcv) {
 198                thor_set_dma(buf, packet_size);
 199                ret_rcv = thor_rx_data();
 200                if (ret_rcv < 0)
 201                        return ret_rcv;
 202                rcv_cnt += ret_rcv;
 203                send_data_rsp(0, ++usb_pkt_cnt);
 204        }
 205
 206        debug("%s: %llu total: %llu cnt: %d\n", __func__, rcv_cnt, total, *cnt);
 207
 208        return rcv_cnt;
 209}
 210
 211static int download_tail(long long int left, int cnt)
 212{
 213        struct dfu_entity *dfu_entity;
 214        void *transfer_buffer;
 215        int ret;
 216
 217        debug("%s: left: %llu cnt: %d\n", __func__, left, cnt);
 218
 219        dfu_entity = dfu_get_entity(alt_setting_num);
 220        if (!dfu_entity) {
 221                error("Alt setting: %d entity not found!\n", alt_setting_num);
 222                return -ENOENT;
 223        }
 224
 225        transfer_buffer = dfu_get_buf(dfu_entity);
 226        if (!transfer_buffer) {
 227                error("Transfer buffer not allocated!");
 228                return -ENXIO;
 229        }
 230
 231        if (left) {
 232                ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++);
 233                if (ret) {
 234                        error("DFU write failed [%d]: left: %llu", ret, left);
 235                        return ret;
 236                }
 237        }
 238
 239        /*
 240         * To store last "packet" or write file from buffer to filesystem
 241         * DFU storage backend requires dfu_flush
 242         *
 243         * This also frees memory malloc'ed by dfu_get_buf(), so no explicit
 244         * need fo call dfu_free_buf() is needed.
 245         */
 246        ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt);
 247        if (ret)
 248                error("DFU flush failed!");
 249
 250        return ret;
 251}
 252
 253static long long int process_rqt_download(const struct rqt_box *rqt)
 254{
 255        ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
 256        static long long int left, ret_head;
 257        int file_type, ret = 0;
 258        static int cnt;
 259
 260        memset(rsp, 0, sizeof(struct rsp_box));
 261        rsp->rsp = rqt->rqt;
 262        rsp->rsp_data = rqt->rqt_data;
 263
 264        switch (rqt->rqt_data) {
 265        case RQT_DL_INIT:
 266                thor_file_size = rqt->int_data[0];
 267                debug("INIT: total %d bytes\n", rqt->int_data[0]);
 268                break;
 269        case RQT_DL_FILE_INFO:
 270                file_type = rqt->int_data[0];
 271                if (file_type == FILE_TYPE_PIT) {
 272                        puts("PIT table file - not supported\n");
 273                        rsp->ack = -ENOTSUPP;
 274                        ret = rsp->ack;
 275                        break;
 276                }
 277
 278                thor_file_size = rqt->int_data[1];
 279                memcpy(f_name, rqt->str_data[0], F_NAME_BUF_SIZE);
 280
 281                debug("INFO: name(%s, %d), size(%llu), type(%d)\n",
 282                      f_name, 0, thor_file_size, file_type);
 283
 284                rsp->int_data[0] = THOR_PACKET_SIZE;
 285
 286                alt_setting_num = dfu_get_alt(f_name);
 287                if (alt_setting_num < 0) {
 288                        error("Alt setting [%d] to write not found!",
 289                              alt_setting_num);
 290                        rsp->ack = -ENODEV;
 291                        ret = rsp->ack;
 292                }
 293                break;
 294        case RQT_DL_FILE_START:
 295                send_rsp(rsp);
 296                ret_head = download_head(thor_file_size, THOR_PACKET_SIZE,
 297                                         &left, &cnt);
 298                if (ret_head < 0) {
 299                        left = 0;
 300                        cnt = 0;
 301                }
 302                return ret_head;
 303        case RQT_DL_FILE_END:
 304                debug("DL FILE_END\n");
 305                rsp->ack = download_tail(left, cnt);
 306                ret = rsp->ack;
 307                left = 0;
 308                cnt = 0;
 309                break;
 310        case RQT_DL_EXIT:
 311                debug("DL EXIT\n");
 312                break;
 313        default:
 314                error("Operation not supported: %d", rqt->rqt_data);
 315                ret = -ENOTSUPP;
 316        }
 317
 318        send_rsp(rsp);
 319        return ret;
 320}
 321
 322static int process_data(void)
 323{
 324        ALLOC_CACHE_ALIGN_BUFFER(struct rqt_box, rqt, sizeof(struct rqt_box));
 325        int ret = -EINVAL;
 326
 327        memcpy(rqt, thor_rx_data_buf, sizeof(struct rqt_box));
 328
 329        debug("+RQT: %d, %d\n", rqt->rqt, rqt->rqt_data);
 330
 331        switch (rqt->rqt) {
 332        case RQT_INFO:
 333                ret = process_rqt_info(rqt);
 334                break;
 335        case RQT_CMD:
 336                ret = process_rqt_cmd(rqt);
 337                break;
 338        case RQT_DL:
 339                ret = (int) process_rqt_download(rqt);
 340                break;
 341        case RQT_UL:
 342                puts("RQT: UPLOAD not supported!\n");
 343                break;
 344        default:
 345                error("unknown request (%d)", rqt->rqt);
 346        }
 347
 348        return ret;
 349}
 350
 351/* ********************************************************** */
 352/*         THOR USB Function                                  */
 353/* ********************************************************** */
 354
 355static inline struct usb_endpoint_descriptor *
 356ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
 357        struct usb_endpoint_descriptor *fs)
 358{
 359        if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 360                return hs;
 361        return fs;
 362}
 363
 364static struct usb_interface_descriptor thor_downloader_intf_data = {
 365        .bLength =              sizeof(thor_downloader_intf_data),
 366        .bDescriptorType =      USB_DT_INTERFACE,
 367
 368        .bNumEndpoints =        2,
 369        .bInterfaceClass =      USB_CLASS_CDC_DATA,
 370};
 371
 372static struct usb_endpoint_descriptor fs_in_desc = {
 373        .bLength =              USB_DT_ENDPOINT_SIZE,
 374        .bDescriptorType =      USB_DT_ENDPOINT,
 375
 376        .bEndpointAddress =     USB_DIR_IN,
 377        .bmAttributes = USB_ENDPOINT_XFER_BULK,
 378};
 379
 380static struct usb_endpoint_descriptor fs_out_desc = {
 381        .bLength =              USB_DT_ENDPOINT_SIZE,
 382        .bDescriptorType =      USB_DT_ENDPOINT,
 383
 384        .bEndpointAddress =     USB_DIR_OUT,
 385        .bmAttributes = USB_ENDPOINT_XFER_BULK,
 386};
 387
 388/* CDC configuration */
 389static struct usb_interface_descriptor thor_downloader_intf_int = {
 390        .bLength =              sizeof(thor_downloader_intf_int),
 391        .bDescriptorType =      USB_DT_INTERFACE,
 392
 393        .bNumEndpoints =        1,
 394        .bInterfaceClass =      USB_CLASS_COMM,
 395         /* 0x02 Abstract Line Control Model */
 396        .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
 397        /* 0x01 Common AT commands */
 398        .bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
 399};
 400
 401static struct usb_cdc_header_desc thor_downloader_cdc_header = {
 402        .bLength         =    sizeof(thor_downloader_cdc_header),
 403        .bDescriptorType =    0x24, /* CS_INTERFACE */
 404        .bDescriptorSubType = 0x00,
 405        .bcdCDC =             0x0110,
 406};
 407
 408static struct usb_cdc_call_mgmt_descriptor thor_downloader_cdc_call = {
 409        .bLength         =    sizeof(thor_downloader_cdc_call),
 410        .bDescriptorType =    0x24, /* CS_INTERFACE */
 411        .bDescriptorSubType = 0x01,
 412        .bmCapabilities =     0x00,
 413        .bDataInterface =     0x01,
 414};
 415
 416static struct usb_cdc_acm_descriptor thor_downloader_cdc_abstract = {
 417        .bLength         =    sizeof(thor_downloader_cdc_abstract),
 418        .bDescriptorType =    0x24, /* CS_INTERFACE */
 419        .bDescriptorSubType = 0x02,
 420        .bmCapabilities =     0x00,
 421};
 422
 423static struct usb_cdc_union_desc thor_downloader_cdc_union = {
 424        .bLength         =     sizeof(thor_downloader_cdc_union),
 425        .bDescriptorType =     0x24, /* CS_INTERFACE */
 426        .bDescriptorSubType =  USB_CDC_UNION_TYPE,
 427};
 428
 429static struct usb_endpoint_descriptor fs_int_desc = {
 430        .bLength = USB_DT_ENDPOINT_SIZE,
 431        .bDescriptorType = USB_DT_ENDPOINT,
 432
 433        .bEndpointAddress = 3 | USB_DIR_IN,
 434        .bmAttributes = USB_ENDPOINT_XFER_INT,
 435        .wMaxPacketSize = __constant_cpu_to_le16(16),
 436
 437        .bInterval = 0x9,
 438};
 439
 440static struct usb_interface_assoc_descriptor
 441thor_iad_descriptor = {
 442        .bLength =              sizeof(thor_iad_descriptor),
 443        .bDescriptorType =      USB_DT_INTERFACE_ASSOCIATION,
 444
 445        .bFirstInterface =      0,
 446        .bInterfaceCount =      2,      /* control + data */
 447        .bFunctionClass =       USB_CLASS_COMM,
 448        .bFunctionSubClass =    USB_CDC_SUBCLASS_ACM,
 449        .bFunctionProtocol =    USB_CDC_PROTO_NONE,
 450};
 451
 452static struct usb_endpoint_descriptor hs_in_desc = {
 453        .bLength =              USB_DT_ENDPOINT_SIZE,
 454        .bDescriptorType =      USB_DT_ENDPOINT,
 455
 456        .bmAttributes = USB_ENDPOINT_XFER_BULK,
 457        .wMaxPacketSize =       __constant_cpu_to_le16(512),
 458};
 459
 460static struct usb_endpoint_descriptor hs_out_desc = {
 461        .bLength =              USB_DT_ENDPOINT_SIZE,
 462        .bDescriptorType =      USB_DT_ENDPOINT,
 463
 464        .bmAttributes = USB_ENDPOINT_XFER_BULK,
 465        .wMaxPacketSize =       __constant_cpu_to_le16(512),
 466};
 467
 468static struct usb_endpoint_descriptor hs_int_desc = {
 469        .bLength = USB_DT_ENDPOINT_SIZE,
 470        .bDescriptorType = USB_DT_ENDPOINT,
 471
 472        .bmAttributes = USB_ENDPOINT_XFER_INT,
 473        .wMaxPacketSize = __constant_cpu_to_le16(16),
 474
 475        .bInterval = 0x9,
 476};
 477
 478/*
 479 * This attribute vendor descriptor is necessary for correct operation with
 480 * Windows version of THOR download program
 481 *
 482 * It prevents windows driver from sending zero lenght packet (ZLP) after
 483 * each THOR_PACKET_SIZE. This assures consistent behaviour with libusb
 484 */
 485static struct usb_cdc_attribute_vendor_descriptor thor_downloader_cdc_av = {
 486        .bLength =              sizeof(thor_downloader_cdc_av),
 487        .bDescriptorType =      0x24,
 488        .bDescriptorSubType =   0x80,
 489        .DAUType =              0x0002,
 490        .DAULength =            0x0001,
 491        .DAUValue =             0x00,
 492};
 493
 494static const struct usb_descriptor_header *hs_thor_downloader_function[] = {
 495        (struct usb_descriptor_header *)&thor_iad_descriptor,
 496
 497        (struct usb_descriptor_header *)&thor_downloader_intf_int,
 498        (struct usb_descriptor_header *)&thor_downloader_cdc_header,
 499        (struct usb_descriptor_header *)&thor_downloader_cdc_call,
 500        (struct usb_descriptor_header *)&thor_downloader_cdc_abstract,
 501        (struct usb_descriptor_header *)&thor_downloader_cdc_union,
 502        (struct usb_descriptor_header *)&hs_int_desc,
 503
 504        (struct usb_descriptor_header *)&thor_downloader_intf_data,
 505        (struct usb_descriptor_header *)&thor_downloader_cdc_av,
 506        (struct usb_descriptor_header *)&hs_in_desc,
 507        (struct usb_descriptor_header *)&hs_out_desc,
 508        NULL,
 509};
 510
 511/*-------------------------------------------------------------------------*/
 512static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 513{
 514        struct usb_request *req;
 515
 516        req = usb_ep_alloc_request(ep, 0);
 517        if (!req)
 518                return req;
 519
 520        req->length = length;
 521        req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length);
 522        if (!req->buf) {
 523                usb_ep_free_request(ep, req);
 524                req = NULL;
 525        }
 526
 527        return req;
 528}
 529
 530static int thor_rx_data(void)
 531{
 532        struct thor_dev *dev = thor_func->dev;
 533        int data_to_rx, tmp, status;
 534
 535        data_to_rx = dev->out_req->length;
 536        tmp = data_to_rx;
 537        do {
 538                dev->out_req->length = data_to_rx;
 539                debug("dev->out_req->length:%d dev->rxdata:%d\n",
 540                      dev->out_req->length, dev->rxdata);
 541
 542                status = usb_ep_queue(dev->out_ep, dev->out_req, 0);
 543                if (status) {
 544                        error("kill %s:  resubmit %d bytes --> %d",
 545                              dev->out_ep->name, dev->out_req->length, status);
 546                        usb_ep_set_halt(dev->out_ep);
 547                        return -EAGAIN;
 548                }
 549
 550                while (!dev->rxdata) {
 551                        usb_gadget_handle_interrupts(0);
 552                        if (ctrlc())
 553                                return -1;
 554                }
 555                dev->rxdata = 0;
 556                data_to_rx -= dev->out_req->actual;
 557        } while (data_to_rx);
 558
 559        return tmp;
 560}
 561
 562static void thor_tx_data(unsigned char *data, int len)
 563{
 564        struct thor_dev *dev = thor_func->dev;
 565        unsigned char *ptr = dev->in_req->buf;
 566        int status;
 567
 568        memset(ptr, 0, len);
 569        memcpy(ptr, data, len);
 570
 571        dev->in_req->length = len;
 572
 573        debug("%s: dev->in_req->length:%d to_cpy:%zd\n", __func__,
 574              dev->in_req->length, sizeof(data));
 575
 576        status = usb_ep_queue(dev->in_ep, dev->in_req, 0);
 577        if (status) {
 578                error("kill %s:  resubmit %d bytes --> %d",
 579                      dev->in_ep->name, dev->in_req->length, status);
 580                usb_ep_set_halt(dev->in_ep);
 581        }
 582
 583        /* Wait until tx interrupt received */
 584        while (!dev->txdata)
 585                usb_gadget_handle_interrupts(0);
 586
 587        dev->txdata = 0;
 588}
 589
 590static void thor_rx_tx_complete(struct usb_ep *ep, struct usb_request *req)
 591{
 592        struct thor_dev *dev = thor_func->dev;
 593        int status = req->status;
 594
 595        debug("%s: ep_ptr:%p, req_ptr:%p\n", __func__, ep, req);
 596        switch (status) {
 597        case 0:
 598                if (ep == dev->out_ep)
 599                        dev->rxdata = 1;
 600                else
 601                        dev->txdata = 1;
 602
 603                break;
 604
 605        /* this endpoint is normally active while we're configured */
 606        case -ECONNABORTED:             /* hardware forced ep reset */
 607        case -ECONNRESET:               /* request dequeued */
 608        case -ESHUTDOWN:                /* disconnect from host */
 609        case -EREMOTEIO:                /* short read */
 610        case -EOVERFLOW:
 611                error("ERROR:%d", status);
 612                break;
 613        }
 614
 615        debug("%s complete --> %d, %d/%d\n", ep->name,
 616              status, req->actual, req->length);
 617}
 618
 619static struct usb_request *thor_start_ep(struct usb_ep *ep)
 620{
 621        struct usb_request *req;
 622
 623        req = alloc_ep_req(ep, THOR_PACKET_SIZE);
 624        debug("%s: ep:%p req:%p\n", __func__, ep, req);
 625
 626        if (!req)
 627                return NULL;
 628
 629        memset(req->buf, 0, req->length);
 630        req->complete = thor_rx_tx_complete;
 631
 632        return req;
 633}
 634
 635static void thor_setup_complete(struct usb_ep *ep, struct usb_request *req)
 636{
 637        if (req->status || req->actual != req->length)
 638                debug("setup complete --> %d, %d/%d\n",
 639                      req->status, req->actual, req->length);
 640}
 641
 642static int
 643thor_func_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 644{
 645        struct thor_dev *dev = thor_func->dev;
 646        struct usb_request *req = dev->req;
 647        struct usb_gadget *gadget = dev->gadget;
 648        int value = 0;
 649
 650        u16 len = le16_to_cpu(ctrl->wLength);
 651
 652        debug("Req_Type: 0x%x Req: 0x%x wValue: 0x%x wIndex: 0x%x wLen: 0x%x\n",
 653              ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex,
 654              ctrl->wLength);
 655
 656        switch (ctrl->bRequest) {
 657        case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
 658                value = 0;
 659                break;
 660        case USB_CDC_REQ_SET_LINE_CODING:
 661                value = len;
 662                /* Line Coding set done = configuration done */
 663                thor_func->dev->configuration_done = 1;
 664                break;
 665
 666        default:
 667                error("thor_setup: unknown request: %d", ctrl->bRequest);
 668        }
 669
 670        if (value >= 0) {
 671                req->length = value;
 672                req->zero = value < len;
 673                value = usb_ep_queue(gadget->ep0, req, 0);
 674                if (value < 0) {
 675                        debug("%s: ep_queue: %d\n", __func__, value);
 676                        req->status = 0;
 677                }
 678        }
 679
 680        return value;
 681}
 682
 683/* Specific to the THOR protocol */
 684static void thor_set_dma(void *addr, int len)
 685{
 686        struct thor_dev *dev = thor_func->dev;
 687
 688        debug("in_req:%p, out_req:%p\n", dev->in_req, dev->out_req);
 689        debug("addr:%p, len:%d\n", addr, len);
 690
 691        dev->out_req->buf = addr;
 692        dev->out_req->length = len;
 693}
 694
 695int thor_init(void)
 696{
 697        struct thor_dev *dev = thor_func->dev;
 698
 699        /* Wait for a device enumeration and configuration settings */
 700        debug("THOR enumeration/configuration setting....\n");
 701        while (!dev->configuration_done)
 702                usb_gadget_handle_interrupts(0);
 703
 704        thor_set_dma(thor_rx_data_buf, strlen("THOR"));
 705        /* detect the download request from Host PC */
 706        if (thor_rx_data() < 0) {
 707                printf("%s: Data not received!\n", __func__);
 708                return -1;
 709        }
 710
 711        if (!strncmp((char *)thor_rx_data_buf, "THOR", strlen("THOR"))) {
 712                puts("Download request from the Host PC\n");
 713                udelay(30 * 1000); /* 30 ms */
 714
 715                strcpy((char *)thor_tx_data_buf, "ROHT");
 716                thor_tx_data(thor_tx_data_buf, strlen("ROHT"));
 717        } else {
 718                puts("Wrong reply information\n");
 719                return -1;
 720        }
 721
 722        return 0;
 723}
 724
 725int thor_handle(void)
 726{
 727        int ret;
 728
 729        /* receive the data from Host PC */
 730        while (1) {
 731                thor_set_dma(thor_rx_data_buf, sizeof(struct rqt_box));
 732                ret = thor_rx_data();
 733
 734                if (ret > 0) {
 735                        ret = process_data();
 736#ifdef CONFIG_THOR_RESET_OFF
 737                        if (ret == RESET_DONE)
 738                                break;
 739#endif
 740                        if (ret < 0)
 741                                return ret;
 742                } else {
 743                        printf("%s: No data received!\n", __func__);
 744                        break;
 745                }
 746        }
 747
 748        return 0;
 749}
 750
 751static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
 752{
 753        struct usb_gadget *gadget = c->cdev->gadget;
 754        struct f_thor *f_thor = func_to_thor(f);
 755        struct thor_dev *dev;
 756        struct usb_ep *ep;
 757        int status;
 758
 759        thor_func = f_thor;
 760        dev = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*dev));
 761        if (!dev)
 762                return -ENOMEM;
 763
 764        memset(dev, 0, sizeof(*dev));
 765        dev->gadget = gadget;
 766        f_thor->dev = dev;
 767
 768        debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n",
 769              __func__, c, f);
 770        debug("f_thor: 0x%p thor: 0x%p\n", f_thor, dev);
 771
 772        /* EP0  */
 773        /* preallocate control response and buffer */
 774        dev->req = usb_ep_alloc_request(gadget->ep0, 0);
 775        if (!dev->req) {
 776                status = -ENOMEM;
 777                goto fail;
 778        }
 779        dev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
 780                                 THOR_PACKET_SIZE);
 781        if (!dev->req->buf) {
 782                status = -ENOMEM;
 783                goto fail;
 784        }
 785
 786        dev->req->complete = thor_setup_complete;
 787
 788        /* DYNAMIC interface numbers assignments */
 789        status = usb_interface_id(c, f);
 790
 791        if (status < 0)
 792                goto fail;
 793
 794        thor_downloader_intf_int.bInterfaceNumber = status;
 795        thor_downloader_cdc_union.bMasterInterface0 = status;
 796
 797        status = usb_interface_id(c, f);
 798
 799        if (status < 0)
 800                goto fail;
 801
 802        thor_downloader_intf_data.bInterfaceNumber = status;
 803        thor_downloader_cdc_union.bSlaveInterface0 = status;
 804
 805        /* allocate instance-specific endpoints */
 806        ep = usb_ep_autoconfig(gadget, &fs_in_desc);
 807        if (!ep) {
 808                status = -ENODEV;
 809                goto fail;
 810        }
 811
 812        if (gadget_is_dualspeed(gadget)) {
 813                hs_in_desc.bEndpointAddress =
 814                                fs_in_desc.bEndpointAddress;
 815        }
 816
 817        dev->in_ep = ep; /* Store IN EP for enabling @ setup */
 818        ep->driver_data = dev;
 819
 820        ep = usb_ep_autoconfig(gadget, &fs_out_desc);
 821        if (!ep) {
 822                status = -ENODEV;
 823                goto fail;
 824        }
 825
 826        if (gadget_is_dualspeed(gadget))
 827                hs_out_desc.bEndpointAddress =
 828                                fs_out_desc.bEndpointAddress;
 829
 830        dev->out_ep = ep; /* Store OUT EP for enabling @ setup */
 831        ep->driver_data = dev;
 832
 833        ep = usb_ep_autoconfig(gadget, &fs_int_desc);
 834        if (!ep) {
 835                status = -ENODEV;
 836                goto fail;
 837        }
 838
 839        dev->int_ep = ep;
 840        ep->driver_data = dev;
 841
 842        if (gadget_is_dualspeed(gadget)) {
 843                hs_int_desc.bEndpointAddress =
 844                                fs_int_desc.bEndpointAddress;
 845
 846                f->hs_descriptors = (struct usb_descriptor_header **)
 847                        &hs_thor_downloader_function;
 848
 849                if (!f->hs_descriptors)
 850                        goto fail;
 851        }
 852
 853        debug("%s: out_ep:%p out_req:%p\n", __func__,
 854              dev->out_ep, dev->out_req);
 855
 856        return 0;
 857
 858 fail:
 859        free(dev);
 860        return status;
 861}
 862
 863static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
 864{
 865        free(req->buf);
 866        usb_ep_free_request(ep, req);
 867}
 868
 869static void thor_unbind(struct usb_configuration *c, struct usb_function *f)
 870{
 871        struct f_thor *f_thor = func_to_thor(f);
 872        struct thor_dev *dev = f_thor->dev;
 873
 874        free(dev);
 875        memset(thor_func, 0, sizeof(*thor_func));
 876        thor_func = NULL;
 877}
 878
 879static void thor_func_disable(struct usb_function *f)
 880{
 881        struct f_thor *f_thor = func_to_thor(f);
 882        struct thor_dev *dev = f_thor->dev;
 883
 884        debug("%s:\n", __func__);
 885
 886        /* Avoid freeing memory when ep is still claimed */
 887        if (dev->in_ep->driver_data) {
 888                free_ep_req(dev->in_ep, dev->in_req);
 889                usb_ep_disable(dev->in_ep);
 890                dev->in_ep->driver_data = NULL;
 891        }
 892
 893        if (dev->out_ep->driver_data) {
 894                free(dev->out_req->buf);
 895                dev->out_req->buf = NULL;
 896                usb_ep_free_request(dev->out_ep, dev->out_req);
 897                usb_ep_disable(dev->out_ep);
 898                dev->out_ep->driver_data = NULL;
 899        }
 900
 901        if (dev->int_ep->driver_data) {
 902                usb_ep_disable(dev->int_ep);
 903                dev->int_ep->driver_data = NULL;
 904        }
 905}
 906
 907static int thor_eps_setup(struct usb_function *f)
 908{
 909        struct usb_composite_dev *cdev = f->config->cdev;
 910        struct usb_gadget *gadget = cdev->gadget;
 911        struct thor_dev *dev = thor_func->dev;
 912        struct usb_endpoint_descriptor *d;
 913        struct usb_request *req;
 914        struct usb_ep *ep;
 915        int result;
 916
 917        ep = dev->in_ep;
 918        d = ep_desc(gadget, &hs_in_desc, &fs_in_desc);
 919        debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
 920
 921        result = usb_ep_enable(ep, d);
 922        if (result)
 923                goto exit;
 924
 925        ep->driver_data = cdev; /* claim */
 926        req = thor_start_ep(ep);
 927        if (!req) {
 928                usb_ep_disable(ep);
 929                result = -EIO;
 930                goto exit;
 931        }
 932
 933        dev->in_req = req;
 934        ep = dev->out_ep;
 935        d = ep_desc(gadget, &hs_out_desc, &fs_out_desc);
 936        debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
 937
 938        result = usb_ep_enable(ep, d);
 939        if (result)
 940                goto exit;
 941
 942        ep->driver_data = cdev; /* claim */
 943        req = thor_start_ep(ep);
 944        if (!req) {
 945                usb_ep_disable(ep);
 946                result = -EIO;
 947                goto exit;
 948        }
 949
 950        dev->out_req = req;
 951        /* ACM control EP */
 952        ep = dev->int_ep;
 953        ep->driver_data = cdev; /* claim */
 954
 955 exit:
 956        return result;
 957}
 958
 959static int thor_func_set_alt(struct usb_function *f,
 960                             unsigned intf, unsigned alt)
 961{
 962        struct thor_dev *dev = thor_func->dev;
 963        int result;
 964
 965        debug("%s: func: %s intf: %d alt: %d\n",
 966              __func__, f->name, intf, alt);
 967
 968        switch (intf) {
 969        case 0:
 970                debug("ACM INTR interface\n");
 971                break;
 972        case 1:
 973                debug("Communication Data interface\n");
 974                result = thor_eps_setup(f);
 975                if (result)
 976                        error("%s: EPs setup failed!", __func__);
 977                dev->configuration_done = 1;
 978                break;
 979        }
 980
 981        return 0;
 982}
 983
 984static int thor_func_init(struct usb_configuration *c)
 985{
 986        struct f_thor *f_thor;
 987        int status;
 988
 989        debug("%s: cdev: 0x%p\n", __func__, c->cdev);
 990
 991        f_thor = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_thor));
 992        if (!f_thor)
 993                return -ENOMEM;
 994
 995        memset(f_thor, 0, sizeof(*f_thor));
 996
 997        f_thor->usb_function.name = "f_thor";
 998        f_thor->usb_function.bind = thor_func_bind;
 999        f_thor->usb_function.unbind = thor_unbind;
1000        f_thor->usb_function.setup = thor_func_setup;
1001        f_thor->usb_function.set_alt = thor_func_set_alt;
1002        f_thor->usb_function.disable = thor_func_disable;
1003
1004        status = usb_add_function(c, &f_thor->usb_function);
1005        if (status)
1006                free(f_thor);
1007
1008        return status;
1009}
1010
1011int thor_add(struct usb_configuration *c)
1012{
1013        debug("%s:\n", __func__);
1014        return thor_func_init(c);
1015}
1016
1017DECLARE_GADGET_BIND_CALLBACK(usb_dnl_thor, thor_add);
1018