11d4a0b6cSLukasz Majewski /* 21d4a0b6cSLukasz Majewski * g_dnl.c -- USB Downloader Gadget 31d4a0b6cSLukasz Majewski * 41d4a0b6cSLukasz Majewski * Copyright (C) 2012 Samsung Electronics 51d4a0b6cSLukasz Majewski * Lukasz Majewski <l.majewski@samsung.com> 61d4a0b6cSLukasz Majewski * 71d4a0b6cSLukasz Majewski * This program is free software; you can redistribute it and/or modify 81d4a0b6cSLukasz Majewski * it under the terms of the GNU General Public License as published by 91d4a0b6cSLukasz Majewski * the Free Software Foundation; either version 2 of the License, or 101d4a0b6cSLukasz Majewski * (at your option) any later version. 111d4a0b6cSLukasz Majewski * 121d4a0b6cSLukasz Majewski * This program is distributed in the hope that it will be useful, 131d4a0b6cSLukasz Majewski * but WITHOUT ANY WARRANTY; without even the implied warranty of 141d4a0b6cSLukasz Majewski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 151d4a0b6cSLukasz Majewski * GNU General Public License for more details. 161d4a0b6cSLukasz Majewski * 171d4a0b6cSLukasz Majewski * You should have received a copy of the GNU General Public License 181d4a0b6cSLukasz Majewski * along with this program; if not, write to the Free Software 191d4a0b6cSLukasz Majewski * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 201d4a0b6cSLukasz Majewski */ 211d4a0b6cSLukasz Majewski 221d4a0b6cSLukasz Majewski #include <errno.h> 231d4a0b6cSLukasz Majewski #include <common.h> 241d4a0b6cSLukasz Majewski #include <malloc.h> 251d4a0b6cSLukasz Majewski 261d4a0b6cSLukasz Majewski #include <mmc.h> 271d4a0b6cSLukasz Majewski #include <part.h> 281d4a0b6cSLukasz Majewski 291d4a0b6cSLukasz Majewski #include <g_dnl.h> 301d4a0b6cSLukasz Majewski #include "f_dfu.h" 311d4a0b6cSLukasz Majewski 321d4a0b6cSLukasz Majewski #include "gadget_chips.h" 331d4a0b6cSLukasz Majewski #include "composite.c" 34b528f713SLukasz Majewski #include "f_mass_storage.c" 351d4a0b6cSLukasz Majewski 361d4a0b6cSLukasz Majewski /* 371d4a0b6cSLukasz Majewski * One needs to define the following: 381d4a0b6cSLukasz Majewski * CONFIG_G_DNL_VENDOR_NUM 391d4a0b6cSLukasz Majewski * CONFIG_G_DNL_PRODUCT_NUM 401d4a0b6cSLukasz Majewski * CONFIG_G_DNL_MANUFACTURER 411d4a0b6cSLukasz Majewski * at e.g. ./include/configs/<board>.h 421d4a0b6cSLukasz Majewski */ 431d4a0b6cSLukasz Majewski 441d4a0b6cSLukasz Majewski #define STRING_MANUFACTURER 25 451d4a0b6cSLukasz Majewski #define STRING_PRODUCT 2 461d4a0b6cSLukasz Majewski #define STRING_USBDOWN 2 471d4a0b6cSLukasz Majewski #define CONFIG_USBDOWNLOADER 2 481d4a0b6cSLukasz Majewski 491d4a0b6cSLukasz Majewski #define DRIVER_VERSION "usb_dnl 2.0" 501d4a0b6cSLukasz Majewski 511d4a0b6cSLukasz Majewski static const char shortname[] = "usb_dnl_"; 521d4a0b6cSLukasz Majewski static const char product[] = "USB download gadget"; 531d4a0b6cSLukasz Majewski static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER; 541d4a0b6cSLukasz Majewski 551d4a0b6cSLukasz Majewski static struct usb_device_descriptor device_desc = { 561d4a0b6cSLukasz Majewski .bLength = sizeof device_desc, 571d4a0b6cSLukasz Majewski .bDescriptorType = USB_DT_DEVICE, 581d4a0b6cSLukasz Majewski 591d4a0b6cSLukasz Majewski .bcdUSB = __constant_cpu_to_le16(0x0200), 601d4a0b6cSLukasz Majewski .bDeviceClass = USB_CLASS_COMM, 611d4a0b6cSLukasz Majewski .bDeviceSubClass = 0x02, /*0x02:CDC-modem , 0x00:CDC-serial*/ 621d4a0b6cSLukasz Majewski 631d4a0b6cSLukasz Majewski .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM), 641d4a0b6cSLukasz Majewski .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM), 651d4a0b6cSLukasz Majewski .iProduct = STRING_PRODUCT, 661d4a0b6cSLukasz Majewski .bNumConfigurations = 1, 671d4a0b6cSLukasz Majewski }; 681d4a0b6cSLukasz Majewski 691d4a0b6cSLukasz Majewski /* static strings, in UTF-8 */ 701d4a0b6cSLukasz Majewski static struct usb_string g_dnl_string_defs[] = { 711d4a0b6cSLukasz Majewski { 0, manufacturer, }, 721d4a0b6cSLukasz Majewski { 1, product, }, 73598cf606SPantelis Antoniou { } /* end of list */ 741d4a0b6cSLukasz Majewski }; 751d4a0b6cSLukasz Majewski 761d4a0b6cSLukasz Majewski static struct usb_gadget_strings g_dnl_string_tab = { 771d4a0b6cSLukasz Majewski .language = 0x0409, /* en-us */ 781d4a0b6cSLukasz Majewski .strings = g_dnl_string_defs, 791d4a0b6cSLukasz Majewski }; 801d4a0b6cSLukasz Majewski 811d4a0b6cSLukasz Majewski static struct usb_gadget_strings *g_dnl_composite_strings[] = { 821d4a0b6cSLukasz Majewski &g_dnl_string_tab, 831d4a0b6cSLukasz Majewski NULL, 841d4a0b6cSLukasz Majewski }; 851d4a0b6cSLukasz Majewski 861d4a0b6cSLukasz Majewski static int g_dnl_unbind(struct usb_composite_dev *cdev) 871d4a0b6cSLukasz Majewski { 885a413caeSPantelis Antoniou struct usb_gadget *gadget = cdev->gadget; 895a413caeSPantelis Antoniou 905a413caeSPantelis Antoniou debug("%s: calling usb_gadget_disconnect for " 915a413caeSPantelis Antoniou "controller '%s'\n", shortname, gadget->name); 925a413caeSPantelis Antoniou usb_gadget_disconnect(gadget); 935a413caeSPantelis Antoniou 941d4a0b6cSLukasz Majewski return 0; 951d4a0b6cSLukasz Majewski } 961d4a0b6cSLukasz Majewski 971d4a0b6cSLukasz Majewski static int g_dnl_do_config(struct usb_configuration *c) 981d4a0b6cSLukasz Majewski { 991d4a0b6cSLukasz Majewski const char *s = c->cdev->driver->name; 1001d4a0b6cSLukasz Majewski int ret = -1; 1011d4a0b6cSLukasz Majewski 1021d4a0b6cSLukasz Majewski debug("%s: configuration: 0x%p composite dev: 0x%p\n", 1031d4a0b6cSLukasz Majewski __func__, c, c->cdev); 1041d4a0b6cSLukasz Majewski 1051d4a0b6cSLukasz Majewski printf("GADGET DRIVER: %s\n", s); 1061d4a0b6cSLukasz Majewski if (!strcmp(s, "usb_dnl_dfu")) 1071d4a0b6cSLukasz Majewski ret = dfu_add(c); 108b528f713SLukasz Majewski else if (!strcmp(s, "usb_dnl_ums")) 109b528f713SLukasz Majewski ret = fsg_add(c); 1101d4a0b6cSLukasz Majewski 1111d4a0b6cSLukasz Majewski return ret; 1121d4a0b6cSLukasz Majewski } 1131d4a0b6cSLukasz Majewski 1141d4a0b6cSLukasz Majewski static int g_dnl_config_register(struct usb_composite_dev *cdev) 1151d4a0b6cSLukasz Majewski { 1161d4a0b6cSLukasz Majewski static struct usb_configuration config = { 1171d4a0b6cSLukasz Majewski .label = "usb_dnload", 1181d4a0b6cSLukasz Majewski .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 1191d4a0b6cSLukasz Majewski .bConfigurationValue = CONFIG_USBDOWNLOADER, 1201d4a0b6cSLukasz Majewski .iConfiguration = STRING_USBDOWN, 1211d4a0b6cSLukasz Majewski 1221d4a0b6cSLukasz Majewski .bind = g_dnl_do_config, 1231d4a0b6cSLukasz Majewski }; 1241d4a0b6cSLukasz Majewski 1251d4a0b6cSLukasz Majewski return usb_add_config(cdev, &config); 1261d4a0b6cSLukasz Majewski } 1271d4a0b6cSLukasz Majewski 128*c5398cc9SHeiko Schocher __weak 129*c5398cc9SHeiko Schocher int g_dnl_bind_fixup(struct usb_device_descriptor *dev) 130*c5398cc9SHeiko Schocher { 131*c5398cc9SHeiko Schocher return 0; 132*c5398cc9SHeiko Schocher } 133*c5398cc9SHeiko Schocher 1341d4a0b6cSLukasz Majewski static int g_dnl_bind(struct usb_composite_dev *cdev) 1351d4a0b6cSLukasz Majewski { 1361d4a0b6cSLukasz Majewski struct usb_gadget *gadget = cdev->gadget; 1371d4a0b6cSLukasz Majewski int id, ret; 1381d4a0b6cSLukasz Majewski int gcnum; 1391d4a0b6cSLukasz Majewski 1401d4a0b6cSLukasz Majewski debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev); 1411d4a0b6cSLukasz Majewski 1421d4a0b6cSLukasz Majewski id = usb_string_id(cdev); 1431d4a0b6cSLukasz Majewski 1441d4a0b6cSLukasz Majewski if (id < 0) 1451d4a0b6cSLukasz Majewski return id; 1461d4a0b6cSLukasz Majewski g_dnl_string_defs[0].id = id; 1471d4a0b6cSLukasz Majewski device_desc.iManufacturer = id; 1481d4a0b6cSLukasz Majewski 1491d4a0b6cSLukasz Majewski id = usb_string_id(cdev); 1501d4a0b6cSLukasz Majewski if (id < 0) 1511d4a0b6cSLukasz Majewski return id; 1521d4a0b6cSLukasz Majewski 1531d4a0b6cSLukasz Majewski g_dnl_string_defs[1].id = id; 1541d4a0b6cSLukasz Majewski device_desc.iProduct = id; 1551d4a0b6cSLukasz Majewski 156*c5398cc9SHeiko Schocher g_dnl_bind_fixup(&device_desc); 1571d4a0b6cSLukasz Majewski ret = g_dnl_config_register(cdev); 1581d4a0b6cSLukasz Majewski if (ret) 1591d4a0b6cSLukasz Majewski goto error; 1601d4a0b6cSLukasz Majewski 1611d4a0b6cSLukasz Majewski gcnum = usb_gadget_controller_number(gadget); 1621d4a0b6cSLukasz Majewski 1631d4a0b6cSLukasz Majewski debug("gcnum: %d\n", gcnum); 1641d4a0b6cSLukasz Majewski if (gcnum >= 0) 1651d4a0b6cSLukasz Majewski device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); 1661d4a0b6cSLukasz Majewski else { 1671d4a0b6cSLukasz Majewski debug("%s: controller '%s' not recognized\n", 1681d4a0b6cSLukasz Majewski shortname, gadget->name); 1691d4a0b6cSLukasz Majewski device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); 1701d4a0b6cSLukasz Majewski } 1711d4a0b6cSLukasz Majewski 1725a413caeSPantelis Antoniou debug("%s: calling usb_gadget_connect for " 1735a413caeSPantelis Antoniou "controller '%s'\n", shortname, gadget->name); 1745a413caeSPantelis Antoniou usb_gadget_connect(gadget); 1755a413caeSPantelis Antoniou 1761d4a0b6cSLukasz Majewski return 0; 1771d4a0b6cSLukasz Majewski 1781d4a0b6cSLukasz Majewski error: 1791d4a0b6cSLukasz Majewski g_dnl_unbind(cdev); 1801d4a0b6cSLukasz Majewski return -ENOMEM; 1811d4a0b6cSLukasz Majewski } 1821d4a0b6cSLukasz Majewski 1831d4a0b6cSLukasz Majewski static struct usb_composite_driver g_dnl_driver = { 1841d4a0b6cSLukasz Majewski .name = NULL, 1851d4a0b6cSLukasz Majewski .dev = &device_desc, 1861d4a0b6cSLukasz Majewski .strings = g_dnl_composite_strings, 1871d4a0b6cSLukasz Majewski 1881d4a0b6cSLukasz Majewski .bind = g_dnl_bind, 1891d4a0b6cSLukasz Majewski .unbind = g_dnl_unbind, 1901d4a0b6cSLukasz Majewski }; 1911d4a0b6cSLukasz Majewski 1921d4a0b6cSLukasz Majewski int g_dnl_register(const char *type) 1931d4a0b6cSLukasz Majewski { 1941d4a0b6cSLukasz Majewski /* We only allow "dfu" atm, so 3 should be enough */ 1951d4a0b6cSLukasz Majewski static char name[sizeof(shortname) + 3]; 1961d4a0b6cSLukasz Majewski int ret; 1971d4a0b6cSLukasz Majewski 1981d4a0b6cSLukasz Majewski if (!strcmp(type, "dfu")) { 1991d4a0b6cSLukasz Majewski strcpy(name, shortname); 2001d4a0b6cSLukasz Majewski strcat(name, type); 201b528f713SLukasz Majewski } else if (!strcmp(type, "ums")) { 202b528f713SLukasz Majewski strcpy(name, shortname); 203b528f713SLukasz Majewski strcat(name, type); 2041d4a0b6cSLukasz Majewski } else { 2051d4a0b6cSLukasz Majewski printf("%s: unknown command: %s\n", __func__, type); 2061d4a0b6cSLukasz Majewski return -EINVAL; 2071d4a0b6cSLukasz Majewski } 2081d4a0b6cSLukasz Majewski 2091d4a0b6cSLukasz Majewski g_dnl_driver.name = name; 2101d4a0b6cSLukasz Majewski 2111d4a0b6cSLukasz Majewski debug("%s: g_dnl_driver.name: %s\n", __func__, g_dnl_driver.name); 2121d4a0b6cSLukasz Majewski ret = usb_composite_register(&g_dnl_driver); 2131d4a0b6cSLukasz Majewski 2141d4a0b6cSLukasz Majewski if (ret) { 2151d4a0b6cSLukasz Majewski printf("%s: failed!, error: %d\n", __func__, ret); 2161d4a0b6cSLukasz Majewski return ret; 2171d4a0b6cSLukasz Majewski } 2181d4a0b6cSLukasz Majewski 2191d4a0b6cSLukasz Majewski return 0; 2201d4a0b6cSLukasz Majewski } 2211d4a0b6cSLukasz Majewski 2221d4a0b6cSLukasz Majewski void g_dnl_unregister(void) 2231d4a0b6cSLukasz Majewski { 2241d4a0b6cSLukasz Majewski usb_composite_unregister(&g_dnl_driver); 2251d4a0b6cSLukasz Majewski } 226