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