1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * USBA: Solaris USB Architecture support for the hub 27 * including root hub 28 * Most of the code for hubd resides in this file and 29 * is shared between the HCD root hub support and hubd 30 */ 31 #define USBA_FRAMEWORK 32 #include <sys/usb/usba.h> 33 #include <sys/usb/usba/usba_devdb.h> 34 #include <sys/sunndi.h> 35 #include <sys/usb/usba/usba_impl.h> 36 #include <sys/usb/usba/usba_types.h> 37 #include <sys/usb/usba/hubdi.h> 38 #include <sys/usb/usba/hcdi_impl.h> 39 #include <sys/usb/hubd/hub.h> 40 #include <sys/usb/hubd/hubdvar.h> 41 #include <sys/usb/hubd/hubd_impl.h> 42 #include <sys/kobj.h> 43 #include <sys/kobj_lex.h> 44 #include <sys/fs/dv_node.h> 45 #include <sys/strsun.h> 46 47 /* 48 * External functions 49 */ 50 extern boolean_t consconfig_console_is_ready(void); 51 52 /* 53 * Prototypes for static functions 54 */ 55 static int usba_hubdi_bus_ctl( 56 dev_info_t *dip, 57 dev_info_t *rdip, 58 ddi_ctl_enum_t op, 59 void *arg, 60 void *result); 61 62 static int usba_hubdi_map_fault( 63 dev_info_t *dip, 64 dev_info_t *rdip, 65 struct hat *hat, 66 struct seg *seg, 67 caddr_t addr, 68 struct devpage *dp, 69 pfn_t pfn, 70 uint_t prot, 71 uint_t lock); 72 73 static int hubd_busop_get_eventcookie(dev_info_t *dip, 74 dev_info_t *rdip, 75 char *eventname, 76 ddi_eventcookie_t *cookie); 77 static int hubd_busop_add_eventcall(dev_info_t *dip, 78 dev_info_t *rdip, 79 ddi_eventcookie_t cookie, 80 void (*callback)(dev_info_t *dip, 81 ddi_eventcookie_t cookie, void *arg, 82 void *bus_impldata), 83 void *arg, ddi_callback_id_t *cb_id); 84 static int hubd_busop_remove_eventcall(dev_info_t *dip, 85 ddi_callback_id_t cb_id); 86 static int hubd_bus_config(dev_info_t *dip, 87 uint_t flag, 88 ddi_bus_config_op_t op, 89 void *arg, 90 dev_info_t **child); 91 static int hubd_bus_unconfig(dev_info_t *dip, 92 uint_t flag, 93 ddi_bus_config_op_t op, 94 void *arg); 95 static int hubd_bus_power(dev_info_t *dip, void *impl_arg, 96 pm_bus_power_op_t op, void *arg, void *result); 97 98 static usb_port_t hubd_get_port_num(hubd_t *, struct devctl_iocdata *); 99 static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t); 100 static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t); 101 static int hubd_toggle_port(hubd_t *, usb_port_t); 102 static void hubd_register_cpr_callback(hubd_t *); 103 static void hubd_unregister_cpr_callback(hubd_t *); 104 105 /* 106 * Busops vector for USB HUB's 107 */ 108 struct bus_ops usba_hubdi_busops = { 109 BUSO_REV, 110 nullbusmap, /* bus_map */ 111 NULL, /* bus_get_intrspec */ 112 NULL, /* bus_add_intrspec */ 113 NULL, /* bus_remove_intrspec */ 114 usba_hubdi_map_fault, /* bus_map_fault */ 115 ddi_dma_map, /* bus_dma_map */ 116 ddi_dma_allochdl, 117 ddi_dma_freehdl, 118 ddi_dma_bindhdl, 119 ddi_dma_unbindhdl, 120 ddi_dma_flush, 121 ddi_dma_win, 122 ddi_dma_mctl, /* bus_dma_ctl */ 123 usba_hubdi_bus_ctl, /* bus_ctl */ 124 ddi_bus_prop_op, /* bus_prop_op */ 125 hubd_busop_get_eventcookie, 126 hubd_busop_add_eventcall, 127 hubd_busop_remove_eventcall, 128 NULL, /* bus_post_event */ 129 NULL, /* bus_intr_ctl */ 130 hubd_bus_config, /* bus_config */ 131 hubd_bus_unconfig, /* bus_unconfig */ 132 NULL, /* bus_fm_init */ 133 NULL, /* bus_fm_fini */ 134 NULL, /* bus_fm_access_enter */ 135 NULL, /* bus_fm_access_exit */ 136 hubd_bus_power /* bus_power */ 137 }; 138 139 #define USB_HUB_INTEL_VID 0x8087 140 #define USB_HUB_INTEL_PID 0x0020 141 142 /* 143 * local variables 144 */ 145 static kmutex_t usba_hubdi_mutex; /* protects USBA HUB data structures */ 146 147 static usba_list_entry_t usba_hubdi_list; 148 149 usb_log_handle_t hubdi_log_handle; 150 uint_t hubdi_errlevel = USB_LOG_L4; 151 uint_t hubdi_errmask = (uint_t)-1; 152 uint8_t hubdi_min_pm_threshold = 5; /* seconds */ 153 uint8_t hubdi_reset_delay = 20; /* seconds */ 154 extern int modrootloaded; 155 156 /* 157 * initialize private data 158 */ 159 void 160 usba_hubdi_initialization() 161 { 162 hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel, 163 &hubdi_errmask, NULL, 0); 164 165 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 166 "usba_hubdi_initialization"); 167 168 mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL); 169 170 usba_init_list(&usba_hubdi_list, NULL, NULL); 171 } 172 173 174 void 175 usba_hubdi_destroy() 176 { 177 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 178 "usba_hubdi_destroy"); 179 180 mutex_destroy(&usba_hubdi_mutex); 181 usba_destroy_list(&usba_hubdi_list); 182 183 usb_free_log_hdl(hubdi_log_handle); 184 } 185 186 187 /* 188 * Called by an HUB to attach an instance of the driver 189 * make this instance known to USBA 190 * the HUB should initialize usba_hubdi structure prior 191 * to calling this interface 192 */ 193 int 194 usba_hubdi_register(dev_info_t *dip, 195 uint_t flags) 196 { 197 usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP); 198 usba_device_t *usba_device = usba_get_usba_device(dip); 199 200 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 201 "usba_hubdi_register: %s", ddi_node_name(dip)); 202 203 hubdi->hubdi_dip = dip; 204 hubdi->hubdi_flags = flags; 205 206 usba_device->usb_hubdi = hubdi; 207 208 /* 209 * add this hubdi instance to the list of known hubdi's 210 */ 211 usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi, 212 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 213 hcdi_iblock_cookie); 214 mutex_enter(&usba_hubdi_mutex); 215 usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list); 216 mutex_exit(&usba_hubdi_mutex); 217 218 return (DDI_SUCCESS); 219 } 220 221 222 /* 223 * Called by an HUB to detach an instance of the driver 224 */ 225 int 226 usba_hubdi_unregister(dev_info_t *dip) 227 { 228 usba_device_t *usba_device = usba_get_usba_device(dip); 229 usba_hubdi_t *hubdi = usba_device->usb_hubdi; 230 231 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 232 "usba_hubdi_unregister: %s", ddi_node_name(dip)); 233 234 mutex_enter(&usba_hubdi_mutex); 235 (void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list); 236 mutex_exit(&usba_hubdi_mutex); 237 238 usba_destroy_list(&hubdi->hubdi_list); 239 240 kmem_free(hubdi, sizeof (usba_hubdi_t)); 241 242 return (DDI_SUCCESS); 243 } 244 245 246 /* 247 * misc bus routines currently not used 248 */ 249 /*ARGSUSED*/ 250 static int 251 usba_hubdi_map_fault(dev_info_t *dip, 252 dev_info_t *rdip, 253 struct hat *hat, 254 struct seg *seg, 255 caddr_t addr, 256 struct devpage *dp, 257 pfn_t pfn, 258 uint_t prot, 259 uint_t lock) 260 { 261 return (DDI_FAILURE); 262 } 263 264 265 /* 266 * root hub support. the root hub uses the same devi as the HCD 267 */ 268 int 269 usba_hubdi_bind_root_hub(dev_info_t *dip, 270 uchar_t *root_hub_config_descriptor, 271 size_t config_length, 272 usb_dev_descr_t *root_hub_device_descriptor) 273 { 274 usba_device_t *usba_device; 275 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip); 276 hubd_t *root_hubd; 277 usb_pipe_handle_t ph = NULL; 278 dev_info_t *child = ddi_get_child(dip); 279 280 if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 281 "root-hub") != NDI_SUCCESS) { 282 283 return (USB_FAILURE); 284 } 285 286 usba_add_root_hub(dip); 287 288 root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP); 289 290 /* 291 * create and initialize a usba_device structure 292 */ 293 usba_device = usba_alloc_usba_device(dip); 294 295 mutex_enter(&usba_device->usb_mutex); 296 usba_device->usb_hcdi_ops = hcdi->hcdi_ops; 297 usba_device->usb_cfg = root_hub_config_descriptor; 298 usba_device->usb_cfg_length = config_length; 299 usba_device->usb_dev_descr = root_hub_device_descriptor; 300 usba_device->usb_port = 1; 301 usba_device->usb_addr = ROOT_HUB_ADDR; 302 usba_device->usb_root_hubd = root_hubd; 303 usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *), 304 KM_SLEEP); 305 usba_device->usb_cfg_array_length = sizeof (uchar_t *); 306 307 usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t), 308 KM_SLEEP); 309 usba_device->usb_cfg_array_len_length = sizeof (uint16_t); 310 311 usba_device->usb_cfg_array[0] = root_hub_config_descriptor; 312 usba_device->usb_cfg_array_len[0] = 313 sizeof (root_hub_config_descriptor); 314 315 usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *), 316 KM_SLEEP); 317 usba_device->usb_n_cfgs = 1; 318 usba_device->usb_n_ifs = 1; 319 usba_device->usb_dip = dip; 320 321 usba_device->usb_client_flags = kmem_zalloc( 322 usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 323 324 usba_device->usb_client_attach_list = kmem_zalloc( 325 usba_device->usb_n_ifs * 326 sizeof (*usba_device->usb_client_attach_list), KM_SLEEP); 327 328 usba_device->usb_client_ev_cb_list = kmem_zalloc( 329 usba_device->usb_n_ifs * 330 sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP); 331 332 /* 333 * The bDeviceProtocol field of root hub device specifies, 334 * whether root hub is a High or Full speed usb device. 335 */ 336 if (root_hub_device_descriptor->bDeviceProtocol) { 337 usba_device->usb_port_status = USBA_HIGH_SPEED_DEV; 338 } else { 339 usba_device->usb_port_status = USBA_FULL_SPEED_DEV; 340 } 341 342 mutex_exit(&usba_device->usb_mutex); 343 344 usba_set_usba_device(dip, usba_device); 345 346 /* 347 * For the root hub the default pipe is not yet open 348 */ 349 if (usb_pipe_open(dip, NULL, NULL, 350 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) { 351 goto fail; 352 } 353 354 /* 355 * kill off all OBP children, they may not be fully 356 * enumerated 357 */ 358 while (child) { 359 dev_info_t *next = ddi_get_next_sibling(child); 360 (void) ddi_remove_child(child, 0); 361 child = next; 362 } 363 364 /* 365 * "attach" the root hub driver 366 */ 367 if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) { 368 goto fail; 369 } 370 371 return (USB_SUCCESS); 372 373 fail: 374 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 375 376 usba_rem_root_hub(dip); 377 378 if (ph) { 379 usb_pipe_close(dip, ph, 380 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 381 } 382 383 kmem_free(usba_device->usb_cfg_array, 384 usba_device->usb_cfg_array_length); 385 kmem_free(usba_device->usb_cfg_array_len, 386 usba_device->usb_cfg_array_len_length); 387 388 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 389 390 usba_free_usba_device(usba_device); 391 392 usba_set_usba_device(dip, NULL); 393 if (root_hubd) { 394 kmem_free(root_hubd, sizeof (hubd_t)); 395 } 396 397 return (USB_FAILURE); 398 } 399 400 401 int 402 usba_hubdi_unbind_root_hub(dev_info_t *dip) 403 { 404 usba_device_t *usba_device; 405 406 /* was root hub attached? */ 407 if (!(usba_is_root_hub(dip))) { 408 409 /* return success anyway */ 410 return (USB_SUCCESS); 411 } 412 413 /* 414 * usba_hubdi_detach also closes the default pipe 415 * and removes properties so there is no need to 416 * do it here 417 */ 418 if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) { 419 420 if (DEVI_IS_ATTACHING(dip)) { 421 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 422 "failure to unbind root hub after attach failure"); 423 } 424 425 return (USB_FAILURE); 426 } 427 428 usba_device = usba_get_usba_device(dip); 429 430 kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t)); 431 432 kmem_free(usba_device->usb_cfg_array, 433 usba_device->usb_cfg_array_length); 434 kmem_free(usba_device->usb_cfg_array_len, 435 usba_device->usb_cfg_array_len_length); 436 437 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 438 439 usba_free_usba_device(usba_device); 440 441 usba_rem_root_hub(dip); 442 443 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 444 445 return (USB_SUCCESS); 446 } 447 448 449 /* 450 * Actual Hub Driver support code: 451 * shared by root hub and non-root hubs 452 */ 453 #include <sys/usb/usba/usbai_version.h> 454 455 /* Debugging support */ 456 uint_t hubd_errlevel = USB_LOG_L4; 457 uint_t hubd_errmask = (uint_t)DPRINT_MASK_ALL; 458 uint_t hubd_instance_debug = (uint_t)-1; 459 static uint_t hubdi_bus_config_debug = 0; 460 461 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel)) 462 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask)) 463 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug)) 464 465 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 466 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 467 468 469 /* 470 * local variables: 471 * 472 * Amount of time to wait between resetting the port and accessing 473 * the device. The value is in microseconds. 474 */ 475 static uint_t hubd_device_delay = 1000000; 476 477 /* 478 * enumeration retry 479 */ 480 #define HUBD_PORT_RETRY 5 481 static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY; 482 483 /* 484 * Stale hotremoved device cleanup delay 485 */ 486 #define HUBD_STALE_DIP_CLEANUP_DELAY 5000000 487 static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY; 488 489 /* 490 * retries for USB suspend and resume 491 */ 492 #define HUBD_SUS_RES_RETRY 2 493 494 void *hubd_statep; 495 496 /* 497 * prototypes 498 */ 499 static int hubd_cleanup(dev_info_t *dip, hubd_t *hubd); 500 static int hubd_check_ports(hubd_t *hubd); 501 502 static int hubd_open_intr_pipe(hubd_t *hubd); 503 static void hubd_start_polling(hubd_t *hubd, int always); 504 static void hubd_stop_polling(hubd_t *hubd); 505 static void hubd_close_intr_pipe(hubd_t *hubd); 506 507 static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req); 508 static void hubd_exception_cb(usb_pipe_handle_t pipe, 509 usb_intr_req_t *req); 510 static void hubd_hotplug_thread(void *arg); 511 static void hubd_reset_thread(void *arg); 512 static int hubd_create_child(dev_info_t *dip, 513 hubd_t *hubd, 514 usba_device_t *usba_device, 515 usb_port_status_t port_status, 516 usb_port_t port, 517 int iteration); 518 519 static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, 520 boolean_t retry); 521 522 static int hubd_get_hub_descriptor(hubd_t *hubd); 523 524 static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status); 525 526 static int hubd_reset_port(hubd_t *hubd, usb_port_t port); 527 528 static int hubd_get_hub_status(hubd_t *hubd); 529 530 static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port); 531 532 static int hubd_disable_port(hubd_t *hubd, usb_port_t port); 533 534 static int hubd_enable_port(hubd_t *hubd, usb_port_t port); 535 static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port); 536 537 static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 538 uint16_t *status, uint16_t *change, uint_t ack_flag); 539 540 static int hubd_enable_all_port_power(hubd_t *hubd); 541 static int hubd_disable_all_port_power(hubd_t *hubd); 542 static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port); 543 static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port); 544 545 static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device); 546 547 static int hubd_can_suspend(hubd_t *hubd); 548 static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd); 549 static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port); 550 static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port); 551 552 static int hubd_register_events(hubd_t *hubd); 553 static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip, 554 ddi_eventcookie_t cookie); 555 static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type); 556 static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type); 557 static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd); 558 559 static int hubd_disconnect_event_cb(dev_info_t *dip); 560 static int hubd_reconnect_event_cb(dev_info_t *dip); 561 static int hubd_pre_suspend_event_cb(dev_info_t *dip); 562 static int hubd_post_resume_event_cb(dev_info_t *dip); 563 static int hubd_cpr_suspend(hubd_t *hubd); 564 static void hubd_cpr_resume(dev_info_t *dip); 565 static int hubd_restore_state_cb(dev_info_t *dip); 566 static int hubd_check_same_device(hubd_t *hubd, usb_port_t port); 567 568 static int hubd_init_power_budget(hubd_t *hubd); 569 570 static ndi_event_definition_t hubd_ndi_event_defs[] = { 571 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 572 NDI_EVENT_POST_TO_ALL}, 573 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 574 NDI_EVENT_POST_TO_ALL}, 575 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 576 NDI_EVENT_POST_TO_ALL}, 577 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 578 NDI_EVENT_POST_TO_ALL} 579 }; 580 581 #define HUBD_N_NDI_EVENTS \ 582 (sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t)) 583 584 static ndi_event_set_t hubd_ndi_events = { 585 NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs}; 586 587 /* events received from parent */ 588 static usb_event_t hubd_events = { 589 hubd_disconnect_event_cb, 590 hubd_reconnect_event_cb, 591 hubd_pre_suspend_event_cb, 592 hubd_post_resume_event_cb 593 }; 594 595 596 /* 597 * hubd_get_soft_state() returns the hubd soft state 598 * 599 * WUSB support extends this function to support wire adapter class 600 * devices. The hubd soft state for the wire adapter class device 601 * would be stored in usb_root_hubd field of the usba_device structure, 602 * just as the USB host controller drivers do. 603 */ 604 hubd_t * 605 hubd_get_soft_state(dev_info_t *dip) 606 { 607 if (dip == NULL) { 608 609 return (NULL); 610 } 611 612 if (usba_is_root_hub(dip) || usba_is_wa(dip)) { 613 usba_device_t *usba_device = usba_get_usba_device(dip); 614 615 return (usba_device->usb_root_hubd); 616 } else { 617 int instance = ddi_get_instance(dip); 618 619 return (ddi_get_soft_state(hubd_statep, instance)); 620 } 621 } 622 623 624 /* 625 * PM support functions: 626 */ 627 /*ARGSUSED*/ 628 static void 629 hubd_pm_busy_component(hubd_t *hubd, dev_info_t *dip, int component) 630 { 631 if (hubd->h_hubpm != NULL) { 632 hubd->h_hubpm->hubp_busy_pm++; 633 mutex_exit(HUBD_MUTEX(hubd)); 634 if (pm_busy_component(dip, 0) != DDI_SUCCESS) { 635 mutex_enter(HUBD_MUTEX(hubd)); 636 hubd->h_hubpm->hubp_busy_pm--; 637 mutex_exit(HUBD_MUTEX(hubd)); 638 } 639 mutex_enter(HUBD_MUTEX(hubd)); 640 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 641 "hubd_pm_busy_component: %d", hubd->h_hubpm->hubp_busy_pm); 642 } 643 } 644 645 646 /*ARGSUSED*/ 647 static void 648 hubd_pm_idle_component(hubd_t *hubd, dev_info_t *dip, int component) 649 { 650 if (hubd->h_hubpm != NULL) { 651 mutex_exit(HUBD_MUTEX(hubd)); 652 if (pm_idle_component(dip, 0) == DDI_SUCCESS) { 653 mutex_enter(HUBD_MUTEX(hubd)); 654 ASSERT(hubd->h_hubpm->hubp_busy_pm > 0); 655 hubd->h_hubpm->hubp_busy_pm--; 656 mutex_exit(HUBD_MUTEX(hubd)); 657 } 658 mutex_enter(HUBD_MUTEX(hubd)); 659 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 660 "hubd_pm_idle_component: %d", hubd->h_hubpm->hubp_busy_pm); 661 } 662 } 663 664 665 /* 666 * track power level changes for children of this instance 667 */ 668 static void 669 hubd_set_child_pwrlvl(hubd_t *hubd, usb_port_t port, uint8_t power) 670 { 671 int old_power, new_power, pwr; 672 usb_port_t portno; 673 hub_power_t *hubpm; 674 675 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 676 "hubd_set_child_pwrlvl: port=%d power=%d", 677 port, power); 678 679 mutex_enter(HUBD_MUTEX(hubd)); 680 hubpm = hubd->h_hubpm; 681 682 old_power = 0; 683 for (portno = 1; portno <= hubd->h_hub_descr.bNbrPorts; portno++) { 684 old_power += hubpm->hubp_child_pwrstate[portno]; 685 } 686 687 /* assign the port power */ 688 pwr = hubd->h_hubpm->hubp_child_pwrstate[port]; 689 hubd->h_hubpm->hubp_child_pwrstate[port] = power; 690 new_power = old_power - pwr + power; 691 692 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 693 "hubd_set_child_pwrlvl: new_power=%d old_power=%d", 694 new_power, old_power); 695 696 if ((new_power > 0) && (old_power == 0)) { 697 /* we have the first child coming out of low power */ 698 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 699 } else if ((new_power == 0) && (old_power > 0)) { 700 /* we have the last child going to low power */ 701 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 702 } 703 mutex_exit(HUBD_MUTEX(hubd)); 704 } 705 706 707 /* 708 * given a child dip, locate its port number 709 */ 710 static usb_port_t 711 hubd_child_dip2port(hubd_t *hubd, dev_info_t *dip) 712 { 713 usb_port_t port; 714 715 mutex_enter(HUBD_MUTEX(hubd)); 716 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 717 if (hubd->h_children_dips[port] == dip) { 718 719 break; 720 } 721 } 722 ASSERT(port <= hubd->h_hub_descr.bNbrPorts); 723 mutex_exit(HUBD_MUTEX(hubd)); 724 725 return (port); 726 } 727 728 729 /* 730 * if the hub can be put into low power mode, return success 731 * NOTE: suspend here means going to lower power, not CPR suspend. 732 */ 733 static int 734 hubd_can_suspend(hubd_t *hubd) 735 { 736 hub_power_t *hubpm; 737 int total_power = 0; 738 usb_port_t port; 739 740 hubpm = hubd->h_hubpm; 741 742 if (DEVI_IS_DETACHING(hubd->h_dip)) { 743 744 return (USB_SUCCESS); 745 } 746 747 /* 748 * Don't go to lower power if haven't been at full power for enough 749 * time to let hotplug thread kickoff. 750 */ 751 if (ddi_get_time() < (hubpm->hubp_time_at_full_power + 752 hubpm->hubp_min_pm_threshold)) { 753 754 return (USB_FAILURE); 755 } 756 757 for (port = 1; (total_power == 0) && 758 (port <= hubd->h_hub_descr.bNbrPorts); port++) { 759 total_power += hubpm->hubp_child_pwrstate[port]; 760 } 761 762 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 763 "hubd_can_suspend: %d", total_power); 764 765 return (total_power ? USB_FAILURE : USB_SUCCESS); 766 } 767 768 769 /* 770 * resume port depending on current device state 771 */ 772 static int 773 hubd_resume_port(hubd_t *hubd, usb_port_t port) 774 { 775 int rval, retry; 776 usb_cr_t completion_reason; 777 usb_cb_flags_t cb_flags; 778 uint16_t status; 779 uint16_t change; 780 int retval = USB_FAILURE; 781 782 mutex_enter(HUBD_MUTEX(hubd)); 783 784 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 785 "hubd_resume_port: port=%d state=0x%x (%s)", port, 786 hubd->h_dev_state, usb_str_dev_state(hubd->h_dev_state)); 787 788 switch (hubd->h_dev_state) { 789 case USB_DEV_HUB_CHILD_PWRLVL: 790 /* 791 * This could be a bus ctl for a port other than the one 792 * that has a remote wakeup condition. So check. 793 */ 794 if ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0) { 795 /* the port isn't suspended, so don't resume */ 796 retval = USB_SUCCESS; 797 798 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 799 "hubd_resume_port: port=%d not suspended", port); 800 801 break; 802 } 803 /* 804 * Device has initiated a wakeup. 805 * Issue a ClearFeature(PortSuspend) 806 */ 807 mutex_exit(HUBD_MUTEX(hubd)); 808 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 809 hubd->h_default_pipe, 810 HUB_HANDLE_PORT_FEATURE_TYPE, 811 USB_REQ_CLEAR_FEATURE, 812 CFS_PORT_SUSPEND, 813 port, 814 0, NULL, 0, 815 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 816 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 817 "ClearFeature(PortSuspend) fails " 818 "rval=%d cr=%d cb=0x%x", rval, 819 completion_reason, cb_flags); 820 } 821 mutex_enter(HUBD_MUTEX(hubd)); 822 823 /* either way ack changes on the port */ 824 (void) hubd_determine_port_status(hubd, port, 825 &status, &change, PORT_CHANGE_PSSC); 826 retval = USB_SUCCESS; 827 828 break; 829 case USB_DEV_HUB_STATE_RECOVER: 830 /* 831 * When hubd's connect event callback posts a connect 832 * event to its child, it results in this busctl call 833 * which is valid 834 */ 835 /* FALLTHRU */ 836 case USB_DEV_ONLINE: 837 if (((hubd->h_port_state[port] & PORT_STATUS_CCS) == 0) || 838 ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0)) { 839 /* 840 * the port isn't suspended, or connected 841 * so don't resume 842 */ 843 retval = USB_SUCCESS; 844 845 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 846 "hubd_resume_port: port=%d not suspended", port); 847 848 break; 849 } 850 /* 851 * prevent kicking off the hotplug thread 852 */ 853 hubd->h_hotplug_thread++; 854 hubd_stop_polling(hubd); 855 856 /* Now ClearFeature(PortSuspend) */ 857 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) { 858 mutex_exit(HUBD_MUTEX(hubd)); 859 rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 860 hubd->h_default_pipe, 861 HUB_HANDLE_PORT_FEATURE_TYPE, 862 USB_REQ_CLEAR_FEATURE, 863 CFS_PORT_SUSPEND, 864 port, 865 0, NULL, 0, 866 &completion_reason, &cb_flags, 0); 867 mutex_enter(HUBD_MUTEX(hubd)); 868 if (rval != USB_SUCCESS) { 869 USB_DPRINTF_L2(DPRINT_MASK_PM, 870 hubd->h_log_handle, 871 "ClearFeature(PortSuspend) fails" 872 "rval=%d cr=%d cb=0x%x", rval, 873 completion_reason, cb_flags); 874 } else { 875 /* 876 * As per spec section 11.9 and 7.1.7.7 877 * hub need to provide at least 20ms of 878 * resume signalling, and s/w provide 10ms of 879 * recovery time before accessing the port. 880 */ 881 mutex_exit(HUBD_MUTEX(hubd)); 882 delay(drv_usectohz(40000)); 883 mutex_enter(HUBD_MUTEX(hubd)); 884 (void) hubd_determine_port_status(hubd, port, 885 &status, &change, PORT_CHANGE_PSSC); 886 887 if ((status & PORT_STATUS_PSS) == 0) { 888 /* the port did finally resume */ 889 retval = USB_SUCCESS; 890 891 break; 892 } 893 } 894 } 895 896 /* allow hotplug thread again */ 897 hubd->h_hotplug_thread--; 898 hubd_start_polling(hubd, 0); 899 900 break; 901 case USB_DEV_DISCONNECTED: 902 /* Ignore - NO Operation */ 903 retval = USB_SUCCESS; 904 905 break; 906 case USB_DEV_SUSPENDED: 907 case USB_DEV_PWRED_DOWN: 908 default: 909 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 910 "Improper state for port Resume"); 911 912 break; 913 } 914 mutex_exit(HUBD_MUTEX(hubd)); 915 916 return (retval); 917 } 918 919 920 /* 921 * suspend port depending on device state 922 */ 923 static int 924 hubd_suspend_port(hubd_t *hubd, usb_port_t port) 925 { 926 int rval, retry; 927 int retval = USB_FAILURE; 928 usb_cr_t completion_reason; 929 usb_cb_flags_t cb_flags; 930 uint16_t status; 931 uint16_t change; 932 933 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 934 "hubd_suspend_port: port=%d", port); 935 936 mutex_enter(HUBD_MUTEX(hubd)); 937 938 switch (hubd->h_dev_state) { 939 case USB_DEV_HUB_STATE_RECOVER: 940 /* 941 * When hubd's connect event callback posts a connect 942 * event to its child, it results in this busctl call 943 * which is valid 944 */ 945 /* FALLTHRU */ 946 case USB_DEV_HUB_CHILD_PWRLVL: 947 /* 948 * When one child is resuming, the other could timeout 949 * and go to low power mode, which is valid 950 */ 951 /* FALLTHRU */ 952 case USB_DEV_ONLINE: 953 hubd->h_hotplug_thread++; 954 hubd_stop_polling(hubd); 955 956 /* 957 * Some devices start an unprovoked resume. According to spec, 958 * normal resume time for port is 10ms. Wait for double that 959 * time, then check to be sure port is really suspended. 960 */ 961 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) { 962 /* Now SetFeature(PortSuspend) */ 963 mutex_exit(HUBD_MUTEX(hubd)); 964 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 965 hubd->h_default_pipe, 966 HUB_HANDLE_PORT_FEATURE_TYPE, 967 USB_REQ_SET_FEATURE, 968 CFS_PORT_SUSPEND, 969 port, 970 0, NULL, 0, 971 &completion_reason, &cb_flags, 0)) != 972 USB_SUCCESS) { 973 USB_DPRINTF_L2(DPRINT_MASK_PM, 974 hubd->h_log_handle, 975 "SetFeature(PortSuspend) fails" 976 "rval=%d cr=%d cb=0x%x", 977 rval, completion_reason, cb_flags); 978 } 979 980 /* 981 * some devices start an unprovoked resume 982 * wait and check port status after some time 983 */ 984 delay(drv_usectohz(20000)); 985 986 /* either ways ack changes on the port */ 987 mutex_enter(HUBD_MUTEX(hubd)); 988 (void) hubd_determine_port_status(hubd, port, 989 &status, &change, PORT_CHANGE_PSSC); 990 if (status & PORT_STATUS_PSS) { 991 /* the port is indeed suspended */ 992 retval = USB_SUCCESS; 993 994 break; 995 } else { 996 USB_DPRINTF_L0(DPRINT_MASK_PM, 997 hubd->h_log_handle, 998 "hubdi: port%d failed to be suspended!", 999 port); 1000 } 1001 } 1002 1003 hubd->h_hotplug_thread--; 1004 hubd_start_polling(hubd, 0); 1005 1006 break; 1007 1008 case USB_DEV_DISCONNECTED: 1009 /* Ignore - No Operation */ 1010 retval = USB_SUCCESS; 1011 1012 break; 1013 1014 case USB_DEV_SUSPENDED: 1015 case USB_DEV_PWRED_DOWN: 1016 default: 1017 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1018 "Improper state for port Suspend"); 1019 1020 break; 1021 } 1022 mutex_exit(HUBD_MUTEX(hubd)); 1023 1024 return (retval); 1025 } 1026 1027 1028 /* 1029 * child post attach/detach notifications 1030 */ 1031 static void 1032 hubd_post_attach(hubd_t *hubd, usb_port_t port, struct attachspec *as) 1033 { 1034 dev_info_t *dip; 1035 1036 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 1037 "hubd_post_attach: port=%d result=%d", 1038 port, as->result); 1039 1040 if (as->result == DDI_SUCCESS) { 1041 /* 1042 * Check if the child created wants to be power managed. 1043 * If yes, the childs power level gets automatically tracked 1044 * by DDI_CTLOPS_POWER busctl. 1045 * If no, we set power of the new child by default 1046 * to USB_DEV_OS_FULL_PWR. Because we should never suspend. 1047 */ 1048 mutex_enter(HUBD_MUTEX(hubd)); 1049 dip = hubd->h_children_dips[port]; 1050 mutex_exit(HUBD_MUTEX(hubd)); 1051 if (DEVI(dip)->devi_pm_info == NULL) { 1052 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_FULL_PWR); 1053 } 1054 } 1055 } 1056 1057 1058 static void 1059 hubd_post_detach(hubd_t *hubd, usb_port_t port, struct detachspec *ds) 1060 { 1061 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 1062 "hubd_post_detach: port=%d result=%d", port, ds->result); 1063 1064 /* 1065 * if the device is successfully detached and is the 1066 * last device to detach, mark component as idle 1067 */ 1068 mutex_enter(HUBD_MUTEX(hubd)); 1069 if (ds->result == DDI_SUCCESS) { 1070 usba_device_t *usba_device = hubd->h_usba_devices[port]; 1071 dev_info_t *pdip = hubd->h_dip; 1072 mutex_exit(HUBD_MUTEX(hubd)); 1073 1074 usba_hubdi_incr_power_budget(pdip, usba_device); 1075 1076 /* 1077 * We set power of the detached child 1078 * to 0, so that we can suspend if all 1079 * our children are gone 1080 */ 1081 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_PWR_OFF); 1082 1083 /* check for leaks on detaching */ 1084 if ((usba_device) && (ds->cmd == DDI_DETACH)) { 1085 usba_check_for_leaks(usba_device); 1086 } 1087 } else { 1088 mutex_exit(HUBD_MUTEX(hubd)); 1089 } 1090 } 1091 1092 1093 /* 1094 * hubd_post_power 1095 * After the child's power entry point has been called 1096 * we record its power level in our local struct. 1097 * If the device has powered off, we suspend port 1098 */ 1099 static int 1100 hubd_post_power(hubd_t *hubd, usb_port_t port, pm_bp_child_pwrchg_t *bpc, 1101 int result) 1102 { 1103 int retval = USB_SUCCESS; 1104 1105 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1106 "hubd_post_power: port=%d", port); 1107 1108 if (result == DDI_SUCCESS) { 1109 1110 /* record this power in our local struct */ 1111 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_nlevel); 1112 1113 if (bpc->bpc_nlevel == USB_DEV_OS_PWR_OFF) { 1114 1115 /* now suspend the port */ 1116 retval = hubd_suspend_port(hubd, port); 1117 } else if (bpc->bpc_nlevel == USB_DEV_OS_FULL_PWR) { 1118 1119 /* make sure the port is resumed */ 1120 retval = hubd_resume_port(hubd, port); 1121 } 1122 } else { 1123 1124 /* record old power in our local struct */ 1125 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_olevel); 1126 1127 if (bpc->bpc_olevel == USB_DEV_OS_PWR_OFF) { 1128 1129 /* 1130 * As this device failed to transition from 1131 * power off state, suspend the port again 1132 */ 1133 retval = hubd_suspend_port(hubd, port); 1134 } 1135 } 1136 1137 return (retval); 1138 } 1139 1140 1141 /* 1142 * bus ctl notifications are handled here, the rest goes up to root hub/hcd 1143 */ 1144 static int 1145 usba_hubdi_bus_ctl(dev_info_t *dip, 1146 dev_info_t *rdip, 1147 ddi_ctl_enum_t op, 1148 void *arg, 1149 void *result) 1150 { 1151 usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 1152 dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 1153 struct attachspec *as; 1154 struct detachspec *ds; 1155 hubd_t *hubd; 1156 usb_port_t port; 1157 int circ, rval; 1158 int retval = DDI_FAILURE; 1159 1160 hubd = hubd_get_soft_state(dip); 1161 1162 mutex_enter(HUBD_MUTEX(hubd)); 1163 1164 /* flag that we are currently running bus_ctl */ 1165 hubd->h_bus_ctls++; 1166 mutex_exit(HUBD_MUTEX(hubd)); 1167 1168 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1169 "usba_hubdi_bus_ctl:\n\t" 1170 "dip=0x%p, rdip=0x%p, op=0x%x, arg=0x%p", 1171 (void *)dip, (void *)rdip, op, arg); 1172 1173 switch (op) { 1174 case DDI_CTLOPS_ATTACH: 1175 as = (struct attachspec *)arg; 1176 port = hubd_child_dip2port(hubd, rdip); 1177 1178 /* there is nothing to do at resume time */ 1179 if (as->cmd == DDI_RESUME) { 1180 break; 1181 } 1182 1183 /* serialize access */ 1184 ndi_devi_enter(hubd->h_dip, &circ); 1185 1186 switch (as->when) { 1187 case DDI_PRE: 1188 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1189 "DDI_PRE DDI_CTLOPS_ATTACH: dip=%p, port=%d", 1190 (void *)rdip, port); 1191 1192 mutex_enter(HUBD_MUTEX(hubd)); 1193 hubd->h_port_state[port] |= HUBD_CHILD_ATTACHING; 1194 1195 /* Go busy here. Matching idle is DDI_POST case. */ 1196 (void) hubd_pm_busy_component(hubd, dip, 0); 1197 mutex_exit(HUBD_MUTEX(hubd)); 1198 1199 /* 1200 * if we suspended the port previously 1201 * because child went to low power state, and 1202 * someone unloaded the driver, the port would 1203 * still be suspended and needs to be resumed 1204 */ 1205 rval = hubd_resume_port(hubd, port); 1206 if (rval == USB_SUCCESS) { 1207 retval = DDI_SUCCESS; 1208 } 1209 1210 break; 1211 case DDI_POST: 1212 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1213 "DDI_POST DDI_CTLOPS_ATTACH: dip=%p, port=%d", 1214 (void *)rdip, port); 1215 1216 mutex_enter(HUBD_MUTEX(hubd)); 1217 hubd->h_port_state[port] &= ~HUBD_CHILD_ATTACHING; 1218 mutex_exit(HUBD_MUTEX(hubd)); 1219 1220 hubd_post_attach(hubd, port, (struct attachspec *)arg); 1221 retval = DDI_SUCCESS; 1222 mutex_enter(HUBD_MUTEX(hubd)); 1223 1224 /* Matching idle call for DDI_PRE busy call. */ 1225 (void) hubd_pm_idle_component(hubd, dip, 0); 1226 mutex_exit(HUBD_MUTEX(hubd)); 1227 } 1228 ndi_devi_exit(hubd->h_dip, circ); 1229 1230 break; 1231 case DDI_CTLOPS_DETACH: 1232 ds = (struct detachspec *)arg; 1233 port = hubd_child_dip2port(hubd, rdip); 1234 1235 /* there is nothing to do at suspend time */ 1236 if (ds->cmd == DDI_SUSPEND) { 1237 break; 1238 } 1239 1240 /* serialize access */ 1241 ndi_devi_enter(hubd->h_dip, &circ); 1242 1243 switch (ds->when) { 1244 case DDI_PRE: 1245 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1246 "DDI_PRE DDI_CTLOPS_DETACH: dip=%p port=%d", 1247 (void *)rdip, port); 1248 1249 mutex_enter(HUBD_MUTEX(hubd)); 1250 hubd->h_port_state[port] |= HUBD_CHILD_DETACHING; 1251 1252 /* Go busy here. Matching idle is DDI_POST case. */ 1253 (void) hubd_pm_busy_component(hubd, dip, 0); 1254 1255 mutex_exit(HUBD_MUTEX(hubd)); 1256 retval = DDI_SUCCESS; 1257 1258 break; 1259 case DDI_POST: 1260 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1261 "DDI_POST DDI_CTLOPS_DETACH: dip=%p port=%d", 1262 (void *)rdip, port); 1263 1264 mutex_enter(HUBD_MUTEX(hubd)); 1265 hubd->h_port_state[port] &= ~HUBD_CHILD_DETACHING; 1266 mutex_exit(HUBD_MUTEX(hubd)); 1267 1268 /* Matching idle call for DDI_PRE busy call. */ 1269 hubd_post_detach(hubd, port, (struct detachspec *)arg); 1270 retval = DDI_SUCCESS; 1271 mutex_enter(HUBD_MUTEX(hubd)); 1272 (void) hubd_pm_idle_component(hubd, dip, 0); 1273 mutex_exit(HUBD_MUTEX(hubd)); 1274 1275 break; 1276 } 1277 ndi_devi_exit(hubd->h_dip, circ); 1278 1279 break; 1280 default: 1281 retval = usba_bus_ctl(root_hub_dip, rdip, op, arg, result); 1282 } 1283 1284 /* decrement bus_ctls count */ 1285 mutex_enter(HUBD_MUTEX(hubd)); 1286 hubd->h_bus_ctls--; 1287 ASSERT(hubd->h_bus_ctls >= 0); 1288 mutex_exit(HUBD_MUTEX(hubd)); 1289 1290 return (retval); 1291 } 1292 1293 /* 1294 * hubd_config_one: 1295 * enumerate one child according to 'port' 1296 */ 1297 1298 static boolean_t 1299 hubd_config_one(hubd_t *hubd, int port) 1300 { 1301 uint16_t status, change; 1302 dev_info_t *hdip = hubd->h_dip; 1303 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 1304 boolean_t online_child = B_FALSE, found = B_FALSE; 1305 int prh_circ, rh_circ, circ; 1306 1307 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1308 "hubd_config_one: started, hubd_reset_port = 0x%x", port); 1309 1310 ndi_hold_devi(hdip); /* so we don't race with detach */ 1311 1312 /* 1313 * this ensures one config activity per system at a time. 1314 * we enter the parent PCI node to have this serialization. 1315 * this also excludes ioctls and deathrow thread 1316 */ 1317 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 1318 ndi_devi_enter(rh_dip, &rh_circ); 1319 1320 /* exclude other threads */ 1321 ndi_devi_enter(hdip, &circ); 1322 mutex_enter(HUBD_MUTEX(hubd)); 1323 1324 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 1325 1326 if (!hubd->h_children_dips[port]) { 1327 1328 (void) hubd_determine_port_status(hubd, port, 1329 &status, &change, HUBD_ACK_ALL_CHANGES); 1330 1331 if (status & PORT_STATUS_CCS) { 1332 online_child |= (hubd_handle_port_connect(hubd, 1333 port) == USB_SUCCESS); 1334 found = online_child; 1335 } 1336 } else { 1337 found = B_TRUE; 1338 } 1339 1340 mutex_exit(HUBD_MUTEX(hubd)); 1341 1342 ndi_devi_exit(hdip, circ); 1343 ndi_devi_exit(rh_dip, rh_circ); 1344 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 1345 1346 if (online_child) { 1347 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1348 "hubd_config_one: onlining child"); 1349 1350 (void) ndi_devi_online(hubd->h_dip, 0); 1351 } 1352 1353 mutex_enter(HUBD_MUTEX(hubd)); 1354 1355 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 1356 1357 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1358 "hubd_config_one: exit"); 1359 1360 mutex_exit(HUBD_MUTEX(hubd)); 1361 1362 ndi_rele_devi(hdip); 1363 1364 return (found); 1365 } 1366 1367 /* 1368 * bus enumeration entry points 1369 */ 1370 static int 1371 hubd_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 1372 void *arg, dev_info_t **child) 1373 { 1374 hubd_t *hubd = hubd_get_soft_state(dip); 1375 int rval, circ; 1376 long port; 1377 1378 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1379 "hubd_bus_config: op=%d", op); 1380 1381 if (hubdi_bus_config_debug) { 1382 flag |= NDI_DEVI_DEBUG; 1383 } 1384 1385 if (op == BUS_CONFIG_ONE) { 1386 boolean_t found; 1387 char cname[80]; 1388 char *name, *addr; 1389 1390 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1391 "hubd_bus_config: op=%d (BUS_CONFIG_ONE)", op); 1392 1393 (void) snprintf(cname, 80, "%s", (char *)arg); 1394 /* split name into "name@addr" parts */ 1395 i_ddi_parse_name(cname, &name, &addr, NULL); 1396 if (addr && *addr) { 1397 (void) ddi_strtol(addr, NULL, 16, &port); 1398 } else { 1399 return (NDI_FAILURE); 1400 } 1401 1402 found = hubd_config_one(hubd, port); 1403 1404 if (found == 0) { 1405 return (NDI_FAILURE); 1406 } 1407 1408 } 1409 ndi_devi_enter(hubd->h_dip, &circ); 1410 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 1411 ndi_devi_exit(hubd->h_dip, circ); 1412 1413 return (rval); 1414 } 1415 1416 1417 static int 1418 hubd_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 1419 void *arg) 1420 { 1421 hubd_t *hubd = hubd_get_soft_state(dip); 1422 dev_info_t *cdip; 1423 usb_port_t port; 1424 int circ; 1425 int rval; 1426 1427 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1428 "hubd_bus_unconfig: op=%d", op); 1429 1430 if (hubdi_bus_config_debug) { 1431 flag |= NDI_DEVI_DEBUG; 1432 } 1433 1434 if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) { 1435 flag |= NDI_DEVI_REMOVE; 1436 } 1437 1438 /* serialize access */ 1439 ndi_devi_enter(dip, &circ); 1440 1441 rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 1442 1443 /* logically zap children's list */ 1444 mutex_enter(HUBD_MUTEX(hubd)); 1445 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 1446 hubd->h_port_state[port] |= HUBD_CHILD_ZAP; 1447 } 1448 mutex_exit(HUBD_MUTEX(hubd)); 1449 1450 /* fill in what's left */ 1451 for (cdip = ddi_get_child(dip); cdip; 1452 cdip = ddi_get_next_sibling(cdip)) { 1453 usba_device_t *usba_device = usba_get_usba_device(cdip); 1454 1455 if (usba_device == NULL) { 1456 1457 continue; 1458 } 1459 mutex_enter(HUBD_MUTEX(hubd)); 1460 port = usba_device->usb_port; 1461 hubd->h_children_dips[port] = cdip; 1462 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP; 1463 mutex_exit(HUBD_MUTEX(hubd)); 1464 } 1465 1466 /* physically zap the children we didn't find */ 1467 mutex_enter(HUBD_MUTEX(hubd)); 1468 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 1469 if (hubd->h_port_state[port] & HUBD_CHILD_ZAP) { 1470 /* zap the dip and usba_device structure as well */ 1471 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 1472 hubd->h_children_dips[port] = NULL; 1473 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP; 1474 } 1475 } 1476 mutex_exit(HUBD_MUTEX(hubd)); 1477 1478 ndi_devi_exit(dip, circ); 1479 1480 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1481 "hubd_bus_unconfig: rval=%d", rval); 1482 1483 return (rval); 1484 } 1485 1486 1487 /* bus_power entry point */ 1488 static int 1489 hubd_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op, 1490 void *arg, void *result) 1491 { 1492 hubd_t *hubd; 1493 int rval, pwrup_res; 1494 usb_port_t port; 1495 int retval = DDI_FAILURE; 1496 pm_bp_child_pwrchg_t *bpc; 1497 pm_bp_nexus_pwrup_t bpn; 1498 1499 hubd = hubd_get_soft_state(dip); 1500 1501 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1502 "hubd_bus_power: dip=%p, impl_arg=%p, power_op=%d, arg=%p, " 1503 "result=%d\n", (void *)dip, impl_arg, op, arg, *(int *)result); 1504 1505 bpc = (pm_bp_child_pwrchg_t *)arg; 1506 1507 mutex_enter(HUBD_MUTEX(hubd)); 1508 hubd->h_bus_pwr++; 1509 mutex_exit(HUBD_MUTEX(hubd)); 1510 1511 switch (op) { 1512 case BUS_POWER_PRE_NOTIFICATION: 1513 port = hubd_child_dip2port(hubd, bpc->bpc_dip); 1514 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1515 "hubd_bus_power: BUS_POWER_PRE_NOTIFICATION, port=%d", 1516 port); 1517 1518 /* go to full power if we are powered down */ 1519 mutex_enter(HUBD_MUTEX(hubd)); 1520 1521 /* 1522 * If this case completes normally, idle will be in 1523 * hubd_bus_power / BUS_POWER_POST_NOTIFICATION 1524 */ 1525 hubd_pm_busy_component(hubd, dip, 0); 1526 1527 /* 1528 * raise power only if we have created the components 1529 * and are currently in low power 1530 */ 1531 if ((hubd->h_dev_state == USB_DEV_PWRED_DOWN) && 1532 hubd->h_hubpm->hubp_wakeup_enabled) { 1533 mutex_exit(HUBD_MUTEX(hubd)); 1534 1535 bpn.bpn_comp = 0; 1536 bpn.bpn_dip = dip; 1537 bpn.bpn_level = USB_DEV_OS_FULL_PWR; 1538 bpn.bpn_private = bpc->bpc_private; 1539 1540 rval = pm_busop_bus_power(dip, impl_arg, 1541 BUS_POWER_NEXUS_PWRUP, (void *)&bpn, 1542 (void *)&pwrup_res); 1543 1544 if (rval != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) { 1545 mutex_enter(HUBD_MUTEX(hubd)); 1546 hubd_pm_idle_component(hubd, dip, 0); 1547 mutex_exit(HUBD_MUTEX(hubd)); 1548 1549 break; 1550 } 1551 mutex_enter(HUBD_MUTEX(hubd)); 1552 } 1553 1554 /* indicate that child is changing power level */ 1555 hubd->h_port_state[port] |= HUBD_CHILD_PWRLVL_CHNG; 1556 mutex_exit(HUBD_MUTEX(hubd)); 1557 1558 if ((bpc->bpc_olevel == 0) && 1559 (bpc->bpc_nlevel > bpc->bpc_olevel)) { 1560 /* 1561 * this child is transitioning from power off 1562 * to power on state - resume port 1563 */ 1564 rval = hubd_resume_port(hubd, port); 1565 if (rval == USB_SUCCESS) { 1566 retval = DDI_SUCCESS; 1567 } else { 1568 /* reset this flag on failure */ 1569 mutex_enter(HUBD_MUTEX(hubd)); 1570 hubd->h_port_state[port] &= 1571 ~HUBD_CHILD_PWRLVL_CHNG; 1572 hubd_pm_idle_component(hubd, dip, 0); 1573 mutex_exit(HUBD_MUTEX(hubd)); 1574 } 1575 } else { 1576 retval = DDI_SUCCESS; 1577 } 1578 1579 break; 1580 case BUS_POWER_POST_NOTIFICATION: 1581 port = hubd_child_dip2port(hubd, bpc->bpc_dip); 1582 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1583 "hubd_bus_power: BUS_POWER_POST_NOTIFICATION, port=%d", 1584 port); 1585 1586 mutex_enter(HUBD_MUTEX(hubd)); 1587 hubd->h_port_state[port] &= ~HUBD_CHILD_PWRLVL_CHNG; 1588 mutex_exit(HUBD_MUTEX(hubd)); 1589 1590 /* record child's pwr and suspend port if required */ 1591 rval = hubd_post_power(hubd, port, bpc, *(int *)result); 1592 if (rval == USB_SUCCESS) { 1593 1594 retval = DDI_SUCCESS; 1595 } 1596 1597 mutex_enter(HUBD_MUTEX(hubd)); 1598 1599 /* 1600 * Matching idle for the busy in 1601 * hubd_bus_power / BUS_POWER_PRE_NOTIFICATION 1602 */ 1603 hubd_pm_idle_component(hubd, dip, 0); 1604 1605 mutex_exit(HUBD_MUTEX(hubd)); 1606 1607 break; 1608 default: 1609 retval = pm_busop_bus_power(dip, impl_arg, op, arg, result); 1610 1611 break; 1612 } 1613 1614 mutex_enter(HUBD_MUTEX(hubd)); 1615 hubd->h_bus_pwr--; 1616 mutex_exit(HUBD_MUTEX(hubd)); 1617 1618 return (retval); 1619 } 1620 1621 1622 /* 1623 * functions to handle power transition for OS levels 0 -> 3 1624 */ 1625 static int 1626 hubd_pwrlvl0(hubd_t *hubd) 1627 { 1628 hub_power_t *hubpm; 1629 1630 /* We can't power down if hotplug thread is running */ 1631 if (hubd->h_hotplug_thread || hubd->h_hubpm->hubp_busy_pm || 1632 (hubd_can_suspend(hubd) == USB_FAILURE)) { 1633 1634 return (USB_FAILURE); 1635 } 1636 1637 switch (hubd->h_dev_state) { 1638 case USB_DEV_ONLINE: 1639 hubpm = hubd->h_hubpm; 1640 1641 /* 1642 * To avoid race with bus_power pre_notify on check over 1643 * dev_state, we need to correctly set the dev state 1644 * before the mutex is dropped in stop polling. 1645 */ 1646 hubd->h_dev_state = USB_DEV_PWRED_DOWN; 1647 hubpm->hubp_current_power = USB_DEV_OS_PWR_OFF; 1648 1649 /* 1650 * if we are the root hub, do not stop polling 1651 * otherwise, we will never see a resume 1652 */ 1653 if (usba_is_root_hub(hubd->h_dip)) { 1654 /* place holder to implement Global Suspend */ 1655 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1656 "Global Suspend: Not Yet Implemented"); 1657 } else { 1658 hubd_stop_polling(hubd); 1659 } 1660 1661 /* Issue USB D3 command to the device here */ 1662 (void) usb_set_device_pwrlvl3(hubd->h_dip); 1663 1664 break; 1665 case USB_DEV_DISCONNECTED: 1666 case USB_DEV_SUSPENDED: 1667 case USB_DEV_PWRED_DOWN: 1668 default: 1669 1670 break; 1671 } 1672 1673 return (USB_SUCCESS); 1674 } 1675 1676 1677 /* ARGSUSED */ 1678 static int 1679 hubd_pwrlvl1(hubd_t *hubd) 1680 { 1681 /* Issue USB D2 command to the device here */ 1682 (void) usb_set_device_pwrlvl2(hubd->h_dip); 1683 1684 return (USB_FAILURE); 1685 } 1686 1687 1688 /* ARGSUSED */ 1689 static int 1690 hubd_pwrlvl2(hubd_t *hubd) 1691 { 1692 /* Issue USB D1 command to the device here */ 1693 (void) usb_set_device_pwrlvl1(hubd->h_dip); 1694 1695 return (USB_FAILURE); 1696 } 1697 1698 1699 static int 1700 hubd_pwrlvl3(hubd_t *hubd) 1701 { 1702 hub_power_t *hubpm; 1703 int rval; 1704 1705 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3"); 1706 1707 hubpm = hubd->h_hubpm; 1708 switch (hubd->h_dev_state) { 1709 case USB_DEV_PWRED_DOWN: 1710 ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF); 1711 if (usba_is_root_hub(hubd->h_dip)) { 1712 /* implement global resume here */ 1713 USB_DPRINTF_L2(DPRINT_MASK_PM, 1714 hubd->h_log_handle, 1715 "Global Resume: Not Yet Implemented"); 1716 } 1717 /* Issue USB D0 command to the device here */ 1718 rval = usb_set_device_pwrlvl0(hubd->h_dip); 1719 ASSERT(rval == USB_SUCCESS); 1720 hubd->h_dev_state = USB_DEV_ONLINE; 1721 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 1722 hubpm->hubp_time_at_full_power = ddi_get_time(); 1723 hubd_start_polling(hubd, 0); 1724 1725 /* FALLTHRU */ 1726 case USB_DEV_ONLINE: 1727 /* we are already in full power */ 1728 1729 /* FALLTHRU */ 1730 case USB_DEV_DISCONNECTED: 1731 case USB_DEV_SUSPENDED: 1732 /* 1733 * PM framework tries to put you in full power 1734 * during system shutdown. If we are disconnected 1735 * return success. Also, we should not change state 1736 * when we are disconnected or suspended or about to 1737 * transition to that state 1738 */ 1739 1740 return (USB_SUCCESS); 1741 default: 1742 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1743 "hubd_pwrlvl3: Illegal dev_state=%d", hubd->h_dev_state); 1744 1745 return (USB_FAILURE); 1746 } 1747 } 1748 1749 1750 /* power entry point */ 1751 /* ARGSUSED */ 1752 int 1753 usba_hubdi_power(dev_info_t *dip, int comp, int level) 1754 { 1755 hubd_t *hubd; 1756 hub_power_t *hubpm; 1757 int retval; 1758 int circ; 1759 1760 hubd = hubd_get_soft_state(dip); 1761 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1762 "usba_hubdi_power: level=%d", level); 1763 1764 ndi_devi_enter(dip, &circ); 1765 1766 mutex_enter(HUBD_MUTEX(hubd)); 1767 hubpm = hubd->h_hubpm; 1768 1769 /* check if we are transitioning to a legal power level */ 1770 if (USB_DEV_PWRSTATE_OK(hubpm->hubp_pwr_states, level)) { 1771 USB_DPRINTF_L2(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1772 "usba_hubdi_power: illegal power level=%d " 1773 "hubp_pwr_states=0x%x", level, hubpm->hubp_pwr_states); 1774 mutex_exit(HUBD_MUTEX(hubd)); 1775 1776 ndi_devi_exit(dip, circ); 1777 1778 return (DDI_FAILURE); 1779 } 1780 1781 switch (level) { 1782 case USB_DEV_OS_PWR_OFF: 1783 retval = hubd_pwrlvl0(hubd); 1784 1785 break; 1786 case USB_DEV_OS_PWR_1: 1787 retval = hubd_pwrlvl1(hubd); 1788 1789 break; 1790 case USB_DEV_OS_PWR_2: 1791 retval = hubd_pwrlvl2(hubd); 1792 1793 break; 1794 case USB_DEV_OS_FULL_PWR: 1795 retval = hubd_pwrlvl3(hubd); 1796 1797 break; 1798 } 1799 mutex_exit(HUBD_MUTEX(hubd)); 1800 1801 ndi_devi_exit(dip, circ); 1802 1803 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1804 } 1805 1806 1807 /* power entry point for the root hub */ 1808 int 1809 usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level) 1810 { 1811 return (usba_hubdi_power(dip, comp, level)); 1812 } 1813 1814 1815 /* 1816 * standard driver entry points support code 1817 */ 1818 int 1819 usba_hubdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1820 { 1821 int instance = ddi_get_instance(dip); 1822 hubd_t *hubd = NULL; 1823 int i, rval; 1824 int minor; 1825 uint8_t ports_count; 1826 char *log_name = NULL; 1827 const char *root_hub_drvname; 1828 usb_ep_data_t *ep_data; 1829 usba_device_t *child_ud = NULL; 1830 usb_dev_descr_t *usb_dev_descr; 1831 usb_port_status_t parent_port_status, child_port_status; 1832 1833 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubdi_log_handle, 1834 "hubd_attach instance %d, cmd=0x%x", instance, cmd); 1835 1836 switch (cmd) { 1837 case DDI_ATTACH: 1838 1839 break; 1840 case DDI_RESUME: 1841 hubd_cpr_resume(dip); 1842 1843 return (DDI_SUCCESS); 1844 default: 1845 return (DDI_FAILURE); 1846 } 1847 1848 /* 1849 * Allocate softc information. 1850 */ 1851 if (usba_is_root_hub(dip)) { 1852 /* soft state has already been allocated */ 1853 hubd = hubd_get_soft_state(dip); 1854 minor = HUBD_IS_ROOT_HUB; 1855 1856 /* generate readable labels for different root hubs */ 1857 root_hub_drvname = ddi_driver_name(dip); 1858 if (strcmp(root_hub_drvname, "ehci") == 0) { 1859 log_name = "eusb"; 1860 } else if (strcmp(root_hub_drvname, "uhci") == 0) { 1861 log_name = "uusb"; 1862 } else { 1863 /* std. for ohci */ 1864 log_name = "usb"; 1865 } 1866 } else { 1867 rval = ddi_soft_state_zalloc(hubd_statep, instance); 1868 minor = 0; 1869 1870 if (rval != DDI_SUCCESS) { 1871 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 1872 "cannot allocate soft state (%d)", instance); 1873 goto fail; 1874 } 1875 1876 hubd = hubd_get_soft_state(dip); 1877 if (hubd == NULL) { 1878 goto fail; 1879 } 1880 } 1881 1882 hubd->h_log_handle = usb_alloc_log_hdl(dip, log_name, &hubd_errlevel, 1883 &hubd_errmask, &hubd_instance_debug, 0); 1884 1885 hubd->h_usba_device = child_ud = usba_get_usba_device(dip); 1886 hubd->h_dip = dip; 1887 hubd->h_instance = instance; 1888 1889 mutex_enter(&child_ud->usb_mutex); 1890 child_port_status = child_ud->usb_port_status; 1891 usb_dev_descr = child_ud->usb_dev_descr; 1892 parent_port_status = (child_ud->usb_hs_hub_usba_dev) ? 1893 child_ud->usb_hs_hub_usba_dev->usb_port_status : 0; 1894 mutex_exit(&child_ud->usb_mutex); 1895 1896 if ((child_port_status == USBA_FULL_SPEED_DEV) && 1897 (parent_port_status == USBA_HIGH_SPEED_DEV) && 1898 (usb_dev_descr->bcdUSB == 0x100)) { 1899 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 1900 "Use of a USB1.0 hub behind a high speed port may " 1901 "cause unexpected failures"); 1902 } 1903 1904 hubd->h_pipe_policy.pp_max_async_reqs = 1; 1905 1906 /* register with USBA as client driver */ 1907 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 1908 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1909 "client attach failed"); 1910 1911 goto fail; 1912 } 1913 1914 if (usb_get_dev_data(dip, &hubd->h_dev_data, 1915 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) { 1916 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1917 "cannot get dev_data"); 1918 1919 goto fail; 1920 } 1921 1922 if ((ep_data = usb_lookup_ep_data(dip, hubd->h_dev_data, 1923 hubd->h_dev_data->dev_curr_if, 0, 0, 1924 (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) { 1925 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1926 "no interrupt IN endpoint found"); 1927 1928 goto fail; 1929 } 1930 1931 hubd->h_ep1_descr = ep_data->ep_descr; 1932 hubd->h_default_pipe = hubd->h_dev_data->dev_default_ph; 1933 1934 mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER, 1935 hubd->h_dev_data->dev_iblock_cookie); 1936 cv_init(&hubd->h_cv_reset_port, NULL, CV_DRIVER, NULL); 1937 cv_init(&hubd->h_cv_hotplug_dev, NULL, CV_DRIVER, NULL); 1938 1939 hubd->h_init_state |= HUBD_LOCKS_DONE; 1940 1941 usb_free_descr_tree(dip, hubd->h_dev_data); 1942 1943 /* 1944 * register this hub instance with usba 1945 */ 1946 rval = usba_hubdi_register(dip, 0); 1947 if (rval != USB_SUCCESS) { 1948 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1949 "usba_hubdi_register failed"); 1950 goto fail; 1951 } 1952 1953 mutex_enter(HUBD_MUTEX(hubd)); 1954 hubd->h_init_state |= HUBD_HUBDI_REGISTERED; 1955 hubd->h_dev_state = USB_DEV_ONLINE; 1956 mutex_exit(HUBD_MUTEX(hubd)); 1957 1958 /* now create components to power manage this device */ 1959 hubd_create_pm_components(dip, hubd); 1960 1961 /* 1962 * Event handling: definition and registration 1963 * 1964 * first the definition: 1965 * get event handle 1966 */ 1967 (void) ndi_event_alloc_hdl(dip, 0, &hubd->h_ndi_event_hdl, NDI_SLEEP); 1968 1969 /* bind event set to the handle */ 1970 if (ndi_event_bind_set(hubd->h_ndi_event_hdl, &hubd_ndi_events, 1971 NDI_SLEEP)) { 1972 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 1973 "binding event set failed"); 1974 1975 goto fail; 1976 } 1977 1978 /* event registration */ 1979 if (hubd_register_events(hubd) != USB_SUCCESS) { 1980 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1981 "hubd_register_events failed"); 1982 1983 goto fail; 1984 } 1985 1986 mutex_enter(HUBD_MUTEX(hubd)); 1987 hubd->h_init_state |= HUBD_EVENTS_REGISTERED; 1988 1989 if ((hubd_get_hub_descriptor(hubd)) != USB_SUCCESS) { 1990 mutex_exit(HUBD_MUTEX(hubd)); 1991 1992 goto fail; 1993 } 1994 1995 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 1996 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 1997 "hub-ignore-power-budget") == 1) { 1998 hubd->h_ignore_pwr_budget = B_TRUE; 1999 } else { 2000 hubd->h_ignore_pwr_budget = B_FALSE; 2001 2002 /* initialize hub power budget variables */ 2003 if (hubd_init_power_budget(hubd) != USB_SUCCESS) { 2004 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2005 "hubd_init_power_budget failed"); 2006 mutex_exit(HUBD_MUTEX(hubd)); 2007 2008 goto fail; 2009 } 2010 } 2011 2012 /* initialize and create children */ 2013 if (hubd_check_ports(hubd) != USB_SUCCESS) { 2014 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2015 "hubd_check_ports failed"); 2016 mutex_exit(HUBD_MUTEX(hubd)); 2017 2018 goto fail; 2019 } 2020 2021 /* 2022 * create cfgadm nodes 2023 */ 2024 hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, KM_SLEEP); 2025 hubd_get_ancestry_str(hubd); 2026 2027 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2028 "#ports=0x%x", hubd->h_hub_descr.bNbrPorts); 2029 2030 for (i = 1; i <= hubd->h_hub_descr.bNbrPorts; i++) { 2031 char ap_name[HUBD_APID_NAMELEN]; 2032 2033 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 2034 hubd->h_ancestry_str, i); 2035 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2036 "ap_name=%s", ap_name); 2037 2038 if (ddi_create_minor_node(dip, ap_name, S_IFCHR, instance, 2039 DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 2040 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2041 "cannot create attachment point node (%d)", 2042 instance); 2043 mutex_exit(HUBD_MUTEX(hubd)); 2044 2045 goto fail; 2046 } 2047 } 2048 2049 ports_count = hubd->h_hub_descr.bNbrPorts; 2050 mutex_exit(HUBD_MUTEX(hubd)); 2051 2052 /* create minor nodes */ 2053 if (ddi_create_minor_node(dip, "hubd", S_IFCHR, 2054 instance | minor, DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 2055 2056 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2057 "cannot create devctl minor node (%d)", instance); 2058 2059 goto fail; 2060 } 2061 2062 mutex_enter(HUBD_MUTEX(hubd)); 2063 hubd->h_init_state |= HUBD_MINOR_NODE_CREATED; 2064 mutex_exit(HUBD_MUTEX(hubd)); 2065 2066 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, 2067 "usb-port-count", ports_count) != DDI_PROP_SUCCESS) { 2068 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2069 "usb-port-count update failed"); 2070 } 2071 2072 /* 2073 * host controller driver has already reported this dev 2074 * if we are the root hub 2075 */ 2076 if (!usba_is_root_hub(dip)) { 2077 ddi_report_dev(dip); 2078 } 2079 2080 /* enable deathrow thread */ 2081 hubd->h_cleanup_enabled = B_TRUE; 2082 mutex_enter(HUBD_MUTEX(hubd)); 2083 hubd_pm_idle_component(hubd, dip, 0); 2084 mutex_exit(HUBD_MUTEX(hubd)); 2085 2086 return (DDI_SUCCESS); 2087 2088 fail: 2089 { 2090 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2091 2092 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 2093 "cannot attach %s", ddi_pathname(dip, pathname)); 2094 2095 kmem_free(pathname, MAXPATHLEN); 2096 } 2097 2098 mutex_enter(HUBD_MUTEX(hubd)); 2099 hubd_pm_idle_component(hubd, dip, 0); 2100 mutex_exit(HUBD_MUTEX(hubd)); 2101 2102 if (hubd) { 2103 rval = hubd_cleanup(dip, hubd); 2104 if (rval != USB_SUCCESS) { 2105 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 2106 "failure to complete cleanup after attach failure"); 2107 } 2108 } 2109 2110 return (DDI_FAILURE); 2111 } 2112 2113 2114 int 2115 usba_hubdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2116 { 2117 hubd_t *hubd = hubd_get_soft_state(dip); 2118 int rval; 2119 2120 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2121 "hubd_detach: cmd=0x%x", cmd); 2122 2123 switch (cmd) { 2124 case DDI_DETACH: 2125 rval = hubd_cleanup(dip, hubd); 2126 2127 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2128 case DDI_SUSPEND: 2129 rval = hubd_cpr_suspend(hubd); 2130 2131 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2132 default: 2133 return (DDI_FAILURE); 2134 } 2135 } 2136 2137 2138 /* 2139 * hubd_setdevaddr 2140 * set the device addrs on this port 2141 */ 2142 static int 2143 hubd_setdevaddr(hubd_t *hubd, usb_port_t port) 2144 { 2145 int rval; 2146 usb_cr_t completion_reason; 2147 usb_cb_flags_t cb_flags; 2148 usb_pipe_handle_t ph; 2149 dev_info_t *child_dip = NULL; 2150 uchar_t address = 0; 2151 usba_device_t *usba_device; 2152 int retry = 0; 2153 long time_delay; 2154 2155 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2156 "hubd_setdevaddr: port=%d", port); 2157 2158 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2159 2160 child_dip = hubd->h_children_dips[port]; 2161 address = hubd->h_usba_devices[port]->usb_addr; 2162 usba_device = hubd->h_usba_devices[port]; 2163 2164 /* close the default pipe with addr x */ 2165 mutex_exit(HUBD_MUTEX(hubd)); 2166 ph = usba_get_dflt_pipe_handle(child_dip); 2167 usb_pipe_close(child_dip, ph, 2168 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2169 mutex_enter(HUBD_MUTEX(hubd)); 2170 2171 /* 2172 * As this device has been reset, temporarily 2173 * assign the default address 2174 */ 2175 mutex_enter(&usba_device->usb_mutex); 2176 address = usba_device->usb_addr; 2177 usba_device->usb_addr = USBA_DEFAULT_ADDR; 2178 mutex_exit(&usba_device->usb_mutex); 2179 2180 mutex_exit(HUBD_MUTEX(hubd)); 2181 2182 time_delay = drv_usectohz(hubd_device_delay / 20); 2183 for (retry = 0; retry < hubd_retry_enumerate; retry++) { 2184 2185 /* open child's default pipe with USBA_DEFAULT_ADDR */ 2186 if (usb_pipe_open(child_dip, NULL, NULL, 2187 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != 2188 USB_SUCCESS) { 2189 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2190 "hubd_setdevaddr: Unable to open default pipe"); 2191 2192 break; 2193 } 2194 2195 /* Set the address of the device */ 2196 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 2197 USB_DEV_REQ_HOST_TO_DEV, 2198 USB_REQ_SET_ADDRESS, /* bRequest */ 2199 address, /* wValue */ 2200 0, /* wIndex */ 2201 0, /* wLength */ 2202 NULL, 0, 2203 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2204 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2205 "hubd_setdevaddr(%d): rval=%d cr=%d cb_fl=0x%x", 2206 retry, rval, completion_reason, cb_flags); 2207 } 2208 2209 usb_pipe_close(child_dip, ph, 2210 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2211 2212 if (rval == USB_SUCCESS) { 2213 2214 break; 2215 } 2216 2217 delay(time_delay); 2218 } 2219 2220 /* Reset to the old address */ 2221 mutex_enter(&usba_device->usb_mutex); 2222 usba_device->usb_addr = address; 2223 mutex_exit(&usba_device->usb_mutex); 2224 mutex_enter(HUBD_MUTEX(hubd)); 2225 2226 usba_clear_data_toggle(usba_device); 2227 2228 return (rval); 2229 } 2230 2231 2232 /* 2233 * hubd_setdevconfig 2234 * set the device addrs on this port 2235 */ 2236 static void 2237 hubd_setdevconfig(hubd_t *hubd, usb_port_t port) 2238 { 2239 int rval; 2240 usb_cr_t completion_reason; 2241 usb_cb_flags_t cb_flags; 2242 usb_pipe_handle_t ph; 2243 dev_info_t *child_dip = NULL; 2244 usba_device_t *usba_device = NULL; 2245 uint16_t config_value; 2246 2247 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2248 "hubd_setdevconfig: port=%d", port); 2249 2250 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2251 2252 child_dip = hubd->h_children_dips[port]; 2253 usba_device = hubd->h_usba_devices[port]; 2254 config_value = hubd->h_usba_devices[port]->usb_cfg_value; 2255 mutex_exit(HUBD_MUTEX(hubd)); 2256 2257 /* open the default control pipe */ 2258 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 2259 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) == 2260 USB_SUCCESS) { 2261 2262 /* Set the default configuration of the device */ 2263 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 2264 USB_DEV_REQ_HOST_TO_DEV, 2265 USB_REQ_SET_CFG, /* bRequest */ 2266 config_value, /* wValue */ 2267 0, /* wIndex */ 2268 0, /* wLength */ 2269 NULL, 0, 2270 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2271 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2272 "hubd_setdevconfig: set device config failed: " 2273 "cr=%d cb_fl=0x%x rval=%d", 2274 completion_reason, cb_flags, rval); 2275 } 2276 /* 2277 * After setting the configuration, we make this default 2278 * control pipe persistent, so that it gets re-opened 2279 * on posting a connect event 2280 */ 2281 usba_persistent_pipe_close(usba_device); 2282 } else { 2283 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2284 "pipe open fails: rval=%d", rval); 2285 } 2286 mutex_enter(HUBD_MUTEX(hubd)); 2287 } 2288 2289 2290 /*ARGSUSED*/ 2291 static int 2292 hubd_check_disconnected_ports(dev_info_t *dip, void *arg) 2293 { 2294 int circ; 2295 usb_port_t port; 2296 hubd_t *hubd; 2297 major_t hub_major = ddi_name_to_major("hubd"); 2298 major_t hwahc_major = ddi_name_to_major("hwahc"); 2299 major_t usbmid_major = ddi_name_to_major("usb_mid"); 2300 2301 /* 2302 * make sure dip is a usb hub, major of root hub is HCD 2303 * major 2304 */ 2305 if (!usba_is_root_hub(dip)) { 2306 if (ddi_driver_major(dip) == usbmid_major) { 2307 /* 2308 * need to walk the children since it might be a 2309 * HWA device 2310 */ 2311 2312 return (DDI_WALK_CONTINUE); 2313 } 2314 2315 /* TODO: DWA device may also need special handling */ 2316 2317 if (((ddi_driver_major(dip) != hub_major) && 2318 (ddi_driver_major(dip) != hwahc_major)) || 2319 !i_ddi_devi_attached(dip)) { 2320 2321 return (DDI_WALK_PRUNECHILD); 2322 } 2323 } 2324 2325 hubd = hubd_get_soft_state(dip); 2326 if (hubd == NULL) { 2327 2328 return (DDI_WALK_PRUNECHILD); 2329 } 2330 2331 /* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */ 2332 ndi_devi_enter(dip, &circ); 2333 2334 if (ddi_driver_major(dip) != hwahc_major) { 2335 /* for normal usb hub or root hub */ 2336 mutex_enter(HUBD_MUTEX(hubd)); 2337 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2338 dev_info_t *cdip = hubd->h_children_dips[port]; 2339 2340 if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) { 2341 2342 continue; 2343 } 2344 2345 (void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE, 2346 B_TRUE); 2347 } 2348 mutex_exit(HUBD_MUTEX(hubd)); 2349 } else { 2350 /* for HWA */ 2351 if (hubd->h_cleanup_child != NULL) { 2352 if (hubd->h_cleanup_child(dip) != USB_SUCCESS) { 2353 ndi_devi_exit(dip, circ); 2354 2355 return (DDI_WALK_PRUNECHILD); 2356 } 2357 } else { 2358 ndi_devi_exit(dip, circ); 2359 2360 return (DDI_WALK_PRUNECHILD); 2361 } 2362 } 2363 2364 ndi_devi_exit(dip, circ); 2365 2366 /* skip siblings of root hub */ 2367 if (usba_is_root_hub(dip)) { 2368 2369 return (DDI_WALK_PRUNESIB); 2370 } 2371 2372 return (DDI_WALK_CONTINUE); 2373 } 2374 2375 2376 /* 2377 * this thread will walk all children under the root hub for this 2378 * USB bus instance and attempt to remove them 2379 */ 2380 static void 2381 hubd_root_hub_cleanup_thread(void *arg) 2382 { 2383 int circ; 2384 hubd_t *root_hubd = (hubd_t *)arg; 2385 dev_info_t *rh_dip = root_hubd->h_dip; 2386 #ifndef __lock_lint 2387 callb_cpr_t cprinfo; 2388 2389 CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr, 2390 "USB root hub"); 2391 #endif 2392 2393 for (;;) { 2394 /* don't race with detach */ 2395 ndi_hold_devi(rh_dip); 2396 2397 mutex_enter(HUBD_MUTEX(root_hubd)); 2398 root_hubd->h_cleanup_needed = 0; 2399 mutex_exit(HUBD_MUTEX(root_hubd)); 2400 2401 (void) devfs_clean(rh_dip, NULL, 0); 2402 2403 ndi_devi_enter(ddi_get_parent(rh_dip), &circ); 2404 ddi_walk_devs(rh_dip, hubd_check_disconnected_ports, 2405 NULL); 2406 #ifdef __lock_lint 2407 (void) hubd_check_disconnected_ports(rh_dip, NULL); 2408 #endif 2409 ndi_devi_exit(ddi_get_parent(rh_dip), circ); 2410 2411 /* quit if we are not enabled anymore */ 2412 mutex_enter(HUBD_MUTEX(root_hubd)); 2413 if ((root_hubd->h_cleanup_enabled == B_FALSE) || 2414 (root_hubd->h_cleanup_needed == B_FALSE)) { 2415 root_hubd->h_cleanup_active = B_FALSE; 2416 mutex_exit(HUBD_MUTEX(root_hubd)); 2417 ndi_rele_devi(rh_dip); 2418 2419 break; 2420 } 2421 mutex_exit(HUBD_MUTEX(root_hubd)); 2422 ndi_rele_devi(rh_dip); 2423 2424 #ifndef __lock_lint 2425 mutex_enter(HUBD_MUTEX(root_hubd)); 2426 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2427 mutex_exit(HUBD_MUTEX(root_hubd)); 2428 2429 delay(drv_usectohz(hubd_dip_cleanup_delay)); 2430 2431 mutex_enter(HUBD_MUTEX(root_hubd)); 2432 CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd)); 2433 mutex_exit(HUBD_MUTEX(root_hubd)); 2434 #endif 2435 } 2436 2437 #ifndef __lock_lint 2438 mutex_enter(HUBD_MUTEX(root_hubd)); 2439 CALLB_CPR_EXIT(&cprinfo); 2440 #endif 2441 } 2442 2443 2444 void 2445 hubd_schedule_cleanup(dev_info_t *rh_dip) 2446 { 2447 hubd_t *root_hubd; 2448 2449 /* 2450 * The usb_root_hub_dip pointer for the child hub of the WUSB 2451 * wire adapter class device points to the wire adapter, not 2452 * the root hub. Need to find the real root hub dip so that 2453 * the cleanup thread only starts from the root hub. 2454 */ 2455 while (!usba_is_root_hub(rh_dip)) { 2456 root_hubd = hubd_get_soft_state(rh_dip); 2457 if (root_hubd != NULL) { 2458 rh_dip = root_hubd->h_usba_device->usb_root_hub_dip; 2459 if (rh_dip == NULL) { 2460 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2461 root_hubd->h_log_handle, 2462 "hubd_schedule_cleanup: null rh dip"); 2463 2464 return; 2465 } 2466 } else { 2467 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2468 root_hubd->h_log_handle, 2469 "hubd_schedule_cleanup: cannot find root hub"); 2470 2471 return; 2472 } 2473 } 2474 root_hubd = hubd_get_soft_state(rh_dip); 2475 2476 mutex_enter(HUBD_MUTEX(root_hubd)); 2477 root_hubd->h_cleanup_needed = B_TRUE; 2478 if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) { 2479 root_hubd->h_cleanup_active = B_TRUE; 2480 mutex_exit(HUBD_MUTEX(root_hubd)); 2481 (void) thread_create(NULL, 0, 2482 hubd_root_hub_cleanup_thread, 2483 (void *)root_hubd, 0, &p0, TS_RUN, 2484 minclsyspri); 2485 } else { 2486 mutex_exit(HUBD_MUTEX(root_hubd)); 2487 } 2488 } 2489 2490 2491 /* 2492 * hubd_restore_device_state: 2493 * - set config for the hub 2494 * - power cycle all the ports 2495 * - for each port that was connected 2496 * - reset port 2497 * - assign addrs to the device on this port 2498 * - restart polling 2499 * - reset suspend flag 2500 */ 2501 static void 2502 hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd) 2503 { 2504 int rval; 2505 int retry; 2506 uint_t hub_prev_state; 2507 usb_port_t port; 2508 uint16_t status; 2509 uint16_t change; 2510 dev_info_t *ch_dip; 2511 boolean_t ehci_root_hub; 2512 2513 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2514 "hubd_restore_device_state:"); 2515 2516 mutex_enter(HUBD_MUTEX(hubd)); 2517 hub_prev_state = hubd->h_dev_state; 2518 ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN); 2519 2520 /* First bring the device to full power */ 2521 (void) hubd_pm_busy_component(hubd, dip, 0); 2522 mutex_exit(HUBD_MUTEX(hubd)); 2523 2524 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2525 2526 if (!usba_is_root_hub(dip) && 2527 (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0, 2528 DPRINT_MASK_HOTPLUG, 2529 USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) { 2530 2531 /* change the device state to disconnected */ 2532 mutex_enter(HUBD_MUTEX(hubd)); 2533 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2534 (void) hubd_pm_idle_component(hubd, dip, 0); 2535 mutex_exit(HUBD_MUTEX(hubd)); 2536 2537 return; 2538 } 2539 2540 ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0); 2541 2542 mutex_enter(HUBD_MUTEX(hubd)); 2543 /* First turn off all port power */ 2544 rval = hubd_disable_all_port_power(hubd); 2545 if (rval != USB_SUCCESS) { 2546 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2547 "hubd_restore_device_state:" 2548 "turning off port power failed"); 2549 } 2550 2551 /* Settling time before turning on again */ 2552 mutex_exit(HUBD_MUTEX(hubd)); 2553 delay(drv_usectohz(hubd_device_delay / 100)); 2554 mutex_enter(HUBD_MUTEX(hubd)); 2555 2556 /* enable power on all ports so we can see connects */ 2557 if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) { 2558 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2559 "hubd_restore_device_state: turn on port power failed"); 2560 2561 /* disable whatever was enabled */ 2562 (void) hubd_disable_all_port_power(hubd); 2563 2564 (void) hubd_pm_idle_component(hubd, dip, 0); 2565 mutex_exit(HUBD_MUTEX(hubd)); 2566 2567 return; 2568 } 2569 2570 /* 2571 * wait at least 3 frames before accessing devices 2572 * (note that delay's minimal time is one clock tick which 2573 * is 10ms unless hires_tick has been changed) 2574 */ 2575 mutex_exit(HUBD_MUTEX(hubd)); 2576 delay(drv_usectohz(10000)); 2577 mutex_enter(HUBD_MUTEX(hubd)); 2578 2579 hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER; 2580 2581 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2582 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2583 "hubd_restore_device_state: port=%d", port); 2584 2585 /* 2586 * the childen_dips list may have dips that have been 2587 * already deallocated. we only get a post_detach notification 2588 * but not a destroy notification 2589 */ 2590 ch_dip = hubd->h_children_dips[port]; 2591 if (ch_dip) { 2592 /* get port status */ 2593 (void) hubd_determine_port_status(hubd, port, 2594 &status, &change, PORT_CHANGE_CSC); 2595 2596 /* check if it is truly connected */ 2597 if (status & PORT_STATUS_CCS) { 2598 /* 2599 * Now reset port and assign the device 2600 * its original address 2601 */ 2602 retry = 0; 2603 do { 2604 (void) hubd_reset_port(hubd, port); 2605 2606 /* required for ppx */ 2607 (void) hubd_enable_port(hubd, port); 2608 2609 if (retry) { 2610 mutex_exit(HUBD_MUTEX(hubd)); 2611 delay(drv_usectohz( 2612 hubd_device_delay/2)); 2613 mutex_enter(HUBD_MUTEX(hubd)); 2614 } 2615 2616 rval = hubd_setdevaddr(hubd, port); 2617 retry++; 2618 } while ((rval != USB_SUCCESS) && 2619 (retry < hubd_retry_enumerate)); 2620 2621 hubd_setdevconfig(hubd, port); 2622 2623 if (hub_prev_state == USB_DEV_DISCONNECTED) { 2624 /* post a connect event */ 2625 mutex_exit(HUBD_MUTEX(hubd)); 2626 hubd_post_event(hubd, port, 2627 USBA_EVENT_TAG_HOT_INSERTION); 2628 mutex_enter(HUBD_MUTEX(hubd)); 2629 } else { 2630 /* 2631 * Since we have this device connected 2632 * mark it reinserted to prevent 2633 * cleanup thread from stepping in. 2634 */ 2635 mutex_exit(HUBD_MUTEX(hubd)); 2636 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2637 DEVI_SET_DEVICE_REINSERTED(ch_dip); 2638 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2639 2640 /* 2641 * reopen pipes for children for 2642 * their DDI_RESUME 2643 */ 2644 rval = usba_persistent_pipe_open( 2645 usba_get_usba_device(ch_dip)); 2646 mutex_enter(HUBD_MUTEX(hubd)); 2647 ASSERT(rval == USB_SUCCESS); 2648 } 2649 } else { 2650 /* 2651 * Mark this dip for deletion as the device 2652 * is not physically present, and schedule 2653 * cleanup thread upon post resume 2654 */ 2655 mutex_exit(HUBD_MUTEX(hubd)); 2656 2657 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2658 hubd->h_log_handle, 2659 "hubd_restore_device_state: " 2660 "dip=%p on port=%d marked for cleanup", 2661 (void *)ch_dip, port); 2662 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2663 DEVI_SET_DEVICE_REMOVED(ch_dip); 2664 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2665 2666 mutex_enter(HUBD_MUTEX(hubd)); 2667 } 2668 } else if (ehci_root_hub) { 2669 /* get port status */ 2670 (void) hubd_determine_port_status(hubd, port, 2671 &status, &change, PORT_CHANGE_CSC); 2672 2673 /* check if it is truly connected */ 2674 if (status & PORT_STATUS_CCS) { 2675 /* 2676 * reset the port to find out if we have 2677 * 2.0 device connected or 1.X. A 2.0 2678 * device will still be seen as connected, 2679 * while a 1.X device will switch over to 2680 * the companion controller. 2681 */ 2682 (void) hubd_reset_port(hubd, port); 2683 2684 (void) hubd_determine_port_status(hubd, port, 2685 &status, &change, PORT_CHANGE_CSC); 2686 2687 if (status & 2688 (PORT_STATUS_CCS | PORT_STATUS_HSDA)) { 2689 /* 2690 * We have a USB 2.0 device 2691 * connected. Power cycle this port 2692 * so that hotplug thread can 2693 * enumerate this device. 2694 */ 2695 (void) hubd_toggle_port(hubd, port); 2696 } else { 2697 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2698 hubd->h_log_handle, 2699 "hubd_restore_device_state: " 2700 "device on port %d switched over", 2701 port); 2702 } 2703 } 2704 2705 } 2706 } 2707 2708 2709 /* if the device had remote wakeup earlier, enable it again */ 2710 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2711 mutex_exit(HUBD_MUTEX(hubd)); 2712 (void) usb_handle_remote_wakeup(hubd->h_dip, 2713 USB_REMOTE_WAKEUP_ENABLE); 2714 mutex_enter(HUBD_MUTEX(hubd)); 2715 } 2716 2717 hubd->h_dev_state = USB_DEV_ONLINE; 2718 hubd_start_polling(hubd, 0); 2719 (void) hubd_pm_idle_component(hubd, dip, 0); 2720 mutex_exit(HUBD_MUTEX(hubd)); 2721 } 2722 2723 2724 /* 2725 * hubd_cleanup: 2726 * cleanup hubd and deallocate. this function is called for 2727 * handling attach failures and detaching including dynamic 2728 * reconfiguration. If called from attaching, it must clean 2729 * up the whole thing and return success. 2730 */ 2731 /*ARGSUSED*/ 2732 static int 2733 hubd_cleanup(dev_info_t *dip, hubd_t *hubd) 2734 { 2735 int circ, rval, old_dev_state; 2736 hub_power_t *hubpm; 2737 #ifdef DEBUG 2738 usb_port_t port; 2739 #endif 2740 2741 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2742 "hubd_cleanup:"); 2743 2744 if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) { 2745 goto done; 2746 } 2747 2748 /* ensure we are the only one active */ 2749 ndi_devi_enter(dip, &circ); 2750 2751 mutex_enter(HUBD_MUTEX(hubd)); 2752 2753 /* Cleanup failure is only allowed if called from detach */ 2754 if (DEVI_IS_DETACHING(dip)) { 2755 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 2756 2757 /* 2758 * We are being called from detach. 2759 * Fail immediately if the hotplug thread is running 2760 * else set the dev_state to disconnected so that 2761 * hotplug thread just exits without doing anything. 2762 */ 2763 if (hubd->h_bus_ctls || hubd->h_bus_pwr || 2764 hubd->h_hotplug_thread) { 2765 mutex_exit(HUBD_MUTEX(hubd)); 2766 ndi_devi_exit(dip, circ); 2767 2768 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2769 "hubd_cleanup: hotplug thread/bus ctl active " 2770 "- failing detach"); 2771 2772 return (USB_FAILURE); 2773 } 2774 2775 /* 2776 * if the deathrow thread is still active or about 2777 * to become active, fail detach 2778 * the roothup can only be detached if nexus drivers 2779 * are unloaded or explicitly offlined 2780 */ 2781 if (rh_dip == dip) { 2782 if (hubd->h_cleanup_needed || 2783 hubd->h_cleanup_active) { 2784 mutex_exit(HUBD_MUTEX(hubd)); 2785 ndi_devi_exit(dip, circ); 2786 2787 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2788 hubd->h_log_handle, 2789 "hubd_cleanup: deathrow still active?" 2790 "- failing detach"); 2791 2792 return (USB_FAILURE); 2793 } 2794 } 2795 } 2796 2797 old_dev_state = hubd->h_dev_state; 2798 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2799 2800 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2801 "hubd_cleanup: stop polling"); 2802 hubd_close_intr_pipe(hubd); 2803 2804 ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr || 2805 hubd->h_hotplug_thread) == 0); 2806 mutex_exit(HUBD_MUTEX(hubd)); 2807 2808 /* 2809 * deallocate events, if events are still registered 2810 * (ie. children still attached) then we have to fail the detach 2811 */ 2812 if (hubd->h_ndi_event_hdl) { 2813 2814 rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl); 2815 if (DEVI_IS_ATTACHING(dip)) { 2816 2817 /* It must return success if attaching. */ 2818 ASSERT(rval == NDI_SUCCESS); 2819 2820 } else if (rval != NDI_SUCCESS) { 2821 2822 USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle, 2823 "hubd_cleanup: ndi_event_free_hdl failed"); 2824 ndi_devi_exit(dip, circ); 2825 2826 return (USB_FAILURE); 2827 2828 } 2829 } 2830 2831 mutex_enter(HUBD_MUTEX(hubd)); 2832 2833 if (hubd->h_init_state & HUBD_CHILDREN_CREATED) { 2834 #ifdef DEBUG 2835 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2836 ASSERT(hubd->h_usba_devices[port] == NULL); 2837 ASSERT(hubd->h_children_dips[port] == NULL); 2838 } 2839 #endif 2840 kmem_free(hubd->h_children_dips, hubd->h_cd_list_length); 2841 kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length); 2842 } 2843 2844 /* 2845 * Disable the event callbacks first, after this point, event 2846 * callbacks will never get called. Note we shouldn't hold 2847 * mutex while unregistering events because there may be a 2848 * competing event callback thread. Event callbacks are done 2849 * with ndi mutex held and this can cause a potential deadlock. 2850 * Note that cleanup can't fail after deregistration of events. 2851 */ 2852 if (hubd->h_init_state & HUBD_EVENTS_REGISTERED) { 2853 mutex_exit(HUBD_MUTEX(hubd)); 2854 usb_unregister_event_cbs(dip, &hubd_events); 2855 hubd_unregister_cpr_callback(hubd); 2856 mutex_enter(HUBD_MUTEX(hubd)); 2857 } 2858 2859 /* restore the old dev state so that device can be put into low power */ 2860 hubd->h_dev_state = old_dev_state; 2861 hubpm = hubd->h_hubpm; 2862 2863 if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) { 2864 (void) hubd_pm_busy_component(hubd, dip, 0); 2865 mutex_exit(HUBD_MUTEX(hubd)); 2866 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2867 /* 2868 * Bring the hub to full power before 2869 * issuing the disable remote wakeup command 2870 */ 2871 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2872 2873 if ((rval = usb_handle_remote_wakeup(hubd->h_dip, 2874 USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 2875 USB_DPRINTF_L2(DPRINT_MASK_PM, 2876 hubd->h_log_handle, 2877 "hubd_cleanup: disable remote wakeup " 2878 "fails=%d", rval); 2879 } 2880 } 2881 2882 (void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF); 2883 2884 mutex_enter(HUBD_MUTEX(hubd)); 2885 (void) hubd_pm_idle_component(hubd, dip, 0); 2886 } 2887 2888 if (hubpm) { 2889 if (hubpm->hubp_child_pwrstate) { 2890 kmem_free(hubpm->hubp_child_pwrstate, 2891 MAX_PORTS + 1); 2892 } 2893 kmem_free(hubpm, sizeof (hub_power_t)); 2894 } 2895 mutex_exit(HUBD_MUTEX(hubd)); 2896 2897 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2898 "hubd_cleanup: freeing space"); 2899 2900 if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) { 2901 rval = usba_hubdi_unregister(dip); 2902 ASSERT(rval == USB_SUCCESS); 2903 } 2904 2905 if (hubd->h_init_state & HUBD_LOCKS_DONE) { 2906 mutex_destroy(HUBD_MUTEX(hubd)); 2907 cv_destroy(&hubd->h_cv_reset_port); 2908 cv_destroy(&hubd->h_cv_hotplug_dev); 2909 } 2910 2911 ndi_devi_exit(dip, circ); 2912 2913 if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) { 2914 ddi_remove_minor_node(dip, NULL); 2915 } 2916 2917 if (usba_is_root_hub(dip)) { 2918 usb_pipe_close(dip, hubd->h_default_pipe, 2919 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2920 } 2921 2922 done: 2923 if (hubd->h_ancestry_str) { 2924 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN); 2925 } 2926 2927 usb_client_detach(dip, hubd->h_dev_data); 2928 2929 usb_free_log_hdl(hubd->h_log_handle); 2930 2931 if (!usba_is_root_hub(dip)) { 2932 ddi_soft_state_free(hubd_statep, ddi_get_instance(dip)); 2933 } 2934 2935 ddi_prop_remove_all(dip); 2936 2937 return (USB_SUCCESS); 2938 } 2939 2940 2941 /* 2942 * hubd_determine_port_connection: 2943 * Determine which port is in connect status but does not 2944 * have connect status change bit set, and mark port change 2945 * bit accordingly. 2946 * This function is applied during hub attach time. 2947 */ 2948 static usb_port_mask_t 2949 hubd_determine_port_connection(hubd_t *hubd) 2950 { 2951 usb_port_t port; 2952 usb_hub_descr_t *hub_descr; 2953 uint16_t status; 2954 uint16_t change; 2955 usb_port_mask_t port_change = 0; 2956 2957 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2958 2959 hub_descr = &hubd->h_hub_descr; 2960 2961 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 2962 2963 (void) hubd_determine_port_status(hubd, port, &status, 2964 &change, 0); 2965 2966 /* Check if port is in connect status */ 2967 if (!(status & PORT_STATUS_CCS)) { 2968 2969 continue; 2970 } 2971 2972 /* 2973 * Check if port Connect Status Change bit has been set. 2974 * If already set, the connection will be handled by 2975 * intr polling callback, not during attach. 2976 */ 2977 if (change & PORT_CHANGE_CSC) { 2978 2979 continue; 2980 } 2981 2982 port_change |= 1 << port; 2983 } 2984 2985 return (port_change); 2986 } 2987 2988 2989 /* 2990 * hubd_check_ports: 2991 * - get hub descriptor 2992 * - check initial port status 2993 * - enable power on all ports 2994 * - enable polling on ep1 2995 */ 2996 static int 2997 hubd_check_ports(hubd_t *hubd) 2998 { 2999 int rval; 3000 usb_port_mask_t port_change = 0; 3001 hubd_hotplug_arg_t *arg; 3002 3003 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3004 3005 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3006 "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip)); 3007 3008 /* 3009 * First turn off all port power 3010 */ 3011 if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) { 3012 3013 /* disable whatever was enabled */ 3014 (void) hubd_disable_all_port_power(hubd); 3015 3016 return (rval); 3017 } 3018 3019 /* 3020 * do not switch on immediately (instantly on root hub) 3021 * and allow time to settle 3022 */ 3023 mutex_exit(HUBD_MUTEX(hubd)); 3024 delay(drv_usectohz(10000)); 3025 mutex_enter(HUBD_MUTEX(hubd)); 3026 3027 /* 3028 * enable power on all ports so we can see connects 3029 */ 3030 if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) { 3031 /* disable whatever was enabled */ 3032 (void) hubd_disable_all_port_power(hubd); 3033 3034 return (rval); 3035 } 3036 3037 /* wait at least 3 frames before accessing devices */ 3038 mutex_exit(HUBD_MUTEX(hubd)); 3039 delay(drv_usectohz(10000)); 3040 mutex_enter(HUBD_MUTEX(hubd)); 3041 3042 /* 3043 * allocate arrays for saving the dips of each child per port 3044 * 3045 * ports go from 1 - n, allocate 1 more entry 3046 */ 3047 hubd->h_cd_list_length = 3048 (sizeof (dev_info_t **)) * (hubd->h_hub_descr.bNbrPorts + 1); 3049 3050 hubd->h_children_dips = (dev_info_t **)kmem_zalloc( 3051 hubd->h_cd_list_length, KM_SLEEP); 3052 hubd->h_usba_devices = (usba_device_t **)kmem_zalloc( 3053 hubd->h_cd_list_length, KM_SLEEP); 3054 3055 hubd->h_init_state |= HUBD_CHILDREN_CREATED; 3056 3057 mutex_exit(HUBD_MUTEX(hubd)); 3058 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3059 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3060 mutex_enter(HUBD_MUTEX(hubd)); 3061 3062 if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) { 3063 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3064 3065 return (rval); 3066 } 3067 3068 hubd_start_polling(hubd, 0); 3069 3070 /* 3071 * Some hub devices, like the embedded hub in the CKS ErgoMagic 3072 * keyboard, may only have connection status bit set, but not 3073 * have connect status change bit set when a device has been 3074 * connected to its downstream port before the hub is enumerated. 3075 * Then when the hub is in enumeration, the devices connected to 3076 * it cannot be detected by the intr pipe and won't be enumerated. 3077 * We need to check such situation here and enumerate the downstream 3078 * devices for such hubs. 3079 */ 3080 port_change = hubd_determine_port_connection(hubd); 3081 3082 if (port_change) { 3083 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3084 3085 arg->hubd = hubd; 3086 arg->hotplug_during_attach = B_TRUE; 3087 hubd->h_port_change |= port_change; 3088 3089 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 3090 "hubd_check_ports: port change=0x%x, need to connect", 3091 hubd->h_port_change); 3092 3093 if (usb_async_req(hubd->h_dip, hubd_hotplug_thread, 3094 (void *)arg, 0) == USB_SUCCESS) { 3095 hubd->h_hotplug_thread++; 3096 } else { 3097 /* mark this device as idle */ 3098 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3099 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3100 } 3101 } else { 3102 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3103 } 3104 3105 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3106 "hubd_check_ports done"); 3107 3108 return (USB_SUCCESS); 3109 } 3110 3111 3112 /* 3113 * hubd_get_hub_descriptor: 3114 */ 3115 static int 3116 hubd_get_hub_descriptor(hubd_t *hubd) 3117 { 3118 usb_hub_descr_t *hub_descr = &hubd->h_hub_descr; 3119 mblk_t *data = NULL; 3120 usb_cr_t completion_reason; 3121 usb_cb_flags_t cb_flags; 3122 uint16_t length; 3123 int rval; 3124 usb_req_attrs_t attr = 0; 3125 3126 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3127 "hubd_get_hub_descriptor:"); 3128 3129 if ((hubd->h_dev_data->dev_descr->idVendor == USB_HUB_INTEL_VID) && 3130 (hubd->h_dev_data->dev_descr->idProduct == USB_HUB_INTEL_PID)) { 3131 attr = USB_ATTRS_SHORT_XFER_OK; 3132 } 3133 3134 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3135 ASSERT(hubd->h_default_pipe != 0); 3136 3137 /* get hub descriptor length first by requesting 8 bytes only */ 3138 mutex_exit(HUBD_MUTEX(hubd)); 3139 3140 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3141 hubd->h_default_pipe, 3142 HUB_CLASS_REQ_TYPE, 3143 USB_REQ_GET_DESCR, /* bRequest */ 3144 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3145 0, /* wIndex */ 3146 8, /* wLength */ 3147 &data, 0, 3148 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 3149 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3150 "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d", 3151 completion_reason, cb_flags, rval); 3152 freemsg(data); 3153 mutex_enter(HUBD_MUTEX(hubd)); 3154 3155 return (rval); 3156 } 3157 3158 length = *(data->b_rptr); 3159 3160 if (length > 8) { 3161 freemsg(data); 3162 data = NULL; 3163 3164 /* get complete hub descriptor */ 3165 rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3166 hubd->h_default_pipe, 3167 HUB_CLASS_REQ_TYPE, 3168 USB_REQ_GET_DESCR, /* bRequest */ 3169 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3170 0, /* wIndex */ 3171 length, /* wLength */ 3172 &data, attr, 3173 &completion_reason, &cb_flags, 0); 3174 3175 /* 3176 * Hub descriptor data less than 9 bytes is not valid and 3177 * may cause trouble if we use it. See USB2.0 Tab11-13. 3178 */ 3179 if ((rval != USB_SUCCESS) || (MBLKL(data) <= 8)) { 3180 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3181 "get hub descriptor failed: " 3182 "cr=%d cb_fl=0x%x rval=%d, len=%ld", 3183 completion_reason, cb_flags, rval, 3184 (data)?MBLKL(data):0); 3185 freemsg(data); 3186 mutex_enter(HUBD_MUTEX(hubd)); 3187 3188 return (rval); 3189 } 3190 } 3191 3192 mutex_enter(HUBD_MUTEX(hubd)); 3193 3194 /* parse the hub descriptor */ 3195 /* only 32 ports are supported at present */ 3196 ASSERT(*(data->b_rptr + 2) <= 32); 3197 if (usb_parse_CV_descr("cccscccccc", 3198 data->b_rptr, MBLKL(data), 3199 (void *)hub_descr, sizeof (usb_hub_descr_t)) == 0) { 3200 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3201 "parsing hub descriptor failed"); 3202 3203 freemsg(data); 3204 3205 return (USB_FAILURE); 3206 } 3207 3208 freemsg(data); 3209 3210 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3211 "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x " 3212 "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval, 3213 hub_descr->bNbrPorts, hub_descr->wHubCharacteristics, 3214 hub_descr->bPwrOn2PwrGood, hub_descr->bHubContrCurrent); 3215 3216 if (hub_descr->bNbrPorts > MAX_PORTS) { 3217 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 3218 "Hub driver supports max of %d ports on hub. " 3219 "Hence using the first %d port of %d ports available", 3220 MAX_PORTS, MAX_PORTS, hub_descr->bNbrPorts); 3221 3222 hub_descr->bNbrPorts = MAX_PORTS; 3223 } 3224 3225 return (USB_SUCCESS); 3226 } 3227 3228 3229 /* 3230 * hubd_get_hub_status_words: 3231 */ 3232 static int 3233 hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status) 3234 { 3235 usb_cr_t completion_reason; 3236 usb_cb_flags_t cb_flags; 3237 mblk_t *data = NULL; 3238 3239 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3240 3241 mutex_exit(HUBD_MUTEX(hubd)); 3242 3243 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe, 3244 HUB_CLASS_REQ_TYPE, 3245 USB_REQ_GET_STATUS, 3246 0, 3247 0, 3248 GET_STATUS_LENGTH, 3249 &data, 0, 3250 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 3251 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3252 "get hub status failed: cr=%d cb=0x%x", 3253 completion_reason, cb_flags); 3254 3255 if (data) { 3256 freemsg(data); 3257 } 3258 3259 mutex_enter(HUBD_MUTEX(hubd)); 3260 3261 return (USB_FAILURE); 3262 } 3263 3264 mutex_enter(HUBD_MUTEX(hubd)); 3265 3266 status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 3267 status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 3268 3269 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 3270 "hub status=0x%x change=0x%x", status[0], status[1]); 3271 3272 freemsg(data); 3273 3274 return (USB_SUCCESS); 3275 } 3276 3277 3278 /* 3279 * hubd_open_intr_pipe: 3280 * we read all descriptors first for curiosity and then simply 3281 * open the pipe 3282 */ 3283 static int 3284 hubd_open_intr_pipe(hubd_t *hubd) 3285 { 3286 int rval; 3287 3288 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3289 "hubd_open_intr_pipe:"); 3290 3291 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE); 3292 3293 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING; 3294 mutex_exit(HUBD_MUTEX(hubd)); 3295 3296 if ((rval = usb_pipe_open(hubd->h_dip, 3297 &hubd->h_ep1_descr, &hubd->h_pipe_policy, 3298 0, &hubd->h_ep1_ph)) != USB_SUCCESS) { 3299 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3300 "open intr pipe failed (%d)", rval); 3301 3302 mutex_enter(HUBD_MUTEX(hubd)); 3303 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3304 3305 return (rval); 3306 } 3307 3308 mutex_enter(HUBD_MUTEX(hubd)); 3309 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3310 3311 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3312 "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph); 3313 3314 return (USB_SUCCESS); 3315 } 3316 3317 3318 /* 3319 * hubd_start_polling: 3320 * start or restart the polling 3321 */ 3322 static void 3323 hubd_start_polling(hubd_t *hubd, int always) 3324 { 3325 usb_intr_req_t *reqp; 3326 int rval; 3327 usb_pipe_state_t pipe_state; 3328 3329 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3330 "start polling: always=%d dev_state=%d pipe_state=%d\n\t" 3331 "thread=%d ep1_ph=0x%p", 3332 always, hubd->h_dev_state, hubd->h_intr_pipe_state, 3333 hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph); 3334 3335 /* 3336 * start or restart polling on the intr pipe 3337 * only if hotplug thread is not running 3338 */ 3339 if ((always == HUBD_ALWAYS_START_POLLING) || 3340 ((hubd->h_dev_state == USB_DEV_ONLINE) && 3341 (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3342 (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) { 3343 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3344 "start polling requested"); 3345 3346 reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP); 3347 3348 reqp->intr_client_private = (usb_opaque_t)hubd; 3349 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 3350 USB_ATTRS_AUTOCLEARING; 3351 reqp->intr_len = hubd->h_ep1_descr.wMaxPacketSize; 3352 reqp->intr_cb = hubd_read_cb; 3353 reqp->intr_exc_cb = hubd_exception_cb; 3354 mutex_exit(HUBD_MUTEX(hubd)); 3355 if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp, 3356 USB_FLAGS_SLEEP)) != USB_SUCCESS) { 3357 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3358 "start polling failed, rval=%d", rval); 3359 usb_free_intr_req(reqp); 3360 } 3361 3362 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3363 USB_FLAGS_SLEEP); 3364 if (pipe_state != USB_PIPE_STATE_ACTIVE) { 3365 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3366 "intr pipe state=%d, rval=%d", pipe_state, rval); 3367 } 3368 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3369 "start polling request 0x%p", (void *)reqp); 3370 3371 mutex_enter(HUBD_MUTEX(hubd)); 3372 } 3373 } 3374 3375 3376 /* 3377 * hubd_stop_polling 3378 * stop polling but do not close the pipe 3379 */ 3380 static void 3381 hubd_stop_polling(hubd_t *hubd) 3382 { 3383 int rval; 3384 usb_pipe_state_t pipe_state; 3385 3386 if (hubd->h_ep1_ph) { 3387 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3388 "hubd_stop_polling:"); 3389 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED; 3390 mutex_exit(HUBD_MUTEX(hubd)); 3391 3392 usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP); 3393 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3394 USB_FLAGS_SLEEP); 3395 3396 if (pipe_state != USB_PIPE_STATE_IDLE) { 3397 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3398 "intr pipe state=%d, rval=%d", pipe_state, rval); 3399 } 3400 mutex_enter(HUBD_MUTEX(hubd)); 3401 if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) { 3402 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3403 } 3404 } 3405 } 3406 3407 3408 /* 3409 * hubd_close_intr_pipe: 3410 * close the pipe (which also stops the polling 3411 * and wait for the hotplug thread to exit 3412 */ 3413 static void 3414 hubd_close_intr_pipe(hubd_t *hubd) 3415 { 3416 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3417 "hubd_close_intr_pipe:"); 3418 3419 /* 3420 * Now that no async operation is outstanding on pipe, 3421 * we can change the state to HUBD_INTR_PIPE_CLOSING 3422 */ 3423 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING; 3424 3425 ASSERT(hubd->h_hotplug_thread == 0); 3426 3427 if (hubd->h_ep1_ph) { 3428 mutex_exit(HUBD_MUTEX(hubd)); 3429 usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP, 3430 NULL, NULL); 3431 mutex_enter(HUBD_MUTEX(hubd)); 3432 hubd->h_ep1_ph = NULL; 3433 } 3434 3435 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3436 } 3437 3438 3439 /* 3440 * hubd_exception_cb 3441 * interrupt ep1 exception callback function. 3442 * this callback executes in taskq thread context and assumes 3443 * autoclearing 3444 */ 3445 /*ARGSUSED*/ 3446 static void 3447 hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3448 { 3449 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3450 3451 USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3452 "hubd_exception_cb: " 3453 "req=0x%p cr=%d data=0x%p cb_flags=0x%x", (void *)reqp, 3454 reqp->intr_completion_reason, (void *)reqp->intr_data, 3455 reqp->intr_cb_flags); 3456 3457 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3458 3459 mutex_enter(HUBD_MUTEX(hubd)); 3460 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3461 3462 switch (reqp->intr_completion_reason) { 3463 case USB_CR_PIPE_RESET: 3464 /* only restart polling after autoclearing */ 3465 if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3466 (hubd->h_port_reset_wait == 0)) { 3467 hubd_start_polling(hubd, 0); 3468 } 3469 3470 break; 3471 case USB_CR_DEV_NOT_RESP: 3472 case USB_CR_STOPPED_POLLING: 3473 case USB_CR_PIPE_CLOSING: 3474 case USB_CR_UNSPECIFIED_ERR: 3475 /* never restart polling on these conditions */ 3476 default: 3477 /* for all others, wait for the autoclearing PIPE_RESET cb */ 3478 3479 break; 3480 } 3481 3482 usb_free_intr_req(reqp); 3483 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3484 mutex_exit(HUBD_MUTEX(hubd)); 3485 } 3486 3487 3488 /* 3489 * helper function to convert LE bytes to a portmask 3490 */ 3491 static usb_port_mask_t 3492 hubd_mblk2portmask(mblk_t *data) 3493 { 3494 int len = min(MBLKL(data), sizeof (usb_port_mask_t)); 3495 usb_port_mask_t rval = 0; 3496 int i; 3497 3498 for (i = 0; i < len; i++) { 3499 rval |= data->b_rptr[i] << (i * 8); 3500 } 3501 3502 return (rval); 3503 } 3504 3505 3506 /* 3507 * hubd_read_cb: 3508 * interrupt ep1 callback function 3509 * 3510 * the status indicates just a change on the pipe with no indication 3511 * of what the change was 3512 * 3513 * known conditions: 3514 * - reset port completion 3515 * - connect 3516 * - disconnect 3517 * 3518 * for handling the hotplugging, create a new thread that can do 3519 * synchronous usba calls 3520 */ 3521 static void 3522 hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3523 { 3524 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3525 size_t length; 3526 mblk_t *data = reqp->intr_data; 3527 int mem_flag = 0; 3528 hubd_hotplug_arg_t *arg; 3529 3530 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3531 "hubd_read_cb: ph=0x%p req=0x%p", (void *)pipe, (void *)reqp); 3532 3533 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3534 3535 /* 3536 * At present, we are not handling notification for completion of 3537 * asynchronous pipe reset, for which this data ptr could be NULL 3538 */ 3539 3540 if (data == NULL) { 3541 usb_free_intr_req(reqp); 3542 3543 return; 3544 } 3545 3546 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3547 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3548 mem_flag = 1; 3549 3550 mutex_enter(HUBD_MUTEX(hubd)); 3551 3552 if ((hubd->h_dev_state == USB_DEV_SUSPENDED) || 3553 (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) { 3554 mutex_exit(HUBD_MUTEX(hubd)); 3555 usb_free_intr_req(reqp); 3556 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3557 3558 return; 3559 } 3560 3561 ASSERT(hubd->h_ep1_ph == pipe); 3562 3563 length = MBLKL(data); 3564 3565 /* 3566 * Only look at the data and startup the hotplug thread if 3567 * there actually is data. 3568 */ 3569 if (length != 0) { 3570 usb_port_mask_t port_change = hubd_mblk2portmask(data); 3571 3572 /* 3573 * if a port change was already reported and we are waiting for 3574 * reset port completion then wake up the hotplug thread which 3575 * should be waiting on reset port completion 3576 * 3577 * if there is disconnect event instead of reset completion, let 3578 * the hotplug thread figure this out 3579 */ 3580 3581 /* remove the reset wait bits from the status */ 3582 hubd->h_port_change |= port_change & 3583 ~hubd->h_port_reset_wait; 3584 3585 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3586 "port change=0x%x port_reset_wait=0x%x", 3587 hubd->h_port_change, hubd->h_port_reset_wait); 3588 3589 /* there should be only one reset bit active at the time */ 3590 if (hubd->h_port_reset_wait & port_change) { 3591 hubd->h_port_reset_wait = 0; 3592 cv_signal(&hubd->h_cv_reset_port); 3593 } 3594 3595 /* 3596 * kick off the thread only if device is ONLINE and it is not 3597 * during attaching or detaching 3598 */ 3599 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 3600 (!DEVI_IS_ATTACHING(hubd->h_dip)) && 3601 (!DEVI_IS_DETACHING(hubd->h_dip)) && 3602 (hubd->h_port_change) && 3603 (hubd->h_hotplug_thread == 0)) { 3604 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3605 "creating hotplug thread: " 3606 "dev_state=%d", hubd->h_dev_state); 3607 3608 /* 3609 * Mark this device as busy. The will be marked idle 3610 * if the async req fails or at the exit of hotplug 3611 * thread 3612 */ 3613 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3614 3615 arg->hubd = hubd; 3616 arg->hotplug_during_attach = B_FALSE; 3617 3618 if (usb_async_req(hubd->h_dip, 3619 hubd_hotplug_thread, 3620 (void *)arg, 0) == USB_SUCCESS) { 3621 hubd->h_hotplug_thread++; 3622 mem_flag = 0; 3623 } else { 3624 /* mark this device as idle */ 3625 (void) hubd_pm_idle_component(hubd, 3626 hubd->h_dip, 0); 3627 } 3628 } 3629 } 3630 mutex_exit(HUBD_MUTEX(hubd)); 3631 3632 if (mem_flag == 1) { 3633 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3634 } 3635 3636 usb_free_intr_req(reqp); 3637 } 3638 3639 3640 /* 3641 * hubd_hotplug_thread: 3642 * handles resetting of port, and creating children 3643 * 3644 * the ports to check are indicated in h_port_change bit mask 3645 * XXX note that one time poll doesn't work on the root hub 3646 */ 3647 static void 3648 hubd_hotplug_thread(void *arg) 3649 { 3650 hubd_hotplug_arg_t *hd_arg = (hubd_hotplug_arg_t *)arg; 3651 hubd_t *hubd = hd_arg->hubd; 3652 boolean_t attach_flg = hd_arg->hotplug_during_attach; 3653 usb_port_t port; 3654 uint16_t nports; 3655 uint16_t status, change; 3656 hub_power_t *hubpm; 3657 dev_info_t *hdip = hubd->h_dip; 3658 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 3659 dev_info_t *child_dip; 3660 boolean_t online_child = B_FALSE; 3661 boolean_t offline_child = B_FALSE; 3662 boolean_t pwrup_child = B_FALSE; 3663 int prh_circ, rh_circ, chld_circ, circ, old_state; 3664 3665 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3666 "hubd_hotplug_thread: started"); 3667 3668 /* 3669 * Before console is init'd, we temporarily block the hotplug 3670 * threads so that BUS_CONFIG_ONE through hubd_bus_config() can be 3671 * processed quickly. This reduces the time needed for vfs_mountroot() 3672 * to mount the root FS from a USB disk. And on SPARC platform, 3673 * in order to load 'consconfig' successfully after OBP is gone, 3674 * we need to check 'modrootloaded' to make sure root filesystem is 3675 * available. 3676 */ 3677 while (!modrootloaded || !consconfig_console_is_ready()) { 3678 delay(drv_usectohz(10000)); 3679 } 3680 3681 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3682 3683 /* 3684 * if our bus power entry point is active, process the change 3685 * on the next notification of interrupt pipe 3686 */ 3687 mutex_enter(HUBD_MUTEX(hubd)); 3688 if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) { 3689 hubd->h_hotplug_thread--; 3690 3691 /* mark this device as idle */ 3692 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3693 mutex_exit(HUBD_MUTEX(hubd)); 3694 3695 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3696 "hubd_hotplug_thread: " 3697 "bus_power in progress/hotplugging undesirable - quit"); 3698 3699 return; 3700 } 3701 mutex_exit(HUBD_MUTEX(hubd)); 3702 3703 ndi_hold_devi(hdip); /* so we don't race with detach */ 3704 3705 mutex_enter(HUBD_MUTEX(hubd)); 3706 3707 /* is this the root hub? */ 3708 if (hdip == rh_dip) { 3709 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) { 3710 hubpm = hubd->h_hubpm; 3711 3712 /* mark the root hub as full power */ 3713 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 3714 hubpm->hubp_time_at_full_power = ddi_get_time(); 3715 mutex_exit(HUBD_MUTEX(hubd)); 3716 3717 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3718 "hubd_hotplug_thread: call pm_power_has_changed"); 3719 3720 (void) pm_power_has_changed(hdip, 0, 3721 USB_DEV_OS_FULL_PWR); 3722 3723 mutex_enter(HUBD_MUTEX(hubd)); 3724 hubd->h_dev_state = USB_DEV_ONLINE; 3725 } 3726 3727 } else { 3728 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3729 "hubd_hotplug_thread: not root hub"); 3730 } 3731 3732 mutex_exit(HUBD_MUTEX(hubd)); 3733 3734 /* 3735 * this ensures one hotplug activity per system at a time. 3736 * we enter the parent PCI node to have this serialization. 3737 * this also excludes ioctls and deathrow thread 3738 * (a bit crude but easier to debug) 3739 */ 3740 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 3741 ndi_devi_enter(rh_dip, &rh_circ); 3742 3743 /* exclude other threads */ 3744 ndi_devi_enter(hdip, &circ); 3745 mutex_enter(HUBD_MUTEX(hubd)); 3746 3747 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE); 3748 3749 nports = hubd->h_hub_descr.bNbrPorts; 3750 3751 hubd_stop_polling(hubd); 3752 3753 while ((hubd->h_dev_state == USB_DEV_ONLINE) && 3754 (hubd->h_port_change)) { 3755 /* 3756 * The 0th bit is the hub status change bit. 3757 * handle loss of local power here 3758 */ 3759 if (hubd->h_port_change & HUB_CHANGE_STATUS) { 3760 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3761 "hubd_hotplug_thread: hub status change!"); 3762 3763 /* 3764 * This should be handled properly. For now, 3765 * mask off the bit. 3766 */ 3767 hubd->h_port_change &= ~HUB_CHANGE_STATUS; 3768 3769 /* 3770 * check and ack hub status 3771 * this causes stall conditions 3772 * when local power is removed 3773 */ 3774 (void) hubd_get_hub_status(hubd); 3775 } 3776 3777 for (port = 1; port <= nports; port++) { 3778 usb_port_mask_t port_mask; 3779 boolean_t was_connected; 3780 3781 port_mask = 1 << port; 3782 was_connected = 3783 (hubd->h_port_state[port] & PORT_STATUS_CCS) && 3784 (hubd->h_children_dips[port]); 3785 3786 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3787 "hubd_hotplug_thread: " 3788 "port %d mask=0x%x change=0x%x connected=0x%x", 3789 port, port_mask, hubd->h_port_change, 3790 was_connected); 3791 3792 /* 3793 * is this a port connection that changed? 3794 */ 3795 if ((hubd->h_port_change & port_mask) == 0) { 3796 3797 continue; 3798 } 3799 hubd->h_port_change &= ~port_mask; 3800 3801 /* ack all changes */ 3802 (void) hubd_determine_port_status(hubd, port, 3803 &status, &change, HUBD_ACK_ALL_CHANGES); 3804 3805 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3806 "handle port %d:\n\t" 3807 "new status=0x%x change=0x%x was_conn=0x%x ", 3808 port, status, change, was_connected); 3809 3810 /* Recover a disabled port */ 3811 if (change & PORT_CHANGE_PESC) { 3812 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 3813 hubd->h_log_handle, 3814 "port%d Disabled - " 3815 "status=0x%x, change=0x%x", 3816 port, status, change); 3817 3818 /* 3819 * if the port was connected and is still 3820 * connected, recover the port 3821 */ 3822 if (was_connected && (status & 3823 PORT_STATUS_CCS)) { 3824 online_child |= 3825 (hubd_recover_disabled_port(hubd, 3826 port) == USB_SUCCESS); 3827 } 3828 } 3829 3830 /* 3831 * Now check what changed on the port 3832 */ 3833 if ((change & PORT_CHANGE_CSC) || attach_flg) { 3834 if ((status & PORT_STATUS_CCS) && 3835 (!was_connected)) { 3836 /* new device plugged in */ 3837 online_child |= 3838 (hubd_handle_port_connect(hubd, 3839 port) == USB_SUCCESS); 3840 3841 } else if ((status & PORT_STATUS_CCS) && 3842 was_connected) { 3843 /* 3844 * In this case we can never be sure 3845 * if the device indeed got hotplugged 3846 * or the hub is falsely reporting the 3847 * change. 3848 */ 3849 child_dip = hubd->h_children_dips[port]; 3850 3851 mutex_exit(HUBD_MUTEX(hubd)); 3852 /* 3853 * this ensures we do not race with 3854 * other threads which are detaching 3855 * the child driver at the same time. 3856 */ 3857 ndi_devi_enter(child_dip, &chld_circ); 3858 /* 3859 * Now check if the driver remains 3860 * attached. 3861 */ 3862 if (i_ddi_devi_attached(child_dip)) { 3863 /* 3864 * first post a disconnect event 3865 * to the child. 3866 */ 3867 hubd_post_event(hubd, port, 3868 USBA_EVENT_TAG_HOT_REMOVAL); 3869 mutex_enter(HUBD_MUTEX(hubd)); 3870 3871 /* 3872 * then reset the port and 3873 * recover the device 3874 */ 3875 online_child |= 3876 (hubd_handle_port_connect( 3877 hubd, port) == USB_SUCCESS); 3878 3879 mutex_exit(HUBD_MUTEX(hubd)); 3880 } 3881 3882 ndi_devi_exit(child_dip, chld_circ); 3883 mutex_enter(HUBD_MUTEX(hubd)); 3884 } else if (was_connected) { 3885 /* this is a disconnect */ 3886 mutex_exit(HUBD_MUTEX(hubd)); 3887 hubd_post_event(hubd, port, 3888 USBA_EVENT_TAG_HOT_REMOVAL); 3889 mutex_enter(HUBD_MUTEX(hubd)); 3890 3891 offline_child = B_TRUE; 3892 } 3893 } 3894 3895 /* 3896 * Check if any port is coming out of suspend 3897 */ 3898 if (change & PORT_CHANGE_PSSC) { 3899 /* a resuming device could have disconnected */ 3900 if (was_connected && 3901 hubd->h_children_dips[port]) { 3902 3903 /* device on this port resuming */ 3904 dev_info_t *dip; 3905 3906 dip = hubd->h_children_dips[port]; 3907 3908 /* 3909 * Don't raise power on detaching child 3910 */ 3911 if (!DEVI_IS_DETACHING(dip)) { 3912 /* 3913 * As this child is not 3914 * detaching, we set this 3915 * flag, causing bus_ctls 3916 * to stall detach till 3917 * pm_raise_power returns 3918 * and flag it for a deferred 3919 * raise_power. 3920 * 3921 * pm_raise_power is deferred 3922 * because we need to release 3923 * the locks first. 3924 */ 3925 hubd->h_port_state[port] |= 3926 HUBD_CHILD_RAISE_POWER; 3927 pwrup_child = B_TRUE; 3928 mutex_exit(HUBD_MUTEX(hubd)); 3929 3930 /* 3931 * make sure that child 3932 * doesn't disappear 3933 */ 3934 ndi_hold_devi(dip); 3935 3936 mutex_enter(HUBD_MUTEX(hubd)); 3937 } 3938 } 3939 } 3940 3941 /* 3942 * Check if the port is over-current 3943 */ 3944 if (change & PORT_CHANGE_OCIC) { 3945 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 3946 hubd->h_log_handle, 3947 "Port%d in over current condition, " 3948 "please check the attached device to " 3949 "clear the condition. The system will " 3950 "try to recover the port, but if not " 3951 "successful, you need to re-connect " 3952 "the hub or reboot the system to bring " 3953 "the port back to work", port); 3954 3955 if (!(status & PORT_STATUS_PPS)) { 3956 /* 3957 * Try to enable port power, but 3958 * possibly fail. Ignore failure 3959 */ 3960 (void) hubd_enable_port_power(hubd, 3961 port); 3962 3963 /* 3964 * Delay some time to avoid 3965 * over-current event to happen 3966 * too frequently in some cases 3967 */ 3968 mutex_exit(HUBD_MUTEX(hubd)); 3969 delay(drv_usectohz(500000)); 3970 mutex_enter(HUBD_MUTEX(hubd)); 3971 } 3972 } 3973 } 3974 } 3975 3976 /* release locks so we can do a devfs_clean */ 3977 mutex_exit(HUBD_MUTEX(hubd)); 3978 3979 /* delete cached dv_node's but drop locks first */ 3980 ndi_devi_exit(hdip, circ); 3981 ndi_devi_exit(rh_dip, rh_circ); 3982 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 3983 3984 (void) devfs_clean(rh_dip, NULL, 0); 3985 3986 /* now check if any children need onlining */ 3987 if (online_child) { 3988 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3989 "hubd_hotplug_thread: onlining children"); 3990 3991 (void) ndi_devi_online(hubd->h_dip, 0); 3992 } 3993 3994 /* now check if any disconnected devices need to be cleaned up */ 3995 if (offline_child) { 3996 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3997 "hubd_hotplug_thread: scheduling cleanup"); 3998 3999 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 4000 } 4001 4002 mutex_enter(HUBD_MUTEX(hubd)); 4003 4004 /* now raise power on the children that have woken up */ 4005 if (pwrup_child) { 4006 old_state = hubd->h_dev_state; 4007 hubd->h_dev_state = USB_DEV_HUB_CHILD_PWRLVL; 4008 for (port = 1; port <= nports; port++) { 4009 if (hubd->h_port_state[port] & HUBD_CHILD_RAISE_POWER) { 4010 dev_info_t *dip = hubd->h_children_dips[port]; 4011 4012 mutex_exit(HUBD_MUTEX(hubd)); 4013 4014 /* Get the device to full power */ 4015 (void) pm_busy_component(dip, 0); 4016 (void) pm_raise_power(dip, 0, 4017 USB_DEV_OS_FULL_PWR); 4018 (void) pm_idle_component(dip, 0); 4019 4020 /* release the hold on the child */ 4021 ndi_rele_devi(dip); 4022 mutex_enter(HUBD_MUTEX(hubd)); 4023 hubd->h_port_state[port] &= 4024 ~HUBD_CHILD_RAISE_POWER; 4025 } 4026 } 4027 /* 4028 * make sure that we don't accidentally 4029 * over write the disconnect state 4030 */ 4031 if (hubd->h_dev_state == USB_DEV_HUB_CHILD_PWRLVL) { 4032 hubd->h_dev_state = old_state; 4033 } 4034 } 4035 4036 /* 4037 * start polling can immediately kick off read callback 4038 * we need to set the h_hotplug_thread to 0 so that 4039 * the callback is not dropped 4040 * 4041 * if there is device during reset, still stop polling to avoid the 4042 * read callback interrupting the reset, the polling will be started 4043 * in hubd_reset_thread. 4044 */ 4045 for (port = 1; port <= MAX_PORTS; port++) { 4046 if (hubd->h_reset_port[port]) { 4047 4048 break; 4049 } 4050 } 4051 if (port > MAX_PORTS) { 4052 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 4053 } 4054 4055 /* 4056 * Earlier we would set the h_hotplug_thread = 0 before 4057 * polling was restarted so that 4058 * if there is any root hub status change interrupt, we can still kick 4059 * off the hotplug thread. This was valid when this interrupt was 4060 * delivered in hardware, and only ONE interrupt would be delivered. 4061 * Now that we poll on the root hub looking for status change in 4062 * software, this assignment is no longer required. 4063 */ 4064 hubd->h_hotplug_thread--; 4065 4066 /* mark this device as idle */ 4067 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 4068 4069 cv_broadcast(&hubd->h_cv_hotplug_dev); 4070 4071 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4072 "hubd_hotplug_thread: exit"); 4073 4074 mutex_exit(HUBD_MUTEX(hubd)); 4075 4076 ndi_rele_devi(hdip); 4077 } 4078 4079 4080 /* 4081 * hubd_handle_port_connect: 4082 * Transition a port from Disabled to Enabled. Ensure that the 4083 * port is in the correct state before attempting to 4084 * access the device. 4085 */ 4086 static int 4087 hubd_handle_port_connect(hubd_t *hubd, usb_port_t port) 4088 { 4089 int rval; 4090 int retry; 4091 long time_delay; 4092 long settling_time; 4093 uint16_t status; 4094 uint16_t change; 4095 usb_addr_t hubd_usb_addr; 4096 usba_device_t *usba_device; 4097 usb_port_status_t port_status = 0; 4098 usb_port_status_t hub_port_status = 0; 4099 4100 /* Get the hub address and port status */ 4101 usba_device = hubd->h_usba_device; 4102 mutex_enter(&usba_device->usb_mutex); 4103 hubd_usb_addr = usba_device->usb_addr; 4104 hub_port_status = usba_device->usb_port_status; 4105 mutex_exit(&usba_device->usb_mutex); 4106 4107 /* 4108 * If a device is connected, transition the 4109 * port from Disabled to the Enabled state. 4110 * The device will receive downstream packets 4111 * in the Enabled state. 4112 * 4113 * reset port and wait for the hub to report 4114 * completion 4115 */ 4116 change = status = 0; 4117 4118 /* 4119 * According to section 9.1.2 of USB 2.0 spec, the host should 4120 * wait for atleast 100ms to allow completion of an insertion 4121 * process and for power at the device to become stable. 4122 * We wait for 200 ms 4123 */ 4124 settling_time = drv_usectohz(hubd_device_delay / 5); 4125 mutex_exit(HUBD_MUTEX(hubd)); 4126 delay(settling_time); 4127 mutex_enter(HUBD_MUTEX(hubd)); 4128 4129 /* calculate 600 ms delay time */ 4130 time_delay = (6 * drv_usectohz(hubd_device_delay)) / 10; 4131 4132 for (retry = 0; (hubd->h_dev_state == USB_DEV_ONLINE) && 4133 (retry < hubd_retry_enumerate); retry++) { 4134 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4135 "resetting port%d, retry=%d", port, retry); 4136 4137 if ((rval = hubd_reset_port(hubd, port)) != USB_SUCCESS) { 4138 (void) hubd_determine_port_status(hubd, 4139 port, &status, &change, 0); 4140 4141 /* continue only if port is still connected */ 4142 if (status & PORT_STATUS_CCS) { 4143 continue; 4144 } 4145 4146 /* carry on regardless */ 4147 } 4148 4149 /* 4150 * according to USB 2.0 spec section 11.24.2.7.1.2 4151 * at the end of port reset, the hub enables the port. 4152 * But for some strange reasons, uhci port remains disabled. 4153 * And because the port remains disabled for the settling 4154 * time below, the device connected to the port gets wedged 4155 * - fails to enumerate (device not responding) 4156 * Hence, we enable it here immediately and later again after 4157 * the delay 4158 */ 4159 (void) hubd_enable_port(hubd, port); 4160 4161 /* we skip this delay in the first iteration */ 4162 if (retry) { 4163 /* 4164 * delay for device to signal disconnect/connect so 4165 * that hub properly recognizes the speed of the device 4166 */ 4167 mutex_exit(HUBD_MUTEX(hubd)); 4168 delay(settling_time); 4169 mutex_enter(HUBD_MUTEX(hubd)); 4170 4171 /* 4172 * When a low speed device is connected to any port of 4173 * PPX it has to be explicitly enabled 4174 * Also, if device intentionally signals 4175 * disconnect/connect, it will disable the port. 4176 * So enable it again. 4177 */ 4178 (void) hubd_enable_port(hubd, port); 4179 } 4180 4181 if ((rval = hubd_determine_port_status(hubd, port, &status, 4182 &change, 0)) != USB_SUCCESS) { 4183 4184 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4185 "getting status failed (%d)", rval); 4186 4187 (void) hubd_disable_port(hubd, port); 4188 4189 continue; 4190 } 4191 4192 if (status & PORT_STATUS_POCI) { 4193 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4194 "port %d overcurrent", port); 4195 4196 (void) hubd_disable_port(hubd, port); 4197 4198 /* ack changes */ 4199 (void) hubd_determine_port_status(hubd, 4200 port, &status, &change, PORT_CHANGE_OCIC); 4201 4202 continue; 4203 } 4204 4205 /* is status really OK? */ 4206 if ((status & PORT_STATUS_OK) != PORT_STATUS_OK) { 4207 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4208 "port %d status (0x%x) not OK on retry %d", 4209 port, status, retry); 4210 4211 /* check if we still have the connection */ 4212 if (!(status & PORT_STATUS_CCS)) { 4213 /* lost connection, set exit condition */ 4214 retry = hubd_retry_enumerate; 4215 4216 break; 4217 } 4218 } else { 4219 /* 4220 * Determine if the device is high or full 4221 * or low speed. 4222 */ 4223 if (status & PORT_STATUS_LSDA) { 4224 port_status = USBA_LOW_SPEED_DEV; 4225 } else if (status & PORT_STATUS_HSDA) { 4226 port_status = USBA_HIGH_SPEED_DEV; 4227 } else { 4228 port_status = USBA_FULL_SPEED_DEV; 4229 } 4230 4231 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4232 "creating child port%d, status=0x%x " 4233 "port status=0x%x", 4234 port, status, port_status); 4235 4236 /* 4237 * if the child already exists, set addrs and config 4238 * to the device post connect event to the child 4239 */ 4240 if (hubd->h_children_dips[port]) { 4241 /* set addrs to this device */ 4242 rval = hubd_setdevaddr(hubd, port); 4243 4244 /* 4245 * This delay is important for the CATC hub 4246 * to enumerate. But, avoid delay in the first 4247 * iteration 4248 */ 4249 if (retry) { 4250 mutex_exit(HUBD_MUTEX(hubd)); 4251 delay(drv_usectohz( 4252 hubd_device_delay/100)); 4253 mutex_enter(HUBD_MUTEX(hubd)); 4254 } 4255 4256 if (rval == USB_SUCCESS) { 4257 /* 4258 * if the port is resetting, check if 4259 * device's descriptors have changed. 4260 */ 4261 if ((hubd->h_reset_port[port]) && 4262 (hubd_check_same_device(hubd, 4263 port) != USB_SUCCESS)) { 4264 retry = hubd_retry_enumerate; 4265 4266 break; 4267 } 4268 4269 /* 4270 * set the default config for 4271 * this device 4272 */ 4273 hubd_setdevconfig(hubd, port); 4274 4275 /* 4276 * if we are doing Default reset, do 4277 * not post reconnect event since we 4278 * don't know where reset function is 4279 * called. 4280 */ 4281 if (hubd->h_reset_port[port]) { 4282 4283 return (USB_SUCCESS); 4284 } 4285 4286 /* 4287 * indicate to the child that 4288 * it is online again 4289 */ 4290 mutex_exit(HUBD_MUTEX(hubd)); 4291 hubd_post_event(hubd, port, 4292 USBA_EVENT_TAG_HOT_INSERTION); 4293 mutex_enter(HUBD_MUTEX(hubd)); 4294 4295 return (USB_SUCCESS); 4296 } 4297 } else { 4298 /* 4299 * We need to release access here 4300 * so that busctls on other ports can 4301 * continue and don't cause a deadlock 4302 * when busctl and removal of prom node 4303 * takes concurrently. This also ensures 4304 * busctls for attach of successfully 4305 * enumerated devices on other ports can 4306 * continue concurrently with the process 4307 * of enumerating the new devices. This 4308 * reduces the overall boot time of the system. 4309 */ 4310 rval = hubd_create_child(hubd->h_dip, 4311 hubd, 4312 hubd->h_usba_device, 4313 port_status, port, 4314 retry); 4315 if (rval == USB_SUCCESS) { 4316 usba_update_hotplug_stats(hubd->h_dip, 4317 USBA_TOTAL_HOTPLUG_SUCCESS| 4318 USBA_HOTPLUG_SUCCESS); 4319 hubd->h_total_hotplug_success++; 4320 4321 if (retry > 0) { 4322 USB_DPRINTF_L2( 4323 DPRINT_MASK_HOTPLUG, 4324 hubd->h_log_handle, 4325 "device on port %d " 4326 "enumerated after %d %s", 4327 port, retry, 4328 (retry > 1) ? "retries" : 4329 "retry"); 4330 4331 } 4332 4333 return (USB_SUCCESS); 4334 } 4335 } 4336 } 4337 4338 /* wait a while until it settles? */ 4339 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4340 "disabling port %d again", port); 4341 4342 (void) hubd_disable_port(hubd, port); 4343 if (retry) { 4344 mutex_exit(HUBD_MUTEX(hubd)); 4345 delay(time_delay); 4346 mutex_enter(HUBD_MUTEX(hubd)); 4347 } 4348 4349 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4350 "retrying on port %d", port); 4351 } 4352 4353 if (retry >= hubd_retry_enumerate) { 4354 /* 4355 * If it is a High Speed Root Hub and connected device 4356 * Is a Low/Full Speed, it will be handled by USB 1.1 4357 * Host Controller. In this case, USB 2.0 Host Controller 4358 * will transfer the ownership of this port to USB 1.1 4359 * Host Controller. So don't display any error message on 4360 * the console. 4361 */ 4362 if ((hubd_usb_addr == ROOT_HUB_ADDR) && 4363 (hub_port_status == USBA_HIGH_SPEED_DEV) && 4364 (port_status != USBA_HIGH_SPEED_DEV)) { 4365 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4366 hubd->h_log_handle, 4367 "hubd_handle_port_connect: Low/Full speed " 4368 "device is connected to High Speed root hub"); 4369 } else { 4370 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4371 hubd->h_log_handle, 4372 "Connecting device on port %d failed", port); 4373 } 4374 4375 (void) hubd_disable_port(hubd, port); 4376 usba_update_hotplug_stats(hubd->h_dip, 4377 USBA_TOTAL_HOTPLUG_FAILURE|USBA_HOTPLUG_FAILURE); 4378 hubd->h_total_hotplug_failure++; 4379 4380 /* 4381 * the port should be automagically 4382 * disabled but just in case, we do 4383 * it here 4384 */ 4385 (void) hubd_disable_port(hubd, port); 4386 4387 /* ack all changes because we disabled this port */ 4388 (void) hubd_determine_port_status(hubd, 4389 port, &status, &change, HUBD_ACK_ALL_CHANGES); 4390 4391 } 4392 4393 return (USB_FAILURE); 4394 } 4395 4396 4397 /* 4398 * hubd_get_hub_status: 4399 */ 4400 static int 4401 hubd_get_hub_status(hubd_t *hubd) 4402 { 4403 int rval; 4404 usb_cr_t completion_reason; 4405 usb_cb_flags_t cb_flags; 4406 uint16_t stword[2]; 4407 uint16_t status; 4408 uint16_t change; 4409 usb_cfg_descr_t cfg_descr; 4410 size_t cfg_length; 4411 uchar_t *usb_cfg; 4412 uint8_t MaxPower; 4413 usb_hub_descr_t *hub_descr; 4414 usb_port_t port; 4415 4416 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4417 "hubd_get_hub_status:"); 4418 4419 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4420 4421 if ((hubd_get_hub_status_words(hubd, stword)) != USB_SUCCESS) { 4422 4423 return (USB_FAILURE); 4424 } 4425 status = stword[0]; 4426 change = stword[1]; 4427 4428 mutex_exit(HUBD_MUTEX(hubd)); 4429 4430 /* Obtain the raw configuration descriptor */ 4431 usb_cfg = usb_get_raw_cfg_data(hubd->h_dip, &cfg_length); 4432 4433 /* get configuration descriptor */ 4434 rval = usb_parse_cfg_descr(usb_cfg, cfg_length, 4435 &cfg_descr, USB_CFG_DESCR_SIZE); 4436 4437 if (rval != USB_CFG_DESCR_SIZE) { 4438 4439 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4440 "get hub configuration descriptor failed."); 4441 4442 mutex_enter(HUBD_MUTEX(hubd)); 4443 4444 return (USB_FAILURE); 4445 } else { 4446 MaxPower = cfg_descr.bMaxPower; 4447 } 4448 4449 /* check if local power status changed. */ 4450 if (change & C_HUB_LOCAL_POWER_STATUS) { 4451 4452 /* 4453 * local power has been lost, check the maximum 4454 * power consumption of current configuration. 4455 * see USB2.0 spec Table 11-12. 4456 */ 4457 if (status & HUB_LOCAL_POWER_STATUS) { 4458 4459 if (MaxPower == 0) { 4460 4461 /* 4462 * Self-powered only hub. Because it could 4463 * not draw any power from USB bus. 4464 * It can't work well on this condition. 4465 */ 4466 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 4467 hubd->h_log_handle, 4468 "local power has been lost, " 4469 "please disconnect hub"); 4470 } else { 4471 4472 /* 4473 * Bus-powered only or self/bus-powered hub. 4474 */ 4475 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 4476 hubd->h_log_handle, 4477 "local power has been lost," 4478 "the hub could draw %d" 4479 " mA power from the USB bus.", 4480 2*MaxPower); 4481 } 4482 4483 } 4484 4485 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4486 "clearing feature C_HUB_LOCAL_POWER "); 4487 4488 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4489 hubd->h_default_pipe, 4490 HUB_HANDLE_HUB_FEATURE_TYPE, 4491 USB_REQ_CLEAR_FEATURE, 4492 CFS_C_HUB_LOCAL_POWER, 4493 0, 4494 0, 4495 NULL, 0, 4496 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4497 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4498 hubd->h_log_handle, 4499 "clear feature C_HUB_LOCAL_POWER " 4500 "failed (%d 0x%x %d)", 4501 rval, completion_reason, cb_flags); 4502 } 4503 4504 } 4505 4506 if (change & C_HUB_OVER_CURRENT) { 4507 4508 if (status & HUB_OVER_CURRENT) { 4509 4510 if (usba_is_root_hub(hubd->h_dip)) { 4511 /* 4512 * The root hub should be automatically 4513 * recovered when over-current condition is 4514 * cleared. But there might be exception and 4515 * need user interaction to recover. 4516 */ 4517 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4518 hubd->h_log_handle, 4519 "Root hub over current condition, " 4520 "please check your system to clear the " 4521 "condition as soon as possible. And you " 4522 "may need to reboot the system to bring " 4523 "the root hub back to work if it cannot " 4524 "recover automatically"); 4525 } else { 4526 /* 4527 * The driver would try to recover port power 4528 * on over current condition. When the recovery 4529 * fails, the user may still need to offline 4530 * this hub in order to recover. 4531 * The port power is automatically disabled, 4532 * so we won't see disconnects. 4533 */ 4534 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4535 hubd->h_log_handle, 4536 "Hub global over current condition, " 4537 "please disconnect the devices connected " 4538 "to the hub to clear the condition. And " 4539 "you may need to re-connect the hub if " 4540 "the ports do not work"); 4541 } 4542 } 4543 4544 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4545 "clearing feature C_HUB_OVER_CURRENT"); 4546 4547 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4548 hubd->h_default_pipe, 4549 HUB_HANDLE_HUB_FEATURE_TYPE, 4550 USB_REQ_CLEAR_FEATURE, 4551 CFS_C_HUB_OVER_CURRENT, 4552 0, 4553 0, 4554 NULL, 0, 4555 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4556 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4557 hubd->h_log_handle, 4558 "clear feature C_HUB_OVER_CURRENT " 4559 "failed (%d 0x%x %d)", 4560 rval, completion_reason, cb_flags); 4561 } 4562 4563 /* 4564 * Try to recover all port power if they are turned off. 4565 * Don't do this for root hub, but rely on the root hub 4566 * to recover itself. 4567 */ 4568 if (!usba_is_root_hub(hubd->h_dip)) { 4569 4570 mutex_enter(HUBD_MUTEX(hubd)); 4571 4572 /* 4573 * Only check the power status of the 1st port 4574 * since all port power status should be the same. 4575 */ 4576 (void) hubd_determine_port_status(hubd, 1, &status, 4577 &change, 0); 4578 4579 if (status & PORT_STATUS_PPS) { 4580 4581 return (USB_SUCCESS); 4582 } 4583 4584 hub_descr = &hubd->h_hub_descr; 4585 4586 for (port = 1; port <= hub_descr->bNbrPorts; 4587 port++) { 4588 4589 (void) hubd_enable_port_power(hubd, port); 4590 } 4591 4592 mutex_exit(HUBD_MUTEX(hubd)); 4593 4594 /* 4595 * Delay some time to avoid over-current event 4596 * to happen too frequently in some cases 4597 */ 4598 delay(drv_usectohz(500000)); 4599 } 4600 } 4601 4602 mutex_enter(HUBD_MUTEX(hubd)); 4603 4604 return (USB_SUCCESS); 4605 } 4606 4607 4608 /* 4609 * hubd_reset_port: 4610 */ 4611 static int 4612 hubd_reset_port(hubd_t *hubd, usb_port_t port) 4613 { 4614 int rval; 4615 usb_cr_t completion_reason; 4616 usb_cb_flags_t cb_flags; 4617 usb_port_mask_t port_mask = 1 << port; 4618 mblk_t *data; 4619 uint16_t status; 4620 uint16_t change; 4621 int i; 4622 clock_t delta; 4623 4624 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4625 "hubd_reset_port: port=%d", port); 4626 4627 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4628 4629 hubd->h_port_reset_wait |= port_mask; 4630 4631 mutex_exit(HUBD_MUTEX(hubd)); 4632 4633 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4634 hubd->h_default_pipe, 4635 HUB_HANDLE_PORT_FEATURE_TYPE, 4636 USB_REQ_SET_FEATURE, 4637 CFS_PORT_RESET, 4638 port, 4639 0, 4640 NULL, 0, 4641 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4642 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4643 "reset port%d failed (%d 0x%x %d)", 4644 port, completion_reason, cb_flags, rval); 4645 4646 mutex_enter(HUBD_MUTEX(hubd)); 4647 4648 return (USB_FAILURE); 4649 } 4650 4651 mutex_enter(HUBD_MUTEX(hubd)); 4652 4653 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4654 "waiting on cv for reset completion"); 4655 4656 /* 4657 * wait for port status change event 4658 */ 4659 delta = drv_usectohz(hubd_device_delay / 10); 4660 for (i = 0; i < hubd_retry_enumerate; i++) { 4661 /* 4662 * start polling ep1 for receiving notification on 4663 * reset completion 4664 */ 4665 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 4666 4667 /* 4668 * sleep a max of 100ms for reset completion 4669 * notification to be received 4670 */ 4671 if (hubd->h_port_reset_wait & port_mask) { 4672 rval = cv_reltimedwait(&hubd->h_cv_reset_port, 4673 &hubd->h_mutex, delta, TR_CLOCK_TICK); 4674 if ((rval <= 0) && 4675 (hubd->h_port_reset_wait & port_mask)) { 4676 /* we got woken up because of a timeout */ 4677 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4678 hubd->h_log_handle, 4679 "timeout: reset port=%d failed", port); 4680 4681 hubd->h_port_reset_wait &= ~port_mask; 4682 4683 hubd_stop_polling(hubd); 4684 4685 return (USB_FAILURE); 4686 } 4687 } 4688 4689 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4690 "reset completion received"); 4691 4692 hubd_stop_polling(hubd); 4693 4694 data = NULL; 4695 4696 /* check status to determine whether reset completed */ 4697 mutex_exit(HUBD_MUTEX(hubd)); 4698 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4699 hubd->h_default_pipe, 4700 HUB_GET_PORT_STATUS_TYPE, 4701 USB_REQ_GET_STATUS, 4702 0, 4703 port, 4704 GET_STATUS_LENGTH, 4705 &data, 0, 4706 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4707 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4708 hubd->h_log_handle, 4709 "get status port%d failed (%d 0x%x %d)", 4710 port, completion_reason, cb_flags, rval); 4711 4712 if (data) { 4713 freemsg(data); 4714 data = NULL; 4715 } 4716 mutex_enter(HUBD_MUTEX(hubd)); 4717 4718 continue; 4719 } 4720 4721 status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4722 change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4723 4724 freemsg(data); 4725 4726 /* continue only if port is still connected */ 4727 if (!(status & PORT_STATUS_CCS)) { 4728 4729 /* lost connection, set exit condition */ 4730 i = hubd_retry_enumerate; 4731 4732 mutex_enter(HUBD_MUTEX(hubd)); 4733 4734 break; 4735 } 4736 4737 if (status & PORT_STATUS_PRS) { 4738 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4739 "port%d reset active", port); 4740 mutex_enter(HUBD_MUTEX(hubd)); 4741 4742 continue; 4743 } else { 4744 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4745 "port%d reset inactive", port); 4746 } 4747 4748 if (change & PORT_CHANGE_PRSC) { 4749 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4750 "clearing feature CFS_C_PORT_RESET"); 4751 4752 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4753 hubd->h_default_pipe, 4754 HUB_HANDLE_PORT_FEATURE_TYPE, 4755 USB_REQ_CLEAR_FEATURE, 4756 CFS_C_PORT_RESET, 4757 port, 4758 0, 4759 NULL, 0, 4760 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 4761 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4762 hubd->h_log_handle, 4763 "clear feature CFS_C_PORT_RESET" 4764 " port%d failed (%d 0x%x %d)", 4765 port, completion_reason, cb_flags, rval); 4766 } 4767 } 4768 mutex_enter(HUBD_MUTEX(hubd)); 4769 4770 break; 4771 } 4772 4773 if (i >= hubd_retry_enumerate) { 4774 /* port reset has failed */ 4775 rval = USB_FAILURE; 4776 } 4777 4778 return (rval); 4779 } 4780 4781 4782 /* 4783 * hubd_enable_port: 4784 * this may fail if the hub as been disconnected 4785 */ 4786 static int 4787 hubd_enable_port(hubd_t *hubd, usb_port_t port) 4788 { 4789 int rval; 4790 usb_cr_t completion_reason; 4791 usb_cb_flags_t cb_flags; 4792 4793 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4794 "hubd_enable_port: port=%d", port); 4795 4796 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4797 4798 mutex_exit(HUBD_MUTEX(hubd)); 4799 4800 /* Do not issue a SetFeature(PORT_ENABLE) on external hubs */ 4801 if (!usba_is_root_hub(hubd->h_dip)) { 4802 mutex_enter(HUBD_MUTEX(hubd)); 4803 4804 return (USB_SUCCESS); 4805 } 4806 4807 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4808 hubd->h_default_pipe, 4809 HUB_HANDLE_PORT_FEATURE_TYPE, 4810 USB_REQ_SET_FEATURE, 4811 CFS_PORT_ENABLE, 4812 port, 4813 0, 4814 NULL, 0, 4815 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4816 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4817 "enable port%d failed (%d 0x%x %d)", 4818 port, completion_reason, cb_flags, rval); 4819 } 4820 4821 mutex_enter(HUBD_MUTEX(hubd)); 4822 4823 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4824 "enabling port done"); 4825 4826 return (rval); 4827 } 4828 4829 4830 /* 4831 * hubd_disable_port 4832 */ 4833 static int 4834 hubd_disable_port(hubd_t *hubd, usb_port_t port) 4835 { 4836 int rval; 4837 usb_cr_t completion_reason; 4838 usb_cb_flags_t cb_flags; 4839 4840 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4841 "hubd_disable_port: port=%d", port); 4842 4843 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4844 4845 mutex_exit(HUBD_MUTEX(hubd)); 4846 4847 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4848 hubd->h_default_pipe, 4849 HUB_HANDLE_PORT_FEATURE_TYPE, 4850 USB_REQ_CLEAR_FEATURE, 4851 CFS_PORT_ENABLE, 4852 port, 4853 0, 4854 NULL, 0, 4855 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4856 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4857 "disable port%d failed (%d 0x%x %d)", port, 4858 completion_reason, cb_flags, rval); 4859 mutex_enter(HUBD_MUTEX(hubd)); 4860 4861 return (USB_FAILURE); 4862 } 4863 4864 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4865 "clearing feature CFS_C_PORT_ENABLE"); 4866 4867 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4868 hubd->h_default_pipe, 4869 HUB_HANDLE_PORT_FEATURE_TYPE, 4870 USB_REQ_CLEAR_FEATURE, 4871 CFS_C_PORT_ENABLE, 4872 port, 4873 0, 4874 NULL, 0, 4875 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4876 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4877 hubd->h_log_handle, 4878 "clear feature CFS_C_PORT_ENABLE port%d failed " 4879 "(%d 0x%x %d)", 4880 port, completion_reason, cb_flags, rval); 4881 4882 mutex_enter(HUBD_MUTEX(hubd)); 4883 4884 return (USB_FAILURE); 4885 } 4886 4887 mutex_enter(HUBD_MUTEX(hubd)); 4888 4889 return (USB_SUCCESS); 4890 } 4891 4892 4893 /* 4894 * hubd_determine_port_status: 4895 */ 4896 static int 4897 hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 4898 uint16_t *status, uint16_t *change, uint_t ack_flag) 4899 { 4900 int rval; 4901 mblk_t *data = NULL; 4902 usb_cr_t completion_reason; 4903 usb_cb_flags_t cb_flags; 4904 4905 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4906 "hubd_determine_port_status: port=%d, state=0x%x ack=0x%x", port, 4907 hubd->h_port_state[port], ack_flag); 4908 4909 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4910 4911 mutex_exit(HUBD_MUTEX(hubd)); 4912 4913 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4914 hubd->h_default_pipe, 4915 HUB_GET_PORT_STATUS_TYPE, 4916 USB_REQ_GET_STATUS, 4917 0, 4918 port, 4919 GET_STATUS_LENGTH, 4920 &data, 0, 4921 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4922 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4923 "port=%d get status failed (%d 0x%x %d)", 4924 port, completion_reason, cb_flags, rval); 4925 4926 if (data) { 4927 freemsg(data); 4928 } 4929 4930 *status = *change = 0; 4931 mutex_enter(HUBD_MUTEX(hubd)); 4932 4933 return (rval); 4934 } 4935 4936 mutex_enter(HUBD_MUTEX(hubd)); 4937 if (MBLKL(data) != GET_STATUS_LENGTH) { 4938 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4939 "port %d: length incorrect %ld", 4940 port, MBLKL(data)); 4941 freemsg(data); 4942 *status = *change = 0; 4943 4944 return (rval); 4945 } 4946 4947 4948 *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4949 *change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4950 4951 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4952 "port%d status=0x%x, change=0x%x", port, *status, *change); 4953 4954 freemsg(data); 4955 4956 if (*status & PORT_STATUS_CCS) { 4957 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4958 "port%d connected", port); 4959 4960 hubd->h_port_state[port] |= (PORT_STATUS_CCS & ack_flag); 4961 } else { 4962 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4963 "port%d disconnected", port); 4964 4965 hubd->h_port_state[port] &= ~(PORT_STATUS_CCS & ack_flag); 4966 } 4967 4968 if (*status & PORT_STATUS_PES) { 4969 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4970 "port%d enabled", port); 4971 4972 hubd->h_port_state[port] |= (PORT_STATUS_PES & ack_flag); 4973 } else { 4974 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4975 "port%d disabled", port); 4976 4977 hubd->h_port_state[port] &= ~(PORT_STATUS_PES & ack_flag); 4978 } 4979 4980 if (*status & PORT_STATUS_PSS) { 4981 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4982 "port%d suspended", port); 4983 4984 hubd->h_port_state[port] |= (PORT_STATUS_PSS & ack_flag); 4985 } else { 4986 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4987 "port%d not suspended", port); 4988 4989 hubd->h_port_state[port] &= ~(PORT_STATUS_PSS & ack_flag); 4990 } 4991 4992 if (*change & PORT_CHANGE_PRSC) { 4993 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4994 "port%d reset completed", port); 4995 4996 hubd->h_port_state[port] |= (PORT_CHANGE_PRSC & ack_flag); 4997 } else { 4998 4999 hubd->h_port_state[port] &= ~(PORT_CHANGE_PRSC & ack_flag); 5000 } 5001 5002 if (*status & PORT_STATUS_POCI) { 5003 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5004 "port%d overcurrent!", port); 5005 5006 hubd->h_port_state[port] |= (PORT_STATUS_POCI & ack_flag); 5007 } else { 5008 5009 hubd->h_port_state[port] &= ~(PORT_STATUS_POCI & ack_flag); 5010 } 5011 5012 if (*status & PORT_STATUS_PRS) { 5013 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5014 "port%d reset active", port); 5015 5016 hubd->h_port_state[port] |= (PORT_STATUS_PRS & ack_flag); 5017 } else { 5018 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5019 "port%d reset inactive", port); 5020 5021 hubd->h_port_state[port] &= ~(PORT_STATUS_PRS & ack_flag); 5022 } 5023 if (*status & PORT_STATUS_PPS) { 5024 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5025 "port%d power on", port); 5026 5027 hubd->h_port_state[port] |= (PORT_STATUS_PPS & ack_flag); 5028 } else { 5029 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5030 "port%d power off", port); 5031 5032 hubd->h_port_state[port] &= ~(PORT_STATUS_PPS & ack_flag); 5033 } 5034 if (*status & PORT_STATUS_LSDA) { 5035 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5036 "port%d low speed", port); 5037 5038 hubd->h_port_state[port] |= (PORT_STATUS_LSDA & ack_flag); 5039 } else { 5040 hubd->h_port_state[port] &= ~(PORT_STATUS_LSDA & ack_flag); 5041 if (*status & PORT_STATUS_HSDA) { 5042 USB_DPRINTF_L3(DPRINT_MASK_PORT, 5043 hubd->h_log_handle, "port%d " 5044 "high speed", port); 5045 5046 hubd->h_port_state[port] |= 5047 (PORT_STATUS_HSDA & ack_flag); 5048 } else { 5049 USB_DPRINTF_L3(DPRINT_MASK_PORT, 5050 hubd->h_log_handle, "port%d " 5051 "full speed", port); 5052 5053 hubd->h_port_state[port] &= 5054 ~(PORT_STATUS_HSDA & ack_flag); 5055 } 5056 } 5057 5058 /* 5059 * Acknowledge connection, enable, reset status 5060 */ 5061 if (ack_flag) { 5062 mutex_exit(HUBD_MUTEX(hubd)); 5063 if (*change & PORT_CHANGE_CSC & ack_flag) { 5064 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5065 "clearing feature CFS_C_PORT_CONNECTION"); 5066 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5067 hubd->h_default_pipe, 5068 HUB_HANDLE_PORT_FEATURE_TYPE, 5069 USB_REQ_CLEAR_FEATURE, 5070 CFS_C_PORT_CONNECTION, 5071 port, 5072 0, NULL, 0, 5073 &completion_reason, &cb_flags, 0)) != 5074 USB_SUCCESS) { 5075 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5076 hubd->h_log_handle, 5077 "clear feature CFS_C_PORT_CONNECTION" 5078 " port%d failed (%d 0x%x %d)", 5079 port, completion_reason, cb_flags, rval); 5080 } 5081 } 5082 if (*change & PORT_CHANGE_PESC & ack_flag) { 5083 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5084 "clearing feature CFS_C_PORT_ENABLE"); 5085 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5086 hubd->h_default_pipe, 5087 HUB_HANDLE_PORT_FEATURE_TYPE, 5088 USB_REQ_CLEAR_FEATURE, 5089 CFS_C_PORT_ENABLE, 5090 port, 5091 0, NULL, 0, 5092 &completion_reason, &cb_flags, 0)) != 5093 USB_SUCCESS) { 5094 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5095 hubd->h_log_handle, 5096 "clear feature CFS_C_PORT_ENABLE" 5097 " port%d failed (%d 0x%x %d)", 5098 port, completion_reason, cb_flags, rval); 5099 } 5100 } 5101 if (*change & PORT_CHANGE_PSSC & ack_flag) { 5102 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5103 "clearing feature CFS_C_PORT_SUSPEND"); 5104 5105 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5106 hubd->h_default_pipe, 5107 HUB_HANDLE_PORT_FEATURE_TYPE, 5108 USB_REQ_CLEAR_FEATURE, 5109 CFS_C_PORT_SUSPEND, 5110 port, 5111 0, NULL, 0, 5112 &completion_reason, &cb_flags, 0)) != 5113 USB_SUCCESS) { 5114 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5115 hubd->h_log_handle, 5116 "clear feature CFS_C_PORT_SUSPEND" 5117 " port%d failed (%d 0x%x %d)", 5118 port, completion_reason, cb_flags, rval); 5119 } 5120 } 5121 if (*change & PORT_CHANGE_OCIC & ack_flag) { 5122 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5123 "clearing feature CFS_C_PORT_OVER_CURRENT"); 5124 5125 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5126 hubd->h_default_pipe, 5127 HUB_HANDLE_PORT_FEATURE_TYPE, 5128 USB_REQ_CLEAR_FEATURE, 5129 CFS_C_PORT_OVER_CURRENT, 5130 port, 5131 0, NULL, 0, 5132 &completion_reason, &cb_flags, 0)) != 5133 USB_SUCCESS) { 5134 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5135 hubd->h_log_handle, 5136 "clear feature CFS_C_PORT_OVER_CURRENT" 5137 " port%d failed (%d 0x%x %d)", 5138 port, completion_reason, cb_flags, rval); 5139 } 5140 } 5141 if (*change & PORT_CHANGE_PRSC & ack_flag) { 5142 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5143 "clearing feature CFS_C_PORT_RESET"); 5144 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5145 hubd->h_default_pipe, 5146 HUB_HANDLE_PORT_FEATURE_TYPE, 5147 USB_REQ_CLEAR_FEATURE, 5148 CFS_C_PORT_RESET, 5149 port, 5150 0, NULL, 0, 5151 &completion_reason, &cb_flags, 0)) != 5152 USB_SUCCESS) { 5153 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5154 hubd->h_log_handle, 5155 "clear feature CFS_C_PORT_RESET" 5156 " port%d failed (%d 0x%x %d)", 5157 port, completion_reason, cb_flags, rval); 5158 } 5159 } 5160 mutex_enter(HUBD_MUTEX(hubd)); 5161 } 5162 5163 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5164 "new port%d state 0x%x", port, hubd->h_port_state[port]); 5165 5166 5167 return (USB_SUCCESS); 5168 } 5169 5170 5171 /* 5172 * hubd_recover_disabled_port 5173 * if the port got disabled because of an error 5174 * enable it. If hub doesn't suport enable port, 5175 * reset the port to bring the device to life again 5176 */ 5177 static int 5178 hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port) 5179 { 5180 uint16_t status; 5181 uint16_t change; 5182 int rval = USB_FAILURE; 5183 5184 /* first try enabling the port */ 5185 (void) hubd_enable_port(hubd, port); 5186 5187 /* read the port status */ 5188 (void) hubd_determine_port_status(hubd, port, &status, &change, 5189 PORT_CHANGE_PESC); 5190 5191 if (status & PORT_STATUS_PES) { 5192 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5193 "Port%d now Enabled", port); 5194 } else if (status & PORT_STATUS_CCS) { 5195 /* first post a disconnect event to the child */ 5196 mutex_exit(HUBD_MUTEX(hubd)); 5197 hubd_post_event(hubd, port, USBA_EVENT_TAG_HOT_REMOVAL); 5198 mutex_enter(HUBD_MUTEX(hubd)); 5199 5200 /* then reset the port and recover the device */ 5201 rval = hubd_handle_port_connect(hubd, port); 5202 5203 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5204 "Port%d now Enabled by force", port); 5205 } 5206 5207 return (rval); 5208 } 5209 5210 5211 /* 5212 * hubd_enable_all_port_power: 5213 */ 5214 static int 5215 hubd_enable_all_port_power(hubd_t *hubd) 5216 { 5217 usb_hub_descr_t *hub_descr; 5218 int wait; 5219 usb_port_t port; 5220 uint_t retry; 5221 uint16_t status; 5222 uint16_t change; 5223 5224 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5225 "hubd_enable_all_port_power"); 5226 5227 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5228 5229 hub_descr = &hubd->h_hub_descr; 5230 5231 /* 5232 * According to section 11.11 of USB, for hubs with no power 5233 * switches, bPwrOn2PwrGood is zero. But we wait for some 5234 * arbitrary time to enable power to become stable. 5235 * 5236 * If an hub supports port power switching, we need to wait 5237 * at least 20ms before accessing corresponding usb port. 5238 */ 5239 if ((hub_descr->wHubCharacteristics & 5240 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 5241 wait = hubd_device_delay / 10; 5242 } else { 5243 wait = max(HUB_DEFAULT_POPG, 5244 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 5245 } 5246 5247 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5248 "hubd_enable_all_port_power: popg=%d wait=%d", 5249 hub_descr->bPwrOn2PwrGood, wait); 5250 5251 /* 5252 * Enable power per port. we ignore gang power and power mask 5253 * and always enable all ports one by one. 5254 */ 5255 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 5256 /* 5257 * Transition the port from the Powered Off to the 5258 * Disconnected state by supplying power to the port. 5259 */ 5260 USB_DPRINTF_L4(DPRINT_MASK_PORT, 5261 hubd->h_log_handle, 5262 "hubd_enable_all_port_power: power port=%d", port); 5263 5264 (void) hubd_enable_port_power(hubd, port); 5265 } 5266 5267 mutex_exit(HUBD_MUTEX(hubd)); 5268 delay(drv_usectohz(wait)); 5269 mutex_enter(HUBD_MUTEX(hubd)); 5270 5271 /* For retry if any, use some extra delay */ 5272 wait = max(wait, hubd_device_delay / 10); 5273 5274 /* Check each port power status for a given usb hub */ 5275 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 5276 5277 /* Get port status */ 5278 (void) hubd_determine_port_status(hubd, port, 5279 &status, &change, 0); 5280 5281 for (retry = 0; ((!(status & PORT_STATUS_PPS)) && 5282 (retry < HUBD_PORT_RETRY)); retry++) { 5283 5284 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5285 "Retry is in progress %d: port %d status %d", 5286 retry, port, status); 5287 5288 (void) hubd_enable_port_power(hubd, port); 5289 5290 mutex_exit(HUBD_MUTEX(hubd)); 5291 delay(drv_usectohz(wait)); 5292 mutex_enter(HUBD_MUTEX(hubd)); 5293 5294 /* Get port status */ 5295 (void) hubd_determine_port_status(hubd, port, 5296 &status, &change, 0); 5297 } 5298 5299 /* Print warning message if port has no power */ 5300 if (!(status & PORT_STATUS_PPS)) { 5301 5302 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5303 "hubd_enable_all_port_power: port %d power-on " 5304 "failed, port status 0x%x", port, status); 5305 } 5306 } 5307 5308 return (USB_SUCCESS); 5309 } 5310 5311 5312 /* 5313 * hubd_enable_port_power: 5314 * enable individual port power 5315 */ 5316 static int 5317 hubd_enable_port_power(hubd_t *hubd, usb_port_t port) 5318 { 5319 int rval; 5320 usb_cr_t completion_reason; 5321 usb_cb_flags_t cb_flags; 5322 5323 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5324 "hubd_enable_port_power: port=%d", port); 5325 5326 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5327 ASSERT(hubd->h_default_pipe != 0); 5328 5329 mutex_exit(HUBD_MUTEX(hubd)); 5330 5331 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5332 hubd->h_default_pipe, 5333 HUB_HANDLE_PORT_FEATURE_TYPE, 5334 USB_REQ_SET_FEATURE, 5335 CFS_PORT_POWER, 5336 port, 5337 0, NULL, 0, 5338 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5339 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5340 "set port power failed (%d 0x%x %d)", 5341 completion_reason, cb_flags, rval); 5342 mutex_enter(HUBD_MUTEX(hubd)); 5343 5344 return (USB_FAILURE); 5345 } else { 5346 mutex_enter(HUBD_MUTEX(hubd)); 5347 hubd->h_port_state[port] |= PORT_STATUS_PPS; 5348 5349 return (USB_SUCCESS); 5350 } 5351 } 5352 5353 5354 /* 5355 * hubd_disable_all_port_power: 5356 */ 5357 static int 5358 hubd_disable_all_port_power(hubd_t *hubd) 5359 { 5360 usb_port_t port; 5361 5362 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5363 "hubd_disable_all_port_power"); 5364 5365 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5366 5367 /* 5368 * disable power per port, ignore gang power and power mask 5369 */ 5370 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 5371 (void) hubd_disable_port_power(hubd, port); 5372 } 5373 5374 return (USB_SUCCESS); 5375 } 5376 5377 5378 /* 5379 * hubd_disable_port_power: 5380 * disable individual port power 5381 */ 5382 static int 5383 hubd_disable_port_power(hubd_t *hubd, usb_port_t port) 5384 { 5385 int rval; 5386 usb_cr_t completion_reason; 5387 usb_cb_flags_t cb_flags; 5388 5389 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5390 "hubd_disable_port_power: port=%d", port); 5391 5392 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5393 5394 mutex_exit(HUBD_MUTEX(hubd)); 5395 5396 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5397 hubd->h_default_pipe, 5398 HUB_HANDLE_PORT_FEATURE_TYPE, 5399 USB_REQ_CLEAR_FEATURE, 5400 CFS_PORT_POWER, 5401 port, 5402 0, NULL, 0, 5403 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5404 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5405 "clearing port%d power failed (%d 0x%x %d)", 5406 port, completion_reason, cb_flags, rval); 5407 5408 mutex_enter(HUBD_MUTEX(hubd)); 5409 5410 return (USB_FAILURE); 5411 } else { 5412 5413 mutex_enter(HUBD_MUTEX(hubd)); 5414 ASSERT(completion_reason == 0); 5415 hubd->h_port_state[port] &= ~PORT_STATUS_PPS; 5416 5417 return (USB_SUCCESS); 5418 } 5419 } 5420 5421 5422 /* 5423 * Search the database of user preferences and find out the preferred 5424 * configuration for this new device 5425 */ 5426 int 5427 hubd_select_device_configuration(hubd_t *hubd, usb_port_t port, 5428 dev_info_t *child_dip, usba_device_t *child_ud) 5429 { 5430 char *pathname = NULL; 5431 char *tmp_path = NULL; 5432 int user_conf; 5433 int pathlen; 5434 usb_dev_descr_t *usbdev_ptr; 5435 usba_configrec_t *user_pref; 5436 5437 mutex_enter(&child_ud->usb_mutex); 5438 usbdev_ptr = child_ud->usb_dev_descr; 5439 mutex_exit(&child_ud->usb_mutex); 5440 5441 /* try to get pathname for this device */ 5442 tmp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5443 (void) ddi_pathname(child_dip, tmp_path); 5444 5445 pathlen = strlen(tmp_path) + 32; 5446 pathname = kmem_zalloc(pathlen, KM_SLEEP); 5447 5448 /* 5449 * We haven't initialized the node and it doesn't have an address 5450 * yet. Append port number to the physical pathname 5451 */ 5452 (void) sprintf(pathname, "%s@%d", tmp_path, port); 5453 5454 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5455 "hubd_select_device_configuration: Device=%s\n\t" 5456 "Child path=%s", 5457 usba_get_mfg_prod_sn_str(child_dip, tmp_path, MAXPATHLEN), 5458 pathname); 5459 kmem_free(tmp_path, MAXPATHLEN); 5460 5461 5462 /* database search for user preferences */ 5463 user_pref = usba_devdb_get_user_preferences(usbdev_ptr->idVendor, 5464 usbdev_ptr->idProduct, child_ud->usb_serialno_str, pathname); 5465 5466 if (user_pref) { 5467 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5468 "hubd_select_device_configuration: " 5469 "usba_devdb_get_user_preferences " 5470 "return user_conf=%d\npreferred driver=%s path=%s", 5471 user_pref->cfg_index, user_pref->driver, 5472 user_pref->pathname); 5473 5474 user_conf = user_pref->cfg_index; 5475 5476 if (user_pref->driver) { 5477 mutex_enter(&child_ud->usb_mutex); 5478 child_ud->usb_preferred_driver = user_pref->driver; 5479 mutex_exit(&child_ud->usb_mutex); 5480 } 5481 } else { 5482 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5483 "hubd_select_device_configuration: No match found"); 5484 5485 /* select default configuration for this device */ 5486 user_conf = USBA_DEV_CONFIG_INDEX_UNDEFINED; 5487 } 5488 kmem_free(pathname, pathlen); 5489 5490 /* if the device has just one configuration, set default value */ 5491 if (usbdev_ptr->bNumConfigurations == 1) { 5492 user_conf = USB_DEV_DEFAULT_CONFIG_INDEX; 5493 } 5494 5495 return (user_conf); 5496 } 5497 5498 5499 /* 5500 * Retrieves config cloud for this configuration 5501 */ 5502 int 5503 hubd_get_this_config_cloud(hubd_t *hubd, dev_info_t *dip, 5504 usba_device_t *child_ud, uint16_t conf_index) 5505 { 5506 usb_cfg_descr_t *confdescr; 5507 mblk_t *pdata = NULL; 5508 int rval; 5509 size_t size; 5510 char *tmpbuf; 5511 usb_cr_t completion_reason; 5512 usb_cb_flags_t cb_flags; 5513 usb_pipe_handle_t def_ph; 5514 5515 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5516 "hubd_get_this_config_cloud: conf_index=%d", conf_index); 5517 5518 5519 /* alloc temporary space for config descriptor */ 5520 confdescr = (usb_cfg_descr_t *)kmem_zalloc(USB_CFG_DESCR_SIZE, 5521 KM_SLEEP); 5522 5523 /* alloc temporary space for string descriptor */ 5524 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 5525 5526 def_ph = usba_get_dflt_pipe_handle(dip); 5527 5528 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5529 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5530 USB_REQ_GET_DESCR, 5531 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5532 0, 5533 USB_CFG_DESCR_SIZE, 5534 &pdata, 5535 0, 5536 &completion_reason, 5537 &cb_flags, 5538 0)) == USB_SUCCESS) { 5539 5540 /* this must be true since we didn't allow data underruns */ 5541 if (MBLKL(pdata) != USB_CFG_DESCR_SIZE) { 5542 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5543 "device returned incorrect configuration " 5544 "descriptor size."); 5545 5546 rval = USB_FAILURE; 5547 goto done; 5548 } 5549 5550 /* 5551 * Parse the configuration descriptor 5552 */ 5553 size = usb_parse_cfg_descr(pdata->b_rptr, 5554 MBLKL(pdata), confdescr, 5555 USB_CFG_DESCR_SIZE); 5556 5557 /* if parse cfg descr error, it should return failure */ 5558 if (size == USB_PARSE_ERROR) { 5559 5560 if (pdata->b_rptr[1] != USB_DESCR_TYPE_CFG) { 5561 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5562 hubd->h_log_handle, 5563 "device returned incorrect " 5564 "configuration descriptor type."); 5565 } 5566 rval = USB_FAILURE; 5567 goto done; 5568 } 5569 5570 if (confdescr->wTotalLength < USB_CFG_DESCR_SIZE) { 5571 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5572 hubd->h_log_handle, 5573 "device returned incorrect " 5574 "configuration descriptor size."); 5575 5576 rval = USB_FAILURE; 5577 goto done; 5578 } 5579 5580 freemsg(pdata); 5581 pdata = NULL; 5582 5583 /* Now fetch the complete config cloud */ 5584 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5585 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5586 USB_REQ_GET_DESCR, 5587 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5588 0, 5589 confdescr->wTotalLength, 5590 &pdata, 5591 0, 5592 &completion_reason, 5593 &cb_flags, 5594 0)) == USB_SUCCESS) { 5595 5596 if (MBLKL(pdata) != 5597 confdescr->wTotalLength) { 5598 5599 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5600 hubd->h_log_handle, 5601 "device returned incorrect " 5602 "configuration descriptor."); 5603 5604 rval = USB_FAILURE; 5605 goto done; 5606 } 5607 5608 /* 5609 * copy config descriptor into usba_device 5610 */ 5611 mutex_enter(&child_ud->usb_mutex); 5612 child_ud->usb_cfg_array[conf_index] = 5613 kmem_alloc(confdescr->wTotalLength, KM_SLEEP); 5614 child_ud->usb_cfg_array_len[conf_index] = 5615 confdescr->wTotalLength; 5616 bcopy((caddr_t)pdata->b_rptr, 5617 (caddr_t)child_ud->usb_cfg_array[conf_index], 5618 confdescr->wTotalLength); 5619 mutex_exit(&child_ud->usb_mutex); 5620 5621 /* 5622 * retrieve string descriptor describing this 5623 * configuration 5624 */ 5625 if (confdescr->iConfiguration) { 5626 5627 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 5628 hubd->h_log_handle, 5629 "Get conf str descr for config_index=%d", 5630 conf_index); 5631 5632 /* 5633 * Now fetch the string descriptor describing 5634 * this configuration 5635 */ 5636 if ((rval = usb_get_string_descr(dip, 5637 USB_LANG_ID, confdescr->iConfiguration, 5638 tmpbuf, USB_MAXSTRINGLEN)) == 5639 USB_SUCCESS) { 5640 size = strlen(tmpbuf); 5641 if (size > 0) { 5642 child_ud->usb_cfg_str_descr 5643 [conf_index] = (char *) 5644 kmem_zalloc(size + 1, 5645 KM_SLEEP); 5646 (void) strcpy( 5647 child_ud->usb_cfg_str_descr 5648 [conf_index], tmpbuf); 5649 } 5650 } else { 5651 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5652 hubd->h_log_handle, 5653 "hubd_get_this_config_cloud: " 5654 "getting config string (%d) " 5655 "failed", 5656 confdescr->iConfiguration); 5657 5658 /* ignore this error */ 5659 rval = USB_SUCCESS; 5660 } 5661 } 5662 } 5663 } 5664 5665 done: 5666 if (rval != USB_SUCCESS) { 5667 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5668 "hubd_get_this_config_cloud: " 5669 "error in retrieving config descriptor for " 5670 "config index=%d rval=%d cr=%d", 5671 conf_index, rval, completion_reason); 5672 } 5673 5674 if (pdata) { 5675 freemsg(pdata); 5676 pdata = NULL; 5677 } 5678 5679 kmem_free(confdescr, USB_CFG_DESCR_SIZE); 5680 kmem_free(tmpbuf, USB_MAXSTRINGLEN); 5681 5682 return (rval); 5683 } 5684 5685 5686 /* 5687 * Retrieves the entire config cloud for all configurations of the device 5688 */ 5689 int 5690 hubd_get_all_device_config_cloud(hubd_t *hubd, dev_info_t *dip, 5691 usba_device_t *child_ud) 5692 { 5693 int rval = USB_SUCCESS; 5694 int ncfgs; 5695 uint16_t size; 5696 uint16_t conf_index; 5697 uchar_t **cfg_array; 5698 uint16_t *cfg_array_len; 5699 char **str_descr; 5700 5701 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5702 "hubd_get_all_device_config_cloud: Start"); 5703 5704 /* alloc pointer array for conf. descriptors */ 5705 mutex_enter(&child_ud->usb_mutex); 5706 ncfgs = child_ud->usb_n_cfgs; 5707 mutex_exit(&child_ud->usb_mutex); 5708 5709 size = sizeof (uchar_t *) * ncfgs; 5710 cfg_array = kmem_zalloc(size, KM_SLEEP); 5711 cfg_array_len = kmem_zalloc(ncfgs * sizeof (uint16_t), KM_SLEEP); 5712 str_descr = kmem_zalloc(size, KM_SLEEP); 5713 5714 mutex_enter(&child_ud->usb_mutex); 5715 child_ud->usb_cfg_array = cfg_array; 5716 child_ud->usb_cfg_array_len = cfg_array_len; 5717 child_ud->usb_cfg_array_length = size; 5718 child_ud->usb_cfg_array_len_length = ncfgs * sizeof (uint16_t); 5719 child_ud->usb_cfg_str_descr = str_descr; 5720 mutex_exit(&child_ud->usb_mutex); 5721 5722 /* Get configuration descriptor for each configuration */ 5723 for (conf_index = 0; (conf_index < ncfgs) && 5724 (rval == USB_SUCCESS); conf_index++) { 5725 5726 rval = hubd_get_this_config_cloud(hubd, dip, child_ud, 5727 conf_index); 5728 } 5729 5730 return (rval); 5731 } 5732 5733 5734 /* 5735 * hubd_ready_device: 5736 * Update the usba_device structure 5737 * Set the given configuration 5738 * Prepares the device node for driver to online. If an existing 5739 * OBP node is found, it will switch to the OBP node. 5740 */ 5741 dev_info_t * 5742 hubd_ready_device(hubd_t *hubd, dev_info_t *child_dip, usba_device_t *child_ud, 5743 uint_t config_index) 5744 { 5745 usb_cr_t completion_reason; 5746 usb_cb_flags_t cb_flags; 5747 size_t size; 5748 usb_cfg_descr_t config_descriptor; 5749 usb_pipe_handle_t def_ph; 5750 usba_pipe_handle_data_t *ph; 5751 5752 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5753 "hubd_ready_device: dip=0x%p, user_conf_index=%d", 5754 (void *)child_dip, config_index); 5755 5756 size = usb_parse_cfg_descr( 5757 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 5758 &config_descriptor, USB_CFG_DESCR_SIZE); 5759 ASSERT(size == USB_CFG_DESCR_SIZE); 5760 5761 def_ph = usba_get_dflt_pipe_handle(child_dip); 5762 5763 /* Set the configuration */ 5764 (void) usb_pipe_sync_ctrl_xfer(child_dip, def_ph, 5765 USB_DEV_REQ_HOST_TO_DEV, 5766 USB_REQ_SET_CFG, /* bRequest */ 5767 config_descriptor.bConfigurationValue, /* wValue */ 5768 0, /* wIndex */ 5769 0, /* wLength */ 5770 NULL, 5771 0, 5772 &completion_reason, 5773 &cb_flags, 5774 0); 5775 5776 mutex_enter(&child_ud->usb_mutex); 5777 child_ud->usb_active_cfg_ndx = config_index; 5778 child_ud->usb_cfg = child_ud->usb_cfg_array[config_index]; 5779 child_ud->usb_cfg_length = config_descriptor.wTotalLength; 5780 child_ud->usb_cfg_value = config_descriptor.bConfigurationValue; 5781 child_ud->usb_n_ifs = config_descriptor.bNumInterfaces; 5782 child_ud->usb_dip = child_dip; 5783 5784 child_ud->usb_client_flags = kmem_zalloc( 5785 child_ud->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 5786 5787 child_ud->usb_client_attach_list = kmem_zalloc( 5788 child_ud->usb_n_ifs * 5789 sizeof (*child_ud->usb_client_attach_list), KM_SLEEP); 5790 5791 child_ud->usb_client_ev_cb_list = kmem_zalloc( 5792 child_ud->usb_n_ifs * 5793 sizeof (*child_ud->usb_client_ev_cb_list), KM_SLEEP); 5794 5795 mutex_exit(&child_ud->usb_mutex); 5796 5797 /* ready the device node */ 5798 child_dip = usba_ready_device_node(child_dip); 5799 5800 /* set owner of default pipe to child dip */ 5801 ph = usba_get_ph_data(def_ph); 5802 mutex_enter(&ph->p_mutex); 5803 mutex_enter(&ph->p_ph_impl->usba_ph_mutex); 5804 ph->p_ph_impl->usba_ph_dip = ph->p_dip = child_dip; 5805 mutex_exit(&ph->p_ph_impl->usba_ph_mutex); 5806 mutex_exit(&ph->p_mutex); 5807 5808 return (child_dip); 5809 } 5810 5811 5812 /* 5813 * hubd_create_child 5814 * - create child dip 5815 * - open default pipe 5816 * - get device descriptor 5817 * - set the address 5818 * - get device string descriptors 5819 * - get the entire config cloud (all configurations) of the device 5820 * - set user preferred configuration 5821 * - close default pipe 5822 * - load appropriate driver(s) 5823 */ 5824 static int 5825 hubd_create_child(dev_info_t *dip, 5826 hubd_t *hubd, 5827 usba_device_t *hubd_ud, 5828 usb_port_status_t port_status, 5829 usb_port_t port, 5830 int iteration) 5831 { 5832 dev_info_t *child_dip = NULL; 5833 usb_dev_descr_t usb_dev_descr; 5834 int rval; 5835 usba_device_t *child_ud = NULL; 5836 usba_device_t *parent_ud = NULL; 5837 usb_pipe_handle_t ph = NULL; /* default pipe handle */ 5838 mblk_t *pdata = NULL; 5839 usb_cr_t completion_reason; 5840 int user_conf_index; 5841 uint_t config_index; 5842 usb_cb_flags_t cb_flags; 5843 uchar_t address = 0; 5844 uint16_t length; 5845 size_t size; 5846 usb_addr_t parent_usb_addr; 5847 usb_port_t parent_usb_port; 5848 usba_device_t *parent_usba_dev; 5849 usb_port_status_t parent_port_status; 5850 5851 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5852 "hubd_create_child: port=%d", port); 5853 5854 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5855 ASSERT(hubd->h_usba_devices[port] == NULL); 5856 5857 mutex_exit(HUBD_MUTEX(hubd)); 5858 5859 /* 5860 * create a dip which can be used to open the pipe. we set 5861 * the name after getting the descriptors from the device 5862 */ 5863 rval = usba_create_child_devi(dip, 5864 "device", /* driver name */ 5865 hubd_ud->usb_hcdi_ops, /* usba_hcdi ops */ 5866 hubd_ud->usb_root_hub_dip, 5867 port_status, /* low speed device */ 5868 child_ud, 5869 &child_dip); 5870 5871 if (rval != USB_SUCCESS) { 5872 5873 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5874 "usb_create_child_devi failed (%d)", rval); 5875 5876 goto fail_cleanup; 5877 } 5878 5879 child_ud = usba_get_usba_device(child_dip); 5880 ASSERT(child_ud != NULL); 5881 5882 parent_ud = hubd->h_usba_device; 5883 mutex_enter(&parent_ud->usb_mutex); 5884 parent_port_status = parent_ud->usb_port_status; 5885 5886 /* 5887 * To support split transactions, update address and port 5888 * of high speed hub to which given device is connected. 5889 */ 5890 if (parent_port_status == USBA_HIGH_SPEED_DEV) { 5891 parent_usba_dev = parent_ud; 5892 parent_usb_addr = parent_ud->usb_addr; 5893 parent_usb_port = port; 5894 } else { 5895 parent_usba_dev = parent_ud->usb_hs_hub_usba_dev; 5896 parent_usb_addr = parent_ud->usb_hs_hub_addr; 5897 parent_usb_port = parent_ud->usb_hs_hub_port; 5898 } 5899 mutex_exit(&parent_ud->usb_mutex); 5900 5901 mutex_enter(&child_ud->usb_mutex); 5902 address = child_ud->usb_addr; 5903 child_ud->usb_addr = 0; 5904 child_ud->usb_dev_descr = kmem_alloc(sizeof (usb_dev_descr_t), 5905 KM_SLEEP); 5906 bzero(&usb_dev_descr, sizeof (usb_dev_descr_t)); 5907 usb_dev_descr.bMaxPacketSize0 = 5908 (port_status == USBA_LOW_SPEED_DEV) ? 8 : 64; 5909 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5910 sizeof (usb_dev_descr_t)); 5911 child_ud->usb_port = port; 5912 child_ud->usb_hs_hub_usba_dev = parent_usba_dev; 5913 child_ud->usb_hs_hub_addr = parent_usb_addr; 5914 child_ud->usb_hs_hub_port = parent_usb_port; 5915 mutex_exit(&child_ud->usb_mutex); 5916 5917 /* Open the default pipe */ 5918 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5919 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 5920 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5921 "usb_pipe_open failed (%d)", rval); 5922 5923 goto fail_cleanup; 5924 } 5925 5926 /* 5927 * get device descriptor 5928 */ 5929 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5930 "hubd_create_child: get device descriptor: 64 bytes"); 5931 5932 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5933 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5934 USB_REQ_GET_DESCR, /* bRequest */ 5935 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5936 0, /* wIndex */ 5937 64, /* wLength */ 5938 &pdata, USB_ATTRS_SHORT_XFER_OK, 5939 &completion_reason, &cb_flags, 0); 5940 5941 if ((rval != USB_SUCCESS) && 5942 (!((completion_reason == USB_CR_DATA_OVERRUN) && pdata))) { 5943 5944 /* 5945 * rval != USB_SUCCESS AND 5946 * completion_reason != USB_CR_DATA_OVERRUN 5947 * pdata could be != NULL. 5948 * Free pdata now to prevent memory leak. 5949 */ 5950 freemsg(pdata); 5951 pdata = NULL; 5952 5953 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5954 "hubd_create_child: get device descriptor: 8 bytes"); 5955 5956 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5957 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5958 USB_REQ_GET_DESCR, /* bRequest */ 5959 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5960 0, /* wIndex */ 5961 8, /* wLength */ 5962 &pdata, USB_ATTRS_NONE, 5963 &completion_reason, &cb_flags, 0); 5964 5965 if (rval != USB_SUCCESS) { 5966 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5967 "getting device descriptor failed (%s 0x%x %d)", 5968 usb_str_cr(completion_reason), cb_flags, rval); 5969 goto fail_cleanup; 5970 } 5971 } else { 5972 ASSERT(completion_reason == USB_CR_OK); 5973 } 5974 5975 ASSERT(pdata != NULL); 5976 5977 size = usb_parse_dev_descr( 5978 pdata->b_rptr, 5979 MBLKL(pdata), 5980 &usb_dev_descr, 5981 sizeof (usb_dev_descr_t)); 5982 5983 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5984 "parsing device descriptor returned %lu", size); 5985 5986 length = *(pdata->b_rptr); 5987 freemsg(pdata); 5988 pdata = NULL; 5989 if (size < 8) { 5990 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5991 "get device descriptor returned %lu bytes", size); 5992 5993 goto fail_cleanup; 5994 } 5995 5996 if (length < 8) { 5997 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5998 "fail enumeration: bLength=%d", length); 5999 6000 goto fail_cleanup; 6001 } 6002 6003 /* Set the address of the device */ 6004 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6005 USB_DEV_REQ_HOST_TO_DEV, 6006 USB_REQ_SET_ADDRESS, /* bRequest */ 6007 address, /* wValue */ 6008 0, /* wIndex */ 6009 0, /* wLength */ 6010 NULL, 0, 6011 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 6012 char buffer[64]; 6013 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6014 "setting address failed (cr=%s cb_flags=%s rval=%d)", 6015 usb_str_cr(completion_reason), 6016 usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)), 6017 rval); 6018 6019 goto fail_cleanup; 6020 } 6021 6022 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6023 "set address 0x%x done", address); 6024 6025 /* now close the pipe for addr 0 */ 6026 usb_pipe_close(child_dip, ph, 6027 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 6028 6029 /* 6030 * This delay is important for the CATC hub to enumerate 6031 * But, avoid delay in the first iteration 6032 */ 6033 if (iteration) { 6034 delay(drv_usectohz(hubd_device_delay/100)); 6035 } 6036 6037 /* assign the address in the usba_device structure */ 6038 mutex_enter(&child_ud->usb_mutex); 6039 child_ud->usb_addr = address; 6040 child_ud->usb_no_cpr = 0; 6041 child_ud->usb_port_status = port_status; 6042 /* save this device descriptor */ 6043 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 6044 sizeof (usb_dev_descr_t)); 6045 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 6046 mutex_exit(&child_ud->usb_mutex); 6047 6048 /* re-open the pipe for the device with the new address */ 6049 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 6050 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 6051 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6052 "usb_pipe_open failed (%d)", rval); 6053 6054 goto fail_cleanup; 6055 } 6056 6057 /* 6058 * Get full device descriptor only if we have not received full 6059 * device descriptor earlier. 6060 */ 6061 if (size < length) { 6062 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6063 "hubd_create_child: get full device descriptor: " 6064 "%d bytes", length); 6065 6066 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6067 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 6068 USB_REQ_GET_DESCR, /* bRequest */ 6069 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 6070 0, /* wIndex */ 6071 length, /* wLength */ 6072 &pdata, 0, 6073 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 6074 freemsg(pdata); 6075 pdata = NULL; 6076 6077 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 6078 hubd->h_log_handle, 6079 "hubd_create_child: get full device descriptor: " 6080 "64 bytes"); 6081 6082 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6083 USB_DEV_REQ_DEV_TO_HOST | 6084 USB_DEV_REQ_TYPE_STANDARD, 6085 USB_REQ_GET_DESCR, /* bRequest */ 6086 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 6087 0, /* wIndex */ 6088 64, /* wLength */ 6089 &pdata, USB_ATTRS_SHORT_XFER_OK, 6090 &completion_reason, &cb_flags, 0); 6091 6092 /* we have to trust the data now */ 6093 if (pdata) { 6094 int len = *(pdata->b_rptr); 6095 6096 length = MBLKL(pdata); 6097 if (length < len) { 6098 6099 goto fail_cleanup; 6100 } 6101 } else if (rval != USB_SUCCESS) { 6102 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6103 hubd->h_log_handle, 6104 "getting device descriptor failed " 6105 "(%d 0x%x %d)", 6106 completion_reason, cb_flags, rval); 6107 6108 goto fail_cleanup; 6109 } 6110 } 6111 6112 size = usb_parse_dev_descr( 6113 pdata->b_rptr, 6114 MBLKL(pdata), 6115 &usb_dev_descr, 6116 sizeof (usb_dev_descr_t)); 6117 6118 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6119 "parsing device descriptor returned %lu", size); 6120 6121 /* 6122 * For now, free the data 6123 * eventually, each configuration may need to be looked at 6124 */ 6125 freemsg(pdata); 6126 pdata = NULL; 6127 6128 if (size != USB_DEV_DESCR_SIZE) { 6129 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6130 "fail enumeration: descriptor size=%lu " 6131 "expected size=%u", size, USB_DEV_DESCR_SIZE); 6132 6133 goto fail_cleanup; 6134 } 6135 6136 /* 6137 * save the device descriptor in usba_device since it is needed 6138 * later on again 6139 */ 6140 mutex_enter(&child_ud->usb_mutex); 6141 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 6142 sizeof (usb_dev_descr_t)); 6143 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 6144 mutex_exit(&child_ud->usb_mutex); 6145 } 6146 6147 if (usb_dev_descr.bNumConfigurations == 0) { 6148 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6149 "device descriptor:\n\t" 6150 "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t" 6151 "protocol=0x%x maxpktsize=0x%x " 6152 "Vid=0x%x Pid=0x%x rel=0x%x\n\t" 6153 "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x", 6154 usb_dev_descr.bLength, usb_dev_descr.bDescriptorType, 6155 usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass, 6156 usb_dev_descr.bDeviceSubClass, 6157 usb_dev_descr.bDeviceProtocol, 6158 usb_dev_descr.bMaxPacketSize0, 6159 usb_dev_descr.idVendor, 6160 usb_dev_descr.idProduct, usb_dev_descr.bcdDevice, 6161 usb_dev_descr.iManufacturer, usb_dev_descr.iProduct, 6162 usb_dev_descr.iSerialNumber, 6163 usb_dev_descr.bNumConfigurations); 6164 goto fail_cleanup; 6165 } 6166 6167 6168 /* get the device string descriptor(s) */ 6169 usba_get_dev_string_descrs(child_dip, child_ud); 6170 6171 /* retrieve config cloud for all configurations */ 6172 rval = hubd_get_all_device_config_cloud(hubd, child_dip, child_ud); 6173 if (rval != USB_SUCCESS) { 6174 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6175 "failed to get configuration descriptor(s)"); 6176 6177 goto fail_cleanup; 6178 } 6179 6180 /* get the preferred configuration for this device */ 6181 user_conf_index = hubd_select_device_configuration(hubd, port, 6182 child_dip, child_ud); 6183 6184 /* Check if the user selected configuration index is in range */ 6185 if ((user_conf_index >= usb_dev_descr.bNumConfigurations) || 6186 (user_conf_index < 0)) { 6187 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6188 "Configuration index for device idVendor=%d " 6189 "idProduct=%d is=%d, and is out of range[0..%d]", 6190 usb_dev_descr.idVendor, usb_dev_descr.idProduct, 6191 user_conf_index, usb_dev_descr.bNumConfigurations - 1); 6192 6193 /* treat this as user didn't specify configuration */ 6194 user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED; 6195 } 6196 6197 6198 /* 6199 * Warn users of a performance hit if connecting a 6200 * High Speed behind a 1.1 hub, which is behind a 6201 * 2.0 port. 6202 */ 6203 if ((parent_port_status != USBA_HIGH_SPEED_DEV) && 6204 !(usba_is_root_hub(parent_ud->usb_dip)) && 6205 (parent_usb_addr)) { 6206 6207 /* 6208 * Now that we know the root port is a high speed port 6209 * and that the parent port is not a high speed port, 6210 * let's find out if the device itself is a high speed 6211 * device. If it is a high speed device, 6212 * USB_DESCR_TYPE_SETUP_DEV_QLF should return a value, 6213 * otherwise the command will fail. 6214 */ 6215 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6216 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 6217 USB_REQ_GET_DESCR, /* bRequest */ 6218 USB_DESCR_TYPE_SETUP_DEV_QLF, /* wValue */ 6219 0, /* wIndex */ 6220 10, /* wLength */ 6221 &pdata, USB_ATTRS_SHORT_XFER_OK, 6222 &completion_reason, &cb_flags, 0); 6223 6224 if (pdata) { 6225 freemsg(pdata); 6226 pdata = NULL; 6227 } 6228 6229 /* 6230 * USB_DESCR_TYPE_SETUP_DEV_QLF query was successful 6231 * that means this is a high speed device behind a 6232 * high speed root hub, but running at full speed 6233 * because there is a full speed hub in the middle. 6234 */ 6235 if (rval == USB_SUCCESS) { 6236 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 6237 hubd->h_log_handle, 6238 "Connecting a high speed device to a " 6239 "non high speed hub (port %d) will result " 6240 "in a loss of performance. Please connect " 6241 "the device to a high speed hub to get " 6242 "the maximum performance.", 6243 port); 6244 } 6245 } 6246 6247 /* 6248 * Now we try to online the device by attaching a driver 6249 * The following truth table illustrates the logic:- 6250 * Cfgndx Driver Action 6251 * 0 0 loop all configs for driver with full 6252 * compatible properties. 6253 * 0 1 set first configuration, 6254 * compatible prop = drivername. 6255 * 1 0 Set config, full compatible prop 6256 * 1 1 Set config, compatible prop = drivername. 6257 * 6258 * Note: 6259 * cfgndx = user_conf_index 6260 * Driver = usb_preferred_driver 6261 */ 6262 if (user_conf_index == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 6263 if (child_ud->usb_preferred_driver) { 6264 /* 6265 * It is the job of the "preferred driver" to put the 6266 * device in the desired configuration. Till then 6267 * put the device in config index 0. 6268 */ 6269 if ((rval = usba_hubdi_check_power_budget(dip, child_ud, 6270 USB_DEV_DEFAULT_CONFIG_INDEX)) != USB_SUCCESS) { 6271 6272 goto fail_cleanup; 6273 } 6274 6275 child_dip = hubd_ready_device(hubd, child_dip, 6276 child_ud, USB_DEV_DEFAULT_CONFIG_INDEX); 6277 6278 /* 6279 * Assign the dip before onlining to avoid race 6280 * with busctl 6281 */ 6282 mutex_enter(HUBD_MUTEX(hubd)); 6283 hubd->h_children_dips[port] = child_dip; 6284 mutex_exit(HUBD_MUTEX(hubd)); 6285 6286 (void) usba_bind_driver(child_dip); 6287 } else { 6288 /* 6289 * loop through all the configurations to see if we 6290 * can find a driver for any one config. If not, set 6291 * the device in config_index 0 6292 */ 6293 rval = USB_FAILURE; 6294 for (config_index = 0; 6295 (config_index < usb_dev_descr.bNumConfigurations) && 6296 (rval != USB_SUCCESS); config_index++) { 6297 6298 child_dip = hubd_ready_device(hubd, child_dip, 6299 child_ud, config_index); 6300 6301 /* 6302 * Assign the dip before onlining to avoid race 6303 * with busctl 6304 */ 6305 mutex_enter(HUBD_MUTEX(hubd)); 6306 hubd->h_children_dips[port] = child_dip; 6307 mutex_exit(HUBD_MUTEX(hubd)); 6308 6309 rval = usba_bind_driver(child_dip); 6310 6311 /* 6312 * Normally power budget should be checked 6313 * before device is configured. A failure in 6314 * power budget checking will stop the device 6315 * from being configured with current 6316 * config_index and may enable the device to 6317 * be configured in another configuration. 6318 * This may break the user experience that a 6319 * device which previously worked in config 6320 * A now works in config B after power budget 6321 * control is enabled. To avoid such situation, 6322 * power budget checking is moved here and will 6323 * fail the child creation directly if config 6324 * A exceeds the power available. 6325 */ 6326 if (rval == USB_SUCCESS) { 6327 if ((usba_hubdi_check_power_budget(dip, 6328 child_ud, config_index)) != 6329 USB_SUCCESS) { 6330 6331 goto fail_cleanup; 6332 } 6333 } 6334 } 6335 if (rval != USB_SUCCESS) { 6336 6337 if ((usba_hubdi_check_power_budget(dip, 6338 child_ud, 0)) != USB_SUCCESS) { 6339 6340 goto fail_cleanup; 6341 } 6342 6343 child_dip = hubd_ready_device(hubd, child_dip, 6344 child_ud, 0); 6345 mutex_enter(HUBD_MUTEX(hubd)); 6346 hubd->h_children_dips[port] = child_dip; 6347 mutex_exit(HUBD_MUTEX(hubd)); 6348 } 6349 } /* end else loop all configs */ 6350 } else { 6351 6352 if ((usba_hubdi_check_power_budget(dip, child_ud, 6353 (uint_t)user_conf_index)) != USB_SUCCESS) { 6354 6355 goto fail_cleanup; 6356 } 6357 6358 child_dip = hubd_ready_device(hubd, child_dip, 6359 child_ud, (uint_t)user_conf_index); 6360 6361 /* 6362 * Assign the dip before onlining to avoid race 6363 * with busctl 6364 */ 6365 mutex_enter(HUBD_MUTEX(hubd)); 6366 hubd->h_children_dips[port] = child_dip; 6367 mutex_exit(HUBD_MUTEX(hubd)); 6368 6369 (void) usba_bind_driver(child_dip); 6370 } 6371 6372 usba_hubdi_decr_power_budget(dip, child_ud); 6373 6374 mutex_enter(HUBD_MUTEX(hubd)); 6375 if (hubd->h_usba_devices[port] == NULL) { 6376 hubd->h_usba_devices[port] = usba_get_usba_device(child_dip); 6377 } else { 6378 ASSERT(hubd->h_usba_devices[port] == 6379 usba_get_usba_device(child_dip)); 6380 } 6381 6382 return (USB_SUCCESS); 6383 6384 6385 fail_cleanup: 6386 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6387 "hubd_create_child: fail_cleanup"); 6388 6389 mutex_enter(HUBD_MUTEX(hubd)); 6390 hubd->h_children_dips[port] = NULL; 6391 mutex_exit(HUBD_MUTEX(hubd)); 6392 6393 if (pdata) { 6394 freemsg(pdata); 6395 } 6396 6397 if (ph) { 6398 usb_pipe_close(child_dip, ph, 6399 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 6400 } 6401 6402 if (child_dip) { 6403 int rval = usba_destroy_child_devi(child_dip, 6404 NDI_DEVI_REMOVE); 6405 if (rval != USB_SUCCESS) { 6406 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6407 "failure to remove child node"); 6408 } 6409 } 6410 6411 if (child_ud) { 6412 /* to make sure we free the address */ 6413 mutex_enter(&child_ud->usb_mutex); 6414 child_ud->usb_addr = address; 6415 ASSERT(child_ud->usb_ref_count == 0); 6416 mutex_exit(&child_ud->usb_mutex); 6417 6418 mutex_enter(HUBD_MUTEX(hubd)); 6419 if (hubd->h_usba_devices[port] == NULL) { 6420 mutex_exit(HUBD_MUTEX(hubd)); 6421 usba_free_usba_device(child_ud); 6422 } else { 6423 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 6424 mutex_exit(HUBD_MUTEX(hubd)); 6425 } 6426 } 6427 6428 mutex_enter(HUBD_MUTEX(hubd)); 6429 6430 return (USB_FAILURE); 6431 } 6432 6433 6434 /* 6435 * hubd_delete_child: 6436 * - free usb address 6437 * - lookup child dips, there may be multiple on this port 6438 * - offline each child devi 6439 */ 6440 static int 6441 hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, boolean_t retry) 6442 { 6443 dev_info_t *child_dip; 6444 usba_device_t *usba_device; 6445 int rval = USB_SUCCESS; 6446 6447 child_dip = hubd->h_children_dips[port]; 6448 usba_device = hubd->h_usba_devices[port]; 6449 6450 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6451 "hubd_delete_child: port=%d, dip=0x%p usba_device=0x%p", 6452 port, (void *)child_dip, (void *)usba_device); 6453 6454 mutex_exit(HUBD_MUTEX(hubd)); 6455 if (child_dip) { 6456 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6457 "hubd_delete_child:\n\t" 6458 "dip = 0x%p (%s) at port %d", 6459 (void *)child_dip, ddi_node_name(child_dip), port); 6460 6461 if (usba_device) { 6462 usba_hubdi_incr_power_budget(hubd->h_dip, usba_device); 6463 } 6464 6465 rval = usba_destroy_child_devi(child_dip, flag); 6466 6467 if ((rval != USB_SUCCESS) && usba_is_hwa(child_dip)) { 6468 /* 6469 * This is only useful for HWA device node. 6470 * Since hwahc interface must hold hwarc interface 6471 * open until hwahc is detached, the first call to 6472 * ndi_devi_unconfig_one() can only offline hwahc 6473 * driver but not hwarc driver. Need to make a second 6474 * call to ndi_devi_unconfig_one() to make the hwarc 6475 * driver detach. 6476 */ 6477 rval = usba_destroy_child_devi(child_dip, flag); 6478 } 6479 6480 if ((rval == USB_SUCCESS) && (flag & NDI_DEVI_REMOVE)) { 6481 /* 6482 * if the child was still < DS_INITIALIZED 6483 * then our bus_unconfig was not called and 6484 * we have to zap the child here 6485 */ 6486 mutex_enter(HUBD_MUTEX(hubd)); 6487 if (hubd->h_children_dips[port] == child_dip) { 6488 usba_device_t *ud = 6489 hubd->h_usba_devices[port]; 6490 hubd->h_children_dips[port] = NULL; 6491 if (ud) { 6492 mutex_exit(HUBD_MUTEX(hubd)); 6493 6494 mutex_enter(&ud->usb_mutex); 6495 ud->usb_ref_count = 0; 6496 mutex_exit(&ud->usb_mutex); 6497 6498 usba_free_usba_device(ud); 6499 mutex_enter(HUBD_MUTEX(hubd)); 6500 hubd->h_usba_devices[port] = NULL; 6501 } 6502 } 6503 mutex_exit(HUBD_MUTEX(hubd)); 6504 } 6505 } 6506 6507 if ((rval != USB_SUCCESS) && retry) { 6508 6509 hubd_schedule_cleanup(usba_device->usb_root_hub_dip); 6510 } 6511 mutex_enter(HUBD_MUTEX(hubd)); 6512 6513 return (rval); 6514 } 6515 6516 6517 /* 6518 * hubd_free_usba_device: 6519 * free usb device structure unless it is associated with 6520 * the root hub which is handled differently 6521 */ 6522 static void 6523 hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device) 6524 { 6525 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6526 "hubd_free_usba_device: hubd=0x%p, usba_device=0x%p", 6527 (void *)hubd, (void *)usba_device); 6528 6529 if (usba_device && (usba_device->usb_addr != ROOT_HUB_ADDR)) { 6530 usb_port_t port = usba_device->usb_port; 6531 dev_info_t *dip = hubd->h_children_dips[port]; 6532 6533 #ifdef DEBUG 6534 if (dip) { 6535 ASSERT(i_ddi_node_state(dip) < DS_INITIALIZED); 6536 } 6537 #endif 6538 6539 port = usba_device->usb_port; 6540 hubd->h_usba_devices[port] = NULL; 6541 6542 mutex_exit(HUBD_MUTEX(hubd)); 6543 usba_free_usba_device(usba_device); 6544 mutex_enter(HUBD_MUTEX(hubd)); 6545 } 6546 } 6547 6548 6549 /* 6550 * event support 6551 * 6552 * busctl event support 6553 */ 6554 static int 6555 hubd_busop_get_eventcookie(dev_info_t *dip, 6556 dev_info_t *rdip, 6557 char *eventname, 6558 ddi_eventcookie_t *cookie) 6559 { 6560 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6561 6562 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6563 "hubd_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 6564 "event=%s", (void *)dip, (void *)rdip, eventname); 6565 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6566 "(dip=%s%d, rdip=%s%d)", 6567 ddi_driver_name(dip), ddi_get_instance(dip), 6568 ddi_driver_name(rdip), ddi_get_instance(rdip)); 6569 6570 /* return event cookie, iblock cookie, and level */ 6571 return (ndi_event_retrieve_cookie(hubd->h_ndi_event_hdl, 6572 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 6573 } 6574 6575 6576 static int 6577 hubd_busop_add_eventcall(dev_info_t *dip, 6578 dev_info_t *rdip, 6579 ddi_eventcookie_t cookie, 6580 void (*callback)(dev_info_t *dip, 6581 ddi_eventcookie_t cookie, void *arg, 6582 void *bus_impldata), 6583 void *arg, ddi_callback_id_t *cb_id) 6584 { 6585 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6586 usb_port_t port = hubd_child_dip2port(hubd, rdip); 6587 6588 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6589 "hubd_busop_add_eventcall: dip=0x%p, rdip=0x%p " 6590 "cookie=0x%p, cb=0x%p, arg=0x%p", 6591 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 6592 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6593 "(dip=%s%d, rdip=%s%d, event=%s)", 6594 ddi_driver_name(dip), ddi_get_instance(dip), 6595 ddi_driver_name(rdip), ddi_get_instance(rdip), 6596 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, cookie)); 6597 6598 /* Set flag on children registering events */ 6599 switch (ndi_event_cookie_to_tag(hubd->h_ndi_event_hdl, cookie)) { 6600 case USBA_EVENT_TAG_HOT_REMOVAL: 6601 mutex_enter(HUBD_MUTEX(hubd)); 6602 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6603 mutex_exit(HUBD_MUTEX(hubd)); 6604 6605 break; 6606 case USBA_EVENT_TAG_PRE_SUSPEND: 6607 mutex_enter(HUBD_MUTEX(hubd)); 6608 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6609 mutex_exit(HUBD_MUTEX(hubd)); 6610 6611 break; 6612 default: 6613 6614 break; 6615 } 6616 6617 /* add callback to our event set */ 6618 return (ndi_event_add_callback(hubd->h_ndi_event_hdl, 6619 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 6620 } 6621 6622 6623 static int 6624 hubd_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 6625 { 6626 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6627 ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id; 6628 6629 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6630 "hubd_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 6631 "cookie=0x%p", (void *)dip, (void *)id->ndi_evtcb_dip, 6632 (void *)id->ndi_evtcb_cookie); 6633 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6634 "(dip=%s%d, rdip=%s%d, event=%s)", 6635 ddi_driver_name(dip), ddi_get_instance(dip), 6636 ddi_driver_name(id->ndi_evtcb_dip), 6637 ddi_get_instance(id->ndi_evtcb_dip), 6638 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, 6639 id->ndi_evtcb_cookie)); 6640 6641 /* remove event registration from our event set */ 6642 return (ndi_event_remove_callback(hubd->h_ndi_event_hdl, cb_id)); 6643 } 6644 6645 6646 /* 6647 * event distribution 6648 * 6649 * hubd_do_callback: 6650 * Post this event to the specified child 6651 */ 6652 static void 6653 hubd_do_callback(hubd_t *hubd, dev_info_t *cdip, ddi_eventcookie_t cookie) 6654 { 6655 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6656 "hubd_do_callback"); 6657 6658 (void) ndi_event_do_callback(hubd->h_ndi_event_hdl, cdip, cookie, NULL); 6659 } 6660 6661 6662 /* 6663 * hubd_run_callbacks: 6664 * Send this event to all children 6665 */ 6666 static void 6667 hubd_run_callbacks(hubd_t *hubd, usba_event_t type) 6668 { 6669 usb_port_t port; 6670 6671 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6672 "hubd_run_callbacks"); 6673 6674 mutex_enter(HUBD_MUTEX(hubd)); 6675 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 6676 /* 6677 * the childen_dips list may have dips that have been 6678 * already deallocated. we only get a post_detach notification 6679 * but not a destroy notification 6680 */ 6681 if (hubd->h_children_dips[port]) { 6682 mutex_exit(HUBD_MUTEX(hubd)); 6683 hubd_post_event(hubd, port, type); 6684 mutex_enter(HUBD_MUTEX(hubd)); 6685 } 6686 } 6687 mutex_exit(HUBD_MUTEX(hubd)); 6688 } 6689 6690 6691 /* 6692 * hubd_post_event 6693 * post event to a child on the port depending on the type 6694 */ 6695 static void 6696 hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type) 6697 { 6698 int rval; 6699 dev_info_t *dip; 6700 usba_device_t *usba_device; 6701 ddi_eventcookie_t cookie, rm_cookie, suspend_cookie; 6702 6703 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6704 "hubd_post_event: port=%d event=%s", port, 6705 ndi_event_tag_to_name(hubd->h_ndi_event_hdl, type)); 6706 6707 cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, type); 6708 rm_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6709 USBA_EVENT_TAG_HOT_REMOVAL); 6710 suspend_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6711 USBA_EVENT_TAG_PRE_SUSPEND); 6712 6713 /* 6714 * Hotplug daemon may be attaching a driver that may be registering 6715 * event callbacks. So it already has got the device tree lock and 6716 * event handle mutex. So to prevent a deadlock while posting events, 6717 * we grab and release the locks in the same order. 6718 */ 6719 mutex_enter(HUBD_MUTEX(hubd)); 6720 dip = hubd->h_children_dips[port]; 6721 usba_device = hubd->h_usba_devices[port]; 6722 mutex_exit(HUBD_MUTEX(hubd)); 6723 6724 switch (type) { 6725 case USBA_EVENT_TAG_HOT_REMOVAL: 6726 /* Clear the registered event flag */ 6727 mutex_enter(HUBD_MUTEX(hubd)); 6728 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_DISCONNECT; 6729 mutex_exit(HUBD_MUTEX(hubd)); 6730 6731 hubd_do_callback(hubd, dip, cookie); 6732 usba_persistent_pipe_close(usba_device); 6733 6734 /* 6735 * Mark the dip for deletion only after the driver has 6736 * seen the disconnect event to prevent cleanup thread 6737 * from stepping in between. 6738 */ 6739 mutex_enter(&(DEVI(dip)->devi_lock)); 6740 DEVI_SET_DEVICE_REMOVED(dip); 6741 mutex_exit(&(DEVI(dip)->devi_lock)); 6742 6743 break; 6744 case USBA_EVENT_TAG_PRE_SUSPEND: 6745 mutex_enter(HUBD_MUTEX(hubd)); 6746 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_PRESUSPEND; 6747 mutex_exit(HUBD_MUTEX(hubd)); 6748 6749 hubd_do_callback(hubd, dip, cookie); 6750 /* 6751 * persistent pipe close for this event is taken care by the 6752 * caller after verfying that all children can suspend 6753 */ 6754 6755 break; 6756 case USBA_EVENT_TAG_HOT_INSERTION: 6757 /* 6758 * Check if this child has missed the disconnect event before 6759 * it registered for event callbacks 6760 */ 6761 mutex_enter(HUBD_MUTEX(hubd)); 6762 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_DISCONNECT) { 6763 /* clear the flag and post disconnect event */ 6764 hubd->h_child_events[port] &= 6765 ~HUBD_CHILD_EVENT_DISCONNECT; 6766 mutex_exit(HUBD_MUTEX(hubd)); 6767 hubd_do_callback(hubd, dip, rm_cookie); 6768 usba_persistent_pipe_close(usba_device); 6769 mutex_enter(HUBD_MUTEX(hubd)); 6770 } 6771 mutex_exit(HUBD_MUTEX(hubd)); 6772 6773 /* 6774 * Mark the dip as reinserted to prevent cleanup thread 6775 * from stepping in. 6776 */ 6777 mutex_enter(&(DEVI(dip)->devi_lock)); 6778 DEVI_SET_DEVICE_REINSERTED(dip); 6779 mutex_exit(&(DEVI(dip)->devi_lock)); 6780 6781 rval = usba_persistent_pipe_open(usba_device); 6782 if (rval != USB_SUCCESS) { 6783 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6784 hubd->h_log_handle, 6785 "failed to reopen all pipes on reconnect"); 6786 } 6787 6788 hubd_do_callback(hubd, dip, cookie); 6789 6790 /* 6791 * We might see a connect event only if hotplug thread for 6792 * disconnect event don't run in time. 6793 * Set the flag again, so we don't miss posting a 6794 * disconnect event. 6795 */ 6796 mutex_enter(HUBD_MUTEX(hubd)); 6797 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6798 mutex_exit(HUBD_MUTEX(hubd)); 6799 6800 break; 6801 case USBA_EVENT_TAG_POST_RESUME: 6802 /* 6803 * Check if this child has missed the pre-suspend event before 6804 * it registered for event callbacks 6805 */ 6806 mutex_enter(HUBD_MUTEX(hubd)); 6807 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_PRESUSPEND) { 6808 /* clear the flag and post pre_suspend event */ 6809 hubd->h_port_state[port] &= 6810 ~HUBD_CHILD_EVENT_PRESUSPEND; 6811 mutex_exit(HUBD_MUTEX(hubd)); 6812 hubd_do_callback(hubd, dip, suspend_cookie); 6813 mutex_enter(HUBD_MUTEX(hubd)); 6814 } 6815 mutex_exit(HUBD_MUTEX(hubd)); 6816 6817 mutex_enter(&usba_device->usb_mutex); 6818 usba_device->usb_no_cpr = 0; 6819 mutex_exit(&usba_device->usb_mutex); 6820 6821 /* 6822 * Since the pipe has already been opened by hub 6823 * at DDI_RESUME time, there is no need for a 6824 * persistent pipe open 6825 */ 6826 hubd_do_callback(hubd, dip, cookie); 6827 6828 /* 6829 * Set the flag again, so we don't miss posting a 6830 * pre-suspend event. This enforces a tighter 6831 * dev_state model. 6832 */ 6833 mutex_enter(HUBD_MUTEX(hubd)); 6834 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6835 mutex_exit(HUBD_MUTEX(hubd)); 6836 break; 6837 } 6838 } 6839 6840 6841 /* 6842 * handling of events coming from above 6843 */ 6844 static int 6845 hubd_disconnect_event_cb(dev_info_t *dip) 6846 { 6847 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6848 usb_port_t port, nports; 6849 usba_device_t *usba_dev; 6850 usba_event_t tag = USBA_EVENT_TAG_HOT_REMOVAL; 6851 int circ; 6852 6853 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6854 "hubd_disconnect_event_cb: tag=%d", tag); 6855 6856 ndi_devi_enter(dip, &circ); 6857 6858 mutex_enter(HUBD_MUTEX(hubd)); 6859 switch (hubd->h_dev_state) { 6860 case USB_DEV_ONLINE: 6861 case USB_DEV_PWRED_DOWN: 6862 hubd->h_dev_state = USB_DEV_DISCONNECTED; 6863 /* stop polling on the interrupt pipe */ 6864 hubd_stop_polling(hubd); 6865 6866 /* FALLTHROUGH */ 6867 case USB_DEV_SUSPENDED: 6868 /* we remain in this state */ 6869 mutex_exit(HUBD_MUTEX(hubd)); 6870 hubd_run_callbacks(hubd, tag); 6871 mutex_enter(HUBD_MUTEX(hubd)); 6872 6873 /* close all the open pipes of our children */ 6874 nports = hubd->h_hub_descr.bNbrPorts; 6875 for (port = 1; port <= nports; port++) { 6876 usba_dev = hubd->h_usba_devices[port]; 6877 if (usba_dev != NULL) { 6878 mutex_exit(HUBD_MUTEX(hubd)); 6879 usba_persistent_pipe_close(usba_dev); 6880 mutex_enter(HUBD_MUTEX(hubd)); 6881 } 6882 } 6883 6884 break; 6885 case USB_DEV_DISCONNECTED: 6886 /* avoid passing multiple disconnects to children */ 6887 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6888 "hubd_disconnect_event_cb: Already disconnected"); 6889 6890 break; 6891 default: 6892 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6893 "hubd_disconnect_event_cb: Illegal devstate=%d", 6894 hubd->h_dev_state); 6895 6896 break; 6897 } 6898 mutex_exit(HUBD_MUTEX(hubd)); 6899 6900 ndi_devi_exit(dip, circ); 6901 6902 return (USB_SUCCESS); 6903 } 6904 6905 6906 static int 6907 hubd_reconnect_event_cb(dev_info_t *dip) 6908 { 6909 int rval, circ; 6910 6911 ndi_devi_enter(dip, &circ); 6912 rval = hubd_restore_state_cb(dip); 6913 ndi_devi_exit(dip, circ); 6914 6915 return (rval); 6916 } 6917 6918 6919 /* 6920 * hubd_pre_suspend_event_cb 6921 * propogate event for binary compatibility of old drivers 6922 */ 6923 static int 6924 hubd_pre_suspend_event_cb(dev_info_t *dip) 6925 { 6926 int circ; 6927 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6928 6929 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6930 "hubd_pre_suspend_event_cb"); 6931 6932 /* disable hotplug thread */ 6933 mutex_enter(HUBD_MUTEX(hubd)); 6934 hubd->h_hotplug_thread++; 6935 hubd_stop_polling(hubd); 6936 6937 /* keep PM out till we see a cpr resume */ 6938 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6939 mutex_exit(HUBD_MUTEX(hubd)); 6940 6941 ndi_devi_enter(dip, &circ); 6942 hubd_run_callbacks(hubd, USBA_EVENT_TAG_PRE_SUSPEND); 6943 ndi_devi_exit(dip, circ); 6944 6945 return (USB_SUCCESS); 6946 } 6947 6948 6949 /* 6950 * hubd_post_resume_event_cb 6951 * propogate event for binary compatibility of old drivers 6952 */ 6953 static int 6954 hubd_post_resume_event_cb(dev_info_t *dip) 6955 { 6956 int circ; 6957 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6958 6959 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6960 "hubd_post_resume_event_cb"); 6961 6962 ndi_devi_enter(dip, &circ); 6963 hubd_run_callbacks(hubd, USBA_EVENT_TAG_POST_RESUME); 6964 ndi_devi_exit(dip, circ); 6965 6966 mutex_enter(HUBD_MUTEX(hubd)); 6967 6968 /* enable PM */ 6969 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6970 6971 /* allow hotplug thread */ 6972 hubd->h_hotplug_thread--; 6973 6974 /* start polling */ 6975 hubd_start_polling(hubd, 0); 6976 mutex_exit(HUBD_MUTEX(hubd)); 6977 6978 return (USB_SUCCESS); 6979 } 6980 6981 6982 /* 6983 * hubd_cpr_suspend 6984 * save the current state of the driver/device 6985 */ 6986 static int 6987 hubd_cpr_suspend(hubd_t *hubd) 6988 { 6989 usb_port_t port, nports; 6990 usba_device_t *usba_dev; 6991 uchar_t no_cpr = 0; 6992 int rval = USB_FAILURE; 6993 6994 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6995 "hubd_cpr_suspend: Begin"); 6996 6997 /* Make sure device is powered up to save state. */ 6998 mutex_enter(HUBD_MUTEX(hubd)); 6999 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7000 mutex_exit(HUBD_MUTEX(hubd)); 7001 7002 /* bring the device to full power */ 7003 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7004 mutex_enter(HUBD_MUTEX(hubd)); 7005 7006 switch (hubd->h_dev_state) { 7007 case USB_DEV_ONLINE: 7008 case USB_DEV_PWRED_DOWN: 7009 case USB_DEV_DISCONNECTED: 7010 /* find out if all our children have been quiesced */ 7011 nports = hubd->h_hub_descr.bNbrPorts; 7012 for (port = 1; (no_cpr == 0) && (port <= nports); port++) { 7013 usba_dev = hubd->h_usba_devices[port]; 7014 if (usba_dev != NULL) { 7015 mutex_enter(&usba_dev->usb_mutex); 7016 no_cpr += usba_dev->usb_no_cpr; 7017 mutex_exit(&usba_dev->usb_mutex); 7018 } 7019 } 7020 if (no_cpr > 0) { 7021 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7022 "Children busy - can't checkpoint"); 7023 /* remain in same state to fail checkpoint */ 7024 7025 break; 7026 } else { 7027 /* 7028 * do not suspend if our hotplug thread 7029 * or the deathrow thread is active 7030 */ 7031 if ((hubd->h_hotplug_thread > 1) || 7032 (hubd->h_cleanup_active == B_TRUE)) { 7033 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 7034 hubd->h_log_handle, 7035 "hotplug thread active - can't cpr"); 7036 /* remain in same state to fail checkpoint */ 7037 7038 break; 7039 } 7040 7041 /* quiesce ourselves now */ 7042 hubd_stop_polling(hubd); 7043 7044 /* close all the open pipes of our children */ 7045 for (port = 1; port <= nports; port++) { 7046 usba_dev = hubd->h_usba_devices[port]; 7047 if (usba_dev != NULL) { 7048 mutex_exit(HUBD_MUTEX(hubd)); 7049 usba_persistent_pipe_close(usba_dev); 7050 if (hubd_suspend_port(hubd, port)) { 7051 USB_DPRINTF_L0( 7052 DPRINT_MASK_HOTPLUG, 7053 hubd->h_log_handle, 7054 "suspending port %d failed", 7055 port); 7056 } 7057 mutex_enter(HUBD_MUTEX(hubd)); 7058 } 7059 7060 } 7061 hubd->h_dev_state = USB_DEV_SUSPENDED; 7062 7063 /* 7064 * if we are the root hub, we close our pipes 7065 * ourselves. 7066 */ 7067 if (usba_is_root_hub(hubd->h_dip)) { 7068 mutex_exit(HUBD_MUTEX(hubd)); 7069 usba_persistent_pipe_close( 7070 usba_get_usba_device(hubd->h_dip)); 7071 mutex_enter(HUBD_MUTEX(hubd)); 7072 } 7073 rval = USB_SUCCESS; 7074 7075 break; 7076 } 7077 case USB_DEV_SUSPENDED: 7078 default: 7079 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7080 "hubd_cpr_suspend: Illegal dev state=%d", 7081 hubd->h_dev_state); 7082 7083 break; 7084 } 7085 7086 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7087 mutex_exit(HUBD_MUTEX(hubd)); 7088 7089 return (rval); 7090 } 7091 7092 static void 7093 hubd_cpr_resume(dev_info_t *dip) 7094 { 7095 int rval, circ; 7096 7097 ndi_devi_enter(dip, &circ); 7098 /* 7099 * if we are the root hub, we open our pipes 7100 * ourselves. 7101 */ 7102 if (usba_is_root_hub(dip)) { 7103 rval = usba_persistent_pipe_open( 7104 usba_get_usba_device(dip)); 7105 ASSERT(rval == USB_SUCCESS); 7106 } 7107 (void) hubd_restore_state_cb(dip); 7108 ndi_devi_exit(dip, circ); 7109 } 7110 7111 7112 /* 7113 * hubd_restore_state_cb 7114 * Event callback to restore device state 7115 */ 7116 static int 7117 hubd_restore_state_cb(dev_info_t *dip) 7118 { 7119 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 7120 7121 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7122 "hubd_restore_state_cb: Begin"); 7123 7124 /* restore the state of this device */ 7125 hubd_restore_device_state(dip, hubd); 7126 7127 return (USB_SUCCESS); 7128 } 7129 7130 7131 /* 7132 * registering for events 7133 */ 7134 static int 7135 hubd_register_events(hubd_t *hubd) 7136 { 7137 int rval = USB_SUCCESS; 7138 7139 if (usba_is_root_hub(hubd->h_dip)) { 7140 hubd_register_cpr_callback(hubd); 7141 } else { 7142 rval = usb_register_event_cbs(hubd->h_dip, &hubd_events, 0); 7143 } 7144 7145 return (rval); 7146 } 7147 7148 7149 /* 7150 * hubd cpr callback related functions 7151 * 7152 * hubd_cpr_post_user_callb: 7153 * This function is called during checkpoint & resume - 7154 * 1. after user threads are stopped during checkpoint 7155 * 2. after kernel threads are resumed during resume 7156 */ 7157 /* ARGSUSED */ 7158 static boolean_t 7159 hubd_cpr_post_user_callb(void *arg, int code) 7160 { 7161 hubd_cpr_t *cpr_cb = (hubd_cpr_t *)arg; 7162 hubd_t *hubd = cpr_cb->statep; 7163 int retry = 0; 7164 7165 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7166 "hubd_cpr_post_user_callb"); 7167 7168 switch (code) { 7169 case CB_CODE_CPR_CHKPT: 7170 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7171 "hubd_cpr_post_user_callb: CB_CODE_CPR_CHKPT"); 7172 7173 mutex_enter(HUBD_MUTEX(hubd)); 7174 7175 /* turn off deathrow thread */ 7176 hubd->h_cleanup_enabled = B_FALSE; 7177 7178 /* give up if deathrow thread doesn't exit */ 7179 while ((hubd->h_cleanup_active == B_TRUE) && (retry++ < 3)) { 7180 mutex_exit(HUBD_MUTEX(hubd)); 7181 delay(drv_usectohz(hubd_dip_cleanup_delay)); 7182 7183 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7184 "hubd_cpr_post_user_callb, waiting for " 7185 "deathrow thread to exit"); 7186 mutex_enter(HUBD_MUTEX(hubd)); 7187 } 7188 7189 mutex_exit(HUBD_MUTEX(hubd)); 7190 7191 /* save the state of the device */ 7192 (void) hubd_pre_suspend_event_cb(hubd->h_dip); 7193 7194 return (B_TRUE); 7195 case CB_CODE_CPR_RESUME: 7196 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7197 "hubd_cpr_post_user_callb: CB_CODE_CPR_RESUME"); 7198 7199 /* restore the state of the device */ 7200 (void) hubd_post_resume_event_cb(hubd->h_dip); 7201 7202 /* turn on deathrow thread */ 7203 mutex_enter(HUBD_MUTEX(hubd)); 7204 hubd->h_cleanup_enabled = B_TRUE; 7205 mutex_exit(HUBD_MUTEX(hubd)); 7206 7207 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 7208 7209 return (B_TRUE); 7210 default: 7211 7212 return (B_FALSE); 7213 } 7214 7215 } 7216 7217 7218 /* register callback with cpr framework */ 7219 void 7220 hubd_register_cpr_callback(hubd_t *hubd) 7221 { 7222 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7223 "hubd_register_cpr_callback"); 7224 7225 mutex_enter(HUBD_MUTEX(hubd)); 7226 hubd->h_cpr_cb = 7227 (hubd_cpr_t *)kmem_zalloc(sizeof (hubd_cpr_t), KM_SLEEP); 7228 mutex_exit(HUBD_MUTEX(hubd)); 7229 mutex_init(&hubd->h_cpr_cb->lockp, NULL, MUTEX_DRIVER, 7230 hubd->h_dev_data->dev_iblock_cookie); 7231 hubd->h_cpr_cb->statep = hubd; 7232 hubd->h_cpr_cb->cpr.cc_lockp = &hubd->h_cpr_cb->lockp; 7233 hubd->h_cpr_cb->cpr.cc_id = callb_add(hubd_cpr_post_user_callb, 7234 (void *)hubd->h_cpr_cb, CB_CL_CPR_POST_USER, "hubd"); 7235 } 7236 7237 7238 /* unregister callback with cpr framework */ 7239 void 7240 hubd_unregister_cpr_callback(hubd_t *hubd) 7241 { 7242 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7243 "hubd_unregister_cpr_callback"); 7244 7245 if (hubd->h_cpr_cb) { 7246 (void) callb_delete(hubd->h_cpr_cb->cpr.cc_id); 7247 mutex_destroy(&hubd->h_cpr_cb->lockp); 7248 mutex_enter(HUBD_MUTEX(hubd)); 7249 kmem_free(hubd->h_cpr_cb, sizeof (hubd_cpr_t)); 7250 mutex_exit(HUBD_MUTEX(hubd)); 7251 } 7252 } 7253 7254 7255 /* 7256 * Power management 7257 * 7258 * create the pm components required for power management 7259 */ 7260 static void 7261 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd) 7262 { 7263 hub_power_t *hubpm; 7264 7265 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7266 "hubd_create_pm_components: Begin"); 7267 7268 /* Allocate the state structure */ 7269 hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP); 7270 7271 hubd->h_hubpm = hubpm; 7272 hubpm->hubp_hubd = hubd; 7273 hubpm->hubp_pm_capabilities = 0; 7274 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 7275 hubpm->hubp_time_at_full_power = ddi_get_time(); 7276 hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold; 7277 7278 /* alloc memory to save power states of children */ 7279 hubpm->hubp_child_pwrstate = (uint8_t *) 7280 kmem_zalloc(MAX_PORTS + 1, KM_SLEEP); 7281 7282 /* 7283 * if the enable remote wakeup fails 7284 * we still want to enable 7285 * parent notification so we can PM the children 7286 */ 7287 usb_enable_parent_notification(dip); 7288 7289 if (usb_handle_remote_wakeup(dip, 7290 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 7291 uint_t pwr_states; 7292 7293 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 7294 "hubd_create_pm_components: " 7295 "Remote Wakeup Enabled"); 7296 7297 if (usb_create_pm_components(dip, &pwr_states) == 7298 USB_SUCCESS) { 7299 mutex_enter(HUBD_MUTEX(hubd)); 7300 hubpm->hubp_wakeup_enabled = 1; 7301 hubpm->hubp_pwr_states = (uint8_t)pwr_states; 7302 7303 /* we are busy now till end of the attach */ 7304 hubd_pm_busy_component(hubd, dip, 0); 7305 mutex_exit(HUBD_MUTEX(hubd)); 7306 7307 /* bring the device to full power */ 7308 (void) pm_raise_power(dip, 0, 7309 USB_DEV_OS_FULL_PWR); 7310 } 7311 } 7312 7313 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7314 "hubd_create_pm_components: END"); 7315 } 7316 7317 7318 /* 7319 * Attachment point management 7320 */ 7321 /* ARGSUSED */ 7322 int 7323 usba_hubdi_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, 7324 cred_t *credp) 7325 { 7326 hubd_t *hubd; 7327 7328 if (otyp != OTYP_CHR) 7329 return (EINVAL); 7330 7331 hubd = hubd_get_soft_state(dip); 7332 if (hubd == NULL) { 7333 return (ENXIO); 7334 } 7335 7336 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7337 "hubd_open:"); 7338 7339 mutex_enter(HUBD_MUTEX(hubd)); 7340 if ((flags & FEXCL) && (hubd->h_softstate & HUBD_SS_ISOPEN)) { 7341 mutex_exit(HUBD_MUTEX(hubd)); 7342 7343 return (EBUSY); 7344 } 7345 7346 hubd->h_softstate |= HUBD_SS_ISOPEN; 7347 mutex_exit(HUBD_MUTEX(hubd)); 7348 7349 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "opened"); 7350 7351 return (0); 7352 } 7353 7354 7355 /* ARGSUSED */ 7356 int 7357 usba_hubdi_close(dev_info_t *dip, dev_t dev, int flag, int otyp, 7358 cred_t *credp) 7359 { 7360 hubd_t *hubd; 7361 7362 if (otyp != OTYP_CHR) { 7363 return (EINVAL); 7364 } 7365 7366 hubd = hubd_get_soft_state(dip); 7367 7368 if (hubd == NULL) { 7369 return (ENXIO); 7370 } 7371 7372 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "hubd_close:"); 7373 7374 mutex_enter(HUBD_MUTEX(hubd)); 7375 hubd->h_softstate &= ~HUBD_SS_ISOPEN; 7376 mutex_exit(HUBD_MUTEX(hubd)); 7377 7378 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "closed"); 7379 7380 return (0); 7381 } 7382 7383 7384 /* 7385 * hubd_ioctl: cfgadm controls 7386 */ 7387 /* ARGSUSED */ 7388 int 7389 usba_hubdi_ioctl(dev_info_t *self, dev_t dev, int cmd, intptr_t arg, 7390 int mode, cred_t *credp, int *rvalp) 7391 { 7392 int rv = 0; 7393 char *msg; /* for messages */ 7394 hubd_t *hubd; 7395 usb_port_t port = 0; 7396 dev_info_t *child_dip = NULL; 7397 dev_info_t *rh_dip; 7398 devctl_ap_state_t ap_state; 7399 struct devctl_iocdata *dcp = NULL; 7400 usb_pipe_state_t prev_pipe_state = 0; 7401 int circ, rh_circ, prh_circ; 7402 7403 if ((hubd = hubd_get_soft_state(self)) == NULL) { 7404 7405 return (ENXIO); 7406 } 7407 7408 rh_dip = hubd->h_usba_device->usb_root_hub_dip; 7409 7410 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7411 "usba_hubdi_ioctl: " 7412 "cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx", 7413 cmd, arg, mode, (void *)credp, (void *)rvalp, dev); 7414 7415 /* read devctl ioctl data */ 7416 if ((cmd != DEVCTL_AP_CONTROL) && 7417 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 7418 7419 return (EFAULT); 7420 } 7421 7422 /* 7423 * make sure the hub is connected before trying any 7424 * of the following operations: 7425 * configure, connect, disconnect 7426 */ 7427 mutex_enter(HUBD_MUTEX(hubd)); 7428 7429 switch (cmd) { 7430 case DEVCTL_AP_DISCONNECT: 7431 case DEVCTL_AP_UNCONFIGURE: 7432 case DEVCTL_AP_CONFIGURE: 7433 if (hubd->h_dev_state == USB_DEV_DISCONNECTED) { 7434 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7435 "hubd: already gone"); 7436 mutex_exit(HUBD_MUTEX(hubd)); 7437 if (dcp) { 7438 ndi_dc_freehdl(dcp); 7439 } 7440 7441 return (EIO); 7442 } 7443 7444 /* FALLTHROUGH */ 7445 case DEVCTL_AP_GETSTATE: 7446 if ((port = hubd_get_port_num(hubd, dcp)) == 0) { 7447 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7448 "hubd: bad port"); 7449 mutex_exit(HUBD_MUTEX(hubd)); 7450 if (dcp) { 7451 ndi_dc_freehdl(dcp); 7452 } 7453 7454 return (EINVAL); 7455 } 7456 break; 7457 7458 case DEVCTL_AP_CONTROL: 7459 7460 break; 7461 default: 7462 mutex_exit(HUBD_MUTEX(hubd)); 7463 if (dcp) { 7464 ndi_dc_freehdl(dcp); 7465 } 7466 7467 return (ENOTTY); 7468 } 7469 7470 /* should not happen, just in case */ 7471 if (hubd->h_dev_state == USB_DEV_SUSPENDED) { 7472 mutex_exit(HUBD_MUTEX(hubd)); 7473 if (dcp) { 7474 ndi_dc_freehdl(dcp); 7475 } 7476 7477 return (EIO); 7478 } 7479 7480 if (hubd->h_reset_port[port]) { 7481 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7482 "This port is resetting, just return"); 7483 mutex_exit(HUBD_MUTEX(hubd)); 7484 if (dcp) { 7485 ndi_dc_freehdl(dcp); 7486 } 7487 7488 return (EIO); 7489 } 7490 7491 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7492 mutex_exit(HUBD_MUTEX(hubd)); 7493 7494 /* go full power */ 7495 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7496 7497 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 7498 ndi_devi_enter(rh_dip, &rh_circ); 7499 ndi_devi_enter(hubd->h_dip, &circ); 7500 7501 mutex_enter(HUBD_MUTEX(hubd)); 7502 7503 hubd->h_hotplug_thread++; 7504 7505 /* stop polling if it was active */ 7506 if (hubd->h_ep1_ph) { 7507 mutex_exit(HUBD_MUTEX(hubd)); 7508 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 7509 USB_FLAGS_SLEEP); 7510 mutex_enter(HUBD_MUTEX(hubd)); 7511 7512 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 7513 hubd_stop_polling(hubd); 7514 } 7515 } 7516 7517 switch (cmd) { 7518 case DEVCTL_AP_DISCONNECT: 7519 if (hubd_delete_child(hubd, port, 7520 NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS) { 7521 rv = EIO; 7522 } 7523 7524 break; 7525 case DEVCTL_AP_UNCONFIGURE: 7526 if (hubd_delete_child(hubd, port, 7527 NDI_UNCONFIG, B_FALSE) != USB_SUCCESS) { 7528 rv = EIO; 7529 } 7530 7531 break; 7532 case DEVCTL_AP_CONFIGURE: 7533 /* toggle port */ 7534 if (hubd_toggle_port(hubd, port) != USB_SUCCESS) { 7535 rv = EIO; 7536 7537 break; 7538 } 7539 7540 (void) hubd_handle_port_connect(hubd, port); 7541 child_dip = hubd_get_child_dip(hubd, port); 7542 mutex_exit(HUBD_MUTEX(hubd)); 7543 7544 ndi_devi_exit(hubd->h_dip, circ); 7545 ndi_devi_exit(rh_dip, rh_circ); 7546 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 7547 if (child_dip == NULL) { 7548 rv = EIO; 7549 } else { 7550 ndi_hold_devi(child_dip); 7551 if (ndi_devi_online(child_dip, 0) != NDI_SUCCESS) 7552 rv = EIO; 7553 ndi_rele_devi(child_dip); 7554 } 7555 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 7556 ndi_devi_enter(rh_dip, &rh_circ); 7557 ndi_devi_enter(hubd->h_dip, &circ); 7558 7559 mutex_enter(HUBD_MUTEX(hubd)); 7560 7561 break; 7562 case DEVCTL_AP_GETSTATE: 7563 switch (hubd_cfgadm_state(hubd, port)) { 7564 case HUBD_CFGADM_DISCONNECTED: 7565 /* port previously 'disconnected' by cfgadm */ 7566 ap_state.ap_rstate = AP_RSTATE_DISCONNECTED; 7567 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7568 ap_state.ap_condition = AP_COND_OK; 7569 7570 break; 7571 case HUBD_CFGADM_UNCONFIGURED: 7572 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7573 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7574 ap_state.ap_condition = AP_COND_OK; 7575 7576 break; 7577 case HUBD_CFGADM_CONFIGURED: 7578 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7579 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7580 ap_state.ap_condition = AP_COND_OK; 7581 7582 break; 7583 case HUBD_CFGADM_STILL_REFERENCED: 7584 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7585 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7586 ap_state.ap_condition = AP_COND_UNUSABLE; 7587 7588 break; 7589 case HUBD_CFGADM_EMPTY: 7590 default: 7591 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7592 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7593 ap_state.ap_condition = AP_COND_OK; 7594 7595 break; 7596 } 7597 7598 ap_state.ap_last_change = (time_t)-1; 7599 ap_state.ap_error_code = 0; 7600 ap_state.ap_in_transition = 0; 7601 7602 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7603 "DEVCTL_AP_GETSTATE: " 7604 "ostate=0x%x, rstate=0x%x, condition=0x%x", 7605 ap_state.ap_ostate, 7606 ap_state.ap_rstate, ap_state.ap_condition); 7607 7608 /* copy the return-AP-state information to the user space */ 7609 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 7610 rv = EFAULT; 7611 } 7612 7613 break; 7614 case DEVCTL_AP_CONTROL: 7615 { 7616 /* 7617 * Generic devctl for hardware-specific functionality. 7618 * For list of sub-commands see hubd_impl.h 7619 */ 7620 hubd_ioctl_data_t ioc; /* for 64 byte copies */ 7621 7622 /* copy user ioctl data in first */ 7623 #ifdef _MULTI_DATAMODEL 7624 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 7625 hubd_ioctl_data_32_t ioc32; 7626 7627 if (ddi_copyin((void *)arg, (void *)&ioc32, 7628 sizeof (ioc32), mode) != 0) { 7629 rv = EFAULT; 7630 7631 break; 7632 } 7633 ioc.cmd = (uint_t)ioc32.cmd; 7634 ioc.port = (uint_t)ioc32.port; 7635 ioc.get_size = (uint_t)ioc32.get_size; 7636 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 7637 ioc.bufsiz = (uint_t)ioc32.bufsiz; 7638 ioc.misc_arg = (uint_t)ioc32.misc_arg; 7639 } else 7640 #endif /* _MULTI_DATAMODEL */ 7641 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc), 7642 mode) != 0) { 7643 rv = EFAULT; 7644 7645 break; 7646 } 7647 7648 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7649 "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d" 7650 "\n\tbuf=0x%p, bufsiz=%d, misc_arg=%d", ioc.cmd, 7651 ioc.port, ioc.get_size, (void *)ioc.buf, ioc.bufsiz, 7652 ioc.misc_arg); 7653 7654 /* 7655 * To avoid BE/LE and 32/64 issues, a get_size always 7656 * returns a 32-bit number. 7657 */ 7658 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) { 7659 rv = EINVAL; 7660 7661 break; 7662 } 7663 7664 switch (ioc.cmd) { 7665 case USB_DESCR_TYPE_DEV: 7666 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC"; 7667 if (ioc.get_size) { 7668 /* uint32 so this works 32/64 */ 7669 uint32_t size = sizeof (usb_dev_descr_t); 7670 7671 if (ddi_copyout((void *)&size, ioc.buf, 7672 ioc.bufsiz, mode) != 0) { 7673 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7674 hubd->h_log_handle, 7675 "%s: get_size copyout failed", msg); 7676 rv = EIO; 7677 7678 break; 7679 } 7680 } else { /* send out the actual descr */ 7681 usb_dev_descr_t *dev_descrp; 7682 7683 /* check child_dip */ 7684 if ((child_dip = hubd_get_child_dip(hubd, 7685 ioc.port)) == NULL) { 7686 rv = EINVAL; 7687 7688 break; 7689 } 7690 7691 dev_descrp = usb_get_dev_descr(child_dip); 7692 if (ioc.bufsiz != sizeof (*dev_descrp)) { 7693 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7694 hubd->h_log_handle, 7695 "%s: bufsize passed (%d) != sizeof " 7696 "usba_device_descr_t (%d)", msg, 7697 ioc.bufsiz, dev_descrp->bLength); 7698 rv = EINVAL; 7699 7700 break; 7701 } 7702 7703 if (ddi_copyout((void *)dev_descrp, 7704 ioc.buf, ioc.bufsiz, mode) != 0) { 7705 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7706 hubd->h_log_handle, 7707 "%s: copyout failed.", msg); 7708 rv = EIO; 7709 7710 break; 7711 } 7712 } 7713 break; 7714 case USB_DESCR_TYPE_STRING: 7715 { 7716 char *str; 7717 uint32_t size; 7718 usba_device_t *usba_device; 7719 7720 msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR"; 7721 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7722 "%s: string request: %d", msg, ioc.misc_arg); 7723 7724 /* recheck */ 7725 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7726 NULL) { 7727 rv = EINVAL; 7728 7729 break; 7730 } 7731 usba_device = usba_get_usba_device(child_dip); 7732 7733 switch (ioc.misc_arg) { 7734 case HUBD_MFG_STR: 7735 str = usba_device->usb_mfg_str; 7736 7737 break; 7738 case HUBD_PRODUCT_STR: 7739 str = usba_device->usb_product_str; 7740 7741 break; 7742 case HUBD_SERIALNO_STR: 7743 str = usba_device->usb_serialno_str; 7744 7745 break; 7746 case HUBD_CFG_DESCR_STR: 7747 mutex_enter(&usba_device->usb_mutex); 7748 str = usba_device->usb_cfg_str_descr[ 7749 usba_device->usb_active_cfg_ndx]; 7750 mutex_exit(&usba_device->usb_mutex); 7751 7752 break; 7753 default: 7754 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7755 hubd->h_log_handle, 7756 "%s: Invalid string request", msg); 7757 rv = EINVAL; 7758 7759 break; 7760 } /* end of switch */ 7761 7762 if (rv != 0) { 7763 7764 break; 7765 } 7766 7767 size = (str != NULL) ? strlen(str) + 1 : 0; 7768 if (ioc.get_size) { 7769 if (ddi_copyout((void *)&size, ioc.buf, 7770 ioc.bufsiz, mode) != 0) { 7771 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7772 hubd->h_log_handle, 7773 "%s: copyout of size failed.", msg); 7774 rv = EIO; 7775 7776 break; 7777 } 7778 } else { 7779 if (size == 0) { 7780 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, 7781 hubd->h_log_handle, 7782 "%s: String is NULL", msg); 7783 rv = EINVAL; 7784 7785 break; 7786 } 7787 7788 if (ioc.bufsiz != size) { 7789 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7790 hubd->h_log_handle, 7791 "%s: string buf size wrong", msg); 7792 rv = EINVAL; 7793 7794 break; 7795 } 7796 7797 if (ddi_copyout((void *)str, ioc.buf, 7798 ioc.bufsiz, mode) != 0) { 7799 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7800 hubd->h_log_handle, 7801 "%s: copyout failed.", msg); 7802 rv = EIO; 7803 7804 break; 7805 } 7806 } 7807 break; 7808 } 7809 case HUBD_GET_CFGADM_NAME: 7810 { 7811 uint32_t name_len; 7812 const char *name; 7813 7814 /* recheck */ 7815 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7816 NULL) { 7817 rv = EINVAL; 7818 7819 break; 7820 } 7821 name = ddi_node_name(child_dip); 7822 if (name == NULL) { 7823 name = "unsupported"; 7824 } 7825 name_len = strlen(name) + 1; 7826 7827 msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME"; 7828 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7829 "%s: name=%s name_len=%d", msg, name, name_len); 7830 7831 if (ioc.get_size) { 7832 if (ddi_copyout((void *)&name_len, 7833 ioc.buf, ioc.bufsiz, mode) != 0) { 7834 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7835 hubd->h_log_handle, 7836 "%s: copyout of size failed", msg); 7837 rv = EIO; 7838 7839 break; 7840 } 7841 } else { 7842 if (ioc.bufsiz != name_len) { 7843 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7844 hubd->h_log_handle, 7845 "%s: string buf length wrong", msg); 7846 rv = EINVAL; 7847 7848 break; 7849 } 7850 7851 if (ddi_copyout((void *)name, ioc.buf, 7852 ioc.bufsiz, mode) != 0) { 7853 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7854 hubd->h_log_handle, 7855 "%s: copyout failed.", msg); 7856 rv = EIO; 7857 7858 break; 7859 } 7860 } 7861 7862 break; 7863 } 7864 7865 /* 7866 * Return the config index for the currently-configured 7867 * configuration. 7868 */ 7869 case HUBD_GET_CURRENT_CONFIG: 7870 { 7871 uint_t config_index; 7872 uint32_t size = sizeof (config_index); 7873 usba_device_t *usba_device; 7874 7875 msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG"; 7876 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7877 "%s", msg); 7878 7879 /* 7880 * Return the config index for the configuration 7881 * currently in use. 7882 * Recheck if child_dip exists 7883 */ 7884 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7885 NULL) { 7886 rv = EINVAL; 7887 7888 break; 7889 } 7890 7891 usba_device = usba_get_usba_device(child_dip); 7892 mutex_enter(&usba_device->usb_mutex); 7893 config_index = usba_device->usb_active_cfg_ndx; 7894 mutex_exit(&usba_device->usb_mutex); 7895 7896 if (ioc.get_size) { 7897 if (ddi_copyout((void *)&size, 7898 ioc.buf, ioc.bufsiz, mode) != 0) { 7899 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7900 hubd->h_log_handle, 7901 "%s: copyout of size failed.", msg); 7902 rv = EIO; 7903 7904 break; 7905 } 7906 } else { 7907 if (ioc.bufsiz != size) { 7908 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7909 hubd->h_log_handle, 7910 "%s: buffer size wrong", msg); 7911 rv = EINVAL; 7912 7913 break; 7914 } 7915 if (ddi_copyout((void *)&config_index, 7916 ioc.buf, ioc.bufsiz, mode) != 0) { 7917 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7918 hubd->h_log_handle, 7919 "%s: copyout failed", msg); 7920 rv = EIO; 7921 } 7922 } 7923 7924 break; 7925 } 7926 case HUBD_GET_DEVICE_PATH: 7927 { 7928 char *path; 7929 uint32_t size; 7930 7931 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH"; 7932 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7933 "%s", msg); 7934 7935 /* Recheck if child_dip exists */ 7936 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7937 NULL) { 7938 rv = EINVAL; 7939 7940 break; 7941 } 7942 7943 /* ddi_pathname doesn't supply /devices, so we do. */ 7944 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7945 (void) strcpy(path, "/devices"); 7946 (void) ddi_pathname(child_dip, path + strlen(path)); 7947 size = strlen(path) + 1; 7948 7949 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7950 "%s: device path=%s size=%d", msg, path, size); 7951 7952 if (ioc.get_size) { 7953 if (ddi_copyout((void *)&size, 7954 ioc.buf, ioc.bufsiz, mode) != 0) { 7955 7956 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7957 hubd->h_log_handle, 7958 "%s: copyout of size failed.", msg); 7959 rv = EIO; 7960 } 7961 } else { 7962 if (ioc.bufsiz != size) { 7963 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7964 hubd->h_log_handle, 7965 "%s: buffer wrong size.", msg); 7966 rv = EINVAL; 7967 } else if (ddi_copyout((void *)path, 7968 ioc.buf, ioc.bufsiz, mode) != 0) { 7969 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7970 hubd->h_log_handle, 7971 "%s: copyout failed.", msg); 7972 rv = EIO; 7973 } 7974 } 7975 kmem_free(path, MAXPATHLEN); 7976 7977 break; 7978 } 7979 case HUBD_REFRESH_DEVDB: 7980 msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB"; 7981 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7982 "%s", msg); 7983 7984 if ((rv = usba_devdb_refresh()) != USB_SUCCESS) { 7985 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7986 hubd->h_log_handle, 7987 "%s: Failed: %d", msg, rv); 7988 rv = EIO; 7989 } 7990 7991 break; 7992 default: 7993 rv = ENOTSUP; 7994 } /* end switch */ 7995 7996 break; 7997 } 7998 7999 default: 8000 rv = ENOTTY; 8001 } 8002 8003 if (dcp) { 8004 ndi_dc_freehdl(dcp); 8005 } 8006 8007 /* allow hotplug thread now */ 8008 hubd->h_hotplug_thread--; 8009 8010 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 8011 hubd->h_ep1_ph && (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 8012 hubd_start_polling(hubd, 0); 8013 } 8014 mutex_exit(HUBD_MUTEX(hubd)); 8015 8016 ndi_devi_exit(hubd->h_dip, circ); 8017 ndi_devi_exit(rh_dip, rh_circ); 8018 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 8019 8020 mutex_enter(HUBD_MUTEX(hubd)); 8021 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 8022 mutex_exit(HUBD_MUTEX(hubd)); 8023 8024 return (rv); 8025 } 8026 8027 8028 /* 8029 * Helper func used only to help construct the names for the attachment point 8030 * minor nodes. Used only in usba_hubdi_attach. 8031 * Returns whether it found ancestry or not (USB_SUCCESS if yes). 8032 * ports between the root hub and the device represented by dip. 8033 * E.g., "2.4.3.1" means this device is 8034 * plugged into port 1 of a hub that is 8035 * plugged into port 3 of a hub that is 8036 * plugged into port 4 of a hub that is 8037 * plugged into port 2 of the root hub. 8038 * NOTE: Max ap_id path len is HUBD_APID_NAMELEN (32 chars), which is 8039 * more than sufficient (as hubs are a max 6 levels deep, port needs 3 8040 * chars plus NULL each) 8041 */ 8042 void 8043 hubd_get_ancestry_str(hubd_t *hubd) 8044 { 8045 char ap_name[HUBD_APID_NAMELEN]; 8046 dev_info_t *pdip; 8047 hubd_t *phubd; 8048 usb_port_t port; 8049 8050 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8051 "hubd_get_ancestry_str: hubd=0x%p", (void *)hubd); 8052 8053 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8054 8055 /* 8056 * The function is extended to support wire adapter class 8057 * devices introduced by WUSB spec. The node name is no 8058 * longer "hub" only. 8059 * Generate the ap_id str based on the parent and child 8060 * relationship instead of retrieving it from the hub 8061 * device path, which simplifies the algorithm. 8062 */ 8063 if (usba_is_root_hub(hubd->h_dip)) { 8064 hubd->h_ancestry_str[0] = '\0'; 8065 } else { 8066 port = hubd->h_usba_device->usb_port; 8067 mutex_exit(HUBD_MUTEX(hubd)); 8068 8069 pdip = ddi_get_parent(hubd->h_dip); 8070 /* 8071 * The parent of wire adapter device might be usb_mid. 8072 * Need to look further up for hub device 8073 */ 8074 if (strcmp(ddi_driver_name(pdip), "usb_mid") == 0) { 8075 pdip = ddi_get_parent(pdip); 8076 ASSERT(pdip != NULL); 8077 } 8078 8079 phubd = hubd_get_soft_state(pdip); 8080 8081 mutex_enter(HUBD_MUTEX(phubd)); 8082 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 8083 phubd->h_ancestry_str, port); 8084 mutex_exit(HUBD_MUTEX(phubd)); 8085 8086 mutex_enter(HUBD_MUTEX(hubd)); 8087 (void) strcpy(hubd->h_ancestry_str, ap_name); 8088 (void) strcat(hubd->h_ancestry_str, "."); 8089 } 8090 } 8091 8092 8093 /* Get which port to operate on. */ 8094 static usb_port_t 8095 hubd_get_port_num(hubd_t *hubd, struct devctl_iocdata *dcp) 8096 { 8097 int32_t port; 8098 8099 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8100 8101 /* Get which port to operate on. */ 8102 if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) { 8103 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8104 "hubd_get_port_num: port lookup failed"); 8105 port = 0; 8106 } 8107 8108 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8109 "hubd_get_port_num: hubd=0x%p, port=%d", (void *)hubd, port); 8110 8111 return ((usb_port_t)port); 8112 } 8113 8114 8115 /* check if child still exists */ 8116 static dev_info_t * 8117 hubd_get_child_dip(hubd_t *hubd, usb_port_t port) 8118 { 8119 dev_info_t *child_dip = hubd->h_children_dips[port]; 8120 8121 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8122 "hubd_get_child_dip: hubd=0x%p, port=%d", (void *)hubd, port); 8123 8124 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8125 8126 return (child_dip); 8127 } 8128 8129 8130 /* 8131 * hubd_cfgadm_state: 8132 * 8133 * child_dip list port_state cfgadm_state 8134 * -------------- ---------- ------------ 8135 * != NULL connected configured or 8136 * unconfigured 8137 * != NULL not connected disconnect but 8138 * busy/still referenced 8139 * NULL connected logically disconnected 8140 * NULL not connected empty 8141 */ 8142 static uint_t 8143 hubd_cfgadm_state(hubd_t *hubd, usb_port_t port) 8144 { 8145 uint_t state; 8146 dev_info_t *child_dip = hubd_get_child_dip(hubd, port); 8147 8148 if (child_dip) { 8149 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 8150 /* 8151 * connected, now check if driver exists 8152 */ 8153 if (DEVI_IS_DEVICE_OFFLINE(child_dip) || 8154 !i_ddi_devi_attached(child_dip)) { 8155 state = HUBD_CFGADM_UNCONFIGURED; 8156 } else { 8157 state = HUBD_CFGADM_CONFIGURED; 8158 } 8159 } else { 8160 /* 8161 * this means that the dip is around for 8162 * a device that is still referenced but 8163 * has been yanked out. So the cfgadm info 8164 * for this state should be EMPTY (port empty) 8165 * and CONFIGURED (dip still valid). 8166 */ 8167 state = HUBD_CFGADM_STILL_REFERENCED; 8168 } 8169 } else { 8170 /* connected but no child dip */ 8171 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 8172 /* logically disconnected */ 8173 state = HUBD_CFGADM_DISCONNECTED; 8174 } else { 8175 /* physically disconnected */ 8176 state = HUBD_CFGADM_EMPTY; 8177 } 8178 } 8179 8180 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8181 "hubd_cfgadm_state: hubd=0x%p, port=%d state=0x%x", 8182 (void *)hubd, port, state); 8183 8184 return (state); 8185 } 8186 8187 8188 /* 8189 * hubd_toggle_port: 8190 */ 8191 static int 8192 hubd_toggle_port(hubd_t *hubd, usb_port_t port) 8193 { 8194 usb_hub_descr_t *hub_descr; 8195 int wait; 8196 uint_t retry; 8197 uint16_t status; 8198 uint16_t change; 8199 8200 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8201 "hubd_toggle_port: hubd=0x%p, port=%d", (void *)hubd, port); 8202 8203 if ((hubd_disable_port_power(hubd, port)) != USB_SUCCESS) { 8204 8205 return (USB_FAILURE); 8206 } 8207 8208 /* 8209 * see hubd_enable_all_port_power() which 8210 * requires longer delay for hubs. 8211 */ 8212 mutex_exit(HUBD_MUTEX(hubd)); 8213 delay(drv_usectohz(hubd_device_delay / 10)); 8214 mutex_enter(HUBD_MUTEX(hubd)); 8215 8216 hub_descr = &hubd->h_hub_descr; 8217 8218 /* 8219 * According to section 11.11 of USB, for hubs with no power 8220 * switches, bPwrOn2PwrGood is zero. But we wait for some 8221 * arbitrary time to enable power to become stable. 8222 * 8223 * If an hub supports port power swicthing, we need to wait 8224 * at least 20ms before accesing corresonding usb port. 8225 */ 8226 if ((hub_descr->wHubCharacteristics & 8227 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 8228 wait = hubd_device_delay / 10; 8229 } else { 8230 wait = max(HUB_DEFAULT_POPG, 8231 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 8232 } 8233 8234 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 8235 "hubd_toggle_port: popg=%d wait=%d", 8236 hub_descr->bPwrOn2PwrGood, wait); 8237 8238 retry = 0; 8239 8240 do { 8241 (void) hubd_enable_port_power(hubd, port); 8242 8243 mutex_exit(HUBD_MUTEX(hubd)); 8244 delay(drv_usectohz(wait)); 8245 mutex_enter(HUBD_MUTEX(hubd)); 8246 8247 /* Get port status */ 8248 (void) hubd_determine_port_status(hubd, port, 8249 &status, &change, 0); 8250 8251 /* For retry if any, use some extra delay */ 8252 wait = max(wait, hubd_device_delay / 10); 8253 8254 retry++; 8255 8256 } while ((!(status & PORT_STATUS_PPS)) && (retry < HUBD_PORT_RETRY)); 8257 8258 /* Print warning message if port has no power */ 8259 if (!(status & PORT_STATUS_PPS)) { 8260 8261 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 8262 "hubd_toggle_port: port %d power-on failed, " 8263 "port status 0x%x", port, status); 8264 8265 return (USB_FAILURE); 8266 } 8267 8268 return (USB_SUCCESS); 8269 } 8270 8271 8272 /* 8273 * hubd_init_power_budget: 8274 * Init power budget variables in hubd structure. According 8275 * to USB spec, the power budget rules are: 8276 * 1. local-powered hubs including root-hubs can supply 8277 * 500mA to each port at maximum 8278 * 2. two bus-powered hubs are not allowed to concatenate 8279 * 3. bus-powered hubs can supply 100mA to each port at 8280 * maximum, and the power consumed by all downstream 8281 * ports and the hub itself cannot exceed the max power 8282 * supplied by the upstream port, i.e., 500mA 8283 * The routine is only called during hub attach time 8284 */ 8285 static int 8286 hubd_init_power_budget(hubd_t *hubd) 8287 { 8288 uint16_t status = 0; 8289 usba_device_t *hubd_ud = NULL; 8290 size_t size; 8291 usb_cfg_descr_t cfg_descr; 8292 dev_info_t *pdip = NULL; 8293 hubd_t *phubd = NULL; 8294 8295 if (hubd->h_ignore_pwr_budget) { 8296 8297 return (USB_SUCCESS); 8298 } 8299 8300 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 8301 "hubd_init_power_budget:"); 8302 8303 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8304 ASSERT(hubd->h_default_pipe != 0); 8305 mutex_exit(HUBD_MUTEX(hubd)); 8306 8307 /* get device status */ 8308 if ((usb_get_status(hubd->h_dip, hubd->h_default_pipe, 8309 HUB_GET_DEVICE_STATUS_TYPE, 8310 0, &status, 0)) != USB_SUCCESS) { 8311 mutex_enter(HUBD_MUTEX(hubd)); 8312 8313 return (USB_FAILURE); 8314 } 8315 8316 hubd_ud = usba_get_usba_device(hubd->h_dip); 8317 8318 size = usb_parse_cfg_descr(hubd_ud->usb_cfg, hubd_ud->usb_cfg_length, 8319 &cfg_descr, USB_CFG_DESCR_SIZE); 8320 8321 if (size != USB_CFG_DESCR_SIZE) { 8322 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8323 "get hub configuration descriptor failed"); 8324 mutex_enter(HUBD_MUTEX(hubd)); 8325 8326 return (USB_FAILURE); 8327 } 8328 8329 mutex_enter(HUBD_MUTEX(hubd)); 8330 8331 hubd->h_local_pwr_capable = (cfg_descr.bmAttributes & 8332 USB_CFG_ATTR_SELFPWR); 8333 8334 if (hubd->h_local_pwr_capable) { 8335 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8336 "hub is capable of local power"); 8337 } 8338 8339 hubd->h_local_pwr_on = (status & 8340 USB_DEV_SLF_PWRD_STATUS) && hubd->h_local_pwr_capable; 8341 8342 if (hubd->h_local_pwr_on) { 8343 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8344 "hub is local-powered"); 8345 8346 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8347 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8348 } else { 8349 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8350 USB_LOW_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8351 8352 hubd->h_pwr_left = (USB_PWR_UNIT_LOAD * 8353 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8354 8355 ASSERT(!usba_is_root_hub(hubd->h_dip)); 8356 8357 if (!usba_is_root_hub(hubd->h_dip)) { 8358 /* 8359 * two bus-powered hubs are not 8360 * allowed to be concatenated 8361 */ 8362 mutex_exit(HUBD_MUTEX(hubd)); 8363 8364 pdip = ddi_get_parent(hubd->h_dip); 8365 phubd = hubd_get_soft_state(pdip); 8366 ASSERT(phubd != NULL); 8367 8368 if (!phubd->h_ignore_pwr_budget) { 8369 mutex_enter(HUBD_MUTEX(phubd)); 8370 if (phubd->h_local_pwr_on == B_FALSE) { 8371 USB_DPRINTF_L1(DPRINT_MASK_HUB, 8372 hubd->h_log_handle, 8373 "two bus-powered hubs cannot " 8374 "be concatenated"); 8375 8376 mutex_exit(HUBD_MUTEX(phubd)); 8377 mutex_enter(HUBD_MUTEX(hubd)); 8378 8379 return (USB_FAILURE); 8380 } 8381 mutex_exit(HUBD_MUTEX(phubd)); 8382 } 8383 8384 mutex_enter(HUBD_MUTEX(hubd)); 8385 8386 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8387 "hub is bus-powered"); 8388 } else { 8389 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8390 "root-hub must be local-powered"); 8391 } 8392 8393 /* 8394 * Subtract the power consumed by the hub itself 8395 * and get the power that can be supplied to 8396 * downstream ports 8397 */ 8398 hubd->h_pwr_left -= 8399 hubd->h_hub_descr.bHubContrCurrent / 8400 USB_CFG_DESCR_PWR_UNIT; 8401 if (hubd->h_pwr_left < 0) { 8402 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8403 "hubd->h_pwr_left is less than bHubContrCurrent, " 8404 "should fail"); 8405 8406 return (USB_FAILURE); 8407 } 8408 } 8409 8410 return (USB_SUCCESS); 8411 } 8412 8413 8414 /* 8415 * usba_hubdi_check_power_budget: 8416 * Check if the hub has enough power budget to allow a 8417 * child device to select a configuration of config_index. 8418 */ 8419 int 8420 usba_hubdi_check_power_budget(dev_info_t *dip, usba_device_t *child_ud, 8421 uint_t config_index) 8422 { 8423 int16_t pwr_left, pwr_limit, pwr_required; 8424 size_t size; 8425 usb_cfg_descr_t cfg_descr; 8426 hubd_t *hubd; 8427 8428 if ((hubd = hubd_get_soft_state(dip)) == NULL) { 8429 8430 return (USB_FAILURE); 8431 } 8432 8433 if (hubd->h_ignore_pwr_budget) { 8434 8435 return (USB_SUCCESS); 8436 } 8437 8438 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8439 "usba_hubdi_check_power_budget: " 8440 "dip=0x%p child_ud=0x%p conf_index=%d", (void *)dip, 8441 (void *)child_ud, config_index); 8442 8443 mutex_enter(HUBD_MUTEX(hubd)); 8444 pwr_limit = hubd->h_pwr_limit; 8445 if (hubd->h_local_pwr_on == B_FALSE) { 8446 pwr_left = hubd->h_pwr_left; 8447 pwr_limit = (pwr_limit <= pwr_left) ? pwr_limit : pwr_left; 8448 } 8449 mutex_exit(HUBD_MUTEX(hubd)); 8450 8451 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8452 "usba_hubdi_check_power_budget: " 8453 "available power is %dmA", pwr_limit * USB_CFG_DESCR_PWR_UNIT); 8454 8455 size = usb_parse_cfg_descr( 8456 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 8457 &cfg_descr, USB_CFG_DESCR_SIZE); 8458 8459 if (size != USB_CFG_DESCR_SIZE) { 8460 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8461 "get hub configuration descriptor failed"); 8462 8463 return (USB_FAILURE); 8464 } 8465 8466 pwr_required = cfg_descr.bMaxPower; 8467 8468 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8469 "usba_hubdi_check_power_budget: " 8470 "child bmAttributes=0x%x bMaxPower=%d " 8471 "with config_index=%d", cfg_descr.bmAttributes, 8472 pwr_required, config_index); 8473 8474 if (pwr_required > pwr_limit) { 8475 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8476 "configuration %d for device %s %s at port %d " 8477 "exceeds power available for this port, please " 8478 "re-insert your device into another hub port which " 8479 "has enough power", 8480 config_index, 8481 child_ud->usb_mfg_str, 8482 child_ud->usb_product_str, 8483 child_ud->usb_port); 8484 8485 return (USB_FAILURE); 8486 } 8487 8488 return (USB_SUCCESS); 8489 } 8490 8491 8492 /* 8493 * usba_hubdi_incr_power_budget: 8494 * Increase the hub power budget value when a child device 8495 * is removed from a bus-powered hub port. 8496 */ 8497 void 8498 usba_hubdi_incr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8499 { 8500 uint16_t pwr_value; 8501 hubd_t *hubd = hubd_get_soft_state(dip); 8502 8503 ASSERT(hubd != NULL); 8504 8505 if (hubd->h_ignore_pwr_budget) { 8506 8507 return; 8508 } 8509 8510 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8511 "usba_hubdi_incr_power_budget: " 8512 "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud); 8513 8514 mutex_enter(HUBD_MUTEX(hubd)); 8515 if (hubd->h_local_pwr_on == B_TRUE) { 8516 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8517 "usba_hubdi_incr_power_budget: " 8518 "hub is local powered"); 8519 mutex_exit(HUBD_MUTEX(hubd)); 8520 8521 return; 8522 } 8523 mutex_exit(HUBD_MUTEX(hubd)); 8524 8525 mutex_enter(&child_ud->usb_mutex); 8526 if (child_ud->usb_pwr_from_hub == 0) { 8527 mutex_exit(&child_ud->usb_mutex); 8528 8529 return; 8530 } 8531 pwr_value = child_ud->usb_pwr_from_hub; 8532 mutex_exit(&child_ud->usb_mutex); 8533 8534 mutex_enter(HUBD_MUTEX(hubd)); 8535 hubd->h_pwr_left += pwr_value; 8536 8537 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8538 "usba_hubdi_incr_power_budget: " 8539 "available power is %dmA, increased by %dmA", 8540 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8541 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8542 8543 mutex_exit(HUBD_MUTEX(hubd)); 8544 8545 mutex_enter(&child_ud->usb_mutex); 8546 child_ud->usb_pwr_from_hub = 0; 8547 mutex_exit(&child_ud->usb_mutex); 8548 } 8549 8550 8551 /* 8552 * usba_hubdi_decr_power_budget: 8553 * Decrease the hub power budget value when a child device 8554 * is inserted to a bus-powered hub port. 8555 */ 8556 void 8557 usba_hubdi_decr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8558 { 8559 uint16_t pwr_value; 8560 size_t size; 8561 usb_cfg_descr_t cfg_descr; 8562 hubd_t *hubd = hubd_get_soft_state(dip); 8563 8564 ASSERT(hubd != NULL); 8565 8566 if (hubd->h_ignore_pwr_budget) { 8567 8568 return; 8569 } 8570 8571 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8572 "usba_hubdi_decr_power_budget: " 8573 "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud); 8574 8575 mutex_enter(HUBD_MUTEX(hubd)); 8576 if (hubd->h_local_pwr_on == B_TRUE) { 8577 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8578 "usba_hubdi_decr_power_budget: " 8579 "hub is local powered"); 8580 mutex_exit(HUBD_MUTEX(hubd)); 8581 8582 return; 8583 } 8584 mutex_exit(HUBD_MUTEX(hubd)); 8585 8586 mutex_enter(&child_ud->usb_mutex); 8587 if (child_ud->usb_pwr_from_hub > 0) { 8588 mutex_exit(&child_ud->usb_mutex); 8589 8590 return; 8591 } 8592 mutex_exit(&child_ud->usb_mutex); 8593 8594 size = usb_parse_cfg_descr( 8595 child_ud->usb_cfg, child_ud->usb_cfg_length, 8596 &cfg_descr, USB_CFG_DESCR_SIZE); 8597 ASSERT(size == USB_CFG_DESCR_SIZE); 8598 8599 mutex_enter(HUBD_MUTEX(hubd)); 8600 pwr_value = cfg_descr.bMaxPower; 8601 hubd->h_pwr_left -= pwr_value; 8602 ASSERT(hubd->h_pwr_left >= 0); 8603 8604 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8605 "usba_hubdi_decr_power_budget: " 8606 "available power is %dmA, decreased by %dmA", 8607 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8608 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8609 8610 mutex_exit(HUBD_MUTEX(hubd)); 8611 8612 mutex_enter(&child_ud->usb_mutex); 8613 child_ud->usb_pwr_from_hub = pwr_value; 8614 mutex_exit(&child_ud->usb_mutex); 8615 } 8616 8617 /* 8618 * hubd_wait_for_hotplug_exit: 8619 * Waiting for the exit of the running hotplug thread or ioctl thread. 8620 */ 8621 static int 8622 hubd_wait_for_hotplug_exit(hubd_t *hubd) 8623 { 8624 clock_t until = drv_usectohz(1000000); 8625 int rval; 8626 8627 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8628 8629 if (hubd->h_hotplug_thread) { 8630 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8631 "waiting for hubd hotplug thread exit"); 8632 rval = cv_reltimedwait(&hubd->h_cv_hotplug_dev, 8633 &hubd->h_mutex, until, TR_CLOCK_TICK); 8634 8635 if ((rval <= 0) && (hubd->h_hotplug_thread)) { 8636 8637 return (USB_FAILURE); 8638 } 8639 } 8640 8641 return (USB_SUCCESS); 8642 } 8643 8644 /* 8645 * hubd_reset_thread: 8646 * handles the "USB_RESET_LVL_REATTACH" reset of usb device. 8647 * 8648 * - delete the child (force detaching the device and its children) 8649 * - reset the corresponding parent hub port 8650 * - create the child (force re-attaching the device and its children) 8651 */ 8652 static void 8653 hubd_reset_thread(void *arg) 8654 { 8655 hubd_reset_arg_t *hd_arg = (hubd_reset_arg_t *)arg; 8656 hubd_t *hubd = hd_arg->hubd; 8657 uint16_t reset_port = hd_arg->reset_port; 8658 uint16_t status, change; 8659 hub_power_t *hubpm; 8660 dev_info_t *hdip = hubd->h_dip; 8661 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 8662 dev_info_t *child_dip; 8663 boolean_t online_child = B_FALSE; 8664 int prh_circ, rh_circ, circ, devinst; 8665 char *devname; 8666 int i = 0; 8667 int rval = USB_FAILURE; 8668 8669 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8670 "hubd_reset_thread: started, hubd_reset_port = 0x%x", reset_port); 8671 8672 kmem_free(arg, sizeof (hubd_reset_arg_t)); 8673 8674 mutex_enter(HUBD_MUTEX(hubd)); 8675 8676 child_dip = hubd->h_children_dips[reset_port]; 8677 ASSERT(child_dip != NULL); 8678 8679 devname = (char *)ddi_driver_name(child_dip); 8680 devinst = ddi_get_instance(child_dip); 8681 8682 /* if our bus power entry point is active, quit the reset */ 8683 if (hubd->h_bus_pwr) { 8684 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8685 "%s%d is under bus power management, cannot be reset. " 8686 "Please disconnect and reconnect this device.", 8687 devname, devinst); 8688 8689 goto Fail; 8690 } 8691 8692 if (hubd_wait_for_hotplug_exit(hubd) == USB_FAILURE) { 8693 /* we got woken up because of a timeout */ 8694 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 8695 hubd->h_log_handle, "Time out when resetting the device" 8696 " %s%d. Please disconnect and reconnect this device.", 8697 devname, devinst); 8698 8699 goto Fail; 8700 } 8701 8702 hubd->h_hotplug_thread++; 8703 8704 /* is this the root hub? */ 8705 if ((hdip == rh_dip) && 8706 (hubd->h_dev_state == USB_DEV_PWRED_DOWN)) { 8707 hubpm = hubd->h_hubpm; 8708 8709 /* mark the root hub as full power */ 8710 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 8711 hubpm->hubp_time_at_full_power = ddi_get_time(); 8712 mutex_exit(HUBD_MUTEX(hubd)); 8713 8714 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8715 "hubd_reset_thread: call pm_power_has_changed"); 8716 8717 (void) pm_power_has_changed(hdip, 0, 8718 USB_DEV_OS_FULL_PWR); 8719 8720 mutex_enter(HUBD_MUTEX(hubd)); 8721 hubd->h_dev_state = USB_DEV_ONLINE; 8722 } 8723 8724 mutex_exit(HUBD_MUTEX(hubd)); 8725 8726 /* 8727 * this ensures one reset activity per system at a time. 8728 * we enter the parent PCI node to have this serialization. 8729 * this also excludes ioctls and deathrow thread 8730 */ 8731 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 8732 ndi_devi_enter(rh_dip, &rh_circ); 8733 8734 /* exclude other threads */ 8735 ndi_devi_enter(hdip, &circ); 8736 mutex_enter(HUBD_MUTEX(hubd)); 8737 8738 /* 8739 * We need to make sure that the child is still online for a hotplug 8740 * thread could have inserted which detached the child. 8741 */ 8742 if (hubd->h_children_dips[reset_port]) { 8743 mutex_exit(HUBD_MUTEX(hubd)); 8744 /* First disconnect the device */ 8745 hubd_post_event(hubd, reset_port, USBA_EVENT_TAG_HOT_REMOVAL); 8746 8747 /* delete cached dv_node's but drop locks first */ 8748 ndi_devi_exit(hdip, circ); 8749 ndi_devi_exit(rh_dip, rh_circ); 8750 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 8751 8752 (void) devfs_clean(rh_dip, NULL, DV_CLEAN_FORCE); 8753 8754 /* 8755 * workaround only for storage device. When it's able to force 8756 * detach a driver, this code can be removed safely. 8757 * 8758 * If we're to reset storage device and the device is used, we 8759 * will wait at most extra 20s for applications to exit and 8760 * close the device. This is especially useful for HAL-based 8761 * applications. 8762 */ 8763 if ((strcmp(devname, "scsa2usb") == 0) && 8764 DEVI(child_dip)->devi_ref != 0) { 8765 while (i++ < hubdi_reset_delay) { 8766 mutex_enter(HUBD_MUTEX(hubd)); 8767 rval = hubd_delete_child(hubd, reset_port, 8768 NDI_DEVI_REMOVE, B_FALSE); 8769 mutex_exit(HUBD_MUTEX(hubd)); 8770 if (rval == USB_SUCCESS) 8771 break; 8772 8773 delay(drv_usectohz(1000000)); /* 1s */ 8774 } 8775 } 8776 8777 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 8778 ndi_devi_enter(rh_dip, &rh_circ); 8779 ndi_devi_enter(hdip, &circ); 8780 8781 mutex_enter(HUBD_MUTEX(hubd)); 8782 8783 /* Then force detaching the device */ 8784 if ((rval != USB_SUCCESS) && (hubd_delete_child(hubd, 8785 reset_port, NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS)) { 8786 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8787 "%s%d cannot be reset due to other applications " 8788 "are using it, please first close these " 8789 "applications, then disconnect and reconnect" 8790 "the device.", devname, devinst); 8791 8792 mutex_exit(HUBD_MUTEX(hubd)); 8793 /* post a re-connect event */ 8794 hubd_post_event(hubd, reset_port, 8795 USBA_EVENT_TAG_HOT_INSERTION); 8796 mutex_enter(HUBD_MUTEX(hubd)); 8797 } else { 8798 (void) hubd_determine_port_status(hubd, reset_port, 8799 &status, &change, HUBD_ACK_ALL_CHANGES); 8800 8801 /* Reset the parent hubd port and create new child */ 8802 if (status & PORT_STATUS_CCS) { 8803 online_child |= (hubd_handle_port_connect(hubd, 8804 reset_port) == USB_SUCCESS); 8805 } 8806 } 8807 } 8808 8809 /* release locks so we can do a devfs_clean */ 8810 mutex_exit(HUBD_MUTEX(hubd)); 8811 8812 /* delete cached dv_node's but drop locks first */ 8813 ndi_devi_exit(hdip, circ); 8814 ndi_devi_exit(rh_dip, rh_circ); 8815 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 8816 8817 (void) devfs_clean(rh_dip, NULL, 0); 8818 8819 /* now check if any children need onlining */ 8820 if (online_child) { 8821 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8822 "hubd_reset_thread: onlining children"); 8823 8824 (void) ndi_devi_online(hubd->h_dip, 0); 8825 } 8826 8827 mutex_enter(HUBD_MUTEX(hubd)); 8828 8829 /* allow hotplug thread now */ 8830 hubd->h_hotplug_thread--; 8831 Fail: 8832 hubd_start_polling(hubd, 0); 8833 8834 /* mark this device as idle */ 8835 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 8836 8837 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8838 "hubd_reset_thread: exit, %d", hubd->h_hotplug_thread); 8839 8840 hubd->h_reset_port[reset_port] = B_FALSE; 8841 8842 mutex_exit(HUBD_MUTEX(hubd)); 8843 8844 ndi_rele_devi(hdip); 8845 } 8846 8847 /* 8848 * hubd_check_same_device: 8849 * - open the default pipe of the device. 8850 * - compare the old and new descriptors of the device. 8851 * - close the default pipe. 8852 */ 8853 static int 8854 hubd_check_same_device(hubd_t *hubd, usb_port_t port) 8855 { 8856 dev_info_t *dip = hubd->h_children_dips[port]; 8857 usb_pipe_handle_t ph; 8858 int rval = USB_FAILURE; 8859 8860 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8861 8862 mutex_exit(HUBD_MUTEX(hubd)); 8863 /* Open the default pipe to operate the device */ 8864 if (usb_pipe_open(dip, NULL, NULL, 8865 USB_FLAGS_SLEEP| USBA_FLAGS_PRIVILEGED, 8866 &ph) == USB_SUCCESS) { 8867 /* 8868 * Check that if the device's descriptors are different 8869 * from the values saved before the port reset. 8870 */ 8871 rval = usb_check_same_device(dip, 8872 hubd->h_log_handle, USB_LOG_L0, 8873 DPRINT_MASK_ALL, USB_CHK_ALL, NULL); 8874 8875 usb_pipe_close(dip, ph, USB_FLAGS_SLEEP | 8876 USBA_FLAGS_PRIVILEGED, NULL, NULL); 8877 } 8878 mutex_enter(HUBD_MUTEX(hubd)); 8879 8880 return (rval); 8881 } 8882 8883 /* 8884 * usba_hubdi_reset_device 8885 * Called by usb_reset_device to handle usb device reset. 8886 */ 8887 int 8888 usba_hubdi_reset_device(dev_info_t *dip, usb_dev_reset_lvl_t reset_level) 8889 { 8890 hubd_t *hubd; 8891 usb_port_t port = 0; 8892 dev_info_t *hdip; 8893 usb_pipe_state_t prev_pipe_state = 0; 8894 usba_device_t *usba_device; 8895 hubd_reset_arg_t *arg; 8896 int i, ph_open_cnt; 8897 int rval = USB_FAILURE; 8898 8899 if ((!dip) || usba_is_root_hub(dip)) { 8900 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8901 "usba_hubdi_reset_device: NULL dip or root hub"); 8902 8903 return (USB_INVALID_ARGS); 8904 } 8905 8906 if (!usb_owns_device(dip)) { 8907 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8908 "usba_hubdi_reset_device: Not owns the device"); 8909 8910 return (USB_INVALID_PERM); 8911 } 8912 8913 if ((reset_level != USB_RESET_LVL_REATTACH) && 8914 (reset_level != USB_RESET_LVL_DEFAULT)) { 8915 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8916 "usba_hubdi_reset_device: Unknown flags"); 8917 8918 return (USB_INVALID_ARGS); 8919 } 8920 8921 if ((hdip = ddi_get_parent(dip)) == NULL) { 8922 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8923 "usba_hubdi_reset_device: fail to get parent hub"); 8924 8925 return (USB_INVALID_ARGS); 8926 } 8927 8928 if ((hubd = hubd_get_soft_state(hdip)) == NULL) { 8929 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8930 "usba_hubdi_reset_device: fail to get hub softstate"); 8931 8932 return (USB_INVALID_ARGS); 8933 } 8934 8935 mutex_enter(HUBD_MUTEX(hubd)); 8936 8937 /* make sure the hub is connected before trying any kinds of reset. */ 8938 if ((hubd->h_dev_state == USB_DEV_DISCONNECTED) || 8939 (hubd->h_dev_state == USB_DEV_SUSPENDED)) { 8940 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8941 "usb_reset_device: the state %d of the hub/roothub " 8942 "associated to the device 0x%p is incorrect", 8943 hubd->h_dev_state, (void *)dip); 8944 mutex_exit(HUBD_MUTEX(hubd)); 8945 8946 return (USB_INVALID_ARGS); 8947 } 8948 8949 mutex_exit(HUBD_MUTEX(hubd)); 8950 8951 port = hubd_child_dip2port(hubd, dip); 8952 8953 mutex_enter(HUBD_MUTEX(hubd)); 8954 8955 if (hubd->h_reset_port[port]) { 8956 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8957 "usb_reset_device: the corresponding port is resetting"); 8958 mutex_exit(HUBD_MUTEX(hubd)); 8959 8960 return (USB_SUCCESS); 8961 } 8962 8963 /* 8964 * For Default reset, client drivers should first close all the pipes 8965 * except default pipe before calling the function, also should not 8966 * call the function during interrupt context. 8967 */ 8968 if (reset_level == USB_RESET_LVL_DEFAULT) { 8969 usba_device = hubd->h_usba_devices[port]; 8970 mutex_exit(HUBD_MUTEX(hubd)); 8971 8972 if (servicing_interrupt()) { 8973 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8974 "usb_reset_device: during interrput context, quit"); 8975 8976 return (USB_INVALID_CONTEXT); 8977 } 8978 /* Check if all the pipes have been closed */ 8979 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) { 8980 if (usba_device->usb_ph_list[i].usba_ph_data) { 8981 ph_open_cnt++; 8982 break; 8983 } 8984 } 8985 if (ph_open_cnt) { 8986 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8987 "usb_reset_device: %d pipes are still open", 8988 ph_open_cnt); 8989 8990 return (USB_BUSY); 8991 } 8992 mutex_enter(HUBD_MUTEX(hubd)); 8993 } 8994 8995 /* Don't perform reset while the device is detaching */ 8996 if (hubd->h_port_state[port] & HUBD_CHILD_DETACHING) { 8997 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8998 "usb_reset_device: the device is detaching, " 8999 "cannot be reset"); 9000 mutex_exit(HUBD_MUTEX(hubd)); 9001 9002 return (USB_FAILURE); 9003 } 9004 9005 hubd->h_reset_port[port] = B_TRUE; 9006 hdip = hubd->h_dip; 9007 mutex_exit(HUBD_MUTEX(hubd)); 9008 9009 /* Don't allow hub detached during the reset */ 9010 ndi_hold_devi(hdip); 9011 9012 mutex_enter(HUBD_MUTEX(hubd)); 9013 hubd_pm_busy_component(hubd, hdip, 0); 9014 mutex_exit(HUBD_MUTEX(hubd)); 9015 /* go full power */ 9016 (void) pm_raise_power(hdip, 0, USB_DEV_OS_FULL_PWR); 9017 mutex_enter(HUBD_MUTEX(hubd)); 9018 9019 hubd->h_hotplug_thread++; 9020 9021 /* stop polling if it was active */ 9022 if (hubd->h_ep1_ph) { 9023 mutex_exit(HUBD_MUTEX(hubd)); 9024 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 9025 USB_FLAGS_SLEEP); 9026 mutex_enter(HUBD_MUTEX(hubd)); 9027 9028 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 9029 hubd_stop_polling(hubd); 9030 } 9031 } 9032 9033 switch (reset_level) { 9034 case USB_RESET_LVL_REATTACH: 9035 mutex_exit(HUBD_MUTEX(hubd)); 9036 arg = (hubd_reset_arg_t *)kmem_zalloc( 9037 sizeof (hubd_reset_arg_t), KM_SLEEP); 9038 arg->hubd = hubd; 9039 arg->reset_port = port; 9040 mutex_enter(HUBD_MUTEX(hubd)); 9041 9042 if ((rval = usb_async_req(hdip, hubd_reset_thread, 9043 (void *)arg, 0)) == USB_SUCCESS) { 9044 hubd->h_hotplug_thread--; 9045 mutex_exit(HUBD_MUTEX(hubd)); 9046 9047 return (USB_SUCCESS); 9048 } else { 9049 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9050 "Cannot create reset thread, the device %s%d failed" 9051 " to reset", ddi_driver_name(dip), 9052 ddi_get_instance(dip)); 9053 9054 kmem_free(arg, sizeof (hubd_reset_arg_t)); 9055 } 9056 9057 break; 9058 case USB_RESET_LVL_DEFAULT: 9059 /* 9060 * Reset hub port and then recover device's address, set back 9061 * device's configuration, hubd_handle_port_connect() will 9062 * handle errors happened during this process. 9063 */ 9064 if ((rval = hubd_handle_port_connect(hubd, port)) 9065 == USB_SUCCESS) { 9066 mutex_exit(HUBD_MUTEX(hubd)); 9067 /* re-open the default pipe */ 9068 rval = usba_persistent_pipe_open(usba_device); 9069 mutex_enter(HUBD_MUTEX(hubd)); 9070 if (rval != USB_SUCCESS) { 9071 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 9072 hubd->h_log_handle, "failed to reopen " 9073 "default pipe after reset, disable hub" 9074 "port for %s%d", ddi_driver_name(dip), 9075 ddi_get_instance(dip)); 9076 /* 9077 * Disable port to set out a hotplug thread 9078 * which will handle errors. 9079 */ 9080 (void) hubd_disable_port(hubd, port); 9081 } 9082 } 9083 9084 break; 9085 default: 9086 9087 break; 9088 } 9089 9090 /* allow hotplug thread now */ 9091 hubd->h_hotplug_thread--; 9092 9093 if ((hubd->h_dev_state == USB_DEV_ONLINE) && hubd->h_ep1_ph && 9094 (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 9095 hubd_start_polling(hubd, 0); 9096 } 9097 9098 hubd_pm_idle_component(hubd, hdip, 0); 9099 9100 /* Clear reset mark for the port. */ 9101 hubd->h_reset_port[port] = B_FALSE; 9102 9103 mutex_exit(HUBD_MUTEX(hubd)); 9104 9105 ndi_rele_devi(hdip); 9106 9107 return (rval); 9108 } 9109