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 void (*callback)(dev_info_t *dip, ddi_eventcookie_t cookie, void *arg, 83 void *bus_impldata), 84 void *arg, 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 void (*callback)(dev_info_t *dip, ddi_eventcookie_t cookie, void *arg, 6889 void *bus_impldata), 6890 void *arg, ddi_callback_id_t *cb_id) 6891 { 6892 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6893 usb_port_t port = hubd_child_dip2port(hubd, rdip); 6894 6895 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6896 "hubd_busop_add_eventcall: dip=0x%p, rdip=0x%p " 6897 "cookie=0x%p, cb=0x%p, arg=0x%p", 6898 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 6899 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6900 "(dip=%s%d, rdip=%s%d, event=%s)", 6901 ddi_driver_name(dip), ddi_get_instance(dip), 6902 ddi_driver_name(rdip), ddi_get_instance(rdip), 6903 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, cookie)); 6904 6905 /* Set flag on children registering events */ 6906 switch (ndi_event_cookie_to_tag(hubd->h_ndi_event_hdl, cookie)) { 6907 case USBA_EVENT_TAG_HOT_REMOVAL: 6908 mutex_enter(HUBD_MUTEX(hubd)); 6909 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6910 mutex_exit(HUBD_MUTEX(hubd)); 6911 6912 break; 6913 case USBA_EVENT_TAG_PRE_SUSPEND: 6914 mutex_enter(HUBD_MUTEX(hubd)); 6915 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6916 mutex_exit(HUBD_MUTEX(hubd)); 6917 6918 break; 6919 default: 6920 6921 break; 6922 } 6923 6924 /* add callback to our event set */ 6925 return (ndi_event_add_callback(hubd->h_ndi_event_hdl, 6926 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 6927 } 6928 6929 6930 static int 6931 hubd_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 6932 { 6933 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6934 ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id; 6935 6936 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6937 "hubd_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 6938 "cookie=0x%p", (void *)dip, (void *)id->ndi_evtcb_dip, 6939 (void *)id->ndi_evtcb_cookie); 6940 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6941 "(dip=%s%d, rdip=%s%d, event=%s)", 6942 ddi_driver_name(dip), ddi_get_instance(dip), 6943 ddi_driver_name(id->ndi_evtcb_dip), 6944 ddi_get_instance(id->ndi_evtcb_dip), 6945 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, 6946 id->ndi_evtcb_cookie)); 6947 6948 /* remove event registration from our event set */ 6949 return (ndi_event_remove_callback(hubd->h_ndi_event_hdl, cb_id)); 6950 } 6951 6952 6953 /* 6954 * event distribution 6955 * 6956 * hubd_do_callback: 6957 * Post this event to the specified child 6958 */ 6959 static void 6960 hubd_do_callback(hubd_t *hubd, dev_info_t *cdip, ddi_eventcookie_t cookie) 6961 { 6962 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6963 "hubd_do_callback"); 6964 6965 (void) ndi_event_do_callback(hubd->h_ndi_event_hdl, cdip, cookie, NULL); 6966 } 6967 6968 6969 /* 6970 * hubd_run_callbacks: 6971 * Send this event to all children 6972 */ 6973 static void 6974 hubd_run_callbacks(hubd_t *hubd, usba_event_t type) 6975 { 6976 usb_port_t port; 6977 6978 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6979 "hubd_run_callbacks"); 6980 6981 mutex_enter(HUBD_MUTEX(hubd)); 6982 for (port = 1; port <= hubd->h_nports; port++) { 6983 /* 6984 * the childen_dips list may have dips that have been 6985 * already deallocated. we only get a post_detach notification 6986 * but not a destroy notification 6987 */ 6988 if (hubd->h_children_dips[port]) { 6989 mutex_exit(HUBD_MUTEX(hubd)); 6990 hubd_post_event(hubd, port, type); 6991 mutex_enter(HUBD_MUTEX(hubd)); 6992 } 6993 } 6994 mutex_exit(HUBD_MUTEX(hubd)); 6995 } 6996 6997 6998 /* 6999 * hubd_post_event 7000 * post event to a child on the port depending on the type 7001 */ 7002 static void 7003 hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type) 7004 { 7005 int rval; 7006 dev_info_t *dip; 7007 usba_device_t *usba_device; 7008 ddi_eventcookie_t cookie, rm_cookie, suspend_cookie; 7009 7010 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7011 "hubd_post_event: port=%d event=%s", port, 7012 ndi_event_tag_to_name(hubd->h_ndi_event_hdl, type)); 7013 7014 cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, type); 7015 rm_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 7016 USBA_EVENT_TAG_HOT_REMOVAL); 7017 suspend_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 7018 USBA_EVENT_TAG_PRE_SUSPEND); 7019 7020 /* 7021 * Hotplug daemon may be attaching a driver that may be registering 7022 * event callbacks. So it already has got the device tree lock and 7023 * event handle mutex. So to prevent a deadlock while posting events, 7024 * we grab and release the locks in the same order. 7025 */ 7026 mutex_enter(HUBD_MUTEX(hubd)); 7027 dip = hubd->h_children_dips[port]; 7028 usba_device = hubd->h_usba_devices[port]; 7029 mutex_exit(HUBD_MUTEX(hubd)); 7030 7031 switch (type) { 7032 case USBA_EVENT_TAG_HOT_REMOVAL: 7033 /* Clear the registered event flag */ 7034 mutex_enter(HUBD_MUTEX(hubd)); 7035 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_DISCONNECT; 7036 mutex_exit(HUBD_MUTEX(hubd)); 7037 7038 hubd_do_callback(hubd, dip, cookie); 7039 usba_persistent_pipe_close(usba_device); 7040 7041 /* 7042 * Mark the dip for deletion only after the driver has 7043 * seen the disconnect event to prevent cleanup thread 7044 * from stepping in between. 7045 */ 7046 mutex_enter(&(DEVI(dip)->devi_lock)); 7047 DEVI_SET_DEVICE_REMOVED(dip); 7048 mutex_exit(&(DEVI(dip)->devi_lock)); 7049 7050 break; 7051 case USBA_EVENT_TAG_PRE_SUSPEND: 7052 mutex_enter(HUBD_MUTEX(hubd)); 7053 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_PRESUSPEND; 7054 mutex_exit(HUBD_MUTEX(hubd)); 7055 7056 hubd_do_callback(hubd, dip, cookie); 7057 /* 7058 * persistent pipe close for this event is taken care by the 7059 * caller after verfying that all children can suspend 7060 */ 7061 7062 break; 7063 case USBA_EVENT_TAG_HOT_INSERTION: 7064 /* 7065 * Check if this child has missed the disconnect event before 7066 * it registered for event callbacks 7067 */ 7068 mutex_enter(HUBD_MUTEX(hubd)); 7069 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_DISCONNECT) { 7070 /* clear the flag and post disconnect event */ 7071 hubd->h_child_events[port] &= 7072 ~HUBD_CHILD_EVENT_DISCONNECT; 7073 mutex_exit(HUBD_MUTEX(hubd)); 7074 hubd_do_callback(hubd, dip, rm_cookie); 7075 usba_persistent_pipe_close(usba_device); 7076 mutex_enter(HUBD_MUTEX(hubd)); 7077 } 7078 mutex_exit(HUBD_MUTEX(hubd)); 7079 7080 /* 7081 * Mark the dip as reinserted to prevent cleanup thread 7082 * from stepping in. 7083 */ 7084 mutex_enter(&(DEVI(dip)->devi_lock)); 7085 DEVI_SET_DEVICE_REINSERTED(dip); 7086 mutex_exit(&(DEVI(dip)->devi_lock)); 7087 7088 rval = usba_persistent_pipe_open(usba_device); 7089 if (rval != USB_SUCCESS) { 7090 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 7091 hubd->h_log_handle, 7092 "failed to reopen all pipes on reconnect"); 7093 } 7094 7095 hubd_do_callback(hubd, dip, cookie); 7096 7097 /* 7098 * We might see a connect event only if hotplug thread for 7099 * disconnect event don't run in time. 7100 * Set the flag again, so we don't miss posting a 7101 * disconnect event. 7102 */ 7103 mutex_enter(HUBD_MUTEX(hubd)); 7104 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 7105 mutex_exit(HUBD_MUTEX(hubd)); 7106 7107 break; 7108 case USBA_EVENT_TAG_POST_RESUME: 7109 /* 7110 * Check if this child has missed the pre-suspend event before 7111 * it registered for event callbacks 7112 */ 7113 mutex_enter(HUBD_MUTEX(hubd)); 7114 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_PRESUSPEND) { 7115 /* clear the flag and post pre_suspend event */ 7116 hubd->h_port_state[port] &= 7117 ~HUBD_CHILD_EVENT_PRESUSPEND; 7118 mutex_exit(HUBD_MUTEX(hubd)); 7119 hubd_do_callback(hubd, dip, suspend_cookie); 7120 mutex_enter(HUBD_MUTEX(hubd)); 7121 } 7122 mutex_exit(HUBD_MUTEX(hubd)); 7123 7124 mutex_enter(&usba_device->usb_mutex); 7125 usba_device->usb_no_cpr = 0; 7126 mutex_exit(&usba_device->usb_mutex); 7127 7128 /* 7129 * Since the pipe has already been opened by hub 7130 * at DDI_RESUME time, there is no need for a 7131 * persistent pipe open 7132 */ 7133 hubd_do_callback(hubd, dip, cookie); 7134 7135 /* 7136 * Set the flag again, so we don't miss posting a 7137 * pre-suspend event. This enforces a tighter 7138 * dev_state model. 7139 */ 7140 mutex_enter(HUBD_MUTEX(hubd)); 7141 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 7142 mutex_exit(HUBD_MUTEX(hubd)); 7143 break; 7144 } 7145 } 7146 7147 7148 /* 7149 * handling of events coming from above 7150 */ 7151 static int 7152 hubd_disconnect_event_cb(dev_info_t *dip) 7153 { 7154 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 7155 usb_port_t port, nports; 7156 usba_device_t *usba_dev; 7157 usba_event_t tag = USBA_EVENT_TAG_HOT_REMOVAL; 7158 7159 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7160 "hubd_disconnect_event_cb: tag=%d", tag); 7161 7162 ndi_devi_enter(dip); 7163 7164 mutex_enter(HUBD_MUTEX(hubd)); 7165 switch (hubd->h_dev_state) { 7166 case USB_DEV_ONLINE: 7167 case USB_DEV_PWRED_DOWN: 7168 hubd->h_dev_state = USB_DEV_DISCONNECTED; 7169 /* stop polling on the interrupt pipe */ 7170 hubd_stop_polling(hubd); 7171 7172 /* FALLTHROUGH */ 7173 case USB_DEV_SUSPENDED: 7174 /* we remain in this state */ 7175 mutex_exit(HUBD_MUTEX(hubd)); 7176 hubd_run_callbacks(hubd, tag); 7177 mutex_enter(HUBD_MUTEX(hubd)); 7178 7179 /* close all the open pipes of our children */ 7180 nports = hubd->h_nports; 7181 for (port = 1; port <= nports; port++) { 7182 usba_dev = hubd->h_usba_devices[port]; 7183 if (usba_dev != NULL) { 7184 mutex_exit(HUBD_MUTEX(hubd)); 7185 usba_persistent_pipe_close(usba_dev); 7186 mutex_enter(HUBD_MUTEX(hubd)); 7187 } 7188 } 7189 7190 break; 7191 case USB_DEV_DISCONNECTED: 7192 /* avoid passing multiple disconnects to children */ 7193 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7194 "hubd_disconnect_event_cb: Already disconnected"); 7195 7196 break; 7197 default: 7198 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7199 "hubd_disconnect_event_cb: Illegal devstate=%d", 7200 hubd->h_dev_state); 7201 7202 break; 7203 } 7204 mutex_exit(HUBD_MUTEX(hubd)); 7205 7206 ndi_devi_exit(dip); 7207 7208 return (USB_SUCCESS); 7209 } 7210 7211 7212 static int 7213 hubd_reconnect_event_cb(dev_info_t *dip) 7214 { 7215 int rval; 7216 7217 ndi_devi_enter(dip); 7218 rval = hubd_restore_state_cb(dip); 7219 ndi_devi_exit(dip); 7220 7221 return (rval); 7222 } 7223 7224 7225 /* 7226 * hubd_pre_suspend_event_cb 7227 * propogate event for binary compatibility of old drivers 7228 */ 7229 static int 7230 hubd_pre_suspend_event_cb(dev_info_t *dip) 7231 { 7232 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 7233 7234 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7235 "hubd_pre_suspend_event_cb"); 7236 7237 /* disable hotplug thread */ 7238 mutex_enter(HUBD_MUTEX(hubd)); 7239 hubd->h_hotplug_thread++; 7240 hubd_stop_polling(hubd); 7241 7242 /* keep PM out till we see a cpr resume */ 7243 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7244 mutex_exit(HUBD_MUTEX(hubd)); 7245 7246 ndi_devi_enter(dip); 7247 hubd_run_callbacks(hubd, USBA_EVENT_TAG_PRE_SUSPEND); 7248 ndi_devi_exit(dip); 7249 7250 return (USB_SUCCESS); 7251 } 7252 7253 7254 /* 7255 * hubd_post_resume_event_cb 7256 * propogate event for binary compatibility of old drivers 7257 */ 7258 static int 7259 hubd_post_resume_event_cb(dev_info_t *dip) 7260 { 7261 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 7262 7263 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7264 "hubd_post_resume_event_cb"); 7265 7266 ndi_devi_enter(dip); 7267 hubd_run_callbacks(hubd, USBA_EVENT_TAG_POST_RESUME); 7268 ndi_devi_exit(dip); 7269 7270 mutex_enter(HUBD_MUTEX(hubd)); 7271 7272 /* enable PM */ 7273 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7274 7275 /* allow hotplug thread */ 7276 hubd->h_hotplug_thread--; 7277 7278 /* start polling */ 7279 hubd_start_polling(hubd, 0); 7280 mutex_exit(HUBD_MUTEX(hubd)); 7281 7282 return (USB_SUCCESS); 7283 } 7284 7285 7286 /* 7287 * hubd_cpr_suspend 7288 * save the current state of the driver/device 7289 */ 7290 static int 7291 hubd_cpr_suspend(hubd_t *hubd) 7292 { 7293 usb_port_t port, nports; 7294 usba_device_t *usba_dev; 7295 uchar_t no_cpr = 0; 7296 int rval = USB_FAILURE; 7297 7298 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7299 "hubd_cpr_suspend: Begin"); 7300 7301 /* Make sure device is powered up to save state. */ 7302 mutex_enter(HUBD_MUTEX(hubd)); 7303 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7304 mutex_exit(HUBD_MUTEX(hubd)); 7305 7306 /* bring the device to full power */ 7307 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7308 mutex_enter(HUBD_MUTEX(hubd)); 7309 7310 switch (hubd->h_dev_state) { 7311 case USB_DEV_ONLINE: 7312 case USB_DEV_PWRED_DOWN: 7313 case USB_DEV_DISCONNECTED: 7314 /* find out if all our children have been quiesced */ 7315 nports = hubd->h_nports; 7316 for (port = 1; (no_cpr == 0) && (port <= nports); port++) { 7317 usba_dev = hubd->h_usba_devices[port]; 7318 if (usba_dev != NULL) { 7319 mutex_enter(&usba_dev->usb_mutex); 7320 no_cpr += usba_dev->usb_no_cpr; 7321 mutex_exit(&usba_dev->usb_mutex); 7322 } 7323 } 7324 if (no_cpr > 0) { 7325 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7326 "Children busy - can't checkpoint"); 7327 /* remain in same state to fail checkpoint */ 7328 7329 break; 7330 } else { 7331 /* 7332 * do not suspend if our hotplug thread 7333 * or the deathrow thread is active 7334 */ 7335 if ((hubd->h_hotplug_thread > 1) || 7336 (hubd->h_cleanup_active == B_TRUE)) { 7337 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 7338 hubd->h_log_handle, 7339 "hotplug thread active - can't cpr"); 7340 /* remain in same state to fail checkpoint */ 7341 7342 break; 7343 } 7344 7345 /* quiesce ourselves now */ 7346 hubd_stop_polling(hubd); 7347 7348 /* close all the open pipes of our children */ 7349 for (port = 1; port <= nports; port++) { 7350 usba_dev = hubd->h_usba_devices[port]; 7351 if (usba_dev != NULL) { 7352 mutex_exit(HUBD_MUTEX(hubd)); 7353 usba_persistent_pipe_close(usba_dev); 7354 if (hubd_suspend_port(hubd, port)) { 7355 USB_DPRINTF_L0( 7356 DPRINT_MASK_HOTPLUG, 7357 hubd->h_log_handle, 7358 "suspending port %d failed", 7359 port); 7360 } 7361 mutex_enter(HUBD_MUTEX(hubd)); 7362 } 7363 7364 } 7365 hubd->h_dev_state = USB_DEV_SUSPENDED; 7366 7367 /* 7368 * if we are the root hub, we close our pipes 7369 * ourselves. 7370 */ 7371 if (usba_is_root_hub(hubd->h_dip)) { 7372 mutex_exit(HUBD_MUTEX(hubd)); 7373 usba_persistent_pipe_close( 7374 usba_get_usba_device(hubd->h_dip)); 7375 mutex_enter(HUBD_MUTEX(hubd)); 7376 } 7377 rval = USB_SUCCESS; 7378 7379 break; 7380 } 7381 case USB_DEV_SUSPENDED: 7382 default: 7383 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7384 "hubd_cpr_suspend: Illegal dev state=%d", 7385 hubd->h_dev_state); 7386 7387 break; 7388 } 7389 7390 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7391 mutex_exit(HUBD_MUTEX(hubd)); 7392 7393 return (rval); 7394 } 7395 7396 static void 7397 hubd_cpr_resume(dev_info_t *dip) 7398 { 7399 int rval; 7400 7401 ndi_devi_enter(dip); 7402 /* 7403 * if we are the root hub, we open our pipes 7404 * ourselves. 7405 */ 7406 if (usba_is_root_hub(dip)) { 7407 rval = usba_persistent_pipe_open( 7408 usba_get_usba_device(dip)); 7409 ASSERT(rval == USB_SUCCESS); 7410 } 7411 (void) hubd_restore_state_cb(dip); 7412 ndi_devi_exit(dip); 7413 } 7414 7415 7416 /* 7417 * hubd_restore_state_cb 7418 * Event callback to restore device state 7419 */ 7420 static int 7421 hubd_restore_state_cb(dev_info_t *dip) 7422 { 7423 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 7424 7425 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7426 "hubd_restore_state_cb: Begin"); 7427 7428 /* restore the state of this device */ 7429 hubd_restore_device_state(dip, hubd); 7430 7431 return (USB_SUCCESS); 7432 } 7433 7434 7435 /* 7436 * registering for events 7437 */ 7438 static int 7439 hubd_register_events(hubd_t *hubd) 7440 { 7441 int rval = USB_SUCCESS; 7442 7443 if (usba_is_root_hub(hubd->h_dip)) { 7444 hubd_register_cpr_callback(hubd); 7445 } else { 7446 rval = usb_register_event_cbs(hubd->h_dip, &hubd_events, 0); 7447 } 7448 7449 return (rval); 7450 } 7451 7452 7453 /* 7454 * hubd cpr callback related functions 7455 * 7456 * hubd_cpr_post_user_callb: 7457 * This function is called during checkpoint & resume - 7458 * 1. after user threads are stopped during checkpoint 7459 * 2. after kernel threads are resumed during resume 7460 */ 7461 /* ARGSUSED */ 7462 static boolean_t 7463 hubd_cpr_post_user_callb(void *arg, int code) 7464 { 7465 hubd_cpr_t *cpr_cb = (hubd_cpr_t *)arg; 7466 hubd_t *hubd = cpr_cb->statep; 7467 int retry = 0; 7468 7469 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7470 "hubd_cpr_post_user_callb"); 7471 7472 switch (code) { 7473 case CB_CODE_CPR_CHKPT: 7474 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7475 "hubd_cpr_post_user_callb: CB_CODE_CPR_CHKPT"); 7476 7477 mutex_enter(HUBD_MUTEX(hubd)); 7478 7479 /* turn off deathrow thread */ 7480 hubd->h_cleanup_enabled = B_FALSE; 7481 7482 /* give up if deathrow thread doesn't exit */ 7483 while ((hubd->h_cleanup_active == B_TRUE) && (retry++ < 3)) { 7484 mutex_exit(HUBD_MUTEX(hubd)); 7485 delay(drv_usectohz(hubd_dip_cleanup_delay)); 7486 7487 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7488 "hubd_cpr_post_user_callb, waiting for " 7489 "deathrow thread to exit"); 7490 mutex_enter(HUBD_MUTEX(hubd)); 7491 } 7492 7493 mutex_exit(HUBD_MUTEX(hubd)); 7494 7495 /* save the state of the device */ 7496 (void) hubd_pre_suspend_event_cb(hubd->h_dip); 7497 7498 return (B_TRUE); 7499 case CB_CODE_CPR_RESUME: 7500 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7501 "hubd_cpr_post_user_callb: CB_CODE_CPR_RESUME"); 7502 7503 /* restore the state of the device */ 7504 (void) hubd_post_resume_event_cb(hubd->h_dip); 7505 7506 /* turn on deathrow thread */ 7507 mutex_enter(HUBD_MUTEX(hubd)); 7508 hubd->h_cleanup_enabled = B_TRUE; 7509 mutex_exit(HUBD_MUTEX(hubd)); 7510 7511 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 7512 7513 return (B_TRUE); 7514 default: 7515 7516 return (B_FALSE); 7517 } 7518 7519 } 7520 7521 7522 /* register callback with cpr framework */ 7523 void 7524 hubd_register_cpr_callback(hubd_t *hubd) 7525 { 7526 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7527 "hubd_register_cpr_callback"); 7528 7529 mutex_enter(HUBD_MUTEX(hubd)); 7530 hubd->h_cpr_cb = 7531 (hubd_cpr_t *)kmem_zalloc(sizeof (hubd_cpr_t), KM_SLEEP); 7532 mutex_exit(HUBD_MUTEX(hubd)); 7533 mutex_init(&hubd->h_cpr_cb->lockp, NULL, MUTEX_DRIVER, 7534 hubd->h_dev_data->dev_iblock_cookie); 7535 hubd->h_cpr_cb->statep = hubd; 7536 hubd->h_cpr_cb->cpr.cc_lockp = &hubd->h_cpr_cb->lockp; 7537 hubd->h_cpr_cb->cpr.cc_id = callb_add(hubd_cpr_post_user_callb, 7538 (void *)hubd->h_cpr_cb, CB_CL_CPR_POST_USER, "hubd"); 7539 } 7540 7541 7542 /* unregister callback with cpr framework */ 7543 void 7544 hubd_unregister_cpr_callback(hubd_t *hubd) 7545 { 7546 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7547 "hubd_unregister_cpr_callback"); 7548 7549 if (hubd->h_cpr_cb) { 7550 (void) callb_delete(hubd->h_cpr_cb->cpr.cc_id); 7551 mutex_destroy(&hubd->h_cpr_cb->lockp); 7552 mutex_enter(HUBD_MUTEX(hubd)); 7553 kmem_free(hubd->h_cpr_cb, sizeof (hubd_cpr_t)); 7554 mutex_exit(HUBD_MUTEX(hubd)); 7555 } 7556 } 7557 7558 7559 /* 7560 * Power management 7561 * 7562 * create the pm components required for power management 7563 */ 7564 static void 7565 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd) 7566 { 7567 hub_power_t *hubpm; 7568 7569 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7570 "hubd_create_pm_components: Begin"); 7571 7572 /* Allocate the state structure */ 7573 hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP); 7574 7575 hubd->h_hubpm = hubpm; 7576 hubpm->hubp_hubd = hubd; 7577 hubpm->hubp_pm_capabilities = 0; 7578 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 7579 hubpm->hubp_time_at_full_power = gethrtime(); 7580 hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold * NANOSEC; 7581 7582 /* alloc memory to save power states of children */ 7583 hubpm->hubp_child_pwrstate = (uint8_t *) 7584 kmem_zalloc(MAX_PORTS + 1, KM_SLEEP); 7585 7586 /* 7587 * if the enable remote wakeup fails 7588 * we still want to enable 7589 * parent notification so we can PM the children 7590 */ 7591 usb_enable_parent_notification(dip); 7592 7593 if (usb_handle_remote_wakeup(dip, 7594 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 7595 uint_t pwr_states; 7596 7597 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 7598 "hubd_create_pm_components: " 7599 "Remote Wakeup Enabled"); 7600 7601 if (usb_create_pm_components(dip, &pwr_states) == 7602 USB_SUCCESS) { 7603 mutex_enter(HUBD_MUTEX(hubd)); 7604 hubpm->hubp_wakeup_enabled = 1; 7605 hubpm->hubp_pwr_states = (uint8_t)pwr_states; 7606 7607 /* we are busy now till end of the attach */ 7608 hubd_pm_busy_component(hubd, dip, 0); 7609 mutex_exit(HUBD_MUTEX(hubd)); 7610 7611 /* bring the device to full power */ 7612 (void) pm_raise_power(dip, 0, 7613 USB_DEV_OS_FULL_PWR); 7614 } 7615 } 7616 7617 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7618 "hubd_create_pm_components: END"); 7619 } 7620 7621 7622 /* 7623 * Attachment point management 7624 */ 7625 /* ARGSUSED */ 7626 int 7627 usba_hubdi_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, 7628 cred_t *credp) 7629 { 7630 hubd_t *hubd; 7631 7632 if (otyp != OTYP_CHR) 7633 return (EINVAL); 7634 7635 hubd = hubd_get_soft_state(dip); 7636 if (hubd == NULL) { 7637 return (ENXIO); 7638 } 7639 7640 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7641 "hubd_open:"); 7642 7643 mutex_enter(HUBD_MUTEX(hubd)); 7644 if ((flags & FEXCL) && (hubd->h_softstate & HUBD_SS_ISOPEN)) { 7645 mutex_exit(HUBD_MUTEX(hubd)); 7646 7647 return (EBUSY); 7648 } 7649 7650 hubd->h_softstate |= HUBD_SS_ISOPEN; 7651 mutex_exit(HUBD_MUTEX(hubd)); 7652 7653 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "opened"); 7654 7655 return (0); 7656 } 7657 7658 7659 /* ARGSUSED */ 7660 int 7661 usba_hubdi_close(dev_info_t *dip, dev_t dev, int flag, int otyp, 7662 cred_t *credp) 7663 { 7664 hubd_t *hubd; 7665 7666 if (otyp != OTYP_CHR) { 7667 return (EINVAL); 7668 } 7669 7670 hubd = hubd_get_soft_state(dip); 7671 7672 if (hubd == NULL) { 7673 return (ENXIO); 7674 } 7675 7676 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "hubd_close:"); 7677 7678 mutex_enter(HUBD_MUTEX(hubd)); 7679 hubd->h_softstate &= ~HUBD_SS_ISOPEN; 7680 mutex_exit(HUBD_MUTEX(hubd)); 7681 7682 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "closed"); 7683 7684 return (0); 7685 } 7686 7687 7688 /* 7689 * hubd_ioctl: cfgadm controls 7690 */ 7691 /* ARGSUSED */ 7692 int 7693 usba_hubdi_ioctl(dev_info_t *self, dev_t dev, int cmd, intptr_t arg, 7694 int mode, cred_t *credp, int *rvalp) 7695 { 7696 int rv = 0; 7697 char *msg; /* for messages */ 7698 hubd_t *hubd; 7699 usb_port_t port = 0; 7700 dev_info_t *child_dip = NULL; 7701 dev_info_t *rh_dip; 7702 devctl_ap_state_t ap_state; 7703 struct devctl_iocdata *dcp = NULL; 7704 usb_pipe_state_t prev_pipe_state = 0; 7705 7706 if ((hubd = hubd_get_soft_state(self)) == NULL) { 7707 7708 return (ENXIO); 7709 } 7710 7711 rh_dip = hubd->h_usba_device->usb_root_hub_dip; 7712 7713 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7714 "usba_hubdi_ioctl: " 7715 "cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx", 7716 cmd, arg, mode, (void *)credp, (void *)rvalp, dev); 7717 7718 /* read devctl ioctl data */ 7719 if ((cmd != DEVCTL_AP_CONTROL) && 7720 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 7721 7722 return (EFAULT); 7723 } 7724 7725 /* 7726 * make sure the hub is connected before trying any 7727 * of the following operations: 7728 * configure, connect, disconnect 7729 */ 7730 mutex_enter(HUBD_MUTEX(hubd)); 7731 7732 switch (cmd) { 7733 case DEVCTL_AP_DISCONNECT: 7734 case DEVCTL_AP_UNCONFIGURE: 7735 case DEVCTL_AP_CONFIGURE: 7736 if (hubd->h_dev_state == USB_DEV_DISCONNECTED) { 7737 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7738 "hubd: already gone"); 7739 mutex_exit(HUBD_MUTEX(hubd)); 7740 if (dcp) { 7741 ndi_dc_freehdl(dcp); 7742 } 7743 7744 return (EIO); 7745 } 7746 7747 /* FALLTHROUGH */ 7748 case DEVCTL_AP_GETSTATE: 7749 if ((port = hubd_get_port_num(hubd, dcp)) == 0) { 7750 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7751 "hubd: bad port"); 7752 mutex_exit(HUBD_MUTEX(hubd)); 7753 if (dcp) { 7754 ndi_dc_freehdl(dcp); 7755 } 7756 7757 return (EINVAL); 7758 } 7759 break; 7760 7761 case DEVCTL_AP_CONTROL: 7762 7763 break; 7764 default: 7765 mutex_exit(HUBD_MUTEX(hubd)); 7766 if (dcp) { 7767 ndi_dc_freehdl(dcp); 7768 } 7769 7770 return (ENOTTY); 7771 } 7772 7773 /* should not happen, just in case */ 7774 if (hubd->h_dev_state == USB_DEV_SUSPENDED) { 7775 mutex_exit(HUBD_MUTEX(hubd)); 7776 if (dcp) { 7777 ndi_dc_freehdl(dcp); 7778 } 7779 7780 return (EIO); 7781 } 7782 7783 if (hubd->h_reset_port[port]) { 7784 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7785 "This port is resetting, just return"); 7786 mutex_exit(HUBD_MUTEX(hubd)); 7787 if (dcp) { 7788 ndi_dc_freehdl(dcp); 7789 } 7790 7791 return (EIO); 7792 } 7793 7794 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7795 mutex_exit(HUBD_MUTEX(hubd)); 7796 7797 /* go full power */ 7798 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7799 7800 ndi_devi_enter(ddi_get_parent(rh_dip)); 7801 ndi_devi_enter(rh_dip); 7802 ndi_devi_enter(hubd->h_dip); 7803 7804 mutex_enter(HUBD_MUTEX(hubd)); 7805 7806 hubd->h_hotplug_thread++; 7807 7808 /* stop polling if it was active */ 7809 if (hubd->h_ep1_ph) { 7810 mutex_exit(HUBD_MUTEX(hubd)); 7811 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 7812 USB_FLAGS_SLEEP); 7813 mutex_enter(HUBD_MUTEX(hubd)); 7814 7815 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 7816 hubd_stop_polling(hubd); 7817 } 7818 } 7819 7820 switch (cmd) { 7821 case DEVCTL_AP_DISCONNECT: 7822 if (hubd_delete_child(hubd, port, 7823 NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS) { 7824 rv = EIO; 7825 } 7826 7827 break; 7828 case DEVCTL_AP_UNCONFIGURE: 7829 if (hubd_delete_child(hubd, port, 7830 NDI_UNCONFIG, B_FALSE) != USB_SUCCESS) { 7831 rv = EIO; 7832 } 7833 7834 break; 7835 case DEVCTL_AP_CONFIGURE: 7836 /* toggle port */ 7837 if (hubd_toggle_port(hubd, port) != USB_SUCCESS) { 7838 rv = EIO; 7839 7840 break; 7841 } 7842 7843 (void) hubd_handle_port_connect(hubd, port); 7844 child_dip = hubd_get_child_dip(hubd, port); 7845 mutex_exit(HUBD_MUTEX(hubd)); 7846 7847 ndi_devi_exit(hubd->h_dip); 7848 ndi_devi_exit(rh_dip); 7849 ndi_devi_exit(ddi_get_parent(rh_dip)); 7850 if (child_dip == NULL) { 7851 rv = EIO; 7852 } else { 7853 ndi_hold_devi(child_dip); 7854 if (ndi_devi_online(child_dip, 0) != NDI_SUCCESS) 7855 rv = EIO; 7856 ndi_rele_devi(child_dip); 7857 } 7858 ndi_devi_enter(ddi_get_parent(rh_dip)); 7859 ndi_devi_enter(rh_dip); 7860 ndi_devi_enter(hubd->h_dip); 7861 7862 mutex_enter(HUBD_MUTEX(hubd)); 7863 7864 break; 7865 case DEVCTL_AP_GETSTATE: 7866 switch (hubd_cfgadm_state(hubd, port)) { 7867 case HUBD_CFGADM_DISCONNECTED: 7868 /* port previously 'disconnected' by cfgadm */ 7869 ap_state.ap_rstate = AP_RSTATE_DISCONNECTED; 7870 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7871 ap_state.ap_condition = AP_COND_OK; 7872 7873 break; 7874 case HUBD_CFGADM_UNCONFIGURED: 7875 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7876 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7877 ap_state.ap_condition = AP_COND_OK; 7878 7879 break; 7880 case HUBD_CFGADM_CONFIGURED: 7881 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7882 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7883 ap_state.ap_condition = AP_COND_OK; 7884 7885 break; 7886 case HUBD_CFGADM_STILL_REFERENCED: 7887 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7888 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7889 ap_state.ap_condition = AP_COND_UNUSABLE; 7890 7891 break; 7892 case HUBD_CFGADM_EMPTY: 7893 default: 7894 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7895 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7896 ap_state.ap_condition = AP_COND_OK; 7897 7898 break; 7899 } 7900 7901 ap_state.ap_last_change = (time_t)-1; 7902 ap_state.ap_error_code = 0; 7903 ap_state.ap_in_transition = 0; 7904 7905 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7906 "DEVCTL_AP_GETSTATE: " 7907 "ostate=0x%x, rstate=0x%x, condition=0x%x", 7908 ap_state.ap_ostate, 7909 ap_state.ap_rstate, ap_state.ap_condition); 7910 7911 /* copy the return-AP-state information to the user space */ 7912 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 7913 rv = EFAULT; 7914 } 7915 7916 break; 7917 case DEVCTL_AP_CONTROL: 7918 { 7919 /* 7920 * Generic devctl for hardware-specific functionality. 7921 * For list of sub-commands see hubd_impl.h 7922 */ 7923 hubd_ioctl_data_t ioc; /* for 64 byte copies */ 7924 7925 /* copy user ioctl data in first */ 7926 #ifdef _MULTI_DATAMODEL 7927 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 7928 hubd_ioctl_data_32_t ioc32; 7929 7930 if (ddi_copyin((void *)arg, (void *)&ioc32, 7931 sizeof (ioc32), mode) != 0) { 7932 rv = EFAULT; 7933 7934 break; 7935 } 7936 ioc.cmd = (uint_t)ioc32.cmd; 7937 ioc.port = (uint_t)ioc32.port; 7938 ioc.get_size = (uint_t)ioc32.get_size; 7939 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 7940 ioc.bufsiz = (uint_t)ioc32.bufsiz; 7941 ioc.misc_arg = (uint_t)ioc32.misc_arg; 7942 } else 7943 #endif /* _MULTI_DATAMODEL */ 7944 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc), 7945 mode) != 0) { 7946 rv = EFAULT; 7947 7948 break; 7949 } 7950 7951 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7952 "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d" 7953 "\n\tbuf=0x%p, bufsiz=%d, misc_arg=%d", ioc.cmd, 7954 ioc.port, ioc.get_size, (void *)ioc.buf, ioc.bufsiz, 7955 ioc.misc_arg); 7956 7957 /* 7958 * To avoid BE/LE and 32/64 issues, a get_size always 7959 * returns a 32-bit number. 7960 */ 7961 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) { 7962 rv = EINVAL; 7963 7964 break; 7965 } 7966 7967 switch (ioc.cmd) { 7968 case USB_DESCR_TYPE_DEV: 7969 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC"; 7970 if (ioc.get_size) { 7971 /* uint32 so this works 32/64 */ 7972 uint32_t size = sizeof (usb_dev_descr_t); 7973 7974 if (ddi_copyout((void *)&size, ioc.buf, 7975 ioc.bufsiz, mode) != 0) { 7976 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7977 hubd->h_log_handle, 7978 "%s: get_size copyout failed", msg); 7979 rv = EIO; 7980 7981 break; 7982 } 7983 } else { /* send out the actual descr */ 7984 usb_dev_descr_t *dev_descrp; 7985 7986 /* check child_dip */ 7987 if ((child_dip = hubd_get_child_dip(hubd, 7988 ioc.port)) == NULL) { 7989 rv = EINVAL; 7990 7991 break; 7992 } 7993 7994 dev_descrp = usb_get_dev_descr(child_dip); 7995 if (ioc.bufsiz != sizeof (*dev_descrp)) { 7996 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7997 hubd->h_log_handle, 7998 "%s: bufsize passed (%d) != sizeof " 7999 "usba_device_descr_t (%d)", msg, 8000 ioc.bufsiz, dev_descrp->bLength); 8001 rv = EINVAL; 8002 8003 break; 8004 } 8005 8006 if (ddi_copyout((void *)dev_descrp, 8007 ioc.buf, ioc.bufsiz, mode) != 0) { 8008 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8009 hubd->h_log_handle, 8010 "%s: copyout failed.", msg); 8011 rv = EIO; 8012 8013 break; 8014 } 8015 } 8016 break; 8017 case USB_DESCR_TYPE_STRING: 8018 { 8019 char *str; 8020 uint32_t size; 8021 usba_device_t *usba_device; 8022 8023 msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR"; 8024 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8025 "%s: string request: %d", msg, ioc.misc_arg); 8026 8027 /* recheck */ 8028 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 8029 NULL) { 8030 rv = EINVAL; 8031 8032 break; 8033 } 8034 usba_device = usba_get_usba_device(child_dip); 8035 8036 switch (ioc.misc_arg) { 8037 case HUBD_MFG_STR: 8038 str = usba_device->usb_mfg_str; 8039 8040 break; 8041 case HUBD_PRODUCT_STR: 8042 str = usba_device->usb_product_str; 8043 8044 break; 8045 case HUBD_SERIALNO_STR: 8046 str = usba_device->usb_serialno_str; 8047 8048 break; 8049 case HUBD_CFG_DESCR_STR: 8050 mutex_enter(&usba_device->usb_mutex); 8051 str = usba_device->usb_cfg_str_descr[ 8052 usba_device->usb_active_cfg_ndx]; 8053 mutex_exit(&usba_device->usb_mutex); 8054 8055 break; 8056 default: 8057 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8058 hubd->h_log_handle, 8059 "%s: Invalid string request", msg); 8060 rv = EINVAL; 8061 8062 break; 8063 } /* end of switch */ 8064 8065 if (rv != 0) { 8066 8067 break; 8068 } 8069 8070 size = (str != NULL) ? strlen(str) + 1 : 0; 8071 if (ioc.get_size) { 8072 if (ddi_copyout((void *)&size, ioc.buf, 8073 ioc.bufsiz, mode) != 0) { 8074 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8075 hubd->h_log_handle, 8076 "%s: copyout of size failed.", msg); 8077 rv = EIO; 8078 8079 break; 8080 } 8081 } else { 8082 if (size == 0) { 8083 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, 8084 hubd->h_log_handle, 8085 "%s: String is NULL", msg); 8086 rv = EINVAL; 8087 8088 break; 8089 } 8090 8091 if (ioc.bufsiz != size) { 8092 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8093 hubd->h_log_handle, 8094 "%s: string buf size wrong", msg); 8095 rv = EINVAL; 8096 8097 break; 8098 } 8099 8100 if (ddi_copyout((void *)str, ioc.buf, 8101 ioc.bufsiz, mode) != 0) { 8102 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8103 hubd->h_log_handle, 8104 "%s: copyout failed.", msg); 8105 rv = EIO; 8106 8107 break; 8108 } 8109 } 8110 break; 8111 } 8112 case HUBD_GET_CFGADM_NAME: 8113 { 8114 uint32_t name_len; 8115 const char *name; 8116 8117 /* recheck */ 8118 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 8119 NULL) { 8120 rv = EINVAL; 8121 8122 break; 8123 } 8124 name = ddi_node_name(child_dip); 8125 if (name == NULL) { 8126 name = "unsupported"; 8127 } 8128 name_len = strlen(name) + 1; 8129 8130 msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME"; 8131 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8132 "%s: name=%s name_len=%d", msg, name, name_len); 8133 8134 if (ioc.get_size) { 8135 if (ddi_copyout((void *)&name_len, 8136 ioc.buf, ioc.bufsiz, mode) != 0) { 8137 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8138 hubd->h_log_handle, 8139 "%s: copyout of size failed", msg); 8140 rv = EIO; 8141 8142 break; 8143 } 8144 } else { 8145 if (ioc.bufsiz != name_len) { 8146 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8147 hubd->h_log_handle, 8148 "%s: string buf length wrong", msg); 8149 rv = EINVAL; 8150 8151 break; 8152 } 8153 8154 if (ddi_copyout((void *)name, ioc.buf, 8155 ioc.bufsiz, mode) != 0) { 8156 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8157 hubd->h_log_handle, 8158 "%s: copyout failed.", msg); 8159 rv = EIO; 8160 8161 break; 8162 } 8163 } 8164 8165 break; 8166 } 8167 8168 /* 8169 * Return the config index for the currently-configured 8170 * configuration. 8171 */ 8172 case HUBD_GET_CURRENT_CONFIG: 8173 { 8174 uint_t config_index; 8175 uint32_t size = sizeof (config_index); 8176 usba_device_t *usba_device; 8177 8178 msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG"; 8179 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8180 "%s", msg); 8181 8182 /* 8183 * Return the config index for the configuration 8184 * currently in use. 8185 * Recheck if child_dip exists 8186 */ 8187 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 8188 NULL) { 8189 rv = EINVAL; 8190 8191 break; 8192 } 8193 8194 usba_device = usba_get_usba_device(child_dip); 8195 mutex_enter(&usba_device->usb_mutex); 8196 config_index = usba_device->usb_active_cfg_ndx; 8197 mutex_exit(&usba_device->usb_mutex); 8198 8199 if (ioc.get_size) { 8200 if (ddi_copyout((void *)&size, 8201 ioc.buf, ioc.bufsiz, mode) != 0) { 8202 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8203 hubd->h_log_handle, 8204 "%s: copyout of size failed.", msg); 8205 rv = EIO; 8206 8207 break; 8208 } 8209 } else { 8210 if (ioc.bufsiz != size) { 8211 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8212 hubd->h_log_handle, 8213 "%s: buffer size wrong", msg); 8214 rv = EINVAL; 8215 8216 break; 8217 } 8218 if (ddi_copyout((void *)&config_index, 8219 ioc.buf, ioc.bufsiz, mode) != 0) { 8220 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8221 hubd->h_log_handle, 8222 "%s: copyout failed", msg); 8223 rv = EIO; 8224 } 8225 } 8226 8227 break; 8228 } 8229 case HUBD_GET_DEVICE_PATH: 8230 { 8231 char *path; 8232 uint32_t size; 8233 8234 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH"; 8235 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8236 "%s", msg); 8237 8238 /* Recheck if child_dip exists */ 8239 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 8240 NULL) { 8241 rv = EINVAL; 8242 8243 break; 8244 } 8245 8246 /* ddi_pathname doesn't supply /devices, so we do. */ 8247 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 8248 (void) strcpy(path, "/devices"); 8249 (void) ddi_pathname(child_dip, path + strlen(path)); 8250 size = strlen(path) + 1; 8251 8252 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8253 "%s: device path=%s size=%d", msg, path, size); 8254 8255 if (ioc.get_size) { 8256 if (ddi_copyout((void *)&size, 8257 ioc.buf, ioc.bufsiz, mode) != 0) { 8258 8259 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8260 hubd->h_log_handle, 8261 "%s: copyout of size failed.", msg); 8262 rv = EIO; 8263 } 8264 } else { 8265 if (ioc.bufsiz != size) { 8266 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8267 hubd->h_log_handle, 8268 "%s: buffer wrong size.", msg); 8269 rv = EINVAL; 8270 } else if (ddi_copyout((void *)path, 8271 ioc.buf, ioc.bufsiz, mode) != 0) { 8272 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8273 hubd->h_log_handle, 8274 "%s: copyout failed.", msg); 8275 rv = EIO; 8276 } 8277 } 8278 kmem_free(path, MAXPATHLEN); 8279 8280 break; 8281 } 8282 case HUBD_REFRESH_DEVDB: 8283 msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB"; 8284 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8285 "%s", msg); 8286 8287 if ((rv = usba_devdb_refresh()) != USB_SUCCESS) { 8288 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 8289 hubd->h_log_handle, 8290 "%s: Failed: %d", msg, rv); 8291 rv = EIO; 8292 } 8293 8294 break; 8295 default: 8296 rv = ENOTSUP; 8297 } /* end switch */ 8298 8299 break; 8300 } 8301 8302 default: 8303 rv = ENOTTY; 8304 } 8305 8306 if (dcp) { 8307 ndi_dc_freehdl(dcp); 8308 } 8309 8310 /* allow hotplug thread now */ 8311 hubd->h_hotplug_thread--; 8312 8313 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 8314 hubd->h_ep1_ph && (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 8315 hubd_start_polling(hubd, 0); 8316 } 8317 mutex_exit(HUBD_MUTEX(hubd)); 8318 8319 ndi_devi_exit(hubd->h_dip); 8320 ndi_devi_exit(rh_dip); 8321 ndi_devi_exit(ddi_get_parent(rh_dip)); 8322 8323 mutex_enter(HUBD_MUTEX(hubd)); 8324 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 8325 mutex_exit(HUBD_MUTEX(hubd)); 8326 8327 return (rv); 8328 } 8329 8330 8331 /* 8332 * Helper func used only to help construct the names for the attachment point 8333 * minor nodes. Used only in usba_hubdi_attach. 8334 * Returns whether it found ancestry or not (USB_SUCCESS if yes). 8335 * ports between the root hub and the device represented by dip. 8336 * E.g., "2.4.3.1" means this device is 8337 * plugged into port 1 of a hub that is 8338 * plugged into port 3 of a hub that is 8339 * plugged into port 4 of a hub that is 8340 * plugged into port 2 of the root hub. 8341 * NOTE: Max ap_id path len is HUBD_APID_NAMELEN (32 chars), which is 8342 * more than sufficient (as hubs are a max 6 levels deep, port needs 3 8343 * chars plus NULL each) 8344 */ 8345 void 8346 hubd_get_ancestry_str(hubd_t *hubd) 8347 { 8348 char ap_name[HUBD_APID_NAMELEN]; 8349 dev_info_t *pdip; 8350 hubd_t *phubd; 8351 usb_port_t port; 8352 8353 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8354 "hubd_get_ancestry_str: hubd=0x%p", (void *)hubd); 8355 8356 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8357 8358 /* 8359 * The function is extended to support wire adapter class 8360 * devices introduced by WUSB spec. The node name is no 8361 * longer "hub" only. 8362 * Generate the ap_id str based on the parent and child 8363 * relationship instead of retrieving it from the hub 8364 * device path, which simplifies the algorithm. 8365 */ 8366 if (usba_is_root_hub(hubd->h_dip)) { 8367 hubd->h_ancestry_str[0] = '\0'; 8368 } else { 8369 port = hubd->h_usba_device->usb_port; 8370 mutex_exit(HUBD_MUTEX(hubd)); 8371 8372 pdip = ddi_get_parent(hubd->h_dip); 8373 /* 8374 * The parent of wire adapter device might be usb_mid. 8375 * Need to look further up for hub device 8376 */ 8377 if (strcmp(ddi_driver_name(pdip), "usb_mid") == 0) { 8378 pdip = ddi_get_parent(pdip); 8379 ASSERT(pdip != NULL); 8380 } 8381 8382 phubd = hubd_get_soft_state(pdip); 8383 8384 mutex_enter(HUBD_MUTEX(phubd)); 8385 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 8386 phubd->h_ancestry_str, port); 8387 mutex_exit(HUBD_MUTEX(phubd)); 8388 8389 mutex_enter(HUBD_MUTEX(hubd)); 8390 (void) strcpy(hubd->h_ancestry_str, ap_name); 8391 (void) strcat(hubd->h_ancestry_str, "."); 8392 } 8393 } 8394 8395 8396 /* Get which port to operate on. */ 8397 static usb_port_t 8398 hubd_get_port_num(hubd_t *hubd, struct devctl_iocdata *dcp) 8399 { 8400 int32_t port; 8401 8402 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8403 8404 /* Get which port to operate on. */ 8405 if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) { 8406 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8407 "hubd_get_port_num: port lookup failed"); 8408 port = 0; 8409 } 8410 8411 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8412 "hubd_get_port_num: hubd=0x%p, port=%d", (void *)hubd, port); 8413 8414 return ((usb_port_t)port); 8415 } 8416 8417 8418 /* check if child still exists */ 8419 static dev_info_t * 8420 hubd_get_child_dip(hubd_t *hubd, usb_port_t port) 8421 { 8422 dev_info_t *child_dip = hubd->h_children_dips[port]; 8423 8424 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8425 "hubd_get_child_dip: hubd=0x%p, port=%d", (void *)hubd, port); 8426 8427 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8428 8429 return (child_dip); 8430 } 8431 8432 8433 /* 8434 * hubd_cfgadm_state: 8435 * 8436 * child_dip list port_state cfgadm_state 8437 * -------------- ---------- ------------ 8438 * != NULL connected configured or 8439 * unconfigured 8440 * != NULL not connected disconnect but 8441 * busy/still referenced 8442 * NULL connected logically disconnected 8443 * NULL not connected empty 8444 */ 8445 static uint_t 8446 hubd_cfgadm_state(hubd_t *hubd, usb_port_t port) 8447 { 8448 uint_t state; 8449 dev_info_t *child_dip = hubd_get_child_dip(hubd, port); 8450 8451 if (child_dip) { 8452 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 8453 /* 8454 * connected, now check if driver exists 8455 */ 8456 if (DEVI_IS_DEVICE_OFFLINE(child_dip) || 8457 !i_ddi_devi_attached(child_dip)) { 8458 state = HUBD_CFGADM_UNCONFIGURED; 8459 } else { 8460 state = HUBD_CFGADM_CONFIGURED; 8461 } 8462 } else { 8463 /* 8464 * this means that the dip is around for 8465 * a device that is still referenced but 8466 * has been yanked out. So the cfgadm info 8467 * for this state should be EMPTY (port empty) 8468 * and CONFIGURED (dip still valid). 8469 */ 8470 state = HUBD_CFGADM_STILL_REFERENCED; 8471 } 8472 } else { 8473 /* connected but no child dip */ 8474 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 8475 /* logically disconnected */ 8476 state = HUBD_CFGADM_DISCONNECTED; 8477 } else { 8478 /* physically disconnected */ 8479 state = HUBD_CFGADM_EMPTY; 8480 } 8481 } 8482 8483 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8484 "hubd_cfgadm_state: hubd=0x%p, port=%d state=0x%x", 8485 (void *)hubd, port, state); 8486 8487 return (state); 8488 } 8489 8490 8491 /* 8492 * hubd_toggle_port: 8493 */ 8494 static int 8495 hubd_toggle_port(hubd_t *hubd, usb_port_t port) 8496 { 8497 int wait; 8498 uint_t retry; 8499 uint16_t status; 8500 uint16_t change; 8501 8502 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8503 "hubd_toggle_port: hubd=0x%p, port=%d", (void *)hubd, port); 8504 8505 if ((hubd_disable_port_power(hubd, port)) != USB_SUCCESS) { 8506 8507 return (USB_FAILURE); 8508 } 8509 8510 /* 8511 * see hubd_enable_all_port_power() which 8512 * requires longer delay for hubs. 8513 */ 8514 mutex_exit(HUBD_MUTEX(hubd)); 8515 delay(drv_usectohz(hubd_device_delay / 10)); 8516 mutex_enter(HUBD_MUTEX(hubd)); 8517 8518 /* 8519 * According to section 11.11 of USB, for hubs with no power 8520 * switches, bPwrOn2PwrGood is zero. But we wait for some 8521 * arbitrary time to enable power to become stable. 8522 * 8523 * If an hub supports port power swicthing, we need to wait 8524 * at least 20ms before accesing corresonding usb port. Note 8525 * this member is stored in the h_power_good member. 8526 */ 8527 if ((hubd->h_hub_chars & HUB_CHARS_NO_POWER_SWITCHING) || 8528 (hubd->h_power_good == 0)) { 8529 wait = hubd_device_delay / 10; 8530 } else { 8531 wait = max(HUB_DEFAULT_POPG, 8532 hubd->h_power_good) * 2 * 1000; 8533 } 8534 8535 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 8536 "hubd_toggle_port: popg=%d wait=%d", 8537 hubd->h_power_good, wait); 8538 8539 retry = 0; 8540 8541 do { 8542 (void) hubd_enable_port_power(hubd, port); 8543 8544 mutex_exit(HUBD_MUTEX(hubd)); 8545 delay(drv_usectohz(wait)); 8546 mutex_enter(HUBD_MUTEX(hubd)); 8547 8548 /* Get port status */ 8549 (void) hubd_determine_port_status(hubd, port, 8550 &status, &change, NULL, 0); 8551 8552 /* For retry if any, use some extra delay */ 8553 wait = max(wait, hubd_device_delay / 10); 8554 8555 retry++; 8556 8557 } while ((!(status & PORT_STATUS_PPS)) && (retry < HUBD_PORT_RETRY)); 8558 8559 /* Print warning message if port has no power */ 8560 if (!(status & PORT_STATUS_PPS)) { 8561 8562 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 8563 "hubd_toggle_port: port %d power-on failed, " 8564 "port status 0x%x", port, status); 8565 8566 return (USB_FAILURE); 8567 } 8568 8569 return (USB_SUCCESS); 8570 } 8571 8572 8573 /* 8574 * hubd_init_power_budget: 8575 * Init power budget variables in hubd structure. According 8576 * to USB spec, the power budget rules are: 8577 * 1. local-powered hubs including root-hubs can supply 8578 * 500mA to each port at maximum 8579 * 2. two bus-powered hubs are not allowed to concatenate 8580 * 3. bus-powered hubs can supply 100mA to each port at 8581 * maximum, and the power consumed by all downstream 8582 * ports and the hub itself cannot exceed the max power 8583 * supplied by the upstream port, i.e., 500mA 8584 * The routine is only called during hub attach time 8585 */ 8586 static int 8587 hubd_init_power_budget(hubd_t *hubd) 8588 { 8589 uint16_t status = 0; 8590 usba_device_t *hubd_ud = NULL; 8591 size_t size; 8592 usb_cfg_descr_t cfg_descr; 8593 dev_info_t *pdip = NULL; 8594 hubd_t *phubd = NULL; 8595 8596 if (hubd->h_ignore_pwr_budget) { 8597 8598 return (USB_SUCCESS); 8599 } 8600 8601 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 8602 "hubd_init_power_budget:"); 8603 8604 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8605 ASSERT(hubd->h_default_pipe != 0); 8606 mutex_exit(HUBD_MUTEX(hubd)); 8607 8608 /* get device status */ 8609 if ((usb_get_status(hubd->h_dip, hubd->h_default_pipe, 8610 HUB_GET_DEVICE_STATUS_TYPE, 8611 0, &status, 0)) != USB_SUCCESS) { 8612 mutex_enter(HUBD_MUTEX(hubd)); 8613 8614 return (USB_FAILURE); 8615 } 8616 8617 hubd_ud = usba_get_usba_device(hubd->h_dip); 8618 8619 size = usb_parse_cfg_descr(hubd_ud->usb_cfg, hubd_ud->usb_cfg_length, 8620 &cfg_descr, USB_CFG_DESCR_SIZE); 8621 8622 if (size != USB_CFG_DESCR_SIZE) { 8623 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8624 "get hub configuration descriptor failed"); 8625 mutex_enter(HUBD_MUTEX(hubd)); 8626 8627 return (USB_FAILURE); 8628 } 8629 8630 mutex_enter(HUBD_MUTEX(hubd)); 8631 8632 hubd->h_local_pwr_capable = (cfg_descr.bmAttributes & 8633 USB_CFG_ATTR_SELFPWR); 8634 8635 if (hubd->h_local_pwr_capable) { 8636 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8637 "hub is capable of local power"); 8638 } 8639 8640 hubd->h_local_pwr_on = (status & 8641 USB_DEV_SLF_PWRD_STATUS) && hubd->h_local_pwr_capable; 8642 8643 if (hubd->h_local_pwr_on) { 8644 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8645 "hub is local-powered"); 8646 8647 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8648 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8649 } else { 8650 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8651 USB_LOW_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8652 8653 hubd->h_pwr_left = (USB_PWR_UNIT_LOAD * 8654 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8655 8656 ASSERT(!usba_is_root_hub(hubd->h_dip)); 8657 8658 if (!usba_is_root_hub(hubd->h_dip)) { 8659 /* 8660 * two bus-powered hubs are not 8661 * allowed to be concatenated 8662 */ 8663 mutex_exit(HUBD_MUTEX(hubd)); 8664 8665 pdip = ddi_get_parent(hubd->h_dip); 8666 phubd = hubd_get_soft_state(pdip); 8667 ASSERT(phubd != NULL); 8668 8669 if (!phubd->h_ignore_pwr_budget) { 8670 mutex_enter(HUBD_MUTEX(phubd)); 8671 if (phubd->h_local_pwr_on == B_FALSE) { 8672 USB_DPRINTF_L1(DPRINT_MASK_HUB, 8673 hubd->h_log_handle, 8674 "two bus-powered hubs cannot " 8675 "be concatenated"); 8676 8677 mutex_exit(HUBD_MUTEX(phubd)); 8678 mutex_enter(HUBD_MUTEX(hubd)); 8679 8680 return (USB_FAILURE); 8681 } 8682 mutex_exit(HUBD_MUTEX(phubd)); 8683 } 8684 8685 mutex_enter(HUBD_MUTEX(hubd)); 8686 8687 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8688 "hub is bus-powered"); 8689 } else { 8690 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8691 "root-hub must be local-powered"); 8692 } 8693 8694 /* 8695 * Subtract the power consumed by the hub itself 8696 * and get the power that can be supplied to 8697 * downstream ports 8698 */ 8699 hubd->h_pwr_left -= hubd->h_current / USB_CFG_DESCR_PWR_UNIT; 8700 if (hubd->h_pwr_left < 0) { 8701 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8702 "hubd->h_pwr_left is less than bHubContrCurrent, " 8703 "should fail"); 8704 8705 return (USB_FAILURE); 8706 } 8707 } 8708 8709 return (USB_SUCCESS); 8710 } 8711 8712 8713 /* 8714 * usba_hubdi_check_power_budget: 8715 * Check if the hub has enough power budget to allow a 8716 * child device to select a configuration of config_index. 8717 */ 8718 int 8719 usba_hubdi_check_power_budget(dev_info_t *dip, usba_device_t *child_ud, 8720 uint_t config_index) 8721 { 8722 int16_t pwr_left, pwr_limit, pwr_required; 8723 size_t size; 8724 usb_cfg_descr_t cfg_descr; 8725 hubd_t *hubd; 8726 8727 if ((hubd = hubd_get_soft_state(dip)) == NULL) { 8728 8729 return (USB_FAILURE); 8730 } 8731 8732 if (hubd->h_ignore_pwr_budget) { 8733 8734 return (USB_SUCCESS); 8735 } 8736 8737 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8738 "usba_hubdi_check_power_budget: " 8739 "dip=0x%p child_ud=0x%p conf_index=%d", (void *)dip, 8740 (void *)child_ud, config_index); 8741 8742 mutex_enter(HUBD_MUTEX(hubd)); 8743 pwr_limit = hubd->h_pwr_limit; 8744 if (hubd->h_local_pwr_on == B_FALSE) { 8745 pwr_left = hubd->h_pwr_left; 8746 pwr_limit = (pwr_limit <= pwr_left) ? pwr_limit : pwr_left; 8747 } 8748 mutex_exit(HUBD_MUTEX(hubd)); 8749 8750 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8751 "usba_hubdi_check_power_budget: " 8752 "available power is %dmA", pwr_limit * USB_CFG_DESCR_PWR_UNIT); 8753 8754 size = usb_parse_cfg_descr( 8755 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 8756 &cfg_descr, USB_CFG_DESCR_SIZE); 8757 8758 if (size != USB_CFG_DESCR_SIZE) { 8759 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8760 "get hub configuration descriptor failed"); 8761 8762 return (USB_FAILURE); 8763 } 8764 8765 pwr_required = cfg_descr.bMaxPower; 8766 8767 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8768 "usba_hubdi_check_power_budget: " 8769 "child bmAttributes=0x%x bMaxPower=%d " 8770 "with config_index=%d", cfg_descr.bmAttributes, 8771 pwr_required, config_index); 8772 8773 if (pwr_required > pwr_limit) { 8774 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8775 "configuration %d for device %s %s at port %d " 8776 "exceeds power available for this port, please " 8777 "re-insert your device into another hub port which " 8778 "has enough power", 8779 config_index, 8780 child_ud->usb_mfg_str, 8781 child_ud->usb_product_str, 8782 child_ud->usb_port); 8783 8784 return (USB_FAILURE); 8785 } 8786 8787 return (USB_SUCCESS); 8788 } 8789 8790 8791 /* 8792 * usba_hubdi_incr_power_budget: 8793 * Increase the hub power budget value when a child device 8794 * is removed from a bus-powered hub port. 8795 */ 8796 void 8797 usba_hubdi_incr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8798 { 8799 uint16_t pwr_value; 8800 hubd_t *hubd = hubd_get_soft_state(dip); 8801 8802 ASSERT(hubd != NULL); 8803 8804 if (hubd->h_ignore_pwr_budget) { 8805 8806 return; 8807 } 8808 8809 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8810 "usba_hubdi_incr_power_budget: " 8811 "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud); 8812 8813 mutex_enter(HUBD_MUTEX(hubd)); 8814 if (hubd->h_local_pwr_on == B_TRUE) { 8815 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8816 "usba_hubdi_incr_power_budget: " 8817 "hub is local powered"); 8818 mutex_exit(HUBD_MUTEX(hubd)); 8819 8820 return; 8821 } 8822 mutex_exit(HUBD_MUTEX(hubd)); 8823 8824 mutex_enter(&child_ud->usb_mutex); 8825 if (child_ud->usb_pwr_from_hub == 0) { 8826 mutex_exit(&child_ud->usb_mutex); 8827 8828 return; 8829 } 8830 pwr_value = child_ud->usb_pwr_from_hub; 8831 mutex_exit(&child_ud->usb_mutex); 8832 8833 mutex_enter(HUBD_MUTEX(hubd)); 8834 hubd->h_pwr_left += pwr_value; 8835 8836 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8837 "usba_hubdi_incr_power_budget: " 8838 "available power is %dmA, increased by %dmA", 8839 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8840 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8841 8842 mutex_exit(HUBD_MUTEX(hubd)); 8843 8844 mutex_enter(&child_ud->usb_mutex); 8845 child_ud->usb_pwr_from_hub = 0; 8846 mutex_exit(&child_ud->usb_mutex); 8847 } 8848 8849 8850 /* 8851 * usba_hubdi_decr_power_budget: 8852 * Decrease the hub power budget value when a child device 8853 * is inserted to a bus-powered hub port. 8854 */ 8855 void 8856 usba_hubdi_decr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8857 { 8858 uint16_t pwr_value; 8859 size_t size; 8860 usb_cfg_descr_t cfg_descr; 8861 hubd_t *hubd = hubd_get_soft_state(dip); 8862 8863 ASSERT(hubd != NULL); 8864 8865 if (hubd->h_ignore_pwr_budget) { 8866 8867 return; 8868 } 8869 8870 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8871 "usba_hubdi_decr_power_budget: " 8872 "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud); 8873 8874 mutex_enter(HUBD_MUTEX(hubd)); 8875 if (hubd->h_local_pwr_on == B_TRUE) { 8876 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8877 "usba_hubdi_decr_power_budget: " 8878 "hub is local powered"); 8879 mutex_exit(HUBD_MUTEX(hubd)); 8880 8881 return; 8882 } 8883 mutex_exit(HUBD_MUTEX(hubd)); 8884 8885 mutex_enter(&child_ud->usb_mutex); 8886 if (child_ud->usb_pwr_from_hub > 0) { 8887 mutex_exit(&child_ud->usb_mutex); 8888 8889 return; 8890 } 8891 mutex_exit(&child_ud->usb_mutex); 8892 8893 size = usb_parse_cfg_descr( 8894 child_ud->usb_cfg, child_ud->usb_cfg_length, 8895 &cfg_descr, USB_CFG_DESCR_SIZE); 8896 ASSERT(size == USB_CFG_DESCR_SIZE); 8897 8898 mutex_enter(HUBD_MUTEX(hubd)); 8899 pwr_value = cfg_descr.bMaxPower; 8900 hubd->h_pwr_left -= pwr_value; 8901 ASSERT(hubd->h_pwr_left >= 0); 8902 8903 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8904 "usba_hubdi_decr_power_budget: " 8905 "available power is %dmA, decreased by %dmA", 8906 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8907 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8908 8909 mutex_exit(HUBD_MUTEX(hubd)); 8910 8911 mutex_enter(&child_ud->usb_mutex); 8912 child_ud->usb_pwr_from_hub = pwr_value; 8913 mutex_exit(&child_ud->usb_mutex); 8914 } 8915 8916 /* 8917 * hubd_wait_for_hotplug_exit: 8918 * Waiting for the exit of the running hotplug thread or ioctl thread. 8919 */ 8920 static int 8921 hubd_wait_for_hotplug_exit(hubd_t *hubd) 8922 { 8923 clock_t until = drv_usectohz(1000000); 8924 int rval; 8925 8926 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8927 8928 if (hubd->h_hotplug_thread) { 8929 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8930 "waiting for hubd hotplug thread exit"); 8931 rval = cv_reltimedwait(&hubd->h_cv_hotplug_dev, 8932 &hubd->h_mutex, until, TR_CLOCK_TICK); 8933 8934 if ((rval <= 0) && (hubd->h_hotplug_thread)) { 8935 8936 return (USB_FAILURE); 8937 } 8938 } 8939 8940 return (USB_SUCCESS); 8941 } 8942 8943 /* 8944 * hubd_reset_thread: 8945 * handles the "USB_RESET_LVL_REATTACH" reset of usb device. 8946 * 8947 * - delete the child (force detaching the device and its children) 8948 * - reset the corresponding parent hub port 8949 * - create the child (force re-attaching the device and its children) 8950 */ 8951 static void 8952 hubd_reset_thread(void *arg) 8953 { 8954 hubd_reset_arg_t *hd_arg = (hubd_reset_arg_t *)arg; 8955 hubd_t *hubd = hd_arg->hubd; 8956 uint16_t reset_port = hd_arg->reset_port; 8957 uint16_t status, change; 8958 hub_power_t *hubpm; 8959 dev_info_t *hdip = hubd->h_dip; 8960 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 8961 dev_info_t *child_dip; 8962 boolean_t online_child = B_FALSE; 8963 int devinst; 8964 char *devname; 8965 int i = 0; 8966 int rval = USB_FAILURE; 8967 8968 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8969 "hubd_reset_thread: started, hubd_reset_port = 0x%x", reset_port); 8970 8971 kmem_free(arg, sizeof (hubd_reset_arg_t)); 8972 8973 mutex_enter(HUBD_MUTEX(hubd)); 8974 8975 child_dip = hubd->h_children_dips[reset_port]; 8976 ASSERT(child_dip != NULL); 8977 8978 devname = (char *)ddi_driver_name(child_dip); 8979 devinst = ddi_get_instance(child_dip); 8980 8981 /* if our bus power entry point is active, quit the reset */ 8982 if (hubd->h_bus_pwr) { 8983 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8984 "%s%d is under bus power management, cannot be reset. " 8985 "Please disconnect and reconnect this device.", 8986 devname, devinst); 8987 8988 goto Fail; 8989 } 8990 8991 if (hubd_wait_for_hotplug_exit(hubd) == USB_FAILURE) { 8992 /* we got woken up because of a timeout */ 8993 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 8994 hubd->h_log_handle, "Time out when resetting the device" 8995 " %s%d. Please disconnect and reconnect this device.", 8996 devname, devinst); 8997 8998 goto Fail; 8999 } 9000 9001 hubd->h_hotplug_thread++; 9002 9003 /* is this the root hub? */ 9004 if ((hdip == rh_dip) && 9005 (hubd->h_dev_state == USB_DEV_PWRED_DOWN)) { 9006 hubpm = hubd->h_hubpm; 9007 9008 /* mark the root hub as full power */ 9009 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 9010 hubpm->hubp_time_at_full_power = gethrtime(); 9011 mutex_exit(HUBD_MUTEX(hubd)); 9012 9013 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 9014 "hubd_reset_thread: call pm_power_has_changed"); 9015 9016 (void) pm_power_has_changed(hdip, 0, 9017 USB_DEV_OS_FULL_PWR); 9018 9019 mutex_enter(HUBD_MUTEX(hubd)); 9020 hubd->h_dev_state = USB_DEV_ONLINE; 9021 } 9022 9023 mutex_exit(HUBD_MUTEX(hubd)); 9024 9025 /* 9026 * this ensures one reset activity per system at a time. 9027 * we enter the parent PCI node to have this serialization. 9028 * this also excludes ioctls and deathrow thread 9029 */ 9030 ndi_devi_enter(ddi_get_parent(rh_dip)); 9031 ndi_devi_enter(rh_dip); 9032 9033 /* exclude other threads */ 9034 ndi_devi_enter(hdip); 9035 mutex_enter(HUBD_MUTEX(hubd)); 9036 9037 /* 9038 * We need to make sure that the child is still online for a hotplug 9039 * thread could have inserted which detached the child. 9040 */ 9041 if (hubd->h_children_dips[reset_port]) { 9042 mutex_exit(HUBD_MUTEX(hubd)); 9043 /* First disconnect the device */ 9044 hubd_post_event(hubd, reset_port, USBA_EVENT_TAG_HOT_REMOVAL); 9045 9046 /* delete cached dv_node's but drop locks first */ 9047 ndi_devi_exit(hdip); 9048 ndi_devi_exit(rh_dip); 9049 ndi_devi_exit(ddi_get_parent(rh_dip)); 9050 9051 (void) devfs_clean(rh_dip, NULL, DV_CLEAN_FORCE); 9052 9053 /* 9054 * workaround only for storage device. When it's able to force 9055 * detach a driver, this code can be removed safely. 9056 * 9057 * If we're to reset storage device and the device is used, we 9058 * will wait at most extra 20s for applications to exit and 9059 * close the device. This is especially useful for HAL-based 9060 * applications. 9061 */ 9062 if ((strcmp(devname, "scsa2usb") == 0) && 9063 DEVI(child_dip)->devi_ref != 0) { 9064 while (i++ < hubdi_reset_delay) { 9065 mutex_enter(HUBD_MUTEX(hubd)); 9066 rval = hubd_delete_child(hubd, reset_port, 9067 NDI_DEVI_REMOVE, B_FALSE); 9068 mutex_exit(HUBD_MUTEX(hubd)); 9069 if (rval == USB_SUCCESS) 9070 break; 9071 9072 delay(drv_usectohz(1000000)); /* 1s */ 9073 } 9074 } 9075 9076 ndi_devi_enter(ddi_get_parent(rh_dip)); 9077 ndi_devi_enter(rh_dip); 9078 ndi_devi_enter(hdip); 9079 9080 mutex_enter(HUBD_MUTEX(hubd)); 9081 9082 /* Then force detaching the device */ 9083 if ((rval != USB_SUCCESS) && (hubd_delete_child(hubd, 9084 reset_port, NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS)) { 9085 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 9086 "%s%d cannot be reset due to other applications " 9087 "are using it, please first close these " 9088 "applications, then disconnect and reconnect" 9089 "the device.", devname, devinst); 9090 9091 mutex_exit(HUBD_MUTEX(hubd)); 9092 /* post a re-connect event */ 9093 hubd_post_event(hubd, reset_port, 9094 USBA_EVENT_TAG_HOT_INSERTION); 9095 mutex_enter(HUBD_MUTEX(hubd)); 9096 } else { 9097 (void) hubd_determine_port_status(hubd, reset_port, 9098 &status, &change, NULL, HUBD_ACK_ALL_CHANGES); 9099 9100 /* Reset the parent hubd port and create new child */ 9101 if (status & PORT_STATUS_CCS) { 9102 online_child |= (hubd_handle_port_connect(hubd, 9103 reset_port) == USB_SUCCESS); 9104 } 9105 } 9106 } 9107 9108 /* release locks so we can do a devfs_clean */ 9109 mutex_exit(HUBD_MUTEX(hubd)); 9110 9111 /* delete cached dv_node's but drop locks first */ 9112 ndi_devi_exit(hdip); 9113 ndi_devi_exit(rh_dip); 9114 ndi_devi_exit(ddi_get_parent(rh_dip)); 9115 9116 (void) devfs_clean(rh_dip, NULL, 0); 9117 9118 /* now check if any children need onlining */ 9119 if (online_child) { 9120 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 9121 "hubd_reset_thread: onlining children"); 9122 9123 (void) ndi_devi_online(hubd->h_dip, 0); 9124 } 9125 9126 mutex_enter(HUBD_MUTEX(hubd)); 9127 9128 /* allow hotplug thread now */ 9129 hubd->h_hotplug_thread--; 9130 Fail: 9131 hubd_start_polling(hubd, 0); 9132 9133 /* mark this device as idle */ 9134 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 9135 9136 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 9137 "hubd_reset_thread: exit, %d", hubd->h_hotplug_thread); 9138 9139 hubd->h_reset_port[reset_port] = B_FALSE; 9140 9141 mutex_exit(HUBD_MUTEX(hubd)); 9142 9143 ndi_rele_devi(hdip); 9144 } 9145 9146 /* 9147 * hubd_check_same_device: 9148 * - open the default pipe of the device. 9149 * - compare the old and new descriptors of the device. 9150 * - close the default pipe. 9151 */ 9152 static int 9153 hubd_check_same_device(hubd_t *hubd, usb_port_t port) 9154 { 9155 dev_info_t *dip = hubd->h_children_dips[port]; 9156 usb_pipe_handle_t ph; 9157 int rval = USB_FAILURE; 9158 9159 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 9160 9161 mutex_exit(HUBD_MUTEX(hubd)); 9162 /* Open the default pipe to operate the device */ 9163 if (usb_pipe_open(dip, NULL, NULL, 9164 USB_FLAGS_SLEEP| USBA_FLAGS_PRIVILEGED, 9165 &ph) == USB_SUCCESS) { 9166 /* 9167 * Check that if the device's descriptors are different 9168 * from the values saved before the port reset. 9169 */ 9170 rval = usb_check_same_device(dip, 9171 hubd->h_log_handle, USB_LOG_L0, 9172 DPRINT_MASK_ALL, USB_CHK_ALL, NULL); 9173 9174 usb_pipe_close(dip, ph, USB_FLAGS_SLEEP | 9175 USBA_FLAGS_PRIVILEGED, NULL, NULL); 9176 } 9177 mutex_enter(HUBD_MUTEX(hubd)); 9178 9179 return (rval); 9180 } 9181 9182 /* 9183 * usba_hubdi_reset_device 9184 * Called by usb_reset_device to handle usb device reset. 9185 */ 9186 int 9187 usba_hubdi_reset_device(dev_info_t *dip, usb_dev_reset_lvl_t reset_level) 9188 { 9189 hubd_t *hubd; 9190 usb_port_t port = 0; 9191 dev_info_t *hdip; 9192 usb_pipe_state_t prev_pipe_state = 0; 9193 usba_device_t *usba_device = NULL; 9194 hubd_reset_arg_t *arg; 9195 int i, ph_open_cnt; 9196 int rval = USB_FAILURE; 9197 9198 if ((!dip) || usba_is_root_hub(dip)) { 9199 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 9200 "usba_hubdi_reset_device: NULL dip or root hub"); 9201 9202 return (USB_INVALID_ARGS); 9203 } 9204 9205 if (!usb_owns_device(dip)) { 9206 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 9207 "usba_hubdi_reset_device: Not owns the device"); 9208 9209 return (USB_INVALID_PERM); 9210 } 9211 9212 if ((reset_level != USB_RESET_LVL_REATTACH) && 9213 (reset_level != USB_RESET_LVL_DEFAULT)) { 9214 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 9215 "usba_hubdi_reset_device: Unknown flags"); 9216 9217 return (USB_INVALID_ARGS); 9218 } 9219 9220 if ((hdip = ddi_get_parent(dip)) == NULL) { 9221 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 9222 "usba_hubdi_reset_device: fail to get parent hub"); 9223 9224 return (USB_INVALID_ARGS); 9225 } 9226 9227 if ((hubd = hubd_get_soft_state(hdip)) == NULL) { 9228 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 9229 "usba_hubdi_reset_device: fail to get hub softstate"); 9230 9231 return (USB_INVALID_ARGS); 9232 } 9233 9234 mutex_enter(HUBD_MUTEX(hubd)); 9235 9236 /* make sure the hub is connected before trying any kinds of reset. */ 9237 if ((hubd->h_dev_state == USB_DEV_DISCONNECTED) || 9238 (hubd->h_dev_state == USB_DEV_SUSPENDED)) { 9239 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9240 "usb_reset_device: the state %d of the hub/roothub " 9241 "associated to the device 0x%p is incorrect", 9242 hubd->h_dev_state, (void *)dip); 9243 mutex_exit(HUBD_MUTEX(hubd)); 9244 9245 return (USB_INVALID_ARGS); 9246 } 9247 9248 mutex_exit(HUBD_MUTEX(hubd)); 9249 9250 port = hubd_child_dip2port(hubd, dip); 9251 9252 mutex_enter(HUBD_MUTEX(hubd)); 9253 9254 if (hubd->h_reset_port[port]) { 9255 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9256 "usb_reset_device: the corresponding port is resetting"); 9257 mutex_exit(HUBD_MUTEX(hubd)); 9258 9259 return (USB_SUCCESS); 9260 } 9261 9262 /* 9263 * For Default reset, client drivers should first close all the pipes 9264 * except default pipe before calling the function, also should not 9265 * call the function during interrupt context. 9266 */ 9267 if (reset_level == USB_RESET_LVL_DEFAULT) { 9268 usba_device = hubd->h_usba_devices[port]; 9269 mutex_exit(HUBD_MUTEX(hubd)); 9270 9271 if (servicing_interrupt()) { 9272 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9273 "usb_reset_device: during interrput context, quit"); 9274 9275 return (USB_INVALID_CONTEXT); 9276 } 9277 /* Check if all the pipes have been closed */ 9278 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) { 9279 if (usba_device->usb_ph_list[i].usba_ph_data) { 9280 ph_open_cnt++; 9281 break; 9282 } 9283 } 9284 if (ph_open_cnt) { 9285 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9286 "usb_reset_device: %d pipes are still open", 9287 ph_open_cnt); 9288 9289 return (USB_BUSY); 9290 } 9291 mutex_enter(HUBD_MUTEX(hubd)); 9292 } 9293 9294 /* Don't perform reset while the device is detaching */ 9295 if (hubd->h_port_state[port] & HUBD_CHILD_DETACHING) { 9296 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9297 "usb_reset_device: the device is detaching, " 9298 "cannot be reset"); 9299 mutex_exit(HUBD_MUTEX(hubd)); 9300 9301 return (USB_FAILURE); 9302 } 9303 9304 hubd->h_reset_port[port] = B_TRUE; 9305 hdip = hubd->h_dip; 9306 mutex_exit(HUBD_MUTEX(hubd)); 9307 9308 /* Don't allow hub detached during the reset */ 9309 ndi_hold_devi(hdip); 9310 9311 mutex_enter(HUBD_MUTEX(hubd)); 9312 hubd_pm_busy_component(hubd, hdip, 0); 9313 mutex_exit(HUBD_MUTEX(hubd)); 9314 /* go full power */ 9315 (void) pm_raise_power(hdip, 0, USB_DEV_OS_FULL_PWR); 9316 mutex_enter(HUBD_MUTEX(hubd)); 9317 9318 hubd->h_hotplug_thread++; 9319 9320 /* stop polling if it was active */ 9321 if (hubd->h_ep1_ph) { 9322 mutex_exit(HUBD_MUTEX(hubd)); 9323 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 9324 USB_FLAGS_SLEEP); 9325 mutex_enter(HUBD_MUTEX(hubd)); 9326 9327 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 9328 hubd_stop_polling(hubd); 9329 } 9330 } 9331 9332 switch (reset_level) { 9333 case USB_RESET_LVL_REATTACH: 9334 mutex_exit(HUBD_MUTEX(hubd)); 9335 arg = (hubd_reset_arg_t *)kmem_zalloc( 9336 sizeof (hubd_reset_arg_t), KM_SLEEP); 9337 arg->hubd = hubd; 9338 arg->reset_port = port; 9339 mutex_enter(HUBD_MUTEX(hubd)); 9340 9341 if ((rval = usb_async_req(hdip, hubd_reset_thread, 9342 (void *)arg, 0)) == USB_SUCCESS) { 9343 hubd->h_hotplug_thread--; 9344 mutex_exit(HUBD_MUTEX(hubd)); 9345 9346 return (USB_SUCCESS); 9347 } else { 9348 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9349 "Cannot create reset thread, the device %s%d failed" 9350 " to reset", ddi_driver_name(dip), 9351 ddi_get_instance(dip)); 9352 9353 kmem_free(arg, sizeof (hubd_reset_arg_t)); 9354 } 9355 9356 break; 9357 case USB_RESET_LVL_DEFAULT: 9358 /* 9359 * Reset hub port and then recover device's address, set back 9360 * device's configuration, hubd_handle_port_connect() will 9361 * handle errors happened during this process. 9362 */ 9363 if ((rval = hubd_handle_port_connect(hubd, port)) 9364 == USB_SUCCESS) { 9365 mutex_exit(HUBD_MUTEX(hubd)); 9366 /* re-open the default pipe */ 9367 ASSERT3P(usba_device, !=, NULL); 9368 rval = usba_persistent_pipe_open(usba_device); 9369 mutex_enter(HUBD_MUTEX(hubd)); 9370 if (rval != USB_SUCCESS) { 9371 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 9372 hubd->h_log_handle, "failed to reopen " 9373 "default pipe after reset, disable hub" 9374 "port for %s%d", ddi_driver_name(dip), 9375 ddi_get_instance(dip)); 9376 /* 9377 * Disable port to set out a hotplug thread 9378 * which will handle errors. 9379 */ 9380 (void) hubd_disable_port(hubd, port); 9381 } 9382 } 9383 9384 break; 9385 default: 9386 9387 break; 9388 } 9389 9390 /* allow hotplug thread now */ 9391 hubd->h_hotplug_thread--; 9392 9393 if ((hubd->h_dev_state == USB_DEV_ONLINE) && hubd->h_ep1_ph && 9394 (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 9395 hubd_start_polling(hubd, 0); 9396 } 9397 9398 hubd_pm_idle_component(hubd, hdip, 0); 9399 9400 /* Clear reset mark for the port. */ 9401 hubd->h_reset_port[port] = B_FALSE; 9402 9403 mutex_exit(HUBD_MUTEX(hubd)); 9404 9405 ndi_rele_devi(hdip); 9406 9407 return (rval); 9408 } 9409