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