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