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