Blame view

drivers/usb/gadget/g_dnl.c 5.83 KB
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
1
2
3
4
5
6
  /*
   * g_dnl.c -- USB Downloader Gadget
   *
   * Copyright (C) 2012 Samsung Electronics
   * Lukasz Majewski  <l.majewski@samsung.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
7
   * SPDX-License-Identifier:	GPL-2.0+
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
8
   */
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
9
10
11
12
13
14
15
  #include <common.h>
  #include <malloc.h>
  
  #include <mmc.h>
  #include <part.h>
  
  #include <g_dnl.h>
ba4e95c9f   Lukasz Majewski   usb:g_dnl:ums: Co...
16
  #include <usb_mass_storage.h>
a6921adcf   Lukasz Majewski   usb:g_dnl:dfu: Do...
17
  #include <dfu.h>
b958fb916   Lukasz Majewski   usb:g_dnl: Suppor...
18
  #include <thor.h>
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  
  #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. ./include/configs/<board>.h
   */
  
  #define STRING_MANUFACTURER 25
  #define STRING_PRODUCT 2
cfc2d0d63   Lukasz Majewski   usb:dfu:g_dnl: Ch...
33
  /* Index of String Descriptor describing this configuration */
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
34
  #define STRING_USBDOWN 2
ec9002e4f   Heiko Schocher   usb, g_dnl: make ...
35
36
37
  /* Index of String serial */
  #define STRING_SERIAL  3
  #define MAX_STRING_SERIAL	32
cfc2d0d63   Lukasz Majewski   usb:dfu:g_dnl: Ch...
38
39
  /* Number of supported configurations */
  #define CONFIGURATION_NUMBER 1
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
40
41
  
  #define DRIVER_VERSION		"usb_dnl 2.0"
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
42
  static const char product[] = "USB download gadget";
ec9002e4f   Heiko Schocher   usb, g_dnl: make ...
43
  static char g_dnl_serial[MAX_STRING_SERIAL];
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
44
  static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
ec9002e4f   Heiko Schocher   usb, g_dnl: make ...
45
46
47
48
49
50
  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));
  }
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
51
52
53
54
55
56
57
58
59
60
61
  static struct usb_device_descriptor device_desc = {
  	.bLength = sizeof device_desc,
  	.bDescriptorType = USB_DT_DEVICE,
  
  	.bcdUSB = __constant_cpu_to_le16(0x0200),
  	.bDeviceClass = USB_CLASS_COMM,
  	.bDeviceSubClass = 0x02, /*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,
ec9002e4f   Heiko Schocher   usb, g_dnl: make ...
62
  	.iSerialNumber = STRING_SERIAL,
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
63
64
  	.bNumConfigurations = 1,
  };
c4219a82c   Lukasz Majewski   usb:dfu:g_dnl: Re...
65
66
67
68
  /*
   * static strings, in UTF-8
   * IDs for those strings are assigned dynamically at g_dnl_bind()
   */
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
69
  static struct usb_string g_dnl_string_defs[] = {
c4219a82c   Lukasz Majewski   usb:dfu:g_dnl: Re...
70
71
  	{.s = manufacturer},
  	{.s = product},
ec9002e4f   Heiko Schocher   usb, g_dnl: make ...
72
  	{.s = g_dnl_serial},
c4219a82c   Lukasz Majewski   usb:dfu:g_dnl: Re...
73
  	{ }		/* end of list */
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  };
  
  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)
  {
5a413cae6   Pantelis Antoniou   g_dnl: Issue conn...
88
  	struct usb_gadget *gadget = cdev->gadget;
7b412ab31   Lukasz Majewski   usb:g_dnl: Replac...
89
90
  	free(cdev->config);
  	cdev->config = NULL;
5a413cae6   Pantelis Antoniou   g_dnl: Issue conn...
91
  	debug("%s: calling usb_gadget_disconnect for "
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
92
93
  			"controller '%s'
  ", __func__, gadget->name);
5a413cae6   Pantelis Antoniou   g_dnl: Issue conn...
94
  	usb_gadget_disconnect(gadget);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
95
96
  	return 0;
  }
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
97
98
99
100
101
102
103
104
105
106
107
  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);
  }
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
108
109
110
  static int g_dnl_do_config(struct usb_configuration *c)
  {
  	const char *s = c->cdev->driver->name;
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
111
  	struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
112
113
114
115
  
  	debug("%s: configuration: 0x%p composite dev: 0x%p
  ",
  	      __func__, c, c->cdev);
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
116
117
118
119
  	for (; callback != g_dnl_bind_callback_end(); callback++)
  		if (!strcmp(s, callback->usb_function_name))
  			return callback->fptr(c);
  	return -ENODEV;
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
120
121
122
123
  }
  
  static int g_dnl_config_register(struct usb_composite_dev *cdev)
  {
7b412ab31   Lukasz Majewski   usb:g_dnl: Replac...
124
125
  	struct usb_configuration *config;
  	const char *name = "usb_dnload";
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
126

7b412ab31   Lukasz Majewski   usb:g_dnl: Replac...
127
128
129
  	config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config));
  	if (!config)
  		return -ENOMEM;
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
130

7b412ab31   Lukasz Majewski   usb:g_dnl: Replac...
131
132
133
134
135
136
137
138
139
  	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);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
140
  }
c5398cc96   Heiko Schocher   usb, g_dnl: make ...
141
  __weak
d6eae7b0b   Lukasz Majewski   usb:g_dnl: Add na...
142
  int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
c5398cc96   Heiko Schocher   usb, g_dnl: make ...
143
144
145
  {
  	return 0;
  }
7a0d463f5   Heiko Schocher   usb, g_dnl: make ...
146
147
148
149
  __weak int g_dnl_get_board_bcd_device_number(int gcnum)
  {
  	return gcnum;
  }
75504e959   Mateusz Zalega   usb: dfu: fix boa...
150
151
152
153
  __weak int g_dnl_board_usb_cable_connected(void)
  {
  	return -EOPNOTSUPP;
  }
7a0d463f5   Heiko Schocher   usb, g_dnl: make ...
154
155
156
157
158
159
160
161
162
163
164
  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);
  }
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  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
  ", __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;
ec9002e4f   Heiko Schocher   usb, g_dnl: make ...
187
188
189
190
191
192
  	id = usb_string_id(cdev);
  	if (id < 0)
  		return id;
  
  	g_dnl_string_defs[2].id = id;
  	device_desc.iSerialNumber = id;
d6eae7b0b   Lukasz Majewski   usb:g_dnl: Add na...
193
  	g_dnl_bind_fixup(&device_desc, cdev->driver->name);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
194
195
196
  	ret = g_dnl_config_register(cdev);
  	if (ret)
  		goto error;
7a0d463f5   Heiko Schocher   usb, g_dnl: make ...
197
  	gcnum = g_dnl_get_bcd_device_number(cdev);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
198
  	if (gcnum >= 0)
7a0d463f5   Heiko Schocher   usb, g_dnl: make ...
199
  		device_desc.bcdDevice = cpu_to_le16(gcnum);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
200
201
202
  	else {
  		debug("%s: controller '%s' not recognized
  ",
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
203
  			__func__, gadget->name);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
204
205
  		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
  	}
5a413cae6   Pantelis Antoniou   g_dnl: Issue conn...
206
  	debug("%s: calling usb_gadget_connect for "
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
207
208
  			"controller '%s'
  ", __func__, gadget->name);
5a413cae6   Pantelis Antoniou   g_dnl: Issue conn...
209
  	usb_gadget_connect(gadget);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  	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,
  };
c4d0e8560   Mateusz Zalega   USB: gadget: adde...
225
226
227
228
229
230
  /*
   * 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)
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
231
  {
25fbf96b2   Stephen Warren   USB: gadget: save...
232
  	int ret;
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
233

c4d0e8560   Mateusz Zalega   USB: gadget: adde...
234
235
  	debug("%s: g_dnl_driver.name = %s
  ", __func__, name);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
236
  	g_dnl_driver.name = name;
25fbf96b2   Stephen Warren   USB: gadget: save...
237
  	ret = usb_composite_register(&g_dnl_driver);
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
238
239
240
241
242
  	if (ret) {
  		printf("%s: failed!, error: %d
  ", __func__, ret);
  		return ret;
  	}
1d4a0b6c0   Lukasz Majewski   dfu:usb: Support ...
243
244
245
246
247
248
249
  	return 0;
  }
  
  void g_dnl_unregister(void)
  {
  	usb_composite_unregister(&g_dnl_driver);
  }