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