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