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