Blame view
common/usb.c
34 KB
affae2bff Initial revision |
1 |
/* |
affae2bff Initial revision |
2 |
* Most of this source has been derived from the Linux USB |
460c322f1 (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 Initial revision |
16 |
* |
1a4596601 Add GPL-2.0+ SPDX... |
17 |
* SPDX-License-Identifier: GPL-2.0+ |
affae2bff Initial revision |
18 |
*/ |
affae2bff 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 dm: usb: Convert ... |
30 |
#include <dm.h> |
cf92e05c0 Move ALLOC_CACHE_... |
31 |
#include <memalign.h> |
affae2bff Initial revision |
32 |
#include <asm/processor.h> |
66cf64107 usb: use noinline... |
33 |
#include <linux/compiler.h> |
9c998aa83 Fix low-level OHC... |
34 |
#include <linux/ctype.h> |
c918261c6 USB: replace old ... |
35 |
#include <asm/byteorder.h> |
b2fb47f18 USB: Use (get|put... |
36 |
#include <asm/unaligned.h> |
97b9eb9e6 usb: Handle -ENOD... |
37 |
#include <errno.h> |
affae2bff Initial revision |
38 |
#include <usb.h> |
affae2bff Initial revision |
39 |
|
cd0a9de68 * Patch by Lauren... |
40 |
#define USB_BUFSIZ 512 |
affae2bff Initial revision |
41 |
static int asynch_allowed; |
e51aae382 Prevent USB comma... |
42 |
char usb_started; /* flag for the started/stopped USB status */ |
95fbfe429 dm: usb: Convert ... |
43 44 45 |
#ifndef CONFIG_DM_USB static struct usb_device usb_dev[USB_MAX_DEVICE]; static int dev_index; |
93c2582fe usb: add support ... |
46 47 48 |
#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif |
affae2bff Initial revision |
49 |
|
affae2bff Initial revision |
50 51 52 |
/*************************************************************************** * Init USB Device */ |
affae2bff Initial revision |
53 54 |
int usb_init(void) { |
93c2582fe usb: add support ... |
55 56 57 |
void *ctrl; struct usb_device *dev; int i, start_index = 0; |
d906bbc26 usb: Do not log a... |
58 |
int controllers_initialized = 0; |
97b9eb9e6 usb: Handle -ENOD... |
59 |
int ret; |
affae2bff Initial revision |
60 |
|
6f5794a6f Refactoring parts... |
61 62 |
dev_index = 0; asynch_allowed = 1; |
affae2bff Initial revision |
63 |
usb_hub_reset(); |
93c2582fe usb: add support ... |
64 65 66 67 68 69 |
/* 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 Initial revision |
70 |
/* init low_level USB */ |
93c2582fe usb: add support ... |
71 72 73 |
for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) { /* init low_level USB */ printf("USB%d: ", i); |
97b9eb9e6 usb: Handle -ENOD... |
74 75 76 77 |
ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl); if (ret == -ENODEV) { /* No such device. */ puts("Port not available. "); |
d906bbc26 usb: Do not log a... |
78 |
controllers_initialized++; |
97b9eb9e6 usb: Handle -ENOD... |
79 80 81 82 |
continue; } if (ret) { /* Other error. */ |
93c2582fe usb: add support ... |
83 84 85 86 87 88 89 90 |
puts("lowlevel init failed "); continue; } /* * lowlevel init is OK, now scan the bus for devices * i.e. search HUBs and configure them */ |
d906bbc26 usb: Do not log a... |
91 |
controllers_initialized++; |
93c2582fe usb: add support ... |
92 93 |
start_index = dev_index; printf("scanning bus %d for devices... ", i); |
79b588872 dm: usb: Adjust u... |
94 95 |
ret = usb_alloc_new_device(ctrl, &dev); if (ret) |
8879be885 usb: Check usb_ne... |
96 |
break; |
93c2582fe usb: add support ... |
97 98 99 100 |
/* * device 0 is always present * (root hub, so let it analyze) */ |
8879be885 usb: Check usb_ne... |
101 102 |
ret = usb_new_device(dev); if (ret) |
79b588872 dm: usb: Adjust u... |
103 |
usb_free_device(dev->controller); |
93c2582fe usb: add support ... |
104 |
|
8879be885 usb: Check usb_ne... |
105 |
if (start_index == dev_index) { |
93c2582fe usb: add support ... |
106 107 |
puts("No USB Device found "); |
8879be885 usb: Check usb_ne... |
108 109 |
continue; } else { |
93c2582fe usb: add support ... |
110 111 112 |
printf("%d USB Device(s) found ", dev_index - start_index); |
8879be885 usb: Check usb_ne... |
113 |
} |
93c2582fe usb: add support ... |
114 |
|
e51aae382 Prevent USB comma... |
115 |
usb_started = 1; |
93c2582fe usb: add support ... |
116 |
} |
ceb4972a8 usb: common: Weed... |
117 118 |
debug("scan end "); |
93c2582fe usb: add support ... |
119 |
/* if we were not able to find at least one working bus, bail out */ |
d906bbc26 usb: Do not log a... |
120 |
if (controllers_initialized == 0) |
93c2582fe usb: add support ... |
121 122 |
puts("USB error: all controllers failed lowlevel init "); |
93c2582fe usb: add support ... |
123 |
|
5a80b3449 usb: usb_new_devi... |
124 |
return usb_started ? 0 : -ENODEV; |
affae2bff Initial revision |
125 126 127 128 129 130 131 |
} /****************************************************************************** * Stop USB this stops the LowLevel Part and deregisters USB devices. */ int usb_stop(void) { |
93c2582fe usb: add support ... |
132 |
int i; |
eba1f2fc7 Make usb-stop() s... |
133 134 135 136 137 |
if (usb_started) { asynch_allowed = 1; usb_started = 0; usb_hub_reset(); |
93c2582fe usb: add support ... |
138 139 140 141 142 143 |
for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) { if (usb_lowlevel_stop(i)) printf("failed to stop USB controller %d ", i); } |
eba1f2fc7 Make usb-stop() s... |
144 |
} |
93c2582fe usb: add support ... |
145 146 |
return 0; |
affae2bff Initial revision |
147 |
} |
08f3bb0bc usb: add device c... |
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
/****************************************************************************** * 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 Initial revision |
173 174 175 |
/* * 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 Add USB host ethe... |
176 |
* Returns the old value so it can be restored later. |
affae2bff Initial revision |
177 |
*/ |
89d48367e Add USB host ethe... |
178 |
int usb_disable_asynch(int disable) |
affae2bff Initial revision |
179 |
{ |
89d48367e Add USB host ethe... |
180 |
int old_value = asynch_allowed; |
6f5794a6f Refactoring parts... |
181 |
asynch_allowed = !disable; |
89d48367e Add USB host ethe... |
182 |
return old_value; |
affae2bff Initial revision |
183 |
} |
95fbfe429 dm: usb: Convert ... |
184 |
#endif /* !CONFIG_DM_USB */ |
affae2bff Initial revision |
185 186 187 188 189 190 191 192 193 194 195 |
/*------------------------------------------------------------------- * Message wrappers. * */ /* * submits an Interrupt Message */ int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, |
6f5794a6f Refactoring parts... |
196 |
void *buffer, int transfer_len, int interval) |
affae2bff Initial revision |
197 |
{ |
6f5794a6f Refactoring parts... |
198 |
return submit_int_msg(dev, pipe, buffer, transfer_len, interval); |
affae2bff Initial revision |
199 200 201 202 203 204 205 206 |
} /* * 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 Fix spelling of "... |
207 |
* returns the transferred length if OK or -1 if error. The transferred length |
affae2bff Initial revision |
208 209 210 211 212 213 214 |
* 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 USB: Align buffer... |
215 |
ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1); |
651d95c8e usb: usb_control_... |
216 |
int err; |
e159e4868 USB: Make struct ... |
217 |
|
6f5794a6f Refactoring parts... |
218 219 |
if ((timeout == 0) && (!asynch_allowed)) { /* request for a asynch control pipe is not allowed */ |
5a80b3449 usb: usb_new_devi... |
220 |
return -EINVAL; |
6f5794a6f Refactoring parts... |
221 |
} |
9c998aa83 Fix low-level OHC... |
222 |
|
affae2bff Initial revision |
223 |
/* set setup command */ |
f57661394 USB: Align buffer... |
224 225 226 227 228 |
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 usb: common: Weed... |
229 230 231 232 |
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 Refactoring parts... |
233 |
dev->status = USB_ST_NOT_PROC; /*not yet processed */ |
affae2bff Initial revision |
234 |
|
651d95c8e usb: usb_control_... |
235 236 237 |
err = submit_control_msg(dev, pipe, data, size, setup_packet); if (err < 0) return err; |
6f5794a6f Refactoring parts... |
238 |
if (timeout == 0) |
affae2bff Initial revision |
239 |
return (int)size; |
6f5794a6f Refactoring parts... |
240 |
|
84d36b301 USB: usb_control_... |
241 242 243 244 245 246 247 248 |
/* * 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 usb: replace wait... |
249 |
mdelay(1); |
488672084 fix USB initialis... |
250 |
} |
84d36b301 USB: usb_control_... |
251 252 |
if (dev->status) return -1; |
488672084 fix USB initialis... |
253 254 |
return dev->act_len; |
84d36b301 USB: usb_control_... |
255 |
|
affae2bff Initial revision |
256 257 258 259 |
} /*------------------------------------------------------------------- * submits bulk message, and waits for completion. returns 0 if Ok or |
5a80b3449 usb: usb_new_devi... |
260 |
* negative if Error. |
affae2bff Initial revision |
261 262 263 264 265 266 |
* 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 usb: usb_new_devi... |
267 |
return -EINVAL; |
6f5794a6f Refactoring parts... |
268 |
dev->status = USB_ST_NOT_PROC; /*not yet processed */ |
fd06028df usb: check return... |
269 |
if (submit_bulk_msg(dev, pipe, data, len) < 0) |
5a80b3449 usb: usb_new_devi... |
270 |
return -EIO; |
6f5794a6f Refactoring parts... |
271 272 |
while (timeout--) { if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC)) |
affae2bff Initial revision |
273 |
break; |
5b84dd67c usb: replace wait... |
274 |
mdelay(1); |
affae2bff Initial revision |
275 |
} |
6f5794a6f Refactoring parts... |
276 277 |
*actual_length = dev->act_len; if (dev->status == 0) |
affae2bff Initial revision |
278 279 |
return 0; else |
5a80b3449 usb: usb_new_devi... |
280 |
return -EIO; |
affae2bff Initial revision |
281 282 283 284 285 286 287 288 289 290 291 |
} /*------------------------------------------------------------------- * Max Packet stuff */ /* * returns the max packet size, depending on the pipe direction and * the configurations values */ |
6f5794a6f Refactoring parts... |
292 |
int usb_maxpacket(struct usb_device *dev, unsigned long pipe) |
affae2bff Initial revision |
293 |
{ |
6f5794a6f Refactoring parts... |
294 295 |
/* direction is out -> use emaxpacket out */ if ((pipe & USB_DIR_IN) == 0) |
de39f8c19 USB style patch, ... |
296 |
return dev->epmaxpacketout[((pipe>>15) & 0xf)]; |
affae2bff Initial revision |
297 |
else |
de39f8c19 USB style patch, ... |
298 |
return dev->epmaxpacketin[((pipe>>15) & 0xf)]; |
affae2bff Initial revision |
299 |
} |
5e8baf878 GCC4.6: Fix commo... |
300 301 |
/* * The routine usb_set_maxpacket_ep() is extracted from the loop of routine |
be19d324e Fix for USB stick... |
302 303 304 305 306 307 |
* 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 GCC4.6: Fix commo... |
308 309 |
* * NOTE: Similar behaviour was observed with GCC4.6 on ARMv5. |
be19d324e Fix for USB stick... |
310 |
*/ |
66cf64107 usb: use noinline... |
311 |
static void noinline |
5e8baf878 GCC4.6: Fix commo... |
312 |
usb_set_maxpacket_ep(struct usb_device *dev, int if_idx, int ep_idx) |
be19d324e Fix for USB stick... |
313 314 |
{ int b; |
5e8baf878 GCC4.6: Fix commo... |
315 |
struct usb_endpoint_descriptor *ep; |
b2fb47f18 USB: Use (get|put... |
316 |
u16 ep_wMaxPacketSize; |
5e8baf878 GCC4.6: Fix commo... |
317 318 |
ep = &dev->config.if_desc[if_idx].ep_desc[ep_idx]; |
be19d324e Fix for USB stick... |
319 320 |
b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; |
b2fb47f18 USB: Use (get|put... |
321 |
ep_wMaxPacketSize = get_unaligned(&ep->wMaxPacketSize); |
be19d324e Fix for USB stick... |
322 323 324 325 |
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ |
b2fb47f18 USB: Use (get|put... |
326 327 |
dev->epmaxpacketout[b] = ep_wMaxPacketSize; dev->epmaxpacketin[b] = ep_wMaxPacketSize; |
ceb4972a8 usb: common: Weed... |
328 329 330 |
debug("##Control EP epmaxpacketout/in[%d] = %d ", b, dev->epmaxpacketin[b]); |
be19d324e Fix for USB stick... |
331 332 333 |
} else { if ((ep->bEndpointAddress & 0x80) == 0) { /* OUT Endpoint */ |
b2fb47f18 USB: Use (get|put... |
334 335 |
if (ep_wMaxPacketSize > dev->epmaxpacketout[b]) { dev->epmaxpacketout[b] = ep_wMaxPacketSize; |
ceb4972a8 usb: common: Weed... |
336 337 338 |
debug("##EP epmaxpacketout[%d] = %d ", b, dev->epmaxpacketout[b]); |
be19d324e Fix for USB stick... |
339 340 341 |
} } else { /* IN Endpoint */ |
b2fb47f18 USB: Use (get|put... |
342 343 |
if (ep_wMaxPacketSize > dev->epmaxpacketin[b]) { dev->epmaxpacketin[b] = ep_wMaxPacketSize; |
ceb4972a8 usb: common: Weed... |
344 345 346 |
debug("##EP epmaxpacketin[%d] = %d ", b, dev->epmaxpacketin[b]); |
be19d324e Fix for USB stick... |
347 348 349 350 |
} } /* if out */ } /* if control */ } |
affae2bff Initial revision |
351 352 353 |
/* * set the max packed value of all endpoints in the given configuration */ |
c08b1b264 USB: Staticize in... |
354 |
static int usb_set_maxpacket(struct usb_device *dev) |
affae2bff Initial revision |
355 |
{ |
be19d324e Fix for USB stick... |
356 |
int i, ii; |
affae2bff Initial revision |
357 |
|
8f8bd565f USB Consolidate d... |
358 359 |
for (i = 0; i < dev->config.desc.bNumInterfaces; i++) for (ii = 0; ii < dev->config.if_desc[i].desc.bNumEndpoints; ii++) |
5e8baf878 GCC4.6: Fix commo... |
360 |
usb_set_maxpacket_ep(dev, i, ii); |
affae2bff Initial revision |
361 |
|
affae2bff Initial revision |
362 363 364 365 366 367 |
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 usb: Use well-kno... |
368 |
* (wTotalLength has already been swapped and sanitized when it was read.) |
affae2bff Initial revision |
369 |
*/ |
c08b1b264 USB: Staticize in... |
370 371 |
static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) |
affae2bff Initial revision |
372 373 |
{ struct usb_descriptor_header *head; |
7455af41d Add rudimentary h... |
374 |
int index, ifno, epno, curr_if_num; |
b2fb47f18 USB: Use (get|put... |
375 |
u16 ep_wMaxPacketSize; |
605bd75af USB: Some cleanup... |
376 |
struct usb_interface *if_desc = NULL; |
7455af41d Add rudimentary h... |
377 378 379 380 381 382 383 |
ifno = -1; epno = -1; curr_if_num = -1; dev->configno = cfgno; head = (struct usb_descriptor_header *) &buffer[0]; |
6f5794a6f Refactoring parts... |
384 385 386 387 |
if (head->bDescriptorType != USB_DT_CONFIG) { printf(" ERROR: NOT USB_CONFIG_DESC %x ", head->bDescriptorType); |
5a80b3449 usb: usb_new_devi... |
388 |
return -EINVAL; |
affae2bff Initial revision |
389 |
} |
eaf3e613e usb: Use well-kno... |
390 391 392 |
if (head->bLength != USB_DT_CONFIG_SIZE) { printf("ERROR: Invalid USB CFG length (%d) ", head->bLength); |
5a80b3449 usb: usb_new_devi... |
393 |
return -EINVAL; |
eaf3e613e usb: Use well-kno... |
394 395 |
} memcpy(&dev->config, head, USB_DT_CONFIG_SIZE); |
7455af41d Add rudimentary h... |
396 |
dev->config.no_of_if = 0; |
affae2bff Initial revision |
397 |
|
8f8bd565f USB Consolidate d... |
398 |
index = dev->config.desc.bLength; |
6f5794a6f Refactoring parts... |
399 400 |
/* Ok the first entry must be a configuration entry, * now process the others */ |
7455af41d Add rudimentary h... |
401 |
head = (struct usb_descriptor_header *) &buffer[index]; |
eaf3e613e usb: Use well-kno... |
402 |
while (index + 1 < dev->config.desc.wTotalLength && head->bLength) { |
6f5794a6f Refactoring parts... |
403 404 |
switch (head->bDescriptorType) { case USB_DT_INTERFACE: |
eaf3e613e usb: Use well-kno... |
405 406 407 408 409 410 411 412 413 414 415 416 |
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 Refactoring parts... |
417 |
if (((struct usb_interface_descriptor *) \ |
eaf3e613e usb: Use well-kno... |
418 |
head)->bInterfaceNumber != curr_if_num) { |
6f5794a6f Refactoring parts... |
419 420 |
/* this is a new interface, copy new desc */ ifno = dev->config.no_of_if; |
eaf3e613e usb: Use well-kno... |
421 422 423 424 |
if (ifno >= USB_MAXINTERFACES) { puts("Too many USB interfaces! "); /* try to go on with what we have */ |
5a80b3449 usb: usb_new_devi... |
425 |
return -EINVAL; |
eaf3e613e usb: Use well-kno... |
426 |
} |
605bd75af USB: Some cleanup... |
427 |
if_desc = &dev->config.if_desc[ifno]; |
6f5794a6f Refactoring parts... |
428 |
dev->config.no_of_if++; |
eaf3e613e usb: Use well-kno... |
429 430 |
memcpy(if_desc, head, USB_DT_INTERFACE_SIZE); |
605bd75af USB: Some cleanup... |
431 432 |
if_desc->no_of_ep = 0; if_desc->num_altsetting = 1; |
6f5794a6f Refactoring parts... |
433 |
curr_if_num = |
605bd75af USB: Some cleanup... |
434 |
if_desc->desc.bInterfaceNumber; |
6f5794a6f Refactoring parts... |
435 436 |
} else { /* found alternate setting for the interface */ |
605bd75af USB: Some cleanup... |
437 438 439 440 |
if (ifno >= 0) { if_desc = &dev->config.if_desc[ifno]; if_desc->num_altsetting++; } |
6f5794a6f Refactoring parts... |
441 442 443 |
} break; case USB_DT_ENDPOINT: |
2f0eb2ac4 usb: Handle audio... |
444 445 |
if (head->bLength != USB_DT_ENDPOINT_SIZE && head->bLength != USB_DT_ENDPOINT_AUDIO_SIZE) { |
eaf3e613e usb: Use well-kno... |
446 447 448 449 450 |
printf("ERROR: Invalid USB EP length (%d) ", head->bLength); break; } |
2f0eb2ac4 usb: Handle audio... |
451 |
if (index + head->bLength > |
eaf3e613e usb: Use well-kno... |
452 453 454 455 456 457 458 459 460 461 |
dev->config.desc.wTotalLength) { puts("USB EP descriptor overflowed buffer! "); break; } if (ifno < 0) { puts("Endpoint descriptor out of order! "); break; } |
6f5794a6f Refactoring parts... |
462 |
epno = dev->config.if_desc[ifno].no_of_ep; |
605bd75af USB: Some cleanup... |
463 |
if_desc = &dev->config.if_desc[ifno]; |
447b9cdf2 common: usb: fix ... |
464 |
if (epno >= USB_MAXENDPOINTS) { |
eaf3e613e usb: Use well-kno... |
465 466 467 |
printf("Interface %d has too many endpoints! ", if_desc->desc.bInterfaceNumber); |
5a80b3449 usb: usb_new_devi... |
468 |
return -EINVAL; |
eaf3e613e usb: Use well-kno... |
469 |
} |
6f5794a6f Refactoring parts... |
470 |
/* found an endpoint */ |
605bd75af USB: Some cleanup... |
471 |
if_desc->no_of_ep++; |
eaf3e613e usb: Use well-kno... |
472 473 |
memcpy(&if_desc->ep_desc[epno], head, USB_DT_ENDPOINT_SIZE); |
b2fb47f18 USB: Use (get|put... |
474 475 476 477 478 479 480 481 482 |
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 usb: common: Weed... |
483 484 |
debug("if %d, ep %d ", ifno, epno); |
6f5794a6f Refactoring parts... |
485 |
break; |
6497c6670 USB: SS: Add supp... |
486 |
case USB_DT_SS_ENDPOINT_COMP: |
eaf3e613e usb: Use well-kno... |
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 |
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 USB: SS: Add supp... |
504 |
if_desc = &dev->config.if_desc[ifno]; |
eaf3e613e usb: Use well-kno... |
505 506 |
memcpy(&if_desc->ss_ep_comp_desc[epno], head, USB_DT_SS_EP_COMP_SIZE); |
6497c6670 USB: SS: Add supp... |
507 |
break; |
6f5794a6f Refactoring parts... |
508 509 |
default: if (head->bLength == 0) |
5a80b3449 usb: usb_new_devi... |
510 |
return -EINVAL; |
6f5794a6f Refactoring parts... |
511 |
|
ceb4972a8 usb: common: Weed... |
512 513 514 |
debug("unknown Description Type : %x ", head->bDescriptorType); |
6f5794a6f Refactoring parts... |
515 |
|
ceb4972a8 usb: common: Weed... |
516 |
#ifdef DEBUG |
6f5794a6f Refactoring parts... |
517 |
{ |
fad2e1b06 common/usb.c: fix... |
518 |
unsigned char *ch = (unsigned char *)head; |
ceb4972a8 usb: common: Weed... |
519 |
int i; |
6f5794a6f Refactoring parts... |
520 |
for (i = 0; i < head->bLength; i++) |
ceb4972a8 usb: common: Weed... |
521 522 523 524 525 |
debug("%02X ", *ch++); debug(" "); |
6f5794a6f Refactoring parts... |
526 |
} |
ceb4972a8 usb: common: Weed... |
527 |
#endif |
6f5794a6f Refactoring parts... |
528 |
break; |
affae2bff Initial revision |
529 |
} |
7455af41d Add rudimentary h... |
530 531 |
index += head->bLength; head = (struct usb_descriptor_header *)&buffer[index]; |
affae2bff Initial revision |
532 |
} |
5a80b3449 usb: usb_new_devi... |
533 |
return 0; |
affae2bff Initial revision |
534 535 536 537 538 539 540 541 542 543 |
} /*********************************************************************** * 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 Fix low-level OHC... |
544 |
int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); |
affae2bff Initial revision |
545 546 |
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
6f5794a6f Refactoring parts... |
547 548 |
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3); |
affae2bff Initial revision |
549 550 551 552 |
/* don't clear if failed */ if (result < 0) return result; |
9c998aa83 Fix low-level OHC... |
553 |
|
095b8a379 Coding style cleanup |
554 |
/* |
9c998aa83 Fix low-level OHC... |
555 556 557 |
* NOTE: we do not get status and verify reset was successful * as some devices are reported to lock up upon this check.. */ |
affae2bff Initial revision |
558 |
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); |
9c998aa83 Fix low-level OHC... |
559 |
|
affae2bff Initial revision |
560 561 562 563 564 565 566 567 568 |
/* toggle is reset on clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); return 0; } /********************************************************************** * get_descriptor type */ |
c08b1b264 USB: Staticize in... |
569 |
static int usb_get_descriptor(struct usb_device *dev, unsigned char type, |
6f5794a6f Refactoring parts... |
570 |
unsigned char index, void *buf, int size) |
affae2bff Initial revision |
571 |
{ |
8319aeb1d usb: squash lines... |
572 573 574 575 |
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, USB_CNTL_TIMEOUT); |
affae2bff Initial revision |
576 577 578 |
} /********************************************************************** |
c75f57fba usb: Alloc buffer... |
579 |
* gets len of configuration cfgno |
affae2bff Initial revision |
580 |
*/ |
c75f57fba usb: Alloc buffer... |
581 |
int usb_get_configuration_len(struct usb_device *dev, int cfgno) |
affae2bff Initial revision |
582 |
{ |
53677ef18 Big white-space c... |
583 |
int result; |
c75f57fba usb: Alloc buffer... |
584 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 9); |
c60795f41 usb: use linux/us... |
585 |
struct usb_config_descriptor *config; |
affae2bff Initial revision |
586 |
|
c60795f41 usb: use linux/us... |
587 |
config = (struct usb_config_descriptor *)&buffer[0]; |
488672084 fix USB initialis... |
588 589 |
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9); if (result < 9) { |
affae2bff Initial revision |
590 |
if (result < 0) |
6f5794a6f Refactoring parts... |
591 592 593 |
printf("unable to get descriptor, error %lX ", dev->status); |
affae2bff Initial revision |
594 |
else |
6f5794a6f Refactoring parts... |
595 |
printf("config descriptor too short " \ |
488672084 fix USB initialis... |
596 597 |
"(expected %i, got %i) ", 9, result); |
5a80b3449 usb: usb_new_devi... |
598 |
return -EIO; |
affae2bff Initial revision |
599 |
} |
c75f57fba usb: Alloc buffer... |
600 601 |
return le16_to_cpu(config->wTotalLength); } |
affae2bff Initial revision |
602 |
|
c75f57fba usb: Alloc buffer... |
603 604 605 606 607 608 609 610 |
/********************************************************************** * 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 * Patch by Lauren... |
611 |
|
c75f57fba usb: Alloc buffer... |
612 |
config = (struct usb_config_descriptor *)&buffer[0]; |
eaf3e613e usb: Use well-kno... |
613 |
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length); |
c75f57fba usb: Alloc buffer... |
614 615 616 617 |
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 usb: Use well-kno... |
618 |
|
affae2bff Initial revision |
619 620 621 622 623 624 625 |
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 USB: Staticize in... |
626 |
static int usb_set_address(struct usb_device *dev) |
affae2bff Initial revision |
627 |
{ |
ceb4972a8 usb: common: Weed... |
628 629 |
debug("set address %d ", dev->devnum); |
8319aeb1d usb: squash lines... |
630 631 632 |
return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, 0, (dev->devnum), 0, NULL, 0, USB_CNTL_TIMEOUT); |
affae2bff Initial revision |
633 634 635 636 637 638 639 |
} /******************************************************************** * set interface number to interface */ int usb_set_interface(struct usb_device *dev, int interface, int alternate) { |
8f8bd565f USB Consolidate d... |
640 |
struct usb_interface *if_face = NULL; |
affae2bff Initial revision |
641 |
int ret, i; |
8f8bd565f USB Consolidate d... |
642 643 |
for (i = 0; i < dev->config.desc.bNumInterfaces; i++) { if (dev->config.if_desc[i].desc.bInterfaceNumber == interface) { |
affae2bff Initial revision |
644 645 646 647 648 649 |
if_face = &dev->config.if_desc[i]; break; } } if (!if_face) { printf("selecting invalid interface %d", interface); |
5a80b3449 usb: usb_new_devi... |
650 |
return -EINVAL; |
affae2bff Initial revision |
651 |
} |
7455af41d Add rudimentary h... |
652 653 |
/* * We should return now for devices with only one alternate setting. |
6f5794a6f Refactoring parts... |
654 655 656 657 |
* 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 Add rudimentary h... |
658 659 660 |
*/ if (if_face->num_altsetting == 1) return 0; |
affae2bff Initial revision |
661 |
|
6f5794a6f Refactoring parts... |
662 663 664 665 666 |
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 Initial revision |
667 |
return ret; |
affae2bff Initial revision |
668 669 670 671 672 673 |
return 0; } /******************************************************************** * set configuration number to configuration */ |
c08b1b264 USB: Staticize in... |
674 |
static int usb_set_configuration(struct usb_device *dev, int configuration) |
affae2bff Initial revision |
675 676 |
{ int res; |
ceb4972a8 usb: common: Weed... |
677 678 |
debug("set configuration %d ", configuration); |
affae2bff Initial revision |
679 |
/* set setup command */ |
6f5794a6f Refactoring parts... |
680 681 682 683 684 |
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 Initial revision |
685 686 687 |
dev->toggle[0] = 0; dev->toggle[1] = 0; return 0; |
6f5794a6f Refactoring parts... |
688 |
} else |
5a80b3449 usb: usb_new_devi... |
689 |
return -EIO; |
affae2bff Initial revision |
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 |
} /******************************************************************** * 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 Refactoring parts... |
715 716 |
int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size) |
affae2bff Initial revision |
717 718 |
{ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
6f5794a6f Refactoring parts... |
719 720 721 |
USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); |
affae2bff Initial revision |
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
} /******************************************************************** * 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 USB: Staticize in... |
738 |
static int usb_get_string(struct usb_device *dev, unsigned short langid, |
6f5794a6f Refactoring parts... |
739 |
unsigned char index, void *buf, int size) |
affae2bff Initial revision |
740 |
{ |
9c998aa83 Fix low-level OHC... |
741 742 743 744 745 746 747 |
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 Coding style cleanup |
748 |
(USB_DT_STRING << 8) + index, langid, buf, size, |
9c998aa83 Fix low-level OHC... |
749 750 751 752 |
USB_CNTL_TIMEOUT); if (result > 0) break; |
095b8a379 Coding style cleanup |
753 |
} |
9c998aa83 Fix low-level OHC... |
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
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 Initial revision |
770 |
} |
9c998aa83 Fix low-level OHC... |
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 |
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 usb: usb_new_devi... |
801 |
rc = -EINVAL; |
9c998aa83 Fix low-level OHC... |
802 803 804 |
return rc; } |
affae2bff Initial revision |
805 806 807 808 809 810 811 |
/******************************************************************** * 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 USB: Align buffer... |
812 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, mybuf, USB_BUFSIZ); |
affae2bff Initial revision |
813 814 815 816 817 |
unsigned char *tbuf; int err; unsigned int u, idx; if (size <= 0 || !buf || !index) |
5a80b3449 usb: usb_new_devi... |
818 |
return -EINVAL; |
affae2bff Initial revision |
819 |
buf[0] = 0; |
d0ff51ba5 Code cleanup: fix... |
820 |
tbuf = &mybuf[0]; |
affae2bff Initial revision |
821 822 823 |
/* get langid for strings if it's not yet known */ if (!dev->have_langid) { |
9c998aa83 Fix low-level OHC... |
824 |
err = usb_string_sub(dev, 0, 0, tbuf); |
affae2bff Initial revision |
825 |
if (err < 0) { |
ceb4972a8 usb: common: Weed... |
826 827 828 |
debug("error getting string descriptor 0 " \ "(error=%lx) ", dev->status); |
5a80b3449 usb: usb_new_devi... |
829 |
return -EIO; |
affae2bff Initial revision |
830 |
} else if (tbuf[0] < 4) { |
ceb4972a8 usb: common: Weed... |
831 832 |
debug("string descriptor 0 too short "); |
5a80b3449 usb: usb_new_devi... |
833 |
return -EIO; |
affae2bff Initial revision |
834 835 |
} else { dev->have_langid = -1; |
6f5794a6f Refactoring parts... |
836 |
dev->string_langid = tbuf[2] | (tbuf[3] << 8); |
affae2bff Initial revision |
837 |
/* always use the first langid listed */ |
ceb4972a8 usb: common: Weed... |
838 839 840 841 |
debug("USB device number %d default " \ "language ID 0x%x ", dev->devnum, dev->string_langid); |
affae2bff Initial revision |
842 843 |
} } |
cd0a9de68 * Patch by Lauren... |
844 |
|
9c998aa83 Fix low-level OHC... |
845 |
err = usb_string_sub(dev, dev->string_langid, index, tbuf); |
affae2bff Initial revision |
846 847 |
if (err < 0) return err; |
9c998aa83 Fix low-level OHC... |
848 |
|
affae2bff Initial revision |
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 |
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 dm: usb: Convert ... |
868 |
#ifndef CONFIG_DM_USB |
affae2bff Initial revision |
869 870 871 872 |
/* returns a pointer to the device with the index [index]. * if the device is not assigned (dev->devnum==-1) returns NULL */ |
6f5794a6f Refactoring parts... |
873 |
struct usb_device *usb_get_dev_index(int index) |
affae2bff Initial revision |
874 |
{ |
6f5794a6f Refactoring parts... |
875 |
if (usb_dev[index].devnum == -1) |
affae2bff Initial revision |
876 877 878 879 |
return NULL; else return &usb_dev[index]; } |
79b588872 dm: usb: Adjust u... |
880 |
int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp) |
affae2bff Initial revision |
881 882 |
{ int i; |
ceb4972a8 usb: common: Weed... |
883 884 |
debug("New Device %d ", dev_index); |
6f5794a6f Refactoring parts... |
885 886 887 |
if (dev_index == USB_MAX_DEVICE) { printf("ERROR, too many USB Devices, max=%d ", USB_MAX_DEVICE); |
79b588872 dm: usb: Adjust u... |
888 |
return -ENOSPC; |
affae2bff Initial revision |
889 |
} |
6f5794a6f Refactoring parts... |
890 891 892 893 894 895 |
/* 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 usb: lowlevel int... |
896 |
usb_dev[dev_index].controller = controller; |
affae2bff Initial revision |
897 |
dev_index++; |
79b588872 dm: usb: Adjust u... |
898 899 900 |
*devp = &usb_dev[dev_index - 1]; return 0; |
affae2bff Initial revision |
901 |
} |
359439d28 usb: Clean up new... |
902 903 904 905 906 |
/* * Free the newly created device node. * Called in error cases where configuring a newly attached * device fails for some reason. */ |
79b588872 dm: usb: Adjust u... |
907 |
void usb_free_device(struct udevice *controller) |
359439d28 usb: Clean up new... |
908 909 |
{ dev_index--; |
ceb4972a8 usb: common: Weed... |
910 911 |
debug("Freeing device node: %d ", dev_index); |
359439d28 usb: Clean up new... |
912 913 914 |
memset(&usb_dev[dev_index], 0, sizeof(struct usb_device)); usb_dev[dev_index].devnum = -1; } |
affae2bff Initial revision |
915 916 |
/* |
5853e1335 USB: xHCI: Add st... |
917 918 919 920 921 922 923 924 925 |
* 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 dm: usb: Convert ... |
926 |
#endif /* !CONFIG_DM_USB */ |
862e75c0d dm: usb: Refactor... |
927 |
|
682c9f8df usb: Pass device ... |
928 |
static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub) |
862e75c0d dm: usb: Refactor... |
929 |
{ |
3ed9eb93c usb: Don't reset ... |
930 |
if (!hub) |
8802f5634 usb: Add an usb_d... |
931 |
usb_reset_root_port(dev); |
862e75c0d dm: usb: Refactor... |
932 933 934 |
return 0; } |
0ed27905c dm: usb: Complete... |
935 |
static int get_descriptor_len(struct usb_device *dev, int len, int expect_len) |
affae2bff Initial revision |
936 |
{ |
128fcac08 dm: usb: Move des... |
937 |
__maybe_unused struct usb_device_descriptor *desc; |
f57661394 USB: Align buffer... |
938 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ); |
0ed27905c dm: usb: Complete... |
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 |
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 USB: xHCI: Add st... |
964 |
/* |
53d8aa0f6 dm: usb: Drop the... |
965 |
* This is a Windows scheme of initialization sequence, with double |
488672084 fix USB initialis... |
966 |
* reset of the device (Linux uses the same sequence) |
c9e8436b1 USB layer of U-Bo... |
967 968 |
* Some equipment is said to work only with such init sequence; this * patch is based on the work by Alan Stern: |
de39f8c19 USB style patch, ... |
969 970 |
* http://sourceforge.net/mailarchive/forum.php? * thread_id=5729457&forum_id=5398 |
9c998aa83 Fix low-level OHC... |
971 |
*/ |
9c998aa83 Fix low-level OHC... |
972 |
|
53d8aa0f6 dm: usb: Drop the... |
973 974 |
/* * send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is |
9c998aa83 Fix low-level OHC... |
975 976 |
* 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 usb: Fix maxpacke... |
977 978 |
* some more, or keeps on retransmitting the 8 byte header. */ |
9c998aa83 Fix low-level OHC... |
979 |
|
2b338ef41 usb: Fix maxpacke... |
980 981 982 983 984 985 986 987 988 |
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 fix USB initialis... |
989 |
|
c008faa77 usb: Only get 64 ... |
990 |
if (do_read && dev->speed == USB_SPEED_FULL) { |
128fcac08 dm: usb: Move des... |
991 |
int err; |
862e75c0d dm: usb: Refactor... |
992 |
|
128fcac08 dm: usb: Move des... |
993 |
/* |
c008faa77 usb: Only get 64 ... |
994 995 996 997 998 999 1000 1001 1002 |
* 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. |
128fcac08 dm: usb: Move des... |
1003 |
* |
c008faa77 usb: Only get 64 ... |
1004 1005 1006 1007 |
* 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. |
128fcac08 dm: usb: Move des... |
1008 |
*/ |
0ed27905c dm: usb: Complete... |
1009 1010 1011 |
err = get_descriptor_len(dev, 64, 8); if (err) return err; |
9c998aa83 Fix low-level OHC... |
1012 |
} |
488672084 fix USB initialis... |
1013 |
|
de39f8c19 USB style patch, ... |
1014 |
dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; |
affae2bff Initial revision |
1015 1016 |
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; switch (dev->descriptor.bMaxPacketSize0) { |
de39f8c19 USB style patch, ... |
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 |
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 usb: Early failur... |
1029 |
default: |
c008faa77 usb: Only get 64 ... |
1030 1031 |
printf("%s: invalid max packet size ", __func__); |
04ee6ee2c usb: Early failur... |
1032 |
return -EIO; |
affae2bff Initial revision |
1033 |
} |
128fcac08 dm: usb: Move des... |
1034 1035 1036 |
return 0; } |
91398f985 dm: usb: Split ou... |
1037 |
static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read, |
9eb72dd1f usb: usb_setup_de... |
1038 |
struct usb_device *parent) |
128fcac08 dm: usb: Move des... |
1039 |
{ |
91398f985 dm: usb: Split ou... |
1040 |
int err; |
128fcac08 dm: usb: Move des... |
1041 1042 1043 1044 1045 1046 1047 |
/* * 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 dm: usb: Split ou... |
1048 1049 |
err = usb_alloc_device(dev); if (err) { |
128fcac08 dm: usb: Move des... |
1050 1051 |
printf("Cannot allocate device context to get SLOT_ID "); |
91398f985 dm: usb: Split ou... |
1052 |
return err; |
128fcac08 dm: usb: Move des... |
1053 |
} |
128fcac08 dm: usb: Move des... |
1054 1055 1056 |
err = usb_setup_descriptor(dev, do_read); if (err) return err; |
682c9f8df usb: Pass device ... |
1057 |
err = usb_hub_port_reset(dev, parent); |
128fcac08 dm: usb: Move des... |
1058 1059 |
if (err) return err; |
affae2bff Initial revision |
1060 1061 1062 1063 1064 |
dev->devnum = addr; err = usb_set_address(dev); /* set address */ if (err < 0) { |
6f5794a6f Refactoring parts... |
1065 1066 1067 1068 |
printf(" USB device not accepting new address " \ "(error=%lX) ", dev->status); |
91398f985 dm: usb: Split ou... |
1069 |
return err; |
affae2bff Initial revision |
1070 |
} |
5b84dd67c usb: replace wait... |
1071 |
mdelay(10); /* Let the SET_ADDRESS settle */ |
affae2bff Initial revision |
1072 |
|
932bb668b usb: Read device ... |
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 |
/* * If we haven't read device descriptor before, read it here * after device is assigned an address. This is only applicable * to xHCI so far. */ if (!do_read) { err = usb_setup_descriptor(dev, true); if (err) return err; } |
91398f985 dm: usb: Split ou... |
1083 1084 |
return 0; } |
95fbfe429 dm: usb: Convert ... |
1085 |
int usb_select_config(struct usb_device *dev) |
91398f985 dm: usb: Split ou... |
1086 |
{ |
2f1b4302e usb: Don't init p... |
1087 |
unsigned char *tmpbuf = NULL; |
0ed27905c dm: usb: Complete... |
1088 |
int err; |
91398f985 dm: usb: Split ou... |
1089 |
|
0ed27905c dm: usb: Complete... |
1090 1091 1092 |
err = get_descriptor_len(dev, USB_DT_DEVICE_SIZE, USB_DT_DEVICE_SIZE); if (err) return err; |
affae2bff Initial revision |
1093 |
|
affae2bff Initial revision |
1094 |
/* correct le values */ |
c918261c6 USB: replace old ... |
1095 1096 1097 1098 |
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 dm: usb: Complete... |
1099 |
|
ef71290be usb: Assure Get D... |
1100 1101 1102 1103 1104 1105 1106 |
/* * 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 Initial revision |
1107 |
/* only support for one config for now */ |
c75f57fba usb: Alloc buffer... |
1108 1109 1110 1111 1112 1113 1114 1115 |
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 usb: fallback saf... |
1116 1117 1118 1119 1120 |
if (err < 0) { printf("usb_new_device: Cannot read configuration, " \ "skipping device %04x:%04x ", dev->descriptor.idVendor, dev->descriptor.idProduct); |
c75f57fba usb: Alloc buffer... |
1121 |
free(tmpbuf); |
0ed27905c dm: usb: Complete... |
1122 |
return err; |
8b8d779da usb: fallback saf... |
1123 |
} |
f57661394 USB: Align buffer... |
1124 |
usb_parse_config(dev, tmpbuf, 0); |
c75f57fba usb: Alloc buffer... |
1125 |
free(tmpbuf); |
affae2bff Initial revision |
1126 |
usb_set_maxpacket(dev); |
0ed27905c dm: usb: Complete... |
1127 1128 1129 1130 1131 1132 1133 |
/* * 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 Refactoring parts... |
1134 1135 1136 |
printf("failed to set default configuration " \ "len %d, status %lX ", dev->act_len, dev->status); |
0ed27905c dm: usb: Complete... |
1137 |
return err; |
affae2bff Initial revision |
1138 |
} |
f647bf0ba usb: Wait after s... |
1139 1140 1141 1142 1143 1144 1145 |
/* * 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 usb: common: Weed... |
1146 1147 1148 1149 |
debug("new device strings: Mfr=%d, Product=%d, SerialNumber=%d ", dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber); |
affae2bff Initial revision |
1150 1151 1152 1153 |
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 Refactoring parts... |
1154 1155 |
usb_string(dev, dev->descriptor.iManufacturer, dev->mf, sizeof(dev->mf)); |
affae2bff Initial revision |
1156 |
if (dev->descriptor.iProduct) |
6f5794a6f Refactoring parts... |
1157 1158 |
usb_string(dev, dev->descriptor.iProduct, dev->prod, sizeof(dev->prod)); |
affae2bff Initial revision |
1159 |
if (dev->descriptor.iSerialNumber) |
6f5794a6f Refactoring parts... |
1160 1161 |
usb_string(dev, dev->descriptor.iSerialNumber, dev->serial, sizeof(dev->serial)); |
ceb4972a8 usb: common: Weed... |
1162 1163 1164 1165 1166 1167 |
debug("Manufacturer %s ", dev->mf); debug("Product %s ", dev->prod); debug("SerialNumber %s ", dev->serial); |
0ed27905c dm: usb: Complete... |
1168 1169 1170 |
return 0; } |
95fbfe429 dm: usb: Convert ... |
1171 |
int usb_setup_device(struct usb_device *dev, bool do_read, |
9eb72dd1f usb: usb_setup_de... |
1172 |
struct usb_device *parent) |
0ed27905c dm: usb: Complete... |
1173 1174 1175 1176 1177 1178 1179 |
{ int addr; int ret; /* We still haven't set the Address yet */ addr = dev->devnum; dev->devnum = 0; |
9eb72dd1f usb: usb_setup_de... |
1180 |
ret = usb_prepare_device(dev, addr, do_read, parent); |
0ed27905c dm: usb: Complete... |
1181 1182 1183 1184 1185 1186 |
if (ret) return ret; ret = usb_select_config(dev); return ret; } |
95fbfe429 dm: usb: Convert ... |
1187 |
#ifndef CONFIG_DM_USB |
0ed27905c dm: usb: Complete... |
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
/* * 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. */ |
0a8cc1a3a usb: move CONFIG_... |
1206 |
#ifdef CONFIG_USB_XHCI_HCD |
0ed27905c dm: usb: Complete... |
1207 1208 |
do_read = false; #endif |
9eb72dd1f usb: usb_setup_de... |
1209 |
err = usb_setup_device(dev, do_read, dev->parent); |
0ed27905c dm: usb: Complete... |
1210 1211 1212 1213 1214 1215 1216 |
if (err) return err; /* Now probe if the device is a hub */ err = usb_hub_probe(dev, 0); if (err < 0) return err; |
affae2bff Initial revision |
1217 1218 |
return 0; } |
95fbfe429 dm: usb: Convert ... |
1219 |
#endif |
affae2bff Initial revision |
1220 |
|
16297cfb2 usb: new board-sp... |
1221 |
__weak |
bba679144 usb: rename board... |
1222 |
int board_usb_init(int index, enum usb_init_type init) |
16297cfb2 usb: new board-sp... |
1223 1224 1225 |
{ return 0; } |
db378d786 common: cmd_dfu: ... |
1226 1227 1228 1229 1230 1231 |
__weak int board_usb_cleanup(int index, enum usb_init_type init) { return 0; } |
95fbfe429 dm: usb: Convert ... |
1232 1233 1234 1235 1236 1237 1238 1239 1240 |
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 usb: Move determi... |
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 1292 1293 1294 1295 1296 |
#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 Initial revision |
1297 |
/* EOF */ |