Blame view

common/usb.c 33.8 KB
affae2bff   wdenk   Initial revision
1
  /*
affae2bff   wdenk   Initial revision
2
   * Most of this source has been derived from the Linux USB
460c322f1   Wolfgang Denk   (re)enabled scsi ...
3
4
5
6
7
8
9
10
11
12
13
14
15
   * project:
   * (C) Copyright Linus Torvalds 1999
   * (C) Copyright Johannes Erdfelt 1999-2001
   * (C) Copyright Andreas Gal 1999
   * (C) Copyright Gregory P. Smith 1999
   * (C) Copyright Deti Fliegl 1999 (new USB architecture)
   * (C) Copyright Randy Dunlap 2000
   * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
   * (C) Copyright Yggdrasil Computing, Inc. 2000
   *     (usb_device_id matching changes by Adam J. Richter)
   *
   * Adapted for U-Boot:
   * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
affae2bff   wdenk   Initial revision
16
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
17
   * SPDX-License-Identifier:	GPL-2.0+
affae2bff   wdenk   Initial revision
18
   */
affae2bff   wdenk   Initial revision
19
20
21
22
23
24
25
26
27
28
29
  /*
   * How it works:
   *
   * Since this is a bootloader, the devices will not be automatic
   * (re)configured on hotplug, but after a restart of the USB the
   * device should work.
   *
   * For each transfer (except "Interrupt") we wait for completion.
   */
  #include <common.h>
  #include <command.h>
95fbfe429   Simon Glass   dm: usb: Convert ...
30
  #include <dm.h>
cf92e05c0   Simon Glass   Move ALLOC_CACHE_...
31
  #include <memalign.h>
affae2bff   wdenk   Initial revision
32
  #include <asm/processor.h>
66cf64107   Mike Frysinger   usb: use noinline...
33
  #include <linux/compiler.h>
9c998aa83   Wolfgang Denk   Fix low-level OHC...
34
  #include <linux/ctype.h>
c918261c6   Christian Eggers   USB: replace old ...
35
  #include <asm/byteorder.h>
b2fb47f18   Tom Rini   USB: Use (get|put...
36
  #include <asm/unaligned.h>
97b9eb9e6   Marek Vasut   usb: Handle -ENOD...
37
  #include <errno.h>
affae2bff   wdenk   Initial revision
38
39
  #include <usb.h>
  #ifdef CONFIG_4xx
3048bcbf0   Stefan Roese   ppc4xx: Rename 40...
40
  #include <asm/4xx_pci.h>
affae2bff   wdenk   Initial revision
41
  #endif
cd0a9de68   wdenk   * Patch by Lauren...
42
  #define USB_BUFSIZ	512
affae2bff   wdenk   Initial revision
43
  static int asynch_allowed;
e51aae382   Bartlomiej Sieka   Prevent USB comma...
44
  char usb_started; /* flag for the started/stopped USB status */
95fbfe429   Simon Glass   dm: usb: Convert ...
45
46
47
  #ifndef CONFIG_DM_USB
  static struct usb_device usb_dev[USB_MAX_DEVICE];
  static int dev_index;
93c2582fe   Lucas Stach   usb: add support ...
48
49
50
  #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
  #define CONFIG_USB_MAX_CONTROLLER_COUNT 1
  #endif
affae2bff   wdenk   Initial revision
51

affae2bff   wdenk   Initial revision
52
53
54
  /***************************************************************************
   * Init USB Device
   */
affae2bff   wdenk   Initial revision
55
56
  int usb_init(void)
  {
93c2582fe   Lucas Stach   usb: add support ...
57
58
59
  	void *ctrl;
  	struct usb_device *dev;
  	int i, start_index = 0;
d906bbc26   Hans de Goede   usb: Do not log a...
60
  	int controllers_initialized = 0;
97b9eb9e6   Marek Vasut   usb: Handle -ENOD...
61
  	int ret;
affae2bff   wdenk   Initial revision
62

6f5794a6f   Remy Bohmer   Refactoring parts...
63
64
  	dev_index = 0;
  	asynch_allowed = 1;
affae2bff   wdenk   Initial revision
65
  	usb_hub_reset();
93c2582fe   Lucas Stach   usb: add support ...
66
67
68
69
70
71
  
  	/* first make all devices unknown */
  	for (i = 0; i < USB_MAX_DEVICE; i++) {
  		memset(&usb_dev[i], 0, sizeof(struct usb_device));
  		usb_dev[i].devnum = -1;
  	}
affae2bff   wdenk   Initial revision
72
  	/* init low_level USB */
93c2582fe   Lucas Stach   usb: add support ...
73
74
75
  	for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
  		/* init low_level USB */
  		printf("USB%d:   ", i);
97b9eb9e6   Marek Vasut   usb: Handle -ENOD...
76
77
78
79
  		ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl);
  		if (ret == -ENODEV) {	/* No such device. */
  			puts("Port not available.
  ");
d906bbc26   Hans de Goede   usb: Do not log a...
80
  			controllers_initialized++;
97b9eb9e6   Marek Vasut   usb: Handle -ENOD...
81
82
83
84
  			continue;
  		}
  
  		if (ret) {		/* Other error. */
93c2582fe   Lucas Stach   usb: add support ...
85
86
87
88
89
90
91
92
  			puts("lowlevel init failed
  ");
  			continue;
  		}
  		/*
  		 * lowlevel init is OK, now scan the bus for devices
  		 * i.e. search HUBs and configure them
  		 */
d906bbc26   Hans de Goede   usb: Do not log a...
93
  		controllers_initialized++;
93c2582fe   Lucas Stach   usb: add support ...
94
95
  		start_index = dev_index;
  		printf("scanning bus %d for devices... ", i);
79b588872   Simon Glass   dm: usb: Adjust u...
96
97
  		ret = usb_alloc_new_device(ctrl, &dev);
  		if (ret)
8879be885   Paul Kocialkowski   usb: Check usb_ne...
98
  			break;
93c2582fe   Lucas Stach   usb: add support ...
99
100
101
102
  		/*
  		 * device 0 is always present
  		 * (root hub, so let it analyze)
  		 */
8879be885   Paul Kocialkowski   usb: Check usb_ne...
103
104
  		ret = usb_new_device(dev);
  		if (ret)
79b588872   Simon Glass   dm: usb: Adjust u...
105
  			usb_free_device(dev->controller);
93c2582fe   Lucas Stach   usb: add support ...
106

8879be885   Paul Kocialkowski   usb: Check usb_ne...
107
  		if (start_index == dev_index) {
93c2582fe   Lucas Stach   usb: add support ...
108
109
  			puts("No USB Device found
  ");
8879be885   Paul Kocialkowski   usb: Check usb_ne...
110
111
  			continue;
  		} else {
93c2582fe   Lucas Stach   usb: add support ...
112
113
114
  			printf("%d USB Device(s) found
  ",
  				dev_index - start_index);
8879be885   Paul Kocialkowski   usb: Check usb_ne...
115
  		}
93c2582fe   Lucas Stach   usb: add support ...
116

e51aae382   Bartlomiej Sieka   Prevent USB comma...
117
  		usb_started = 1;
93c2582fe   Lucas Stach   usb: add support ...
118
  	}
ceb4972a8   Vivek Gautam   usb: common: Weed...
119
120
  	debug("scan end
  ");
93c2582fe   Lucas Stach   usb: add support ...
121
  	/* if we were not able to find at least one working bus, bail out */
d906bbc26   Hans de Goede   usb: Do not log a...
122
  	if (controllers_initialized == 0)
93c2582fe   Lucas Stach   usb: add support ...
123
124
  		puts("USB error: all controllers failed lowlevel init
  ");
93c2582fe   Lucas Stach   usb: add support ...
125

5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
126
  	return usb_started ? 0 : -ENODEV;
affae2bff   wdenk   Initial revision
127
128
129
130
131
132
133
  }
  
  /******************************************************************************
   * Stop USB this stops the LowLevel Part and deregisters USB devices.
   */
  int usb_stop(void)
  {
93c2582fe   Lucas Stach   usb: add support ...
134
  	int i;
eba1f2fc7   Remy Bohmer   Make usb-stop() s...
135
136
137
138
139
  
  	if (usb_started) {
  		asynch_allowed = 1;
  		usb_started = 0;
  		usb_hub_reset();
93c2582fe   Lucas Stach   usb: add support ...
140
141
142
143
144
145
  
  		for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
  			if (usb_lowlevel_stop(i))
  				printf("failed to stop USB controller %d
  ", i);
  		}
eba1f2fc7   Remy Bohmer   Make usb-stop() s...
146
  	}
93c2582fe   Lucas Stach   usb: add support ...
147
148
  
  	return 0;
affae2bff   wdenk   Initial revision
149
  }
08f3bb0bc   Vincent Palatin   usb: add device c...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  /******************************************************************************
   * Detect if a USB device has been plugged or unplugged.
   */
  int usb_detect_change(void)
  {
  	int i, j;
  	int change = 0;
  
  	for (j = 0; j < USB_MAX_DEVICE; j++) {
  		for (i = 0; i < usb_dev[j].maxchild; i++) {
  			struct usb_port_status status;
  
  			if (usb_get_port_status(&usb_dev[j], i + 1,
  						&status) < 0)
  				/* USB request failed */
  				continue;
  
  			if (le16_to_cpu(status.wPortChange) &
  			    USB_PORT_STAT_C_CONNECTION)
  				change++;
  		}
  	}
  
  	return change;
  }
affae2bff   wdenk   Initial revision
175
176
177
  /*
   * disables the asynch behaviour of the control message. This is used for data
   * transfers that uses the exclusiv access to the control and bulk messages.
89d48367e   Simon Glass   Add USB host ethe...
178
   * Returns the old value so it can be restored later.
affae2bff   wdenk   Initial revision
179
   */
89d48367e   Simon Glass   Add USB host ethe...
180
  int usb_disable_asynch(int disable)
affae2bff   wdenk   Initial revision
181
  {
89d48367e   Simon Glass   Add USB host ethe...
182
  	int old_value = asynch_allowed;
6f5794a6f   Remy Bohmer   Refactoring parts...
183
  	asynch_allowed = !disable;
89d48367e   Simon Glass   Add USB host ethe...
184
  	return old_value;
affae2bff   wdenk   Initial revision
185
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
186
  #endif /* !CONFIG_DM_USB */
affae2bff   wdenk   Initial revision
187
188
189
190
191
192
193
194
195
196
197
  
  
  /*-------------------------------------------------------------------
   * Message wrappers.
   *
   */
  
  /*
   * submits an Interrupt Message
   */
  int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
6f5794a6f   Remy Bohmer   Refactoring parts...
198
  			void *buffer, int transfer_len, int interval)
affae2bff   wdenk   Initial revision
199
  {
6f5794a6f   Remy Bohmer   Refactoring parts...
200
  	return submit_int_msg(dev, pipe, buffer, transfer_len, interval);
affae2bff   wdenk   Initial revision
201
202
203
204
205
206
207
208
  }
  
  /*
   * submits a control message and waits for comletion (at least timeout * 1ms)
   * If timeout is 0, we don't wait for completion (used as example to set and
   * clear keyboards LEDs). For data transfers, (storage transfers) we don't
   * allow control messages with 0 timeout, by previousely resetting the flag
   * asynch_allowed (usb_disable_asynch(1)).
a6f70a3d1   Vagrant Cascadian   Fix spelling of "...
209
   * returns the transferred length if OK or -1 if error. The transferred length
affae2bff   wdenk   Initial revision
210
211
212
213
214
215
216
   * and the current status are stored in the dev->act_len and dev->status.
   */
  int usb_control_msg(struct usb_device *dev, unsigned int pipe,
  			unsigned char request, unsigned char requesttype,
  			unsigned short value, unsigned short index,
  			void *data, unsigned short size, int timeout)
  {
f57661394   Puneet Saxena   USB: Align buffer...
217
  	ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1);
651d95c8e   Hans de Goede   usb: usb_control_...
218
  	int err;
e159e4868   Marek Vasut   USB: Make struct ...
219

6f5794a6f   Remy Bohmer   Refactoring parts...
220
221
  	if ((timeout == 0) && (!asynch_allowed)) {
  		/* request for a asynch control pipe is not allowed */
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
222
  		return -EINVAL;
6f5794a6f   Remy Bohmer   Refactoring parts...
223
  	}
9c998aa83   Wolfgang Denk   Fix low-level OHC...
224

affae2bff   wdenk   Initial revision
225
  	/* set setup command */
f57661394   Puneet Saxena   USB: Align buffer...
226
227
228
229
230
  	setup_packet->requesttype = requesttype;
  	setup_packet->request = request;
  	setup_packet->value = cpu_to_le16(value);
  	setup_packet->index = cpu_to_le16(index);
  	setup_packet->length = cpu_to_le16(size);
ceb4972a8   Vivek Gautam   usb: common: Weed...
231
232
233
234
  	debug("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
  	      "value 0x%X index 0x%X length 0x%X
  ",
  	      request, requesttype, value, index, size);
6f5794a6f   Remy Bohmer   Refactoring parts...
235
  	dev->status = USB_ST_NOT_PROC; /*not yet processed */
affae2bff   wdenk   Initial revision
236

651d95c8e   Hans de Goede   usb: usb_control_...
237
238
239
  	err = submit_control_msg(dev, pipe, data, size, setup_packet);
  	if (err < 0)
  		return err;
6f5794a6f   Remy Bohmer   Refactoring parts...
240
  	if (timeout == 0)
affae2bff   wdenk   Initial revision
241
  		return (int)size;
6f5794a6f   Remy Bohmer   Refactoring parts...
242

84d36b301   Remy Bohmer   USB: usb_control_...
243
244
245
246
247
248
249
250
  	/*
  	 * Wait for status to update until timeout expires, USB driver
  	 * interrupt handler may set the status when the USB operation has
  	 * been completed.
  	 */
  	while (timeout--) {
  		if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
  			break;
5b84dd67c   Mike Frysinger   usb: replace wait...
251
  		mdelay(1);
488672084   Remy Bohmer   fix USB initialis...
252
  	}
84d36b301   Remy Bohmer   USB: usb_control_...
253
254
  	if (dev->status)
  		return -1;
488672084   Remy Bohmer   fix USB initialis...
255
256
  
  	return dev->act_len;
84d36b301   Remy Bohmer   USB: usb_control_...
257

affae2bff   wdenk   Initial revision
258
259
260
261
  }
  
  /*-------------------------------------------------------------------
   * submits bulk message, and waits for completion. returns 0 if Ok or
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
262
   * negative if Error.
affae2bff   wdenk   Initial revision
263
264
265
266
267
268
   * synchronous behavior
   */
  int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
  			void *data, int len, int *actual_length, int timeout)
  {
  	if (len < 0)
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
269
  		return -EINVAL;
6f5794a6f   Remy Bohmer   Refactoring parts...
270
  	dev->status = USB_ST_NOT_PROC; /*not yet processed */
fd06028df   Ilya Yanok   usb: check return...
271
  	if (submit_bulk_msg(dev, pipe, data, len) < 0)
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
272
  		return -EIO;
6f5794a6f   Remy Bohmer   Refactoring parts...
273
274
  	while (timeout--) {
  		if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
affae2bff   wdenk   Initial revision
275
  			break;
5b84dd67c   Mike Frysinger   usb: replace wait...
276
  		mdelay(1);
affae2bff   wdenk   Initial revision
277
  	}
6f5794a6f   Remy Bohmer   Refactoring parts...
278
279
  	*actual_length = dev->act_len;
  	if (dev->status == 0)
affae2bff   wdenk   Initial revision
280
281
  		return 0;
  	else
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
282
  		return -EIO;
affae2bff   wdenk   Initial revision
283
284
285
286
287
288
289
290
291
292
293
  }
  
  
  /*-------------------------------------------------------------------
   * Max Packet stuff
   */
  
  /*
   * returns the max packet size, depending on the pipe direction and
   * the configurations values
   */
6f5794a6f   Remy Bohmer   Refactoring parts...
294
  int usb_maxpacket(struct usb_device *dev, unsigned long pipe)
affae2bff   wdenk   Initial revision
295
  {
6f5794a6f   Remy Bohmer   Refactoring parts...
296
297
  	/* direction is out -> use emaxpacket out */
  	if ((pipe & USB_DIR_IN) == 0)
de39f8c19   Michael Trimarchi   USB style patch, ...
298
  		return dev->epmaxpacketout[((pipe>>15) & 0xf)];
affae2bff   wdenk   Initial revision
299
  	else
de39f8c19   Michael Trimarchi   USB style patch, ...
300
  		return dev->epmaxpacketin[((pipe>>15) & 0xf)];
affae2bff   wdenk   Initial revision
301
  }
5e8baf878   Marek Vasut   GCC4.6: Fix commo...
302
303
  /*
   * The routine usb_set_maxpacket_ep() is extracted from the loop of routine
be19d324e   Remy Bohmer   Fix for USB stick...
304
305
306
307
308
309
   * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine
   * when it is inlined in 1 single routine. What happens is that the register r3
   * is used as loop-count 'i', but gets overwritten later on.
   * This is clearly a compiler bug, but it is easier to workaround it here than
   * to update the compiler (Occurs with at least several GCC 4.{1,2},x
   * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM)
5e8baf878   Marek Vasut   GCC4.6: Fix commo...
310
311
   *
   * NOTE: Similar behaviour was observed with GCC4.6 on ARMv5.
be19d324e   Remy Bohmer   Fix for USB stick...
312
   */
66cf64107   Mike Frysinger   usb: use noinline...
313
  static void noinline
5e8baf878   Marek Vasut   GCC4.6: Fix commo...
314
  usb_set_maxpacket_ep(struct usb_device *dev, int if_idx, int ep_idx)
be19d324e   Remy Bohmer   Fix for USB stick...
315
316
  {
  	int b;
5e8baf878   Marek Vasut   GCC4.6: Fix commo...
317
  	struct usb_endpoint_descriptor *ep;
b2fb47f18   Tom Rini   USB: Use (get|put...
318
  	u16 ep_wMaxPacketSize;
5e8baf878   Marek Vasut   GCC4.6: Fix commo...
319
320
  
  	ep = &dev->config.if_desc[if_idx].ep_desc[ep_idx];
be19d324e   Remy Bohmer   Fix for USB stick...
321
322
  
  	b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
b2fb47f18   Tom Rini   USB: Use (get|put...
323
  	ep_wMaxPacketSize = get_unaligned(&ep->wMaxPacketSize);
be19d324e   Remy Bohmer   Fix for USB stick...
324
325
326
327
  
  	if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
  						USB_ENDPOINT_XFER_CONTROL) {
  		/* Control => bidirectional */
b2fb47f18   Tom Rini   USB: Use (get|put...
328
329
  		dev->epmaxpacketout[b] = ep_wMaxPacketSize;
  		dev->epmaxpacketin[b] = ep_wMaxPacketSize;
ceb4972a8   Vivek Gautam   usb: common: Weed...
330
331
332
  		debug("##Control EP epmaxpacketout/in[%d] = %d
  ",
  		      b, dev->epmaxpacketin[b]);
be19d324e   Remy Bohmer   Fix for USB stick...
333
334
335
  	} else {
  		if ((ep->bEndpointAddress & 0x80) == 0) {
  			/* OUT Endpoint */
b2fb47f18   Tom Rini   USB: Use (get|put...
336
337
  			if (ep_wMaxPacketSize > dev->epmaxpacketout[b]) {
  				dev->epmaxpacketout[b] = ep_wMaxPacketSize;
ceb4972a8   Vivek Gautam   usb: common: Weed...
338
339
340
  				debug("##EP epmaxpacketout[%d] = %d
  ",
  				      b, dev->epmaxpacketout[b]);
be19d324e   Remy Bohmer   Fix for USB stick...
341
342
343
  			}
  		} else {
  			/* IN Endpoint */
b2fb47f18   Tom Rini   USB: Use (get|put...
344
345
  			if (ep_wMaxPacketSize > dev->epmaxpacketin[b]) {
  				dev->epmaxpacketin[b] = ep_wMaxPacketSize;
ceb4972a8   Vivek Gautam   usb: common: Weed...
346
347
348
  				debug("##EP epmaxpacketin[%d] = %d
  ",
  				      b, dev->epmaxpacketin[b]);
be19d324e   Remy Bohmer   Fix for USB stick...
349
350
351
352
  			}
  		} /* if out */
  	} /* if control */
  }
affae2bff   wdenk   Initial revision
353
354
355
  /*
   * set the max packed value of all endpoints in the given configuration
   */
c08b1b264   Marek Vasut   USB: Staticize in...
356
  static int usb_set_maxpacket(struct usb_device *dev)
affae2bff   wdenk   Initial revision
357
  {
be19d324e   Remy Bohmer   Fix for USB stick...
358
  	int i, ii;
affae2bff   wdenk   Initial revision
359

8f8bd565f   Tom Rix   USB Consolidate d...
360
361
  	for (i = 0; i < dev->config.desc.bNumInterfaces; i++)
  		for (ii = 0; ii < dev->config.if_desc[i].desc.bNumEndpoints; ii++)
5e8baf878   Marek Vasut   GCC4.6: Fix commo...
362
  			usb_set_maxpacket_ep(dev, i, ii);
affae2bff   wdenk   Initial revision
363

affae2bff   wdenk   Initial revision
364
365
366
367
368
369
  	return 0;
  }
  
  /*******************************************************************************
   * Parse the config, located in buffer, and fills the dev->config structure.
   * Note that all little/big endian swapping are done automatically.
eaf3e613e   Julius Werner   usb: Use well-kno...
370
   * (wTotalLength has already been swapped and sanitized when it was read.)
affae2bff   wdenk   Initial revision
371
   */
c08b1b264   Marek Vasut   USB: Staticize in...
372
373
  static int usb_parse_config(struct usb_device *dev,
  			unsigned char *buffer, int cfgno)
affae2bff   wdenk   Initial revision
374
375
  {
  	struct usb_descriptor_header *head;
7455af41d   Bartlomiej Sieka   Add rudimentary h...
376
  	int index, ifno, epno, curr_if_num;
b2fb47f18   Tom Rini   USB: Use (get|put...
377
  	u16 ep_wMaxPacketSize;
605bd75af   Vivek Gautam   USB: Some cleanup...
378
  	struct usb_interface *if_desc = NULL;
7455af41d   Bartlomiej Sieka   Add rudimentary h...
379
380
381
382
383
384
385
  
  	ifno = -1;
  	epno = -1;
  	curr_if_num = -1;
  
  	dev->configno = cfgno;
  	head = (struct usb_descriptor_header *) &buffer[0];
6f5794a6f   Remy Bohmer   Refactoring parts...
386
387
388
389
  	if (head->bDescriptorType != USB_DT_CONFIG) {
  		printf(" ERROR: NOT USB_CONFIG_DESC %x
  ",
  			head->bDescriptorType);
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
390
  		return -EINVAL;
affae2bff   wdenk   Initial revision
391
  	}
eaf3e613e   Julius Werner   usb: Use well-kno...
392
393
394
  	if (head->bLength != USB_DT_CONFIG_SIZE) {
  		printf("ERROR: Invalid USB CFG length (%d)
  ", head->bLength);
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
395
  		return -EINVAL;
eaf3e613e   Julius Werner   usb: Use well-kno...
396
397
  	}
  	memcpy(&dev->config, head, USB_DT_CONFIG_SIZE);
7455af41d   Bartlomiej Sieka   Add rudimentary h...
398
  	dev->config.no_of_if = 0;
affae2bff   wdenk   Initial revision
399

8f8bd565f   Tom Rix   USB Consolidate d...
400
  	index = dev->config.desc.bLength;
6f5794a6f   Remy Bohmer   Refactoring parts...
401
402
  	/* Ok the first entry must be a configuration entry,
  	 * now process the others */
7455af41d   Bartlomiej Sieka   Add rudimentary h...
403
  	head = (struct usb_descriptor_header *) &buffer[index];
eaf3e613e   Julius Werner   usb: Use well-kno...
404
  	while (index + 1 < dev->config.desc.wTotalLength && head->bLength) {
6f5794a6f   Remy Bohmer   Refactoring parts...
405
406
  		switch (head->bDescriptorType) {
  		case USB_DT_INTERFACE:
eaf3e613e   Julius Werner   usb: Use well-kno...
407
408
409
410
411
412
413
414
415
416
417
418
  			if (head->bLength != USB_DT_INTERFACE_SIZE) {
  				printf("ERROR: Invalid USB IF length (%d)
  ",
  					head->bLength);
  				break;
  			}
  			if (index + USB_DT_INTERFACE_SIZE >
  			    dev->config.desc.wTotalLength) {
  				puts("USB IF descriptor overflowed buffer!
  ");
  				break;
  			}
6f5794a6f   Remy Bohmer   Refactoring parts...
419
  			if (((struct usb_interface_descriptor *) \
eaf3e613e   Julius Werner   usb: Use well-kno...
420
  			     head)->bInterfaceNumber != curr_if_num) {
6f5794a6f   Remy Bohmer   Refactoring parts...
421
422
  				/* this is a new interface, copy new desc */
  				ifno = dev->config.no_of_if;
eaf3e613e   Julius Werner   usb: Use well-kno...
423
424
425
426
  				if (ifno >= USB_MAXINTERFACES) {
  					puts("Too many USB interfaces!
  ");
  					/* try to go on with what we have */
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
427
  					return -EINVAL;
eaf3e613e   Julius Werner   usb: Use well-kno...
428
  				}
605bd75af   Vivek Gautam   USB: Some cleanup...
429
  				if_desc = &dev->config.if_desc[ifno];
6f5794a6f   Remy Bohmer   Refactoring parts...
430
  				dev->config.no_of_if++;
eaf3e613e   Julius Werner   usb: Use well-kno...
431
432
  				memcpy(if_desc, head,
  					USB_DT_INTERFACE_SIZE);
605bd75af   Vivek Gautam   USB: Some cleanup...
433
434
  				if_desc->no_of_ep = 0;
  				if_desc->num_altsetting = 1;
6f5794a6f   Remy Bohmer   Refactoring parts...
435
  				curr_if_num =
605bd75af   Vivek Gautam   USB: Some cleanup...
436
  				     if_desc->desc.bInterfaceNumber;
6f5794a6f   Remy Bohmer   Refactoring parts...
437
438
  			} else {
  				/* found alternate setting for the interface */
605bd75af   Vivek Gautam   USB: Some cleanup...
439
440
441
442
  				if (ifno >= 0) {
  					if_desc = &dev->config.if_desc[ifno];
  					if_desc->num_altsetting++;
  				}
6f5794a6f   Remy Bohmer   Refactoring parts...
443
444
445
  			}
  			break;
  		case USB_DT_ENDPOINT:
eaf3e613e   Julius Werner   usb: Use well-kno...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
  			if (head->bLength != USB_DT_ENDPOINT_SIZE) {
  				printf("ERROR: Invalid USB EP length (%d)
  ",
  					head->bLength);
  				break;
  			}
  			if (index + USB_DT_ENDPOINT_SIZE >
  			    dev->config.desc.wTotalLength) {
  				puts("USB EP descriptor overflowed buffer!
  ");
  				break;
  			}
  			if (ifno < 0) {
  				puts("Endpoint descriptor out of order!
  ");
  				break;
  			}
6f5794a6f   Remy Bohmer   Refactoring parts...
463
  			epno = dev->config.if_desc[ifno].no_of_ep;
605bd75af   Vivek Gautam   USB: Some cleanup...
464
  			if_desc = &dev->config.if_desc[ifno];
447b9cdf2   Peng Fan   common: usb: fix ...
465
  			if (epno >= USB_MAXENDPOINTS) {
eaf3e613e   Julius Werner   usb: Use well-kno...
466
467
468
  				printf("Interface %d has too many endpoints!
  ",
  					if_desc->desc.bInterfaceNumber);
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
469
  				return -EINVAL;
eaf3e613e   Julius Werner   usb: Use well-kno...
470
  			}
6f5794a6f   Remy Bohmer   Refactoring parts...
471
  			/* found an endpoint */
605bd75af   Vivek Gautam   USB: Some cleanup...
472
  			if_desc->no_of_ep++;
eaf3e613e   Julius Werner   usb: Use well-kno...
473
474
  			memcpy(&if_desc->ep_desc[epno], head,
  				USB_DT_ENDPOINT_SIZE);
b2fb47f18   Tom Rini   USB: Use (get|put...
475
476
477
478
479
480
481
482
483
  			ep_wMaxPacketSize = get_unaligned(&dev->config.\
  							if_desc[ifno].\
  							ep_desc[epno].\
  							wMaxPacketSize);
  			put_unaligned(le16_to_cpu(ep_wMaxPacketSize),
  					&dev->config.\
  					if_desc[ifno].\
  					ep_desc[epno].\
  					wMaxPacketSize);
ceb4972a8   Vivek Gautam   usb: common: Weed...
484
485
  			debug("if %d, ep %d
  ", ifno, epno);
6f5794a6f   Remy Bohmer   Refactoring parts...
486
  			break;
6497c6670   Vivek Gautam   USB: SS: Add supp...
487
  		case USB_DT_SS_ENDPOINT_COMP:
eaf3e613e   Julius Werner   usb: Use well-kno...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
  			if (head->bLength != USB_DT_SS_EP_COMP_SIZE) {
  				printf("ERROR: Invalid USB EPC length (%d)
  ",
  					head->bLength);
  				break;
  			}
  			if (index + USB_DT_SS_EP_COMP_SIZE >
  			    dev->config.desc.wTotalLength) {
  				puts("USB EPC descriptor overflowed buffer!
  ");
  				break;
  			}
  			if (ifno < 0 || epno < 0) {
  				puts("EPC descriptor out of order!
  ");
  				break;
  			}
6497c6670   Vivek Gautam   USB: SS: Add supp...
505
  			if_desc = &dev->config.if_desc[ifno];
eaf3e613e   Julius Werner   usb: Use well-kno...
506
507
  			memcpy(&if_desc->ss_ep_comp_desc[epno], head,
  				USB_DT_SS_EP_COMP_SIZE);
6497c6670   Vivek Gautam   USB: SS: Add supp...
508
  			break;
6f5794a6f   Remy Bohmer   Refactoring parts...
509
510
  		default:
  			if (head->bLength == 0)
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
511
  				return -EINVAL;
6f5794a6f   Remy Bohmer   Refactoring parts...
512

ceb4972a8   Vivek Gautam   usb: common: Weed...
513
514
515
  			debug("unknown Description Type : %x
  ",
  			      head->bDescriptorType);
6f5794a6f   Remy Bohmer   Refactoring parts...
516

ceb4972a8   Vivek Gautam   usb: common: Weed...
517
  #ifdef DEBUG
6f5794a6f   Remy Bohmer   Refactoring parts...
518
  			{
fad2e1b06   Wolfgang Denk   common/usb.c: fix...
519
  				unsigned char *ch = (unsigned char *)head;
ceb4972a8   Vivek Gautam   usb: common: Weed...
520
  				int i;
6f5794a6f   Remy Bohmer   Refactoring parts...
521
  				for (i = 0; i < head->bLength; i++)
ceb4972a8   Vivek Gautam   usb: common: Weed...
522
523
524
525
526
  					debug("%02X ", *ch++);
  				debug("
  
  
  ");
6f5794a6f   Remy Bohmer   Refactoring parts...
527
  			}
ceb4972a8   Vivek Gautam   usb: common: Weed...
528
  #endif
6f5794a6f   Remy Bohmer   Refactoring parts...
529
  			break;
affae2bff   wdenk   Initial revision
530
  		}
7455af41d   Bartlomiej Sieka   Add rudimentary h...
531
532
  		index += head->bLength;
  		head = (struct usb_descriptor_header *)&buffer[index];
affae2bff   wdenk   Initial revision
533
  	}
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
534
  	return 0;
affae2bff   wdenk   Initial revision
535
536
537
538
539
540
541
542
543
544
  }
  
  /***********************************************************************
   * Clears an endpoint
   * endp: endpoint number in bits 0-3;
   * direction flag in bit 7 (1 = IN, 0 = OUT)
   */
  int usb_clear_halt(struct usb_device *dev, int pipe)
  {
  	int result;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
545
  	int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
affae2bff   wdenk   Initial revision
546
547
  
  	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
6f5794a6f   Remy Bohmer   Refactoring parts...
548
549
  				 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
  				 endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
affae2bff   wdenk   Initial revision
550
551
552
553
  
  	/* don't clear if failed */
  	if (result < 0)
  		return result;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
554

095b8a379   Wolfgang Denk   Coding style cleanup
555
  	/*
9c998aa83   Wolfgang Denk   Fix low-level OHC...
556
557
558
  	 * NOTE: we do not get status and verify reset was successful
  	 * as some devices are reported to lock up upon this check..
  	 */
affae2bff   wdenk   Initial revision
559
  	usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
9c998aa83   Wolfgang Denk   Fix low-level OHC...
560

affae2bff   wdenk   Initial revision
561
562
563
564
565
566
567
568
569
  	/* toggle is reset on clear */
  	usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
  	return 0;
  }
  
  
  /**********************************************************************
   * get_descriptor type
   */
c08b1b264   Marek Vasut   USB: Staticize in...
570
  static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
6f5794a6f   Remy Bohmer   Refactoring parts...
571
  			unsigned char index, void *buf, int size)
affae2bff   wdenk   Initial revision
572
573
  {
  	int res;
53677ef18   Wolfgang Denk   Big white-space c...
574
  	res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
affae2bff   wdenk   Initial revision
575
576
577
578
579
580
581
  			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
  			(type << 8) + index, 0,
  			buf, size, USB_CNTL_TIMEOUT);
  	return res;
  }
  
  /**********************************************************************
c75f57fba   Stefan Brüns   usb: Alloc buffer...
582
   * gets len of configuration cfgno
affae2bff   wdenk   Initial revision
583
   */
c75f57fba   Stefan Brüns   usb: Alloc buffer...
584
  int usb_get_configuration_len(struct usb_device *dev, int cfgno)
affae2bff   wdenk   Initial revision
585
  {
53677ef18   Wolfgang Denk   Big white-space c...
586
  	int result;
c75f57fba   Stefan Brüns   usb: Alloc buffer...
587
  	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 9);
c60795f41   Ilya Yanok   usb: use linux/us...
588
  	struct usb_config_descriptor *config;
affae2bff   wdenk   Initial revision
589

c60795f41   Ilya Yanok   usb: use linux/us...
590
  	config = (struct usb_config_descriptor *)&buffer[0];
488672084   Remy Bohmer   fix USB initialis...
591
592
  	result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9);
  	if (result < 9) {
affae2bff   wdenk   Initial revision
593
  		if (result < 0)
6f5794a6f   Remy Bohmer   Refactoring parts...
594
595
596
  			printf("unable to get descriptor, error %lX
  ",
  				dev->status);
affae2bff   wdenk   Initial revision
597
  		else
6f5794a6f   Remy Bohmer   Refactoring parts...
598
  			printf("config descriptor too short " \
488672084   Remy Bohmer   fix USB initialis...
599
600
  				"(expected %i, got %i)
  ", 9, result);
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
601
  		return -EIO;
affae2bff   wdenk   Initial revision
602
  	}
c75f57fba   Stefan Brüns   usb: Alloc buffer...
603
604
  	return le16_to_cpu(config->wTotalLength);
  }
affae2bff   wdenk   Initial revision
605

c75f57fba   Stefan Brüns   usb: Alloc buffer...
606
607
608
609
610
611
612
613
  /**********************************************************************
   * gets configuration cfgno and store it in the buffer
   */
  int usb_get_configuration_no(struct usb_device *dev, int cfgno,
  			     unsigned char *buffer, int length)
  {
  	int result;
  	struct usb_config_descriptor *config;
cd0a9de68   wdenk   * Patch by Lauren...
614

c75f57fba   Stefan Brüns   usb: Alloc buffer...
615
  	config = (struct usb_config_descriptor *)&buffer[0];
eaf3e613e   Julius Werner   usb: Use well-kno...
616
  	result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length);
c75f57fba   Stefan Brüns   usb: Alloc buffer...
617
618
619
620
  	debug("get_conf_no %d Result %d, wLength %d
  ", cfgno, result,
  	      le16_to_cpu(config->wTotalLength));
  	config->wTotalLength = result; /* validated, with CPU byte order */
eaf3e613e   Julius Werner   usb: Use well-kno...
621

affae2bff   wdenk   Initial revision
622
623
624
625
626
627
628
  	return result;
  }
  
  /********************************************************************
   * set address of a device to the value in dev->devnum.
   * This can only be done by addressing the device via the default address (0)
   */
c08b1b264   Marek Vasut   USB: Staticize in...
629
  static int usb_set_address(struct usb_device *dev)
affae2bff   wdenk   Initial revision
630
631
  {
  	int res;
ceb4972a8   Vivek Gautam   usb: common: Weed...
632
633
  	debug("set address %d
  ", dev->devnum);
6f5794a6f   Remy Bohmer   Refactoring parts...
634
635
636
637
  	res = usb_control_msg(dev, usb_snddefctrl(dev),
  				USB_REQ_SET_ADDRESS, 0,
  				(dev->devnum), 0,
  				NULL, 0, USB_CNTL_TIMEOUT);
affae2bff   wdenk   Initial revision
638
639
640
641
642
643
644
645
  	return res;
  }
  
  /********************************************************************
   * set interface number to interface
   */
  int usb_set_interface(struct usb_device *dev, int interface, int alternate)
  {
8f8bd565f   Tom Rix   USB Consolidate d...
646
  	struct usb_interface *if_face = NULL;
affae2bff   wdenk   Initial revision
647
  	int ret, i;
8f8bd565f   Tom Rix   USB Consolidate d...
648
649
  	for (i = 0; i < dev->config.desc.bNumInterfaces; i++) {
  		if (dev->config.if_desc[i].desc.bInterfaceNumber == interface) {
affae2bff   wdenk   Initial revision
650
651
652
653
654
655
  			if_face = &dev->config.if_desc[i];
  			break;
  		}
  	}
  	if (!if_face) {
  		printf("selecting invalid interface %d", interface);
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
656
  		return -EINVAL;
affae2bff   wdenk   Initial revision
657
  	}
7455af41d   Bartlomiej Sieka   Add rudimentary h...
658
659
  	/*
  	 * We should return now for devices with only one alternate setting.
6f5794a6f   Remy Bohmer   Refactoring parts...
660
661
662
663
  	 * According to 9.4.10 of the Universal Serial Bus Specification
  	 * Revision 2.0 such devices can return with a STALL. This results in
  	 * some USB sticks timeouting during initialization and then being
  	 * unusable in U-Boot.
7455af41d   Bartlomiej Sieka   Add rudimentary h...
664
665
666
  	 */
  	if (if_face->num_altsetting == 1)
  		return 0;
affae2bff   wdenk   Initial revision
667

6f5794a6f   Remy Bohmer   Refactoring parts...
668
669
670
671
672
  	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  				USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
  				alternate, interface, NULL, 0,
  				USB_CNTL_TIMEOUT * 5);
  	if (ret < 0)
affae2bff   wdenk   Initial revision
673
  		return ret;
affae2bff   wdenk   Initial revision
674
675
676
677
678
679
  	return 0;
  }
  
  /********************************************************************
   * set configuration number to configuration
   */
c08b1b264   Marek Vasut   USB: Staticize in...
680
  static int usb_set_configuration(struct usb_device *dev, int configuration)
affae2bff   wdenk   Initial revision
681
682
  {
  	int res;
ceb4972a8   Vivek Gautam   usb: common: Weed...
683
684
  	debug("set configuration %d
  ", configuration);
affae2bff   wdenk   Initial revision
685
  	/* set setup command */
6f5794a6f   Remy Bohmer   Refactoring parts...
686
687
688
689
690
  	res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  				USB_REQ_SET_CONFIGURATION, 0,
  				configuration, 0,
  				NULL, 0, USB_CNTL_TIMEOUT);
  	if (res == 0) {
affae2bff   wdenk   Initial revision
691
692
693
  		dev->toggle[0] = 0;
  		dev->toggle[1] = 0;
  		return 0;
6f5794a6f   Remy Bohmer   Refactoring parts...
694
  	} else
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
695
  		return -EIO;
affae2bff   wdenk   Initial revision
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
  }
  
  /********************************************************************
   * set protocol to protocol
   */
  int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
  {
  	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  		USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
  		protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
  }
  
  /********************************************************************
   * set idle
   */
  int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
  {
  	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  		USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
  		(duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
  }
  
  /********************************************************************
   * get report
   */
6f5794a6f   Remy Bohmer   Refactoring parts...
721
722
  int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type,
  		   unsigned char id, void *buf, int size)
affae2bff   wdenk   Initial revision
723
724
  {
  	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
6f5794a6f   Remy Bohmer   Refactoring parts...
725
726
727
  			USB_REQ_GET_REPORT,
  			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
  			(type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
affae2bff   wdenk   Initial revision
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  }
  
  /********************************************************************
   * get class descriptor
   */
  int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
  		unsigned char type, unsigned char id, void *buf, int size)
  {
  	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
  		USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
  		(type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
  }
  
  /********************************************************************
   * get string index in buffer
   */
c08b1b264   Marek Vasut   USB: Staticize in...
744
  static int usb_get_string(struct usb_device *dev, unsigned short langid,
6f5794a6f   Remy Bohmer   Refactoring parts...
745
  		   unsigned char index, void *buf, int size)
affae2bff   wdenk   Initial revision
746
  {
9c998aa83   Wolfgang Denk   Fix low-level OHC...
747
748
749
750
751
752
753
  	int i;
  	int result;
  
  	for (i = 0; i < 3; ++i) {
  		/* some devices are flaky */
  		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
  			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
095b8a379   Wolfgang Denk   Coding style cleanup
754
  			(USB_DT_STRING << 8) + index, langid, buf, size,
9c998aa83   Wolfgang Denk   Fix low-level OHC...
755
756
757
758
  			USB_CNTL_TIMEOUT);
  
  		if (result > 0)
  			break;
095b8a379   Wolfgang Denk   Coding style cleanup
759
  	}
9c998aa83   Wolfgang Denk   Fix low-level OHC...
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
  	return result;
  }
  
  
  static void usb_try_string_workarounds(unsigned char *buf, int *length)
  {
  	int newlength, oldlength = *length;
  
  	for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
  		if (!isprint(buf[newlength]) || buf[newlength + 1])
  			break;
  
  	if (newlength > 2) {
  		buf[0] = newlength;
  		*length = newlength;
  	}
affae2bff   wdenk   Initial revision
776
  }
9c998aa83   Wolfgang Denk   Fix low-level OHC...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  
  static int usb_string_sub(struct usb_device *dev, unsigned int langid,
  		unsigned int index, unsigned char *buf)
  {
  	int rc;
  
  	/* Try to read the string descriptor by asking for the maximum
  	 * possible number of bytes */
  	rc = usb_get_string(dev, langid, index, buf, 255);
  
  	/* If that failed try to read the descriptor length, then
  	 * ask for just that many bytes */
  	if (rc < 2) {
  		rc = usb_get_string(dev, langid, index, buf, 2);
  		if (rc == 2)
  			rc = usb_get_string(dev, langid, index, buf, buf[0]);
  	}
  
  	if (rc >= 2) {
  		if (!buf[0] && !buf[1])
  			usb_try_string_workarounds(buf, &rc);
  
  		/* There might be extra junk at the end of the descriptor */
  		if (buf[0] < rc)
  			rc = buf[0];
  
  		rc = rc - (rc & 1); /* force a multiple of two */
  	}
  
  	if (rc < 2)
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
807
  		rc = -EINVAL;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
808
809
810
  
  	return rc;
  }
affae2bff   wdenk   Initial revision
811
812
813
814
815
816
817
  /********************************************************************
   * usb_string:
   * Get string index and translate it to ascii.
   * returns string length (> 0) or error (< 0)
   */
  int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
  {
f57661394   Puneet Saxena   USB: Align buffer...
818
  	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, mybuf, USB_BUFSIZ);
affae2bff   wdenk   Initial revision
819
820
821
822
823
  	unsigned char *tbuf;
  	int err;
  	unsigned int u, idx;
  
  	if (size <= 0 || !buf || !index)
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
824
  		return -EINVAL;
affae2bff   wdenk   Initial revision
825
  	buf[0] = 0;
d0ff51ba5   Wolfgang Denk   Code cleanup: fix...
826
  	tbuf = &mybuf[0];
affae2bff   wdenk   Initial revision
827
828
829
  
  	/* get langid for strings if it's not yet known */
  	if (!dev->have_langid) {
9c998aa83   Wolfgang Denk   Fix low-level OHC...
830
  		err = usb_string_sub(dev, 0, 0, tbuf);
affae2bff   wdenk   Initial revision
831
  		if (err < 0) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
832
833
834
  			debug("error getting string descriptor 0 " \
  			      "(error=%lx)
  ", dev->status);
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
835
  			return -EIO;
affae2bff   wdenk   Initial revision
836
  		} else if (tbuf[0] < 4) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
837
838
  			debug("string descriptor 0 too short
  ");
5a80b3449   Paul Kocialkowski   usb: usb_new_devi...
839
  			return -EIO;
affae2bff   wdenk   Initial revision
840
841
  		} else {
  			dev->have_langid = -1;
6f5794a6f   Remy Bohmer   Refactoring parts...
842
  			dev->string_langid = tbuf[2] | (tbuf[3] << 8);
affae2bff   wdenk   Initial revision
843
  				/* always use the first langid listed */
ceb4972a8   Vivek Gautam   usb: common: Weed...
844
845
846
847
  			debug("USB device number %d default " \
  			      "language ID 0x%x
  ",
  			      dev->devnum, dev->string_langid);
affae2bff   wdenk   Initial revision
848
849
  		}
  	}
cd0a9de68   wdenk   * Patch by Lauren...
850

9c998aa83   Wolfgang Denk   Fix low-level OHC...
851
  	err = usb_string_sub(dev, dev->string_langid, index, tbuf);
affae2bff   wdenk   Initial revision
852
853
  	if (err < 0)
  		return err;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
854

affae2bff   wdenk   Initial revision
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  	size--;		/* leave room for trailing NULL char in output buffer */
  	for (idx = 0, u = 2; u < err; u += 2) {
  		if (idx >= size)
  			break;
  		if (tbuf[u+1])			/* high byte */
  			buf[idx++] = '?';  /* non-ASCII character */
  		else
  			buf[idx++] = tbuf[u];
  	}
  	buf[idx] = 0;
  	err = idx;
  	return err;
  }
  
  
  /********************************************************************
   * USB device handling:
   * the USB device are static allocated [USB_MAX_DEVICE].
   */
95fbfe429   Simon Glass   dm: usb: Convert ...
874
  #ifndef CONFIG_DM_USB
affae2bff   wdenk   Initial revision
875
876
877
878
  
  /* returns a pointer to the device with the index [index].
   * if the device is not assigned (dev->devnum==-1) returns NULL
   */
6f5794a6f   Remy Bohmer   Refactoring parts...
879
  struct usb_device *usb_get_dev_index(int index)
affae2bff   wdenk   Initial revision
880
  {
6f5794a6f   Remy Bohmer   Refactoring parts...
881
  	if (usb_dev[index].devnum == -1)
affae2bff   wdenk   Initial revision
882
883
884
885
  		return NULL;
  	else
  		return &usb_dev[index];
  }
79b588872   Simon Glass   dm: usb: Adjust u...
886
  int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp)
affae2bff   wdenk   Initial revision
887
888
  {
  	int i;
ceb4972a8   Vivek Gautam   usb: common: Weed...
889
890
  	debug("New Device %d
  ", dev_index);
6f5794a6f   Remy Bohmer   Refactoring parts...
891
892
893
  	if (dev_index == USB_MAX_DEVICE) {
  		printf("ERROR, too many USB Devices, max=%d
  ", USB_MAX_DEVICE);
79b588872   Simon Glass   dm: usb: Adjust u...
894
  		return -ENOSPC;
affae2bff   wdenk   Initial revision
895
  	}
6f5794a6f   Remy Bohmer   Refactoring parts...
896
897
898
899
900
901
  	/* default Address is 0, real addresses start with 1 */
  	usb_dev[dev_index].devnum = dev_index + 1;
  	usb_dev[dev_index].maxchild = 0;
  	for (i = 0; i < USB_MAXCHILDREN; i++)
  		usb_dev[dev_index].children[i] = NULL;
  	usb_dev[dev_index].parent = NULL;
c7e3b2b58   Lucas Stach   usb: lowlevel int...
902
  	usb_dev[dev_index].controller = controller;
affae2bff   wdenk   Initial revision
903
  	dev_index++;
79b588872   Simon Glass   dm: usb: Adjust u...
904
905
906
  	*devp = &usb_dev[dev_index - 1];
  
  	return 0;
affae2bff   wdenk   Initial revision
907
  }
359439d28   Milind Choudhary   usb: Clean up new...
908
909
910
911
912
  /*
   * Free the newly created device node.
   * Called in error cases where configuring a newly attached
   * device fails for some reason.
   */
79b588872   Simon Glass   dm: usb: Adjust u...
913
  void usb_free_device(struct udevice *controller)
359439d28   Milind Choudhary   usb: Clean up new...
914
915
  {
  	dev_index--;
ceb4972a8   Vivek Gautam   usb: common: Weed...
916
917
  	debug("Freeing device node: %d
  ", dev_index);
359439d28   Milind Choudhary   usb: Clean up new...
918
919
920
  	memset(&usb_dev[dev_index], 0, sizeof(struct usb_device));
  	usb_dev[dev_index].devnum = -1;
  }
affae2bff   wdenk   Initial revision
921
922
  
  /*
5853e1335   Vivek Gautam   USB: xHCI: Add st...
923
924
925
926
927
928
929
930
931
   * XHCI issues Enable Slot command and thereafter
   * allocates device contexts. Provide a weak alias
   * function for the purpose, so that XHCI overrides it
   * and EHCI/OHCI just work out of the box.
   */
  __weak int usb_alloc_device(struct usb_device *udev)
  {
  	return 0;
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
932
  #endif /* !CONFIG_DM_USB */
862e75c0d   Simon Glass   dm: usb: Refactor...
933

682c9f8df   Hans de Goede   usb: Pass device ...
934
  static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub)
862e75c0d   Simon Glass   dm: usb: Refactor...
935
  {
3ed9eb93c   Stefan Roese   usb: Don't reset ...
936
  	if (!hub)
8802f5634   Hans de Goede   usb: Add an usb_d...
937
  		usb_reset_root_port(dev);
862e75c0d   Simon Glass   dm: usb: Refactor...
938
939
940
  
  	return 0;
  }
0ed27905c   Simon Glass   dm: usb: Complete...
941
  static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
affae2bff   wdenk   Initial revision
942
  {
128fcac08   Simon Glass   dm: usb: Move des...
943
  	__maybe_unused struct usb_device_descriptor *desc;
f57661394   Puneet Saxena   USB: Align buffer...
944
  	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
0ed27905c   Simon Glass   dm: usb: Complete...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
  	int err;
  
  	desc = (struct usb_device_descriptor *)tmpbuf;
  
  	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, len);
  	if (err < expect_len) {
  		if (err < 0) {
  			printf("unable to get device descriptor (error=%d)
  ",
  				err);
  			return err;
  		} else {
  			printf("USB device descriptor short read (expected %i, got %i)
  ",
  				expect_len, err);
  			return -EIO;
  		}
  	}
  	memcpy(&dev->descriptor, tmpbuf, sizeof(dev->descriptor));
  
  	return 0;
  }
  
  static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
  {
5853e1335   Vivek Gautam   USB: xHCI: Add st...
970
  	/*
53d8aa0f6   Simon Glass   dm: usb: Drop the...
971
  	 * This is a Windows scheme of initialization sequence, with double
488672084   Remy Bohmer   fix USB initialis...
972
  	 * reset of the device (Linux uses the same sequence)
c9e8436b1   Remy Bohmer   USB layer of U-Bo...
973
974
  	 * Some equipment is said to work only with such init sequence; this
  	 * patch is based on the work by Alan Stern:
de39f8c19   Michael Trimarchi   USB style patch, ...
975
976
  	 * http://sourceforge.net/mailarchive/forum.php?
  	 * thread_id=5729457&forum_id=5398
9c998aa83   Wolfgang Denk   Fix low-level OHC...
977
  	 */
9c998aa83   Wolfgang Denk   Fix low-level OHC...
978

53d8aa0f6   Simon Glass   dm: usb: Drop the...
979
980
  	/*
  	 * send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
9c998aa83   Wolfgang Denk   Fix low-level OHC...
981
982
  	 * only 18 bytes long, this will terminate with a short packet.  But if
  	 * the maxpacket size is 8 or 16 the device may be waiting to transmit
2b338ef41   Hans de Goede   usb: Fix maxpacke...
983
984
  	 * some more, or keeps on retransmitting the 8 byte header.
  	 */
9c998aa83   Wolfgang Denk   Fix low-level OHC...
985

2b338ef41   Hans de Goede   usb: Fix maxpacke...
986
987
988
989
990
991
992
993
994
  	if (dev->speed == USB_SPEED_LOW) {
  		dev->descriptor.bMaxPacketSize0 = 8;
  		dev->maxpacketsize = PACKET_SIZE_8;
  	} else {
  		dev->descriptor.bMaxPacketSize0 = 64;
  		dev->maxpacketsize = PACKET_SIZE_64;
  	}
  	dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
  	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
488672084   Remy Bohmer   fix USB initialis...
995

128fcac08   Simon Glass   dm: usb: Move des...
996
997
  	if (do_read) {
  		int err;
862e75c0d   Simon Glass   dm: usb: Refactor...
998

128fcac08   Simon Glass   dm: usb: Move des...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  		/*
  		 * Validate we've received only at least 8 bytes, not that we've
  		 * received the entire descriptor. The reasoning is:
  		 * - The code only uses fields in the first 8 bytes, so that's all we
  		 *   need to have fetched at this stage.
  		 * - The smallest maxpacket size is 8 bytes. Before we know the actual
  		 *   maxpacket the device uses, the USB controller may only accept a
  		 *   single packet. Consequently we are only guaranteed to receive 1
  		 *   packet (at least 8 bytes) even in a non-error case.
  		 *
  		 * At least the DWC2 controller needs to be programmed with the number
  		 * of packets in addition to the number of bytes. A request for 64
  		 * bytes of data with the maxpacket guessed as 64 (above) yields a
  		 * request for 1 packet.
  		 */
0ed27905c   Simon Glass   dm: usb: Complete...
1014
1015
1016
  		err = get_descriptor_len(dev, 64, 8);
  		if (err)
  			return err;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1017
  	}
488672084   Remy Bohmer   fix USB initialis...
1018

de39f8c19   Michael Trimarchi   USB style patch, ...
1019
  	dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
affae2bff   wdenk   Initial revision
1020
1021
  	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
  	switch (dev->descriptor.bMaxPacketSize0) {
de39f8c19   Michael Trimarchi   USB style patch, ...
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  	case 8:
  		dev->maxpacketsize  = PACKET_SIZE_8;
  		break;
  	case 16:
  		dev->maxpacketsize = PACKET_SIZE_16;
  		break;
  	case 32:
  		dev->maxpacketsize = PACKET_SIZE_32;
  		break;
  	case 64:
  		dev->maxpacketsize = PACKET_SIZE_64;
  		break;
04ee6ee2c   Paul Kocialkowski   usb: Early failur...
1034
1035
1036
1037
  	default:
  		printf("usb_new_device: invalid max packet size
  ");
  		return -EIO;
affae2bff   wdenk   Initial revision
1038
  	}
128fcac08   Simon Glass   dm: usb: Move des...
1039
1040
1041
  
  	return 0;
  }
91398f985   Simon Glass   dm: usb: Split ou...
1042
  static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
9eb72dd1f   Hans de Goede   usb: usb_setup_de...
1043
  			      struct usb_device *parent)
128fcac08   Simon Glass   dm: usb: Move des...
1044
  {
91398f985   Simon Glass   dm: usb: Split ou...
1045
  	int err;
128fcac08   Simon Glass   dm: usb: Move des...
1046
1047
1048
1049
1050
1051
1052
  
  	/*
  	 * Allocate usb 3.0 device context.
  	 * USB 3.0 (xHCI) protocol tries to allocate device slot
  	 * and related data structures first. This call does that.
  	 * Refer to sec 4.3.2 in xHCI spec rev1.0
  	 */
91398f985   Simon Glass   dm: usb: Split ou...
1053
1054
  	err = usb_alloc_device(dev);
  	if (err) {
128fcac08   Simon Glass   dm: usb: Move des...
1055
1056
  		printf("Cannot allocate device context to get SLOT_ID
  ");
91398f985   Simon Glass   dm: usb: Split ou...
1057
  		return err;
128fcac08   Simon Glass   dm: usb: Move des...
1058
  	}
128fcac08   Simon Glass   dm: usb: Move des...
1059
1060
1061
  	err = usb_setup_descriptor(dev, do_read);
  	if (err)
  		return err;
682c9f8df   Hans de Goede   usb: Pass device ...
1062
  	err = usb_hub_port_reset(dev, parent);
128fcac08   Simon Glass   dm: usb: Move des...
1063
1064
  	if (err)
  		return err;
affae2bff   wdenk   Initial revision
1065
1066
1067
1068
1069
  	dev->devnum = addr;
  
  	err = usb_set_address(dev); /* set address */
  
  	if (err < 0) {
6f5794a6f   Remy Bohmer   Refactoring parts...
1070
1071
1072
1073
  		printf("
        USB device not accepting new address " \
  			"(error=%lX)
  ", dev->status);
91398f985   Simon Glass   dm: usb: Split ou...
1074
  		return err;
affae2bff   wdenk   Initial revision
1075
  	}
5b84dd67c   Mike Frysinger   usb: replace wait...
1076
  	mdelay(10);	/* Let the SET_ADDRESS settle */
affae2bff   wdenk   Initial revision
1077

91398f985   Simon Glass   dm: usb: Split ou...
1078
1079
  	return 0;
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
1080
  int usb_select_config(struct usb_device *dev)
91398f985   Simon Glass   dm: usb: Split ou...
1081
  {
2f1b4302e   Marek Vasut   usb: Don't init p...
1082
  	unsigned char *tmpbuf = NULL;
0ed27905c   Simon Glass   dm: usb: Complete...
1083
  	int err;
91398f985   Simon Glass   dm: usb: Split ou...
1084

0ed27905c   Simon Glass   dm: usb: Complete...
1085
1086
1087
  	err = get_descriptor_len(dev, USB_DT_DEVICE_SIZE, USB_DT_DEVICE_SIZE);
  	if (err)
  		return err;
affae2bff   wdenk   Initial revision
1088

affae2bff   wdenk   Initial revision
1089
  	/* correct le values */
c918261c6   Christian Eggers   USB: replace old ...
1090
1091
1092
1093
  	le16_to_cpus(&dev->descriptor.bcdUSB);
  	le16_to_cpus(&dev->descriptor.idVendor);
  	le16_to_cpus(&dev->descriptor.idProduct);
  	le16_to_cpus(&dev->descriptor.bcdDevice);
0ed27905c   Simon Glass   dm: usb: Complete...
1094

ef71290be   Marek Vasut   usb: Assure Get D...
1095
1096
1097
1098
1099
1100
1101
  	/*
  	 * Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive
  	 * about this first Get Descriptor request. If there are any other
  	 * requests in the first microframe, the stick crashes. Wait about
  	 * one microframe duration here (1mS for USB 1.x , 125uS for USB 2.0).
  	 */
  	mdelay(1);
affae2bff   wdenk   Initial revision
1102
  	/* only support for one config for now */
c75f57fba   Stefan Brüns   usb: Alloc buffer...
1103
1104
1105
1106
1107
1108
1109
1110
  	err = usb_get_configuration_len(dev, 0);
  	if (err >= 0) {
  		tmpbuf = (unsigned char *)malloc_cache_aligned(err);
  		if (!tmpbuf)
  			err = -ENOMEM;
  		else
  			err = usb_get_configuration_no(dev, 0, tmpbuf, err);
  	}
8b8d779da   Vincent Palatin   usb: fallback saf...
1111
1112
1113
1114
1115
  	if (err < 0) {
  		printf("usb_new_device: Cannot read configuration, " \
  		       "skipping device %04x:%04x
  ",
  		       dev->descriptor.idVendor, dev->descriptor.idProduct);
c75f57fba   Stefan Brüns   usb: Alloc buffer...
1116
  		free(tmpbuf);
0ed27905c   Simon Glass   dm: usb: Complete...
1117
  		return err;
8b8d779da   Vincent Palatin   usb: fallback saf...
1118
  	}
f57661394   Puneet Saxena   USB: Align buffer...
1119
  	usb_parse_config(dev, tmpbuf, 0);
c75f57fba   Stefan Brüns   usb: Alloc buffer...
1120
  	free(tmpbuf);
affae2bff   wdenk   Initial revision
1121
  	usb_set_maxpacket(dev);
0ed27905c   Simon Glass   dm: usb: Complete...
1122
1123
1124
1125
1126
1127
1128
  	/*
  	 * we set the default configuration here
  	 * This seems premature. If the driver wants a different configuration
  	 * it will need to select itself.
  	 */
  	err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue);
  	if (err < 0) {
6f5794a6f   Remy Bohmer   Refactoring parts...
1129
1130
1131
  		printf("failed to set default configuration " \
  			"len %d, status %lX
  ", dev->act_len, dev->status);
0ed27905c   Simon Glass   dm: usb: Complete...
1132
  		return err;
affae2bff   wdenk   Initial revision
1133
  	}
f647bf0ba   Marek Vasut   usb: Wait after s...
1134
1135
1136
1137
1138
1139
1140
  
  	/*
  	 * Wait until the Set Configuration request gets processed by the
  	 * device. This is required by at least SanDisk Cruzer Pop USB 2.0
  	 * and Kingston DT Ultimate 32GB USB 3.0 on DWC2 OTG controller.
  	 */
  	mdelay(10);
ceb4972a8   Vivek Gautam   usb: common: Weed...
1141
1142
1143
1144
  	debug("new device strings: Mfr=%d, Product=%d, SerialNumber=%d
  ",
  	      dev->descriptor.iManufacturer, dev->descriptor.iProduct,
  	      dev->descriptor.iSerialNumber);
affae2bff   wdenk   Initial revision
1145
1146
1147
1148
  	memset(dev->mf, 0, sizeof(dev->mf));
  	memset(dev->prod, 0, sizeof(dev->prod));
  	memset(dev->serial, 0, sizeof(dev->serial));
  	if (dev->descriptor.iManufacturer)
6f5794a6f   Remy Bohmer   Refactoring parts...
1149
1150
  		usb_string(dev, dev->descriptor.iManufacturer,
  			   dev->mf, sizeof(dev->mf));
affae2bff   wdenk   Initial revision
1151
  	if (dev->descriptor.iProduct)
6f5794a6f   Remy Bohmer   Refactoring parts...
1152
1153
  		usb_string(dev, dev->descriptor.iProduct,
  			   dev->prod, sizeof(dev->prod));
affae2bff   wdenk   Initial revision
1154
  	if (dev->descriptor.iSerialNumber)
6f5794a6f   Remy Bohmer   Refactoring parts...
1155
1156
  		usb_string(dev, dev->descriptor.iSerialNumber,
  			   dev->serial, sizeof(dev->serial));
ceb4972a8   Vivek Gautam   usb: common: Weed...
1157
1158
1159
1160
1161
1162
  	debug("Manufacturer %s
  ", dev->mf);
  	debug("Product      %s
  ", dev->prod);
  	debug("SerialNumber %s
  ", dev->serial);
0ed27905c   Simon Glass   dm: usb: Complete...
1163
1164
1165
  
  	return 0;
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
1166
  int usb_setup_device(struct usb_device *dev, bool do_read,
9eb72dd1f   Hans de Goede   usb: usb_setup_de...
1167
  		     struct usb_device *parent)
0ed27905c   Simon Glass   dm: usb: Complete...
1168
1169
1170
1171
1172
1173
1174
  {
  	int addr;
  	int ret;
  
  	/* We still haven't set the Address yet */
  	addr = dev->devnum;
  	dev->devnum = 0;
9eb72dd1f   Hans de Goede   usb: usb_setup_de...
1175
  	ret = usb_prepare_device(dev, addr, do_read, parent);
0ed27905c   Simon Glass   dm: usb: Complete...
1176
1177
1178
1179
1180
1181
  	if (ret)
  		return ret;
  	ret = usb_select_config(dev);
  
  	return ret;
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
1182
  #ifndef CONFIG_DM_USB
0ed27905c   Simon Glass   dm: usb: Complete...
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
  /*
   * By the time we get here, the device has gotten a new device ID
   * and is in the default state. We need to identify the thing and
   * get the ball rolling..
   *
   * Returns 0 for success, != 0 for error.
   */
  int usb_new_device(struct usb_device *dev)
  {
  	bool do_read = true;
  	int err;
  
  	/*
  	 * XHCI needs to issue a Address device command to setup
  	 * proper device context structures, before it can interact
  	 * with the device. So a get_descriptor will fail before any
  	 * of that is done for XHCI unlike EHCI.
  	 */
  #ifdef CONFIG_USB_XHCI
  	do_read = false;
  #endif
9eb72dd1f   Hans de Goede   usb: usb_setup_de...
1204
  	err = usb_setup_device(dev, do_read, dev->parent);
0ed27905c   Simon Glass   dm: usb: Complete...
1205
1206
1207
1208
1209
1210
1211
  	if (err)
  		return err;
  
  	/* Now probe if the device is a hub */
  	err = usb_hub_probe(dev, 0);
  	if (err < 0)
  		return err;
affae2bff   wdenk   Initial revision
1212
1213
  	return 0;
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
1214
  #endif
affae2bff   wdenk   Initial revision
1215

16297cfb2   Mateusz Zalega   usb: new board-sp...
1216
  __weak
bba679144   Troy Kisky   usb: rename board...
1217
  int board_usb_init(int index, enum usb_init_type init)
16297cfb2   Mateusz Zalega   usb: new board-sp...
1218
1219
1220
  {
  	return 0;
  }
db378d786   Kishon Vijay Abraham I   common: cmd_dfu: ...
1221
1222
1223
1224
1225
1226
  
  __weak
  int board_usb_cleanup(int index, enum usb_init_type init)
  {
  	return 0;
  }
95fbfe429   Simon Glass   dm: usb: Convert ...
1227
1228
1229
1230
1231
1232
1233
1234
1235
  
  bool usb_device_has_child_on_port(struct usb_device *parent, int port)
  {
  #ifdef CONFIG_DM_USB
  	return false;
  #else
  	return parent->children[port] != NULL;
  #endif
  }
faa7db24a   Stefan Brüns   usb: Move determi...
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  #ifdef CONFIG_DM_USB
  void usb_find_usb2_hub_address_port(struct usb_device *udev,
  			       uint8_t *hub_address, uint8_t *hub_port)
  {
  	struct udevice *parent;
  	struct usb_device *uparent, *ttdev;
  
  	/*
  	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
  	 * to the parent udevice, not the actual udevice belonging to the
  	 * udev as the device is not instantiated yet. So when searching
  	 * for the first usb-2 parent start with udev->dev not
  	 * udev->dev->parent .
  	 */
  	ttdev = udev;
  	parent = udev->dev;
  	uparent = dev_get_parent_priv(parent);
  
  	while (uparent->speed != USB_SPEED_HIGH) {
  		struct udevice *dev = parent;
  
  		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
  			printf("Error: Cannot find high speed parent of usb-1 device
  ");
  			*hub_address = 0;
  			*hub_port = 0;
  			return;
  		}
  
  		ttdev = dev_get_parent_priv(dev);
  		parent = dev->parent;
  		uparent = dev_get_parent_priv(parent);
  	}
  	*hub_address = uparent->devnum;
  	*hub_port = ttdev->portnr;
  }
  #else
  void usb_find_usb2_hub_address_port(struct usb_device *udev,
  			       uint8_t *hub_address, uint8_t *hub_port)
  {
  	/* Find out the nearest parent which is high speed */
  	while (udev->parent->parent != NULL)
  		if (udev->parent->speed != USB_SPEED_HIGH) {
  			udev = udev->parent;
  		} else {
  			*hub_address = udev->parent->devnum;
  			*hub_port = udev->portnr;
  			return;
  		}
  
  	printf("Error: Cannot find high speed parent of usb-1 device
  ");
  	*hub_address = 0;
  	*hub_port = 0;
  }
  #endif
affae2bff   wdenk   Initial revision
1292
  /* EOF */