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