123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- /*
- * g_dnl.c -- USB Downloader Gadget
- *
- * Copyright (C) 2012 Samsung Electronics
- * Lukasz Majewski <l.majewski@samsung.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <common.h>
- #include <malloc.h>
- #include <mmc.h>
- #include <part.h>
- #include <usb.h>
- #include <g_dnl.h>
- #include <usb_mass_storage.h>
- #include <dfu.h>
- #include <thor.h>
- #include <env_callback.h>
- #include "gadget_chips.h"
- #include "composite.c"
- /*
- * One needs to define the following:
- * CONFIG_G_DNL_VENDOR_NUM
- * CONFIG_G_DNL_PRODUCT_NUM
- * CONFIG_G_DNL_MANUFACTURER
- * at e.g. ./configs/<board>_defconfig
- */
- #define STRING_MANUFACTURER 25
- #define STRING_PRODUCT 2
- /* Index of String Descriptor describing this configuration */
- #define STRING_USBDOWN 2
- /* Index of String serial */
- #define STRING_SERIAL 3
- #define MAX_STRING_SERIAL 32
- /* Number of supported configurations */
- #define CONFIGURATION_NUMBER 1
- #define DRIVER_VERSION "usb_dnl 2.0"
- static const char product[] = "USB download gadget";
- static char g_dnl_serial[MAX_STRING_SERIAL];
- static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
- void g_dnl_set_serialnumber(char *s)
- {
- memset(g_dnl_serial, 0, MAX_STRING_SERIAL);
- if (strlen(s) < MAX_STRING_SERIAL)
- strncpy(g_dnl_serial, s, strlen(s));
- }
- static struct usb_device_descriptor device_desc = {
- .bLength = sizeof device_desc,
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = __constant_cpu_to_le16(0x0200),
- .bDeviceClass = USB_CLASS_PER_INTERFACE,
- .bDeviceSubClass = 0, /*0x02:CDC-modem , 0x00:CDC-serial*/
- .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM),
- .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM),
- .iProduct = STRING_PRODUCT,
- .iSerialNumber = STRING_SERIAL,
- .bNumConfigurations = 1,
- };
- /*
- * static strings, in UTF-8
- * IDs for those strings are assigned dynamically at g_dnl_bind()
- */
- static struct usb_string g_dnl_string_defs[] = {
- {.s = manufacturer},
- {.s = product},
- {.s = g_dnl_serial},
- { } /* end of list */
- };
- static struct usb_gadget_strings g_dnl_string_tab = {
- .language = 0x0409, /* en-us */
- .strings = g_dnl_string_defs,
- };
- static struct usb_gadget_strings *g_dnl_composite_strings[] = {
- &g_dnl_string_tab,
- NULL,
- };
- static int g_dnl_unbind(struct usb_composite_dev *cdev)
- {
- struct usb_gadget *gadget = cdev->gadget;
- debug("%s: calling usb_gadget_disconnect for "
- "controller '%s'\n", __func__, gadget->name);
- usb_gadget_disconnect(gadget);
- return 0;
- }
- static inline struct g_dnl_bind_callback *g_dnl_bind_callback_first(void)
- {
- return ll_entry_start(struct g_dnl_bind_callback,
- g_dnl_bind_callbacks);
- }
- static inline struct g_dnl_bind_callback *g_dnl_bind_callback_end(void)
- {
- return ll_entry_end(struct g_dnl_bind_callback,
- g_dnl_bind_callbacks);
- }
- static int g_dnl_do_config(struct usb_configuration *c)
- {
- const char *s = c->cdev->driver->name;
- struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();
- debug("%s: configuration: 0x%p composite dev: 0x%p\n",
- __func__, c, c->cdev);
- for (; callback != g_dnl_bind_callback_end(); callback++)
- if (!strcmp(s, callback->usb_function_name))
- return callback->fptr(c);
- return -ENODEV;
- }
- static int g_dnl_config_register(struct usb_composite_dev *cdev)
- {
- struct usb_configuration *config;
- const char *name = "usb_dnload";
- config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config));
- if (!config)
- return -ENOMEM;
- memset(config, 0, sizeof(*config));
- config->label = name;
- config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
- config->bConfigurationValue = CONFIGURATION_NUMBER;
- config->iConfiguration = STRING_USBDOWN;
- config->bind = g_dnl_do_config;
- return usb_add_config(cdev, config);
- }
- __weak
- int board_usb_init(int index, enum usb_init_type init)
- {
- return 0;
- }
- __weak
- int board_usb_cleanup(int index, enum usb_init_type init)
- {
- return 0;
- }
- __weak
- int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
- {
- return 0;
- }
- __weak int g_dnl_get_board_bcd_device_number(int gcnum)
- {
- return gcnum;
- }
- __weak int g_dnl_board_usb_cable_connected(void)
- {
- return -EOPNOTSUPP;
- }
- static bool g_dnl_detach_request;
- bool g_dnl_detach(void)
- {
- return g_dnl_detach_request;
- }
- void g_dnl_trigger_detach(void)
- {
- g_dnl_detach_request = true;
- }
- void g_dnl_clear_detach(void)
- {
- g_dnl_detach_request = false;
- }
- static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev)
- {
- struct usb_gadget *gadget = cdev->gadget;
- int gcnum;
- gcnum = usb_gadget_controller_number(gadget);
- if (gcnum > 0)
- gcnum += 0x200;
- return g_dnl_get_board_bcd_device_number(gcnum);
- }
- /**
- * Update internal serial number variable when the "serial#" env var changes.
- *
- * Handle all cases, even when flags == H_PROGRAMMATIC or op == env_op_delete.
- */
- static int on_serialno(const char *name, const char *value, enum env_op op,
- int flags)
- {
- g_dnl_set_serialnumber((char *)value);
- return 0;
- }
- U_BOOT_ENV_CALLBACK(serialno, on_serialno);
- static int g_dnl_bind(struct usb_composite_dev *cdev)
- {
- struct usb_gadget *gadget = cdev->gadget;
- int id, ret;
- int gcnum;
- debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev);
- id = usb_string_id(cdev);
- if (id < 0)
- return id;
- g_dnl_string_defs[0].id = id;
- device_desc.iManufacturer = id;
- id = usb_string_id(cdev);
- if (id < 0)
- return id;
- g_dnl_string_defs[1].id = id;
- device_desc.iProduct = id;
- id = usb_string_id(cdev);
- if (id < 0)
- return id;
- g_dnl_string_defs[2].id = id;
- device_desc.iSerialNumber = id;
- g_dnl_bind_fixup(&device_desc, cdev->driver->name);
- ret = g_dnl_config_register(cdev);
- if (ret)
- goto error;
- gcnum = g_dnl_get_bcd_device_number(cdev);
- if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16(gcnum);
- else {
- debug("%s: controller '%s' not recognized\n",
- __func__, gadget->name);
- device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
- }
- debug("%s: calling usb_gadget_connect for "
- "controller '%s'\n", __func__, gadget->name);
- usb_gadget_connect(gadget);
- return 0;
- error:
- g_dnl_unbind(cdev);
- return -ENOMEM;
- }
- static struct usb_composite_driver g_dnl_driver = {
- .name = NULL,
- .dev = &device_desc,
- .strings = g_dnl_composite_strings,
- .bind = g_dnl_bind,
- .unbind = g_dnl_unbind,
- };
- /*
- * NOTICE:
- * Registering via USB function name won't be necessary after rewriting
- * g_dnl to support multiple USB functions.
- */
- int g_dnl_register(const char *name)
- {
- int ret;
- debug("%s: g_dnl_driver.name = %s\n", __func__, name);
- g_dnl_driver.name = name;
- ret = usb_composite_register(&g_dnl_driver);
- if (ret) {
- printf("%s: failed!, error: %d\n", __func__, ret);
- return ret;
- }
- return 0;
- }
- void g_dnl_unregister(void)
- {
- usb_composite_unregister(&g_dnl_driver);
- }
|