uboot/drivers/usb/gadget/g_dnl.c
<<
>>
Prefs
   1/*
   2 * g_dnl.c -- USB Downloader Gadget
   3 *
   4 * Copyright (C) 2012 Samsung Electronics
   5 * Lukasz Majewski  <l.majewski@samsung.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 */
  21
  22#include <errno.h>
  23#include <common.h>
  24#include <malloc.h>
  25
  26#include <mmc.h>
  27#include <part.h>
  28
  29#include <g_dnl.h>
  30#include "f_dfu.h"
  31
  32#include "gadget_chips.h"
  33#include "composite.c"
  34#include "f_mass_storage.c"
  35
  36/*
  37 * One needs to define the following:
  38 * CONFIG_G_DNL_VENDOR_NUM
  39 * CONFIG_G_DNL_PRODUCT_NUM
  40 * CONFIG_G_DNL_MANUFACTURER
  41 * at e.g. ./include/configs/<board>.h
  42 */
  43
  44#define STRING_MANUFACTURER 25
  45#define STRING_PRODUCT 2
  46#define STRING_USBDOWN 2
  47#define CONFIG_USBDOWNLOADER 2
  48
  49#define DRIVER_VERSION          "usb_dnl 2.0"
  50
  51static const char shortname[] = "usb_dnl_";
  52static const char product[] = "USB download gadget";
  53static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
  54
  55static struct usb_device_descriptor device_desc = {
  56        .bLength = sizeof device_desc,
  57        .bDescriptorType = USB_DT_DEVICE,
  58
  59        .bcdUSB = __constant_cpu_to_le16(0x0200),
  60        .bDeviceClass = USB_CLASS_COMM,
  61        .bDeviceSubClass = 0x02, /*0x02:CDC-modem , 0x00:CDC-serial*/
  62
  63        .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM),
  64        .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM),
  65        .iProduct = STRING_PRODUCT,
  66        .bNumConfigurations = 1,
  67};
  68
  69/* static strings, in UTF-8 */
  70static struct usb_string g_dnl_string_defs[] = {
  71        { 0, manufacturer, },
  72        { 1, product, },
  73        {  }            /* end of list */
  74};
  75
  76static struct usb_gadget_strings g_dnl_string_tab = {
  77        .language = 0x0409, /* en-us */
  78        .strings = g_dnl_string_defs,
  79};
  80
  81static struct usb_gadget_strings *g_dnl_composite_strings[] = {
  82        &g_dnl_string_tab,
  83        NULL,
  84};
  85
  86static int g_dnl_unbind(struct usb_composite_dev *cdev)
  87{
  88        struct usb_gadget *gadget = cdev->gadget;
  89
  90        debug("%s: calling usb_gadget_disconnect for "
  91                        "controller '%s'\n", shortname, gadget->name);
  92        usb_gadget_disconnect(gadget);
  93
  94        return 0;
  95}
  96
  97static int g_dnl_do_config(struct usb_configuration *c)
  98{
  99        const char *s = c->cdev->driver->name;
 100        int ret = -1;
 101
 102        debug("%s: configuration: 0x%p composite dev: 0x%p\n",
 103              __func__, c, c->cdev);
 104
 105        printf("GADGET DRIVER: %s\n", s);
 106        if (!strcmp(s, "usb_dnl_dfu"))
 107                ret = dfu_add(c);
 108        else if (!strcmp(s, "usb_dnl_ums"))
 109                ret = fsg_add(c);
 110
 111        return ret;
 112}
 113
 114static int g_dnl_config_register(struct usb_composite_dev *cdev)
 115{
 116        static struct usb_configuration config = {
 117                .label = "usb_dnload",
 118                .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
 119                .bConfigurationValue =  CONFIG_USBDOWNLOADER,
 120                .iConfiguration =       STRING_USBDOWN,
 121
 122                .bind = g_dnl_do_config,
 123        };
 124
 125        return usb_add_config(cdev, &config);
 126}
 127
 128static int g_dnl_bind(struct usb_composite_dev *cdev)
 129{
 130        struct usb_gadget *gadget = cdev->gadget;
 131        int id, ret;
 132        int gcnum;
 133
 134        debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev);
 135
 136        id = usb_string_id(cdev);
 137
 138        if (id < 0)
 139                return id;
 140        g_dnl_string_defs[0].id = id;
 141        device_desc.iManufacturer = id;
 142
 143        id = usb_string_id(cdev);
 144        if (id < 0)
 145                return id;
 146
 147        g_dnl_string_defs[1].id = id;
 148        device_desc.iProduct = id;
 149
 150        ret = g_dnl_config_register(cdev);
 151        if (ret)
 152                goto error;
 153
 154        gcnum = usb_gadget_controller_number(gadget);
 155
 156        debug("gcnum: %d\n", gcnum);
 157        if (gcnum >= 0)
 158                device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
 159        else {
 160                debug("%s: controller '%s' not recognized\n",
 161                        shortname, gadget->name);
 162                device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
 163        }
 164
 165        debug("%s: calling usb_gadget_connect for "
 166                        "controller '%s'\n", shortname, gadget->name);
 167        usb_gadget_connect(gadget);
 168
 169        return 0;
 170
 171 error:
 172        g_dnl_unbind(cdev);
 173        return -ENOMEM;
 174}
 175
 176static struct usb_composite_driver g_dnl_driver = {
 177        .name = NULL,
 178        .dev = &device_desc,
 179        .strings = g_dnl_composite_strings,
 180
 181        .bind = g_dnl_bind,
 182        .unbind = g_dnl_unbind,
 183};
 184
 185int g_dnl_register(const char *type)
 186{
 187        /* We only allow "dfu" atm, so 3 should be enough */
 188        static char name[sizeof(shortname) + 3];
 189        int ret;
 190
 191        if (!strcmp(type, "dfu")) {
 192                strcpy(name, shortname);
 193                strcat(name, type);
 194        } else if (!strcmp(type, "ums")) {
 195                strcpy(name, shortname);
 196                strcat(name, type);
 197        } else {
 198                printf("%s: unknown command: %s\n", __func__, type);
 199                return -EINVAL;
 200        }
 201
 202        g_dnl_driver.name = name;
 203
 204        debug("%s: g_dnl_driver.name: %s\n", __func__, g_dnl_driver.name);
 205        ret = usb_composite_register(&g_dnl_driver);
 206
 207        if (ret) {
 208                printf("%s: failed!, error: %d\n", __func__, ret);
 209                return ret;
 210        }
 211
 212        return 0;
 213}
 214
 215void g_dnl_unregister(void)
 216{
 217        usb_composite_unregister(&g_dnl_driver);
 218}
 219