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