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