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