blob: 40868c034e42fcde8416d407552e38e2e2daf75b [file] [log] [blame]
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +02001/*
2 * g_dnl.c -- USB Downloader Gadget
3 *
4 * Copyright (C) 2012 Samsung Electronics
5 * Lukasz Majewski <l.majewski@samsung.com>
6 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +02008 */
9
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020010#include <common.h>
11#include <malloc.h>
12
13#include <mmc.h>
14#include <part.h>
15
16#include <g_dnl.h>
Lukasz Majewskiba4e95c2013-09-17 15:58:21 +020017#include <usb_mass_storage.h>
Lukasz Majewskia6921ad2013-09-17 15:58:23 +020018#include <dfu.h>
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020019
20#include "gadget_chips.h"
21#include "composite.c"
22
23/*
24 * One needs to define the following:
25 * CONFIG_G_DNL_VENDOR_NUM
26 * CONFIG_G_DNL_PRODUCT_NUM
27 * CONFIG_G_DNL_MANUFACTURER
28 * at e.g. ./include/configs/<board>.h
29 */
30
31#define STRING_MANUFACTURER 25
32#define STRING_PRODUCT 2
Lukasz Majewskicfc2d0d2013-08-19 17:17:18 +020033/* Index of String Descriptor describing this configuration */
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020034#define STRING_USBDOWN 2
Lukasz Majewskicfc2d0d2013-08-19 17:17:18 +020035/* Number of supported configurations */
36#define CONFIGURATION_NUMBER 1
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020037
38#define DRIVER_VERSION "usb_dnl 2.0"
39
40static const char shortname[] = "usb_dnl_";
41static const char product[] = "USB download gadget";
42static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
43
44static struct usb_device_descriptor device_desc = {
45 .bLength = sizeof device_desc,
46 .bDescriptorType = USB_DT_DEVICE,
47
48 .bcdUSB = __constant_cpu_to_le16(0x0200),
49 .bDeviceClass = USB_CLASS_COMM,
50 .bDeviceSubClass = 0x02, /*0x02:CDC-modem , 0x00:CDC-serial*/
51
52 .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM),
53 .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM),
54 .iProduct = STRING_PRODUCT,
55 .bNumConfigurations = 1,
56};
57
Lukasz Majewskic4219a82013-08-19 17:17:19 +020058/*
59 * static strings, in UTF-8
60 * IDs for those strings are assigned dynamically at g_dnl_bind()
61 */
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020062static struct usb_string g_dnl_string_defs[] = {
Lukasz Majewskic4219a82013-08-19 17:17:19 +020063 {.s = manufacturer},
64 {.s = product},
65 { } /* end of list */
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020066};
67
68static struct usb_gadget_strings g_dnl_string_tab = {
69 .language = 0x0409, /* en-us */
70 .strings = g_dnl_string_defs,
71};
72
73static struct usb_gadget_strings *g_dnl_composite_strings[] = {
74 &g_dnl_string_tab,
75 NULL,
76};
77
78static int g_dnl_unbind(struct usb_composite_dev *cdev)
79{
Pantelis Antoniou5a413ca2012-11-30 08:01:05 +000080 struct usb_gadget *gadget = cdev->gadget;
81
82 debug("%s: calling usb_gadget_disconnect for "
83 "controller '%s'\n", shortname, gadget->name);
84 usb_gadget_disconnect(gadget);
85
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +020086 return 0;
87}
88
89static int g_dnl_do_config(struct usb_configuration *c)
90{
91 const char *s = c->cdev->driver->name;
92 int ret = -1;
93
94 debug("%s: configuration: 0x%p composite dev: 0x%p\n",
95 __func__, c, c->cdev);
96
97 printf("GADGET DRIVER: %s\n", s);
98 if (!strcmp(s, "usb_dnl_dfu"))
99 ret = dfu_add(c);
Lukasz Majewskib528f712013-03-05 12:10:17 +0100100 else if (!strcmp(s, "usb_dnl_ums"))
101 ret = fsg_add(c);
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +0200102
103 return ret;
104}
105
106static int g_dnl_config_register(struct usb_composite_dev *cdev)
107{
108 static struct usb_configuration config = {
109 .label = "usb_dnload",
110 .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
Lukasz Majewskicfc2d0d2013-08-19 17:17:18 +0200111 .bConfigurationValue = CONFIGURATION_NUMBER,
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +0200112 .iConfiguration = STRING_USBDOWN,
113
114 .bind = g_dnl_do_config,
115 };
116
117 return usb_add_config(cdev, &config);
118}
119
Heiko Schocherc5398cc2013-06-04 11:19:50 +0200120__weak
121int g_dnl_bind_fixup(struct usb_device_descriptor *dev)
122{
123 return 0;
124}
125
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +0200126static int g_dnl_bind(struct usb_composite_dev *cdev)
127{
128 struct usb_gadget *gadget = cdev->gadget;
129 int id, ret;
130 int gcnum;
131
132 debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev);
133
134 id = usb_string_id(cdev);
135
136 if (id < 0)
137 return id;
138 g_dnl_string_defs[0].id = id;
139 device_desc.iManufacturer = id;
140
141 id = usb_string_id(cdev);
142 if (id < 0)
143 return id;
144
145 g_dnl_string_defs[1].id = id;
146 device_desc.iProduct = id;
147
Heiko Schocherc5398cc2013-06-04 11:19:50 +0200148 g_dnl_bind_fixup(&device_desc);
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +0200149 ret = g_dnl_config_register(cdev);
150 if (ret)
151 goto error;
152
153 gcnum = usb_gadget_controller_number(gadget);
154
155 debug("gcnum: %d\n", gcnum);
156 if (gcnum >= 0)
157 device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
158 else {
159 debug("%s: controller '%s' not recognized\n",
160 shortname, gadget->name);
161 device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
162 }
163
Pantelis Antoniou5a413ca2012-11-30 08:01:05 +0000164 debug("%s: calling usb_gadget_connect for "
165 "controller '%s'\n", shortname, gadget->name);
166 usb_gadget_connect(gadget);
167
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +0200168 return 0;
169
170 error:
171 g_dnl_unbind(cdev);
172 return -ENOMEM;
173}
174
175static struct usb_composite_driver g_dnl_driver = {
176 .name = NULL,
177 .dev = &device_desc,
178 .strings = g_dnl_composite_strings,
179
180 .bind = g_dnl_bind,
181 .unbind = g_dnl_unbind,
182};
183
184int g_dnl_register(const char *type)
185{
186 /* We only allow "dfu" atm, so 3 should be enough */
187 static char name[sizeof(shortname) + 3];
188 int ret;
189
190 if (!strcmp(type, "dfu")) {
191 strcpy(name, shortname);
192 strcat(name, type);
Lukasz Majewskib528f712013-03-05 12:10:17 +0100193 } else if (!strcmp(type, "ums")) {
194 strcpy(name, shortname);
195 strcat(name, type);
Lukasz Majewski1d4a0b62012-08-06 14:41:05 +0200196 } else {
197 printf("%s: unknown command: %s\n", __func__, type);
198 return -EINVAL;
199 }
200
201 g_dnl_driver.name = name;
202
203 debug("%s: g_dnl_driver.name: %s\n", __func__, g_dnl_driver.name);
204 ret = usb_composite_register(&g_dnl_driver);
205
206 if (ret) {
207 printf("%s: failed!, error: %d\n", __func__, ret);
208 return ret;
209 }
210
211 return 0;
212}
213
214void g_dnl_unregister(void)
215{
216 usb_composite_unregister(&g_dnl_driver);
217}