1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * USB Hub and device discovery code File: usbhub.c 5 * 6 * This module deals with hubs and device discovery. 7 * 8 * Author: Mitch Lichtenberg 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003,2005 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47 48#ifndef _CFE_ 49#include <stdio.h> 50#include <time.h> 51#include <memory.h> 52#include <stdint.h> 53#include "usbhack.h" 54#include "lib_malloc.h" 55#include "lib_queue.h" 56#else 57#include "cfe.h" 58#endif 59 60#include "usbchap9.h" 61#include "usbd.h" 62 63/* For systems with non-coherent DMA, allocate all buffers to be 64 cache-aligned and multiples of a cache line in size, so that they 65 can be safely flushed or invalidated. */ 66 67#define CACHE_ALIGN 32 /* XXX place holder, big enough to now. */ 68#define BUFF_ALIGN 16 69#define ALIGN(n,align) (((n)+((align)-1)) & ~((align)-1)) 70 71#define usb_dma_alloc(n) (KMALLOC(ALIGN((n),CACHE_ALIGN),BUFF_ALIGN)) 72#define usb_dma_free(p) (KFREE(p)) 73 74/* ********************************************************************* 75 * Macros for common hub requests 76 ********************************************************************* */ 77 78#define usbhub_set_port_feature(dev,port,feature) \ 79 usb_simple_request(dev,0x23,USB_HUBREQ_SET_FEATURE,feature,port) 80 81#define usbhub_set_hub_feature(dev,feature) \ 82 usb_simple_request(dev,0x20,USB_HUBREQ_SET_FEATURE,feature,0) 83 84#define usbhub_clear_port_feature(dev,port,feature) \ 85 usb_simple_request(dev,0x23,USB_HUBREQ_CLEAR_FEATURE,feature,port) 86 87#define usbhub_clear_hub_feature(dev,feature) \ 88 usb_simple_request(dev,0x20,USB_HUBREQ_CLEAR_FEATURE,feature,0) 89 90 91/* ********************************************************************* 92 * Externs 93 ********************************************************************* */ 94 95extern int usb_noisy; 96 97/* ********************************************************************* 98 * Forward declarations 99 ********************************************************************* */ 100 101static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv); 102static int usbhub_detach(usbdev_t *dev); 103static void usbhub_markdetached(usbdev_t *dev); 104 105/* ********************************************************************* 106 * Hub-specific data structures 107 ********************************************************************* */ 108 109#define UHUB_MAX_DEVICES 8 110 111#define UHUB_FLG_NEEDSCAN 1 112 113typedef struct usbhub_softc_s { 114 usb_hub_descr_t uhub_descr; 115 usb_hub_status_t uhub_status; 116 int uhub_ipipe; 117 int uhub_ipipemps; 118 int uhub_nports; 119 unsigned int uhub_flags; 120 uint8_t *uhub_imsg; 121 usbdev_t *uhub_devices[UHUB_MAX_DEVICES]; 122} usbhub_softc_t; 123 124usb_driver_t usbhub_driver = { 125 "USB Hub", 126 usbhub_attach, 127 usbhub_detach 128}; 129 130usb_driver_t usbroothub_driver = { 131 "Root Hub", 132 usbhub_attach, 133 usbhub_detach 134}; 135 136 137/* ********************************************************************* 138 * usbhub_ireq_callback(ur) 139 * 140 * this routine is called when the transfer we queued to the 141 * interrupt endpoint on the hub completes. It means that 142 * *some* port on the hub needs attention. The data indicates 143 * which port, but for our purposes we don't really care - if 144 * we get this callback, we'll set a flag and re-probe the bus. 145 * 146 * Input parameters: 147 * ur - usbreq that completed 148 * 149 * Return value: 150 * 0 151 ********************************************************************* */ 152 153static int usbhub_ireq_callback(usbreq_t *ur) 154{ 155 int idx; 156 usbhub_softc_t *uhub = (ur->ur_dev->ud_private); 157 158 /* 159 * Check to see if the request was cancelled by someone 160 * deleting our endpoint. We also check for "device not responding" 161 * which typically happens when a device is removed. 162 * 163 * XXX this is not correct, it appears that hubs sometimes do 164 * return this error. We'll need to redo the whole way 165 * surprise detach works eventually... 166 */ 167 168 if ((ur->ur_status == UR_ERR_CANCELLED) || 169 (ur->ur_status == UR_ERR_DEVICENOTRESPONDING)) { 170 usb_free_request(ur); 171 return 0; 172 } 173 174 /* 175 * Check to see if any of our ports need attention 176 */ 177 178 for (idx = 1; idx <= uhub->uhub_nports; idx++) { 179 if (ur->ur_buffer[0] & (1<<idx)) { 180 181 /* 182 * Mark the hub as needing a scan, and mark the bus as well 183 * so the top-level polling will notice. 184 */ 185 186 uhub->uhub_flags |= UHUB_FLG_NEEDSCAN; 187 ur->ur_dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN; 188 } 189 } 190 191 192 /* 193 * Do NOT requeue the request here. We will do this 194 * during exploration. 195 */ 196 197 usb_free_request(ur); 198 199 return 0; 200} 201 202 203/* ********************************************************************* 204 * usbhub_get_hub_descriptor(dev,dscr,idx,maxlen) 205 * 206 * Obtain the hub descriptor (special for hubs) from the 207 * device. 208 * 209 * Input parameters: 210 * dev - usb device 211 * dscr - place to put hub descriptor 212 * idx - which hub descriptor to get (usually zero) 213 * maxlen - max # of bytes to return 214 * 215 * Return value: 216 * result status 217 ********************************************************************* */ 218 219static int usbhub_get_hub_descriptor(usbdev_t *dev,usb_hub_descr_t *dscr,int idx,int maxlen) 220{ 221 int res; 222 uint8_t *respbuf; 223 int len; 224 225 /* 226 * Get the hub descriptor. Get the first 8 bytes first, then get 227 * the rest if there is more. 228 */ 229 230 respbuf = usb_dma_alloc(USB_HUB_DESCR_SIZE); 231 res = usb_std_request(dev,0xA0, 232 USB_HUBREQ_GET_DESCRIPTOR, 233 0, 0, 234 respbuf, 235 USB_HUB_DESCR_SIZE); 236 len = ((usb_hub_descr_t *)respbuf)->bDescriptorLength; 237 if (len > USB_HUB_DESCR_SIZE) { 238 usb_dma_free(respbuf); 239 respbuf = usb_dma_alloc(USB_HUB_DESCR_SIZE); 240 res = usb_std_request(dev,0xA0, 241 USB_HUBREQ_GET_DESCRIPTOR, 242 0, 0, 243 respbuf, 244 len); 245 } 246 memcpy(dscr, respbuf, (len <= maxlen ? len : maxlen)); 247 usb_dma_free(respbuf); 248 return res; 249} 250 251 252/* ********************************************************************* 253 * usbhub_get_hub_status(dev,status) 254 * 255 * Obtain the hub status (special for hubs) from the 256 * device. 257 * 258 * Input parameters: 259 * dev - usb device 260 * status - where to put hub status structure 261 * 262 * Return value: 263 * # of bytes returned 264 ********************************************************************* */ 265 266#if 0 267static int usbhub_get_hub_status(usbdev_t *dev,usb_hub_status_t *status) 268{ 269 return usb_std_request(dev, 270 0xA0, 271 0x00, 272 0, 273 0, 274 (uint8_t *) status, 275 sizeof(usbhub_status_t)); 276} 277#endif 278 279 280/* ********************************************************************* 281 * usbhub_get_port_status(dev,port,status) 282 * 283 * Obtain the port status for a particular port from 284 * device. 285 * 286 * Input parameters: 287 * dev - usb device 288 * port - 1-based port number 289 * status - where to put port status structure 290 * 291 * Return value: 292 * # of bytes returned 293 ********************************************************************* */ 294 295static int usbhub_get_port_status(usbdev_t *dev,int port,usb_port_status_t *status) 296{ 297 return usb_std_request(dev, 298 0xA3, 299 0, 300 0, 301 port, 302 (uint8_t *) status, 303 sizeof(usb_port_status_t)); 304} 305 306 307/* ********************************************************************* 308 * usbhub_queue_intreq(dev,softc) 309 * 310 * Queue the transfer to the interrupt pipe that will catch 311 * the hub's port status changes 312 * 313 * Input parameters: 314 * dev - usb device 315 * softc - hub-specific data 316 * 317 * Return value: 318 * nothing 319 ********************************************************************* */ 320 321static void usbhub_queue_intreq(usbdev_t *dev,usbhub_softc_t *softc) 322{ 323 usbreq_t *ur; 324 325 ur = usb_make_request(dev, 326 softc->uhub_ipipe, 327 softc->uhub_imsg,softc->uhub_ipipemps, 328 UR_FLAG_IN | UR_FLAG_SHORTOK); 329 330 ur->ur_callback = usbhub_ireq_callback; 331 332 usb_queue_request(ur); 333} 334 335 336/* ********************************************************************* 337 * usbhub_attach(dev,drv) 338 * 339 * This routine is called when the hub attaches to the system. 340 * We complete initialization for the hub and set things up so 341 * that an explore will happen soon. 342 * 343 * Input parameters: 344 * dev - usb device 345 * drv - driver structure 346 * 347 * Return value: 348 * 0 349 ********************************************************************* */ 350 351static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv) 352{ 353 usb_device_status_t devstatus; 354 usb_config_descr_t *cfgdscr; 355 usb_interface_descr_t *ifdscr; 356 usb_endpoint_descr_t *epdscr; 357 usbhub_softc_t *softc; 358 359 /* 360 * Remember the driver dispatch. 361 */ 362 363 dev->ud_drv = drv; 364 365 softc = KMALLOC(sizeof(usbhub_softc_t),0); 366 memset(softc,0,sizeof(usbhub_softc_t)); 367 softc->uhub_imsg = NULL; 368 dev->ud_private = softc; 369 370 /* 371 * Dig out the data from the configuration descriptor 372 * (we got this from the device before attach time) 373 */ 374 375 cfgdscr = dev->ud_cfgdescr; 376 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,0); 377 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); 378 379 /* 380 * Get device status (is this really necessary?) 381 */ 382 383 usb_get_device_status(dev,&devstatus); 384 385 /* 386 * Set us to configuration index 0 387 */ 388 389 usb_set_configuration(dev,cfgdscr->bConfigurationValue); 390 391 /* 392 * Get the hub descriptor. 393 */ 394 395 usbhub_get_hub_descriptor(dev,&softc->uhub_descr,0,sizeof(usb_hub_descr_t)); 396 397 /* 398 * remember stuff from the hub descriptor 399 */ 400 401 softc->uhub_nports = softc->uhub_descr.bNumberOfPorts; 402 403 /* 404 * Open the interrupt pipe 405 */ 406 407 softc->uhub_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize); 408 softc->uhub_imsg = usb_dma_alloc(softc->uhub_ipipemps); 409 softc->uhub_ipipe = usb_open_pipe(dev,epdscr); 410 411 /* 412 * Mark the bus and the hub as needing service. 413 */ 414 415 softc->uhub_flags |= UHUB_FLG_NEEDSCAN; 416 dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN; 417 418 /* 419 * Okay, that's it. The top-level USB daemon will notice 420 * that the bus needs service and will invoke the exploration code. 421 * This may in turn require additional explores until 422 * everything settles down. 423 */ 424 425 return 0; 426} 427 428 429/* ********************************************************************* 430 * usbhub_detach(dev) 431 * 432 * Called when a hub is removed from the system - we remove 433 * all subordinate devices. 434 * 435 * Input parameters: 436 * dev - device (hub) that was removed 437 * 438 * Return value: 439 * 0 440 ********************************************************************* */ 441 442static int usbhub_detach(usbdev_t *dev) 443{ 444 usbhub_softc_t *hub; 445 usbdev_t *deldev; 446 int idx; 447 448 if (!IS_HUB(dev)) return 0; /* should not happen */ 449 450 hub = dev->ud_private; 451 for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { 452 deldev = hub->uhub_devices[idx]; 453 if (deldev) { 454 if (usb_noisy > 0) 455 console_log("USB: Removing device attached to bus %d hub %d port %d", 456 dev->ud_bus->ub_num, 457 dev->ud_address,idx+1); 458 if (deldev->ud_drv) { 459 /* close open pipes, cancel reqs */ 460 usb_destroy_all_pipes(deldev); 461 /* 462 * Try to process the done queue. This will complete any 463 * requests that made it out of the pipes while we were 464 * doing the stuff above. 465 */ 466 usb_poll(deldev->ud_bus); 467 /* Call detach method, clean up device softc */ 468 (*(deldev->ud_drv->udrv_detach))(deldev); 469 } 470 else { 471 if (usb_noisy > 0) { 472 console_log("USB: Detached device on bus %d hub %d port %d " 473 "has no methods", 474 dev->ud_bus->ub_num, 475 dev->ud_address,idx+1); 476 } 477 } 478 if (deldev->ud_cfgdescr) usb_dma_free(deldev->ud_cfgdescr); 479 usb_destroy_device(deldev); 480 } 481 } 482 483 if (hub->uhub_imsg != NULL) { 484 usb_dma_free(hub->uhub_imsg); 485 } 486 KFREE(hub); /* remove softc */ 487 488 return 0; 489} 490 491 492 493/* ********************************************************************* 494 * usbhub_map_tree1(dev,level,func,arg) 495 * 496 * This routine is used in recursive device tree exploration. 497 * We call 'func' for each device at this tree, and descend 498 * when we run into hubs 499 * 500 * Input parameters: 501 * dev - current device pointer 502 * level - current nesting level 503 * func - function to call 504 * arg - argument to pass to function 505 * 506 * Return value: 507 * nothing 508 ********************************************************************* */ 509 510static void usbhub_map_tree1(usbdev_t *dev,int level, 511 int (*func)(usbdev_t *dev,void *arg),void *arg) 512{ 513 usbhub_softc_t *hub; 514 int idx; 515 516 (*func)(dev,arg); 517 518 if (IS_HUB(dev)) { 519 hub = dev->ud_private; 520 for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { 521 if (hub->uhub_devices[idx]) { 522 usbhub_map_tree1(hub->uhub_devices[idx],level+1,func,arg); 523 } 524 } 525 } 526} 527 528/* ********************************************************************* 529 * usbhub_map_tree(bus,func,arg) 530 * 531 * Call a function for each device in the tree 532 * 533 * Input parameters: 534 * bus - bus to scan 535 * func - function to call 536 * arg - argument to pass to function 537 * 538 * Return value: 539 * nothing 540 ********************************************************************* */ 541 542void usbhub_map_tree(usbbus_t *bus,int (*func)(usbdev_t *dev,void *arg),void *arg) 543{ 544 usbhub_map_tree1(bus->ub_roothub,0,func,arg); 545} 546 547void usbhub_map_from_device(usbdev_t *dev,int (*func)(usbdev_t *dev,void *arg),void *arg) 548{ 549 usbhub_map_tree1(dev,0,func,arg); 550} 551 552 553/* ********************************************************************* 554 * usbhub_dumpbus1(dev,arg) 555 * 556 * map function to dump devices in the device tree 557 * 558 * Input parameters: 559 * dev - device we're working on 560 * arg - argument from map_tree call 561 * 562 * Return value: 563 * 0 564 ********************************************************************* */ 565 566static int usbhub_dumpbus1(usbdev_t *dev,void *arg) 567{ 568 uint32_t *verbose = (uint32_t *) arg; 569 570 if ((*verbose & 0x00FF) && (dev->ud_address != (*verbose & 0x00FF))) return 0; 571 572 if (*verbose & 0x100) { 573 printf("============================================================================\n"); 574 } 575 576 usb_dbg_showdevice(dev); 577 578 if (*verbose & 0x100) { 579 usb_dbg_dumpdescriptors(dev,(uint8_t *) &(dev->ud_devdescr),dev->ud_devdescr.bLength); 580 usb_dbg_dumpcfgdescr(dev,0); 581 } 582 583 return 0; 584} 585 586 587/* ********************************************************************* 588 * usbhub_dumpbus(bus,verbose) 589 * 590 * Dump information about devices on the USB bus. 591 * 592 * Input parameters: 593 * bus - bus to dump 594 * verbose - nonzero to display more info, like descriptors 595 * 596 * Return value: 597 * nothing 598 ********************************************************************* */ 599 600void usbhub_dumpbus(usbbus_t *bus,uint32_t verbose) 601{ 602 usbhub_map_tree(bus,usbhub_dumpbus1,&verbose); 603} 604 605 606 607/* ********************************************************************* 608 * usbhub_reset_devicee(dev,port,status) 609 * 610 * Reset a device on a hub port. This routine does a 611 * USB_PORT_FEATURE_RESET on the specified port, waits for the 612 * bit to clear, and returns. It is used to get a device into the 613 * DEFAULT state according to the spec. 614 * 615 * Input parameters: 616 * dev - hub device 617 * port - port number(1-based) 618 * status - place to return port_status structure after 619 * reset completes 620 * 621 * Return value: 622 * nothing 623 ********************************************************************* */ 624 625static void usbhub_reset_device(usbdev_t *dev,int port,usb_port_status_t *portstatus) 626{ 627 if (usb_noisy > 0) 628 console_log("USB: Resetting device on bus %d port %d",dev->ud_bus->ub_num,port); 629#ifndef _CFE_ 630 fflush(stdout); 631#endif 632 633 usbhub_set_port_feature(dev,port,USB_PORT_FEATURE_RESET); 634 635 usbhub_get_port_status(dev,port,portstatus); 636 637 for (;;) { 638 usbhub_get_port_status(dev,port,portstatus); 639 if ((GETUSBFIELD((portstatus),wPortStatus) & USB_PORT_STATUS_RESET) == 0) break; 640 usb_delay_ms(dev->ud_bus,250); 641 } 642 usb_delay_ms(dev->ud_bus,250); 643 644 usbhub_clear_port_feature(dev,port,USB_PORT_FEATURE_C_PORT_RESET); 645} 646 647 648 649/* ********************************************************************* 650 * usbhub_scan_ports(dev,arg) 651 * 652 * Scan the ports on this hub for new or removed devices. 653 * 654 * Input parameters: 655 * dev - hub device 656 * arg - passed from bus scan main routines 657 * 658 * Return value: 659 * nothing 660 ********************************************************************* */ 661 662static void usbhub_scan_ports(usbdev_t *dev,void *arg) 663{ 664 uint16_t current; 665 uint16_t changed; 666 usbhub_softc_t *softc; 667 int idx; 668 int res; 669 int len; 670 uint8_t *buf; 671 usbdev_t *newdev; 672 usb_driver_t *newdrv; 673 int addr; 674 usb_port_status_t *portstatus; 675 usb_config_descr_t cfgdescr; 676 unsigned int powerondelay; 677 678 if (!IS_HUB(dev)) return; /* should not happen. */ 679 680 portstatus = usb_dma_alloc(sizeof(usb_port_status_t)); 681 if (portstatus == NULL) return; 682 683 /* 684 * We know this is a hub. Get the softc back. 685 */ 686 687 softc = (usbhub_softc_t *) dev->ud_private; 688 689 powerondelay = ((unsigned int) softc->uhub_descr.bPowerOnToPowerGood)*2 + 20; 690 691 /* 692 * Turn on the power to the ports whose power is not yet on. 693 */ 694 695 for (idx = 0; idx < softc->uhub_nports; idx++) { 696 697 usbhub_get_port_status(dev,idx+1,portstatus); 698 699 current = GETUSBFIELD(portstatus,wPortStatus); 700 changed = GETUSBFIELD(portstatus,wPortChange); 701 if (usb_noisy > 1) { 702 printf("BeforePowerup: port %d status %04X changed %04X\n",idx+1,current,changed); 703 } 704 705 if (!(current & USB_PORT_STATUS_POWER)) { 706 if (usb_noisy > 1) console_log("USB: Powering up bus %d port %d", 707 dev->ud_bus->ub_num,idx+1); 708 usbhub_set_port_feature(dev,idx+1,USB_PORT_FEATURE_POWER); 709 usb_delay_ms(dev->ud_bus,powerondelay); 710 } 711 } 712 713 /* 714 * Begin exploration at this level. 715 */ 716 717 for (idx = 0; idx < softc->uhub_nports; idx++) { 718 719 usbhub_get_port_status(dev,idx+1,portstatus); 720 721 current = GETUSBFIELD(portstatus,wPortStatus); 722 changed = GETUSBFIELD(portstatus,wPortChange); 723 724 if (usb_noisy > 0) { 725 printf("USB: Explore: Bus %d Hub %d port %d status %04X changed %04X\n", 726 dev->ud_bus->ub_num, 727 dev->ud_address,idx+1,current,changed); 728 usb_dbg_dumpportstatus(idx+1,portstatus,1); 729 } 730 731 732// if (changed & USB_PORT_STATUS_RESET) { 733// usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_RESET); 734// } 735 736 if (changed & USB_PORT_STATUS_ENABLED) { 737 usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_ENABLE); 738 } 739 740 if (changed & USB_PORT_STATUS_CONNECT) { 741 /* 742 * A device was either connected or disconnected. 743 * Clear the status change first. 744 */ 745 746 usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_CONNECTION); 747 748 if (current & USB_PORT_STATUS_CONNECT) { 749 750 /* 751 * The device has been CONNECTED. 752 */ 753 754 console_log("USB: New device connected to bus %d hub %d port %d", 755 dev->ud_bus->ub_num, 756 dev->ud_address,idx+1); 757 758 /* 759 * Reset the device. Reuse our old port status structure 760 * so we get the latest status. Some devices do not report 761 * lowspeed until they are reset. 762 */ 763 764 usbhub_reset_device(dev,idx+1,portstatus); 765 current = GETUSBFIELD(portstatus,wPortStatus); 766 changed = GETUSBFIELD(portstatus,wPortChange); 767 768 /* 769 * Create a device for this port. 770 */ 771 772 newdev = usb_create_device(dev->ud_bus,(current & USB_PORT_STATUS_LOWSPD) ? 1 : 0); 773 774 /* 775 * Get the device descriptor. 776 */ 777 778 res = usb_get_device_descriptor(newdev,&newdev->ud_devdescr,TRUE); 779 780 if (usb_noisy > 1) usb_dbg_dumpdescriptors(newdev,(uint8_t *) &(newdev->ud_devdescr),8); 781 782 /* 783 * Set up the max packet size for the control endpoint, 784 * then get the rest of the descriptor. 785 */ 786 787 usb_set_ep0mps(newdev,newdev->ud_devdescr.bMaxPacketSize0); 788 res = usb_get_device_descriptor(newdev,&newdev->ud_devdescr,FALSE); 789 790 /* 791 * Obtain a new address and set the address of the 792 * root hub to this address. 793 */ 794 795 addr = usb_new_address(newdev->ud_bus); 796 res = usb_set_address(newdev,addr); 797 798 /* 799 * Get the configuration descriptor and all the 800 * associated interface and endpoint descriptors. 801 */ 802 803 res = usb_get_config_descriptor(newdev,&cfgdescr,0, 804 sizeof(usb_config_descr_t)); 805 if (res != sizeof(usb_config_descr_t)) { 806 printf("[a] usb_get_config_descriptor returns %d\n",res); 807 } 808 809 len = GETUSBFIELD(&cfgdescr,wTotalLength); 810 buf = usb_dma_alloc(len); 811 812 res = usb_get_config_descriptor(newdev,(usb_config_descr_t *)buf,0,len); 813 if (res != len) { 814 printf("[b] usb_get_config_descriptor returns %d\n",res); 815 } 816 817 newdev->ud_cfgdescr = (usb_config_descr_t *) buf; 818 819 if (usb_noisy > 1) usb_dbg_dumpdescriptors(newdev,buf,len); 820 821 /* 822 * Point the hub at the devices it owns 823 */ 824 825 softc->uhub_devices[idx] = newdev; 826 827 /* 828 * Find the driver for this. It had better be the hub 829 * driver. 830 */ 831 832 newdrv = usb_find_driver(newdev); 833 834 /* 835 * Call the attach method. 836 */ 837 838 if (newdrv) { 839 newdev->ud_drv = newdrv; /* remember driver dispatch in device */ 840 (*(newdrv->udrv_attach))(newdev,newdrv); 841 } 842 } 843 844 else { 845 846 /* 847 * The device has been DISCONNECTED. 848 */ 849 850 console_log("USB: Device disconnected from bus %d hub %d port %d", 851 dev->ud_bus->ub_num, 852 dev->ud_address,idx+1); 853 854 /* 855 * Recover pointer to device below hub and clear 856 * this pointer. 857 */ 858 859 newdev = softc->uhub_devices[idx]; /* Get device pointer */ 860 861 usbhub_markdetached(newdev); /* mark device and all subordinate 862 devices as "removing" */ 863 864 softc->uhub_devices[idx] = NULL; /* remove device from hub */ 865 866 /* 867 * Deassign the USB device's address and then 868 * call detach method to free resources. Devices that 869 * do not have drivers will not have any methods. 870 */ 871 872 if (newdev) { 873 if (newdev->ud_drv) { 874 /* close open pipes, cancel reqs */ 875 usb_destroy_all_pipes(newdev); 876 /* 877 * Try to process the done queue. This will complete any 878 * requests that made it out of the pipes while we were 879 * doing the stuff above. 880 */ 881 usb_poll(newdev->ud_bus); 882 /* Call detach method, clean up device softc */ 883 (*(newdev->ud_drv->udrv_detach))(newdev); 884 } 885 else { 886 if (usb_noisy > 0) { 887 console_log("USB: Detached device on bus %d hub %d port %d " 888 "has no methods", 889 dev->ud_bus->ub_num, 890 dev->ud_address,idx+1); 891 } 892 } 893 894 if (newdev->ud_cfgdescr) usb_dma_free(newdev->ud_cfgdescr); 895 896 usb_destroy_device(newdev); 897 } 898 899 } 900 } 901 902 } 903 904 usb_dma_free(portstatus); 905 906 /* 907 * Queue up a request for the interrupt pipe. This will catch further 908 * changes at this port. 909 */ 910 911 usbhub_queue_intreq(dev,softc); 912 913} 914 915/* ********************************************************************* 916 * usbhub_markdetached(dev) 917 * 918 * Mark a device and all devices below it as "removing" so we 919 * will change the status of pending requests to cancelled. 920 * 921 * Input parameters: 922 * dev - device in the tree to start at 923 * 924 * Return value: 925 * nothing 926 ********************************************************************* */ 927 928static int usbhub_markdetached1(usbdev_t *dev,void *arg) 929{ 930 dev->ud_flags |= UD_FLAG_REMOVING; 931 return 0; 932} 933 934static void usbhub_markdetached(usbdev_t *dev) 935{ 936 usbhub_map_from_device(dev,usbhub_markdetached1,NULL); 937} 938 939/* ********************************************************************* 940 * usbhub_scan1(dev,arg) 941 * 942 * Scan one device at this level, or descend if we run into a hub 943 * This is part of the device discovery code. 944 * 945 * Input parameters: 946 * dev - current device, maybe a hub 947 * arg - passed from main scan routine 948 * 949 * Return value: 950 * 0 951 ********************************************************************* */ 952 953 954static int usbhub_scan1(usbdev_t *dev,void *arg) 955{ 956 usbhub_softc_t *hub; 957 958 /* 959 * If the device is not a hub, we've reached the leaves of the 960 * tree. 961 */ 962 963 if (!IS_HUB(dev)) return 0; 964 965 /* 966 * Otherwise, scan the ports on this hub. 967 */ 968 969 hub = dev->ud_private; 970 971 if (hub->uhub_flags & UHUB_FLG_NEEDSCAN) { 972 hub->uhub_flags &= ~UHUB_FLG_NEEDSCAN; 973 usbhub_scan_ports(dev,arg); 974 } 975 976 return 0; 977} 978 979/* ********************************************************************* 980 * usb_scan(bus) 981 * 982 * Scan the bus looking for new or removed devices 983 * 984 * Input parameters: 985 * bus - bus to scan 986 * 987 * Return value: 988 * nothing 989 ********************************************************************* */ 990 991void usb_scan(usbbus_t *bus) 992{ 993 /* 994 * Call our tree walker with the scan function. 995 */ 996 997 usbhub_map_tree(bus,usbhub_scan1,NULL); 998} 999 1000 1001 1002