Blame view
common/usb.c
33.8 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 39 |
#include <usb.h> #ifdef CONFIG_4xx |
3048bcbf0 ppc4xx: Rename 40... |
40 |
#include <asm/4xx_pci.h> |
affae2bff Initial revision |
41 |
#endif |
cd0a9de68 * Patch by Lauren... |
42 |
#define USB_BUFSIZ 512 |
affae2bff Initial revision |
43 |
static int asynch_allowed; |
e51aae382 Prevent USB comma... |
44 |
char usb_started; /* flag for the started/stopped USB status */ |
95fbfe429 dm: usb: Convert ... |
45 46 47 |
#ifndef CONFIG_DM_USB static struct usb_device usb_dev[USB_MAX_DEVICE]; static int dev_index; |
93c2582fe usb: add support ... |
48 49 50 |
#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif |
affae2bff Initial revision |
51 |
|
affae2bff Initial revision |
52 53 54 |
/*************************************************************************** * Init USB Device */ |
affae2bff Initial revision |
55 56 |
int usb_init(void) { |
93c2582fe usb: add support ... |
57 58 59 |
void *ctrl; struct usb_device *dev; int i, start_index = 0; |
d906bbc26 usb: Do not log a... |
60 |
int controllers_initialized = 0; |
97b9eb9e6 usb: Handle -ENOD... |
61 |
int ret; |
affae2bff Initial revision |
62 |
|
6f5794a6f Refactoring parts... |
63 64 |
dev_index = 0; asynch_allowed = 1; |
affae2bff Initial revision |
65 |
usb_hub_reset(); |
93c2582fe 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 Initial revision |
72 |
/* init low_level USB */ |
93c2582fe 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 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 usb: Do not log a... |
80 |
controllers_initialized++; |
97b9eb9e6 usb: Handle -ENOD... |
81 82 83 84 |
continue; } if (ret) { /* Other error. */ |
93c2582fe 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 usb: Do not log a... |
93 |
controllers_initialized++; |
93c2582fe usb: add support ... |
94 95 |
start_index = dev_index; printf("scanning bus %d for devices... ", i); |
79b588872 dm: usb: Adjust u... |
96 97 |
ret = usb_alloc_new_device(ctrl, &dev); if (ret) |
8879be885 usb: Check usb_ne... |
98 |
break; |
93c2582fe usb: add support ... |
99 100 101 102 |
/* * device 0 is always present * (root hub, so let it analyze) */ |
8879be885 usb: Check usb_ne... |
103 104 |
ret = usb_new_device(dev); if (ret) |
79b588872 dm: usb: Adjust u... |
105 |
usb_free_device(dev->controller); |
93c2582fe usb: add support ... |
106 |
|
8879be885 usb: Check usb_ne... |
107 |
if (start_index == dev_index) { |
93c2582fe usb: add support ... |
108 109 |
puts("No USB Device found "); |
8879be885 usb: Check usb_ne... |
110 111 |
continue; } else { |
93c2582fe usb: add support ... |
112 113 114 |
printf("%d USB Device(s) found ", dev_index - start_index); |
8879be885 usb: Check usb_ne... |
115 |
} |
93c2582fe usb: add support ... |
116 |
|
e51aae382 Prevent USB comma... |
117 |
usb_started = 1; |
93c2582fe usb: add support ... |
118 |
} |
ceb4972a8 usb: common: Weed... |
119 120 |
debug("scan end "); |
93c2582fe usb: add support ... |
121 |
/* if we were not able to find at least one working bus, bail out */ |
d906bbc26 usb: Do not log a... |
122 |
if (controllers_initialized == 0) |
93c2582fe usb: add support ... |
123 124 |
puts("USB error: all controllers failed lowlevel init "); |
93c2582fe usb: add support ... |
125 |
|
5a80b3449 usb: usb_new_devi... |
126 |
return usb_started ? 0 : -ENODEV; |
affae2bff 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 usb: add support ... |
134 |
int i; |
eba1f2fc7 Make usb-stop() s... |
135 136 137 138 139 |
if (usb_started) { asynch_allowed = 1; usb_started = 0; usb_hub_reset(); |
93c2582fe 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 Make usb-stop() s... |
146 |
} |
93c2582fe usb: add support ... |
147 148 |
return 0; |
affae2bff Initial revision |
149 |
} |
08f3bb0bc 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 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 Add USB host ethe... |
178 |
* Returns the old value so it can be restored later. |
affae2bff Initial revision |
179 |
*/ |
89d48367e Add USB host ethe... |
180 |
int usb_disable_asynch(int disable) |
affae2bff Initial revision |
181 |
{ |
89d48367e Add USB host ethe... |
182 |
int old_value = asynch_allowed; |
6f5794a6f Refactoring parts... |
183 |
asynch_allowed = !disable; |
89d48367e Add USB host ethe... |
184 |
return old_value; |
affae2bff Initial revision |
185 |
} |
95fbfe429 dm: usb: Convert ... |
186 |
#endif /* !CONFIG_DM_USB */ |
affae2bff 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 Refactoring parts... |
198 |
void *buffer, int transfer_len, int interval) |
affae2bff Initial revision |
199 |
{ |
6f5794a6f Refactoring parts... |
200 |
return submit_int_msg(dev, pipe, buffer, transfer_len, interval); |
affae2bff 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 Fix spelling of "... |
209 |
* returns the transferred length if OK or -1 if error. The transferred length |
affae2bff 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 USB: Align buffer... |
217 |
ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1); |
651d95c8e usb: usb_control_... |
218 |
int err; |
e159e4868 USB: Make struct ... |
219 |
|
6f5794a6f Refactoring parts... |
220 221 |
if ((timeout == 0) && (!asynch_allowed)) { /* request for a asynch control pipe is not allowed */ |
5a80b3449 usb: usb_new_devi... |
222 |
return -EINVAL; |
6f5794a6f Refactoring parts... |
223 |
} |
9c998aa83 Fix low-level OHC... |
224 |
|
affae2bff Initial revision |
225 |
/* set setup command */ |
f57661394 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 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 Refactoring parts... |
235 |
dev->status = USB_ST_NOT_PROC; /*not yet processed */ |
affae2bff Initial revision |
236 |
|
651d95c8e usb: usb_control_... |
237 238 239 |
err = submit_control_msg(dev, pipe, data, size, setup_packet); if (err < 0) return err; |
6f5794a6f Refactoring parts... |
240 |
if (timeout == 0) |
affae2bff Initial revision |
241 |
return (int)size; |
6f5794a6f Refactoring parts... |
242 |
|
84d36b301 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 usb: replace wait... |
251 |
mdelay(1); |
488672084 fix USB initialis... |
252 |
} |
84d36b301 USB: usb_control_... |
253 254 |
if (dev->status) return -1; |
488672084 fix USB initialis... |
255 256 |
return dev->act_len; |
84d36b301 USB: usb_control_... |
257 |
|
affae2bff Initial revision |
258 259 260 261 |
} /*------------------------------------------------------------------- * submits bulk message, and waits for completion. returns 0 if Ok or |
5a80b3449 usb: usb_new_devi... |
262 |
* negative if Error. |
affae2bff 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 usb: usb_new_devi... |
269 |
return -EINVAL; |
6f5794a6f Refactoring parts... |
270 |
dev->status = USB_ST_NOT_PROC; /*not yet processed */ |
fd06028df usb: check return... |
271 |
if (submit_bulk_msg(dev, pipe, data, len) < 0) |
5a80b3449 usb: usb_new_devi... |
272 |
return -EIO; |
6f5794a6f Refactoring parts... |
273 274 |
while (timeout--) { if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC)) |
affae2bff Initial revision |
275 |
break; |
5b84dd67c usb: replace wait... |
276 |
mdelay(1); |
affae2bff Initial revision |
277 |
} |
6f5794a6f Refactoring parts... |
278 279 |
*actual_length = dev->act_len; if (dev->status == 0) |
affae2bff Initial revision |
280 281 |
return 0; else |
5a80b3449 usb: usb_new_devi... |
282 |
return -EIO; |
affae2bff 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 Refactoring parts... |
294 |
int usb_maxpacket(struct usb_device *dev, unsigned long pipe) |
affae2bff Initial revision |
295 |
{ |
6f5794a6f Refactoring parts... |
296 297 |
/* direction is out -> use emaxpacket out */ if ((pipe & USB_DIR_IN) == 0) |
de39f8c19 USB style patch, ... |
298 |
return dev->epmaxpacketout[((pipe>>15) & 0xf)]; |
affae2bff Initial revision |
299 |
else |
de39f8c19 USB style patch, ... |
300 |
return dev->epmaxpacketin[((pipe>>15) & 0xf)]; |
affae2bff Initial revision |
301 |
} |
5e8baf878 GCC4.6: Fix commo... |
302 303 |
/* * The routine usb_set_maxpacket_ep() is extracted from the loop of routine |
be19d324e 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 GCC4.6: Fix commo... |
310 311 |
* * NOTE: Similar behaviour was observed with GCC4.6 on ARMv5. |
be19d324e Fix for USB stick... |
312 |
*/ |
66cf64107 usb: use noinline... |
313 |
static void noinline |
5e8baf878 GCC4.6: Fix commo... |
314 |
usb_set_maxpacket_ep(struct usb_device *dev, int if_idx, int ep_idx) |
be19d324e Fix for USB stick... |
315 316 |
{ int b; |
5e8baf878 GCC4.6: Fix commo... |
317 |
struct usb_endpoint_descriptor *ep; |
b2fb47f18 USB: Use (get|put... |
318 |
u16 ep_wMaxPacketSize; |
5e8baf878 GCC4.6: Fix commo... |
319 320 |
ep = &dev->config.if_desc[if_idx].ep_desc[ep_idx]; |
be19d324e Fix for USB stick... |
321 322 |
b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; |
b2fb47f18 USB: Use (get|put... |
323 |
ep_wMaxPacketSize = get_unaligned(&ep->wMaxPacketSize); |
be19d324e Fix for USB stick... |
324 325 326 327 |
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ |
b2fb47f18 USB: Use (get|put... |
328 329 |
dev->epmaxpacketout[b] = ep_wMaxPacketSize; dev->epmaxpacketin[b] = ep_wMaxPacketSize; |
ceb4972a8 usb: common: Weed... |
330 331 332 |
debug("##Control EP epmaxpacketout/in[%d] = %d ", b, dev->epmaxpacketin[b]); |
be19d324e Fix for USB stick... |
333 334 335 |
} else { if ((ep->bEndpointAddress & 0x80) == 0) { /* OUT Endpoint */ |
b2fb47f18 USB: Use (get|put... |
336 337 |
if (ep_wMaxPacketSize > dev->epmaxpacketout[b]) { dev->epmaxpacketout[b] = ep_wMaxPacketSize; |
ceb4972a8 usb: common: Weed... |
338 339 340 |
debug("##EP epmaxpacketout[%d] = %d ", b, dev->epmaxpacketout[b]); |
be19d324e Fix for USB stick... |
341 342 343 |
} } else { /* IN Endpoint */ |
b2fb47f18 USB: Use (get|put... |
344 345 |
if (ep_wMaxPacketSize > dev->epmaxpacketin[b]) { dev->epmaxpacketin[b] = ep_wMaxPacketSize; |
ceb4972a8 usb: common: Weed... |
346 347 348 |
debug("##EP epmaxpacketin[%d] = %d ", b, dev->epmaxpacketin[b]); |
be19d324e Fix for USB stick... |
349 350 351 352 |
} } /* if out */ } /* if control */ } |
affae2bff Initial revision |
353 354 355 |
/* * set the max packed value of all endpoints in the given configuration */ |
c08b1b264 USB: Staticize in... |
356 |
static int usb_set_maxpacket(struct usb_device *dev) |
affae2bff Initial revision |
357 |
{ |
be19d324e Fix for USB stick... |
358 |
int i, ii; |
affae2bff Initial revision |
359 |
|
8f8bd565f 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 GCC4.6: Fix commo... |
362 |
usb_set_maxpacket_ep(dev, i, ii); |
affae2bff Initial revision |
363 |
|
affae2bff 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 usb: Use well-kno... |
370 |
* (wTotalLength has already been swapped and sanitized when it was read.) |
affae2bff Initial revision |
371 |
*/ |
c08b1b264 USB: Staticize in... |
372 373 |
static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) |
affae2bff Initial revision |
374 375 |
{ struct usb_descriptor_header *head; |
7455af41d Add rudimentary h... |
376 |
int index, ifno, epno, curr_if_num; |
b2fb47f18 USB: Use (get|put... |
377 |
u16 ep_wMaxPacketSize; |
605bd75af USB: Some cleanup... |
378 |
struct usb_interface *if_desc = NULL; |
7455af41d 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 Refactoring parts... |
386 387 388 389 |
if (head->bDescriptorType != USB_DT_CONFIG) { printf(" ERROR: NOT USB_CONFIG_DESC %x ", head->bDescriptorType); |
5a80b3449 usb: usb_new_devi... |
390 |
return -EINVAL; |
affae2bff Initial revision |
391 |
} |
eaf3e613e usb: Use well-kno... |
392 393 394 |
if (head->bLength != USB_DT_CONFIG_SIZE) { printf("ERROR: Invalid USB CFG length (%d) ", head->bLength); |
5a80b3449 usb: usb_new_devi... |
395 |
return -EINVAL; |
eaf3e613e usb: Use well-kno... |
396 397 |
} memcpy(&dev->config, head, USB_DT_CONFIG_SIZE); |
7455af41d Add rudimentary h... |
398 |
dev->config.no_of_if = 0; |
affae2bff Initial revision |
399 |
|
8f8bd565f USB Consolidate d... |
400 |
index = dev->config.desc.bLength; |
6f5794a6f Refactoring parts... |
401 402 |
/* Ok the first entry must be a configuration entry, * now process the others */ |
7455af41d Add rudimentary h... |
403 |
head = (struct usb_descriptor_header *) &buffer[index]; |
eaf3e613e usb: Use well-kno... |
404 |
while (index + 1 < dev->config.desc.wTotalLength && head->bLength) { |
6f5794a6f Refactoring parts... |
405 406 |
switch (head->bDescriptorType) { case USB_DT_INTERFACE: |
eaf3e613e 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 Refactoring parts... |
419 |
if (((struct usb_interface_descriptor *) \ |
eaf3e613e usb: Use well-kno... |
420 |
head)->bInterfaceNumber != curr_if_num) { |
6f5794a6f Refactoring parts... |
421 422 |
/* this is a new interface, copy new desc */ ifno = dev->config.no_of_if; |
eaf3e613e 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 usb: usb_new_devi... |
427 |
return -EINVAL; |
eaf3e613e usb: Use well-kno... |
428 |
} |
605bd75af USB: Some cleanup... |
429 |
if_desc = &dev->config.if_desc[ifno]; |
6f5794a6f Refactoring parts... |
430 |
dev->config.no_of_if++; |
eaf3e613e usb: Use well-kno... |
431 432 |
memcpy(if_desc, head, USB_DT_INTERFACE_SIZE); |
605bd75af USB: Some cleanup... |
433 434 |
if_desc->no_of_ep = 0; if_desc->num_altsetting = 1; |
6f5794a6f Refactoring parts... |
435 |
curr_if_num = |
605bd75af USB: Some cleanup... |
436 |
if_desc->desc.bInterfaceNumber; |
6f5794a6f Refactoring parts... |
437 438 |
} else { /* found alternate setting for the interface */ |
605bd75af USB: Some cleanup... |
439 440 441 442 |
if (ifno >= 0) { if_desc = &dev->config.if_desc[ifno]; if_desc->num_altsetting++; } |
6f5794a6f Refactoring parts... |
443 444 445 |
} break; case USB_DT_ENDPOINT: |
eaf3e613e 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 Refactoring parts... |
463 |
epno = dev->config.if_desc[ifno].no_of_ep; |
605bd75af USB: Some cleanup... |
464 |
if_desc = &dev->config.if_desc[ifno]; |
447b9cdf2 common: usb: fix ... |
465 |
if (epno >= USB_MAXENDPOINTS) { |
eaf3e613e usb: Use well-kno... |
466 467 468 |
printf("Interface %d has too many endpoints! ", if_desc->desc.bInterfaceNumber); |
5a80b3449 usb: usb_new_devi... |
469 |
return -EINVAL; |
eaf3e613e usb: Use well-kno... |
470 |
} |
6f5794a6f Refactoring parts... |
471 |
/* found an endpoint */ |
605bd75af USB: Some cleanup... |
472 |
if_desc->no_of_ep++; |
eaf3e613e usb: Use well-kno... |
473 474 |
memcpy(&if_desc->ep_desc[epno], head, USB_DT_ENDPOINT_SIZE); |
b2fb47f18 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 usb: common: Weed... |
484 485 |
debug("if %d, ep %d ", ifno, epno); |
6f5794a6f Refactoring parts... |
486 |
break; |
6497c6670 USB: SS: Add supp... |
487 |
case USB_DT_SS_ENDPOINT_COMP: |
eaf3e613e 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 USB: SS: Add supp... |
505 |
if_desc = &dev->config.if_desc[ifno]; |
eaf3e613e usb: Use well-kno... |
506 507 |
memcpy(&if_desc->ss_ep_comp_desc[epno], head, USB_DT_SS_EP_COMP_SIZE); |
6497c6670 USB: SS: Add supp... |
508 |
break; |
6f5794a6f Refactoring parts... |
509 510 |
default: if (head->bLength == 0) |
5a80b3449 usb: usb_new_devi... |
511 |
return -EINVAL; |
6f5794a6f Refactoring parts... |
512 |
|
ceb4972a8 usb: common: Weed... |
513 514 515 |
debug("unknown Description Type : %x ", head->bDescriptorType); |
6f5794a6f Refactoring parts... |
516 |
|
ceb4972a8 usb: common: Weed... |
517 |
#ifdef DEBUG |
6f5794a6f Refactoring parts... |
518 |
{ |
fad2e1b06 common/usb.c: fix... |
519 |
unsigned char *ch = (unsigned char *)head; |
ceb4972a8 usb: common: Weed... |
520 |
int i; |
6f5794a6f Refactoring parts... |
521 |
for (i = 0; i < head->bLength; i++) |
ceb4972a8 usb: common: Weed... |
522 523 524 525 526 |
debug("%02X ", *ch++); debug(" "); |
6f5794a6f Refactoring parts... |
527 |
} |
ceb4972a8 usb: common: Weed... |
528 |
#endif |
6f5794a6f Refactoring parts... |
529 |
break; |
affae2bff Initial revision |
530 |
} |
7455af41d Add rudimentary h... |
531 532 |
index += head->bLength; head = (struct usb_descriptor_header *)&buffer[index]; |
affae2bff Initial revision |
533 |
} |
5a80b3449 usb: usb_new_devi... |
534 |
return 0; |
affae2bff 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 Fix low-level OHC... |
545 |
int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); |
affae2bff Initial revision |
546 547 |
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
6f5794a6f Refactoring parts... |
548 549 |
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3); |
affae2bff Initial revision |
550 551 552 553 |
/* don't clear if failed */ if (result < 0) return result; |
9c998aa83 Fix low-level OHC... |
554 |
|
095b8a379 Coding style cleanup |
555 |
/* |
9c998aa83 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 Initial revision |
559 |
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); |
9c998aa83 Fix low-level OHC... |
560 |
|
affae2bff 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 USB: Staticize in... |
570 |
static int usb_get_descriptor(struct usb_device *dev, unsigned char type, |
6f5794a6f Refactoring parts... |
571 |
unsigned char index, void *buf, int size) |
affae2bff Initial revision |
572 573 |
{ int res; |
53677ef18 Big white-space c... |
574 |
res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
affae2bff 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 usb: Alloc buffer... |
582 |
* gets len of configuration cfgno |
affae2bff Initial revision |
583 |
*/ |
c75f57fba usb: Alloc buffer... |
584 |
int usb_get_configuration_len(struct usb_device *dev, int cfgno) |
affae2bff Initial revision |
585 |
{ |
53677ef18 Big white-space c... |
586 |
int result; |
c75f57fba usb: Alloc buffer... |
587 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 9); |
c60795f41 usb: use linux/us... |
588 |
struct usb_config_descriptor *config; |
affae2bff Initial revision |
589 |
|
c60795f41 usb: use linux/us... |
590 |
config = (struct usb_config_descriptor *)&buffer[0]; |
488672084 fix USB initialis... |
591 592 |
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9); if (result < 9) { |
affae2bff Initial revision |
593 |
if (result < 0) |
6f5794a6f Refactoring parts... |
594 595 596 |
printf("unable to get descriptor, error %lX ", dev->status); |
affae2bff Initial revision |
597 |
else |
6f5794a6f Refactoring parts... |
598 |
printf("config descriptor too short " \ |
488672084 fix USB initialis... |
599 600 |
"(expected %i, got %i) ", 9, result); |
5a80b3449 usb: usb_new_devi... |
601 |
return -EIO; |
affae2bff Initial revision |
602 |
} |
c75f57fba usb: Alloc buffer... |
603 604 |
return le16_to_cpu(config->wTotalLength); } |
affae2bff Initial revision |
605 |
|
c75f57fba 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 * Patch by Lauren... |
614 |
|
c75f57fba usb: Alloc buffer... |
615 |
config = (struct usb_config_descriptor *)&buffer[0]; |
eaf3e613e usb: Use well-kno... |
616 |
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length); |
c75f57fba 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 usb: Use well-kno... |
621 |
|
affae2bff 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 USB: Staticize in... |
629 |
static int usb_set_address(struct usb_device *dev) |
affae2bff Initial revision |
630 631 |
{ int res; |
ceb4972a8 usb: common: Weed... |
632 633 |
debug("set address %d ", dev->devnum); |
6f5794a6f 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 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 USB Consolidate d... |
646 |
struct usb_interface *if_face = NULL; |
affae2bff Initial revision |
647 |
int ret, i; |
8f8bd565f USB Consolidate d... |
648 649 |
for (i = 0; i < dev->config.desc.bNumInterfaces; i++) { if (dev->config.if_desc[i].desc.bInterfaceNumber == interface) { |
affae2bff 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 usb: usb_new_devi... |
656 |
return -EINVAL; |
affae2bff Initial revision |
657 |
} |
7455af41d Add rudimentary h... |
658 659 |
/* * We should return now for devices with only one alternate setting. |
6f5794a6f 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 Add rudimentary h... |
664 665 666 |
*/ if (if_face->num_altsetting == 1) return 0; |
affae2bff Initial revision |
667 |
|
6f5794a6f 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 Initial revision |
673 |
return ret; |
affae2bff Initial revision |
674 675 676 677 678 679 |
return 0; } /******************************************************************** * set configuration number to configuration */ |
c08b1b264 USB: Staticize in... |
680 |
static int usb_set_configuration(struct usb_device *dev, int configuration) |
affae2bff Initial revision |
681 682 |
{ int res; |
ceb4972a8 usb: common: Weed... |
683 684 |
debug("set configuration %d ", configuration); |
affae2bff Initial revision |
685 |
/* set setup command */ |
6f5794a6f 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 Initial revision |
691 692 693 |
dev->toggle[0] = 0; dev->toggle[1] = 0; return 0; |
6f5794a6f Refactoring parts... |
694 |
} else |
5a80b3449 usb: usb_new_devi... |
695 |
return -EIO; |
affae2bff 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 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 Initial revision |
723 724 |
{ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
6f5794a6f 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 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 USB: Staticize in... |
744 |
static int usb_get_string(struct usb_device *dev, unsigned short langid, |
6f5794a6f Refactoring parts... |
745 |
unsigned char index, void *buf, int size) |
affae2bff Initial revision |
746 |
{ |
9c998aa83 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 Coding style cleanup |
754 |
(USB_DT_STRING << 8) + index, langid, buf, size, |
9c998aa83 Fix low-level OHC... |
755 756 757 758 |
USB_CNTL_TIMEOUT); if (result > 0) break; |
095b8a379 Coding style cleanup |
759 |
} |
9c998aa83 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 Initial revision |
776 |
} |
9c998aa83 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 usb: usb_new_devi... |
807 |
rc = -EINVAL; |
9c998aa83 Fix low-level OHC... |
808 809 810 |
return rc; } |
affae2bff 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 USB: Align buffer... |
818 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, mybuf, USB_BUFSIZ); |
affae2bff Initial revision |
819 820 821 822 823 |
unsigned char *tbuf; int err; unsigned int u, idx; if (size <= 0 || !buf || !index) |
5a80b3449 usb: usb_new_devi... |
824 |
return -EINVAL; |
affae2bff Initial revision |
825 |
buf[0] = 0; |
d0ff51ba5 Code cleanup: fix... |
826 |
tbuf = &mybuf[0]; |
affae2bff Initial revision |
827 828 829 |
/* get langid for strings if it's not yet known */ if (!dev->have_langid) { |
9c998aa83 Fix low-level OHC... |
830 |
err = usb_string_sub(dev, 0, 0, tbuf); |
affae2bff Initial revision |
831 |
if (err < 0) { |
ceb4972a8 usb: common: Weed... |
832 833 834 |
debug("error getting string descriptor 0 " \ "(error=%lx) ", dev->status); |
5a80b3449 usb: usb_new_devi... |
835 |
return -EIO; |
affae2bff Initial revision |
836 |
} else if (tbuf[0] < 4) { |
ceb4972a8 usb: common: Weed... |
837 838 |
debug("string descriptor 0 too short "); |
5a80b3449 usb: usb_new_devi... |
839 |
return -EIO; |
affae2bff Initial revision |
840 841 |
} else { dev->have_langid = -1; |
6f5794a6f Refactoring parts... |
842 |
dev->string_langid = tbuf[2] | (tbuf[3] << 8); |
affae2bff Initial revision |
843 |
/* always use the first langid listed */ |
ceb4972a8 usb: common: Weed... |
844 845 846 847 |
debug("USB device number %d default " \ "language ID 0x%x ", dev->devnum, dev->string_langid); |
affae2bff Initial revision |
848 849 |
} } |
cd0a9de68 * Patch by Lauren... |
850 |
|
9c998aa83 Fix low-level OHC... |
851 |
err = usb_string_sub(dev, dev->string_langid, index, tbuf); |
affae2bff Initial revision |
852 853 |
if (err < 0) return err; |
9c998aa83 Fix low-level OHC... |
854 |
|
affae2bff 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 dm: usb: Convert ... |
874 |
#ifndef CONFIG_DM_USB |
affae2bff 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 Refactoring parts... |
879 |
struct usb_device *usb_get_dev_index(int index) |
affae2bff Initial revision |
880 |
{ |
6f5794a6f Refactoring parts... |
881 |
if (usb_dev[index].devnum == -1) |
affae2bff Initial revision |
882 883 884 885 |
return NULL; else return &usb_dev[index]; } |
79b588872 dm: usb: Adjust u... |
886 |
int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp) |
affae2bff Initial revision |
887 888 |
{ int i; |
ceb4972a8 usb: common: Weed... |
889 890 |
debug("New Device %d ", dev_index); |
6f5794a6f Refactoring parts... |
891 892 893 |
if (dev_index == USB_MAX_DEVICE) { printf("ERROR, too many USB Devices, max=%d ", USB_MAX_DEVICE); |
79b588872 dm: usb: Adjust u... |
894 |
return -ENOSPC; |
affae2bff Initial revision |
895 |
} |
6f5794a6f 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 usb: lowlevel int... |
902 |
usb_dev[dev_index].controller = controller; |
affae2bff Initial revision |
903 |
dev_index++; |
79b588872 dm: usb: Adjust u... |
904 905 906 |
*devp = &usb_dev[dev_index - 1]; return 0; |
affae2bff Initial revision |
907 |
} |
359439d28 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 dm: usb: Adjust u... |
913 |
void usb_free_device(struct udevice *controller) |
359439d28 usb: Clean up new... |
914 915 |
{ dev_index--; |
ceb4972a8 usb: common: Weed... |
916 917 |
debug("Freeing device node: %d ", dev_index); |
359439d28 usb: Clean up new... |
918 919 920 |
memset(&usb_dev[dev_index], 0, sizeof(struct usb_device)); usb_dev[dev_index].devnum = -1; } |
affae2bff Initial revision |
921 922 |
/* |
5853e1335 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 dm: usb: Convert ... |
932 |
#endif /* !CONFIG_DM_USB */ |
862e75c0d dm: usb: Refactor... |
933 |
|
682c9f8df usb: Pass device ... |
934 |
static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub) |
862e75c0d dm: usb: Refactor... |
935 |
{ |
3ed9eb93c usb: Don't reset ... |
936 |
if (!hub) |
8802f5634 usb: Add an usb_d... |
937 |
usb_reset_root_port(dev); |
862e75c0d dm: usb: Refactor... |
938 939 940 |
return 0; } |
0ed27905c dm: usb: Complete... |
941 |
static int get_descriptor_len(struct usb_device *dev, int len, int expect_len) |
affae2bff Initial revision |
942 |
{ |
128fcac08 dm: usb: Move des... |
943 |
__maybe_unused struct usb_device_descriptor *desc; |
f57661394 USB: Align buffer... |
944 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ); |
0ed27905c 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 USB: xHCI: Add st... |
970 |
/* |
53d8aa0f6 dm: usb: Drop the... |
971 |
* This is a Windows scheme of initialization sequence, with double |
488672084 fix USB initialis... |
972 |
* reset of the device (Linux uses the same sequence) |
c9e8436b1 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 USB style patch, ... |
975 976 |
* http://sourceforge.net/mailarchive/forum.php? * thread_id=5729457&forum_id=5398 |
9c998aa83 Fix low-level OHC... |
977 |
*/ |
9c998aa83 Fix low-level OHC... |
978 |
|
53d8aa0f6 dm: usb: Drop the... |
979 980 |
/* * send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is |
9c998aa83 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 usb: Fix maxpacke... |
983 984 |
* some more, or keeps on retransmitting the 8 byte header. */ |
9c998aa83 Fix low-level OHC... |
985 |
|
2b338ef41 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 fix USB initialis... |
995 |
|
128fcac08 dm: usb: Move des... |
996 997 |
if (do_read) { int err; |
862e75c0d dm: usb: Refactor... |
998 |
|
128fcac08 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 dm: usb: Complete... |
1014 1015 1016 |
err = get_descriptor_len(dev, 64, 8); if (err) return err; |
9c998aa83 Fix low-level OHC... |
1017 |
} |
488672084 fix USB initialis... |
1018 |
|
de39f8c19 USB style patch, ... |
1019 |
dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; |
affae2bff Initial revision |
1020 1021 |
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; switch (dev->descriptor.bMaxPacketSize0) { |
de39f8c19 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 usb: Early failur... |
1034 1035 1036 1037 |
default: printf("usb_new_device: invalid max packet size "); return -EIO; |
affae2bff Initial revision |
1038 |
} |
128fcac08 dm: usb: Move des... |
1039 1040 1041 |
return 0; } |
91398f985 dm: usb: Split ou... |
1042 |
static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read, |
9eb72dd1f usb: usb_setup_de... |
1043 |
struct usb_device *parent) |
128fcac08 dm: usb: Move des... |
1044 |
{ |
91398f985 dm: usb: Split ou... |
1045 |
int err; |
128fcac08 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 dm: usb: Split ou... |
1053 1054 |
err = usb_alloc_device(dev); if (err) { |
128fcac08 dm: usb: Move des... |
1055 1056 |
printf("Cannot allocate device context to get SLOT_ID "); |
91398f985 dm: usb: Split ou... |
1057 |
return err; |
128fcac08 dm: usb: Move des... |
1058 |
} |
128fcac08 dm: usb: Move des... |
1059 1060 1061 |
err = usb_setup_descriptor(dev, do_read); if (err) return err; |
682c9f8df usb: Pass device ... |
1062 |
err = usb_hub_port_reset(dev, parent); |
128fcac08 dm: usb: Move des... |
1063 1064 |
if (err) return err; |
affae2bff Initial revision |
1065 1066 1067 1068 1069 |
dev->devnum = addr; err = usb_set_address(dev); /* set address */ if (err < 0) { |
6f5794a6f Refactoring parts... |
1070 1071 1072 1073 |
printf(" USB device not accepting new address " \ "(error=%lX) ", dev->status); |
91398f985 dm: usb: Split ou... |
1074 |
return err; |
affae2bff Initial revision |
1075 |
} |
5b84dd67c usb: replace wait... |
1076 |
mdelay(10); /* Let the SET_ADDRESS settle */ |
affae2bff Initial revision |
1077 |
|
91398f985 dm: usb: Split ou... |
1078 1079 |
return 0; } |
95fbfe429 dm: usb: Convert ... |
1080 |
int usb_select_config(struct usb_device *dev) |
91398f985 dm: usb: Split ou... |
1081 |
{ |
2f1b4302e usb: Don't init p... |
1082 |
unsigned char *tmpbuf = NULL; |
0ed27905c dm: usb: Complete... |
1083 |
int err; |
91398f985 dm: usb: Split ou... |
1084 |
|
0ed27905c dm: usb: Complete... |
1085 1086 1087 |
err = get_descriptor_len(dev, USB_DT_DEVICE_SIZE, USB_DT_DEVICE_SIZE); if (err) return err; |
affae2bff Initial revision |
1088 |
|
affae2bff Initial revision |
1089 |
/* correct le values */ |
c918261c6 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 dm: usb: Complete... |
1094 |
|
ef71290be 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 Initial revision |
1102 |
/* only support for one config for now */ |
c75f57fba 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 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 usb: Alloc buffer... |
1116 |
free(tmpbuf); |
0ed27905c dm: usb: Complete... |
1117 |
return err; |
8b8d779da usb: fallback saf... |
1118 |
} |
f57661394 USB: Align buffer... |
1119 |
usb_parse_config(dev, tmpbuf, 0); |
c75f57fba usb: Alloc buffer... |
1120 |
free(tmpbuf); |
affae2bff Initial revision |
1121 |
usb_set_maxpacket(dev); |
0ed27905c 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 Refactoring parts... |
1129 1130 1131 |
printf("failed to set default configuration " \ "len %d, status %lX ", dev->act_len, dev->status); |
0ed27905c dm: usb: Complete... |
1132 |
return err; |
affae2bff Initial revision |
1133 |
} |
f647bf0ba 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 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 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 Refactoring parts... |
1149 1150 |
usb_string(dev, dev->descriptor.iManufacturer, dev->mf, sizeof(dev->mf)); |
affae2bff Initial revision |
1151 |
if (dev->descriptor.iProduct) |
6f5794a6f Refactoring parts... |
1152 1153 |
usb_string(dev, dev->descriptor.iProduct, dev->prod, sizeof(dev->prod)); |
affae2bff Initial revision |
1154 |
if (dev->descriptor.iSerialNumber) |
6f5794a6f Refactoring parts... |
1155 1156 |
usb_string(dev, dev->descriptor.iSerialNumber, dev->serial, sizeof(dev->serial)); |
ceb4972a8 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 dm: usb: Complete... |
1163 1164 1165 |
return 0; } |
95fbfe429 dm: usb: Convert ... |
1166 |
int usb_setup_device(struct usb_device *dev, bool do_read, |
9eb72dd1f usb: usb_setup_de... |
1167 |
struct usb_device *parent) |
0ed27905c 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 usb: usb_setup_de... |
1175 |
ret = usb_prepare_device(dev, addr, do_read, parent); |
0ed27905c dm: usb: Complete... |
1176 1177 1178 1179 1180 1181 |
if (ret) return ret; ret = usb_select_config(dev); return ret; } |
95fbfe429 dm: usb: Convert ... |
1182 |
#ifndef CONFIG_DM_USB |
0ed27905c 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 usb: usb_setup_de... |
1204 |
err = usb_setup_device(dev, do_read, dev->parent); |
0ed27905c 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 Initial revision |
1212 1213 |
return 0; } |
95fbfe429 dm: usb: Convert ... |
1214 |
#endif |
affae2bff Initial revision |
1215 |
|
16297cfb2 usb: new board-sp... |
1216 |
__weak |
bba679144 usb: rename board... |
1217 |
int board_usb_init(int index, enum usb_init_type init) |
16297cfb2 usb: new board-sp... |
1218 1219 1220 |
{ return 0; } |
db378d786 common: cmd_dfu: ... |
1221 1222 1223 1224 1225 1226 |
__weak int board_usb_cleanup(int index, enum usb_init_type init) { return 0; } |
95fbfe429 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 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 Initial revision |
1292 |
/* EOF */ |