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 * External functions 51 */ 52 extern boolean_t consconfig_console_is_ready(void); 53 54 /* 55 * Prototypes for static functions 56 */ 57 static int usba_hubdi_bus_ctl( 58 dev_info_t *dip, 59 dev_info_t *rdip, 60 ddi_ctl_enum_t op, 61 void *arg, 62 void *result); 63 64 static int usba_hubdi_map_fault( 65 dev_info_t *dip, 66 dev_info_t *rdip, 67 struct hat *hat, 68 struct seg *seg, 69 caddr_t addr, 70 struct devpage *dp, 71 pfn_t pfn, 72 uint_t prot, 73 uint_t lock); 74 75 static int hubd_busop_get_eventcookie(dev_info_t *dip, 76 dev_info_t *rdip, 77 char *eventname, 78 ddi_eventcookie_t *cookie); 79 static int hubd_busop_add_eventcall(dev_info_t *dip, 80 dev_info_t *rdip, 81 ddi_eventcookie_t cookie, 82 void (*callback)(dev_info_t *dip, 83 ddi_eventcookie_t cookie, void *arg, 84 void *bus_impldata), 85 void *arg, ddi_callback_id_t *cb_id); 86 static int hubd_busop_remove_eventcall(dev_info_t *dip, 87 ddi_callback_id_t cb_id); 88 static int hubd_bus_config(dev_info_t *dip, 89 uint_t flag, 90 ddi_bus_config_op_t op, 91 void *arg, 92 dev_info_t **child); 93 static int hubd_bus_unconfig(dev_info_t *dip, 94 uint_t flag, 95 ddi_bus_config_op_t op, 96 void *arg); 97 static int hubd_bus_power(dev_info_t *dip, void *impl_arg, 98 pm_bus_power_op_t op, void *arg, void *result); 99 100 static usb_port_t hubd_get_port_num(hubd_t *, struct devctl_iocdata *); 101 static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t); 102 static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t); 103 static int hubd_toggle_port(hubd_t *, usb_port_t); 104 static void hubd_register_cpr_callback(hubd_t *); 105 static void hubd_unregister_cpr_callback(hubd_t *); 106 107 /* 108 * Busops vector for USB HUB's 109 */ 110 struct bus_ops usba_hubdi_busops = { 111 BUSO_REV, 112 nullbusmap, /* bus_map */ 113 NULL, /* bus_get_intrspec */ 114 NULL, /* bus_add_intrspec */ 115 NULL, /* bus_remove_intrspec */ 116 usba_hubdi_map_fault, /* bus_map_fault */ 117 ddi_dma_map, /* bus_dma_map */ 118 ddi_dma_allochdl, 119 ddi_dma_freehdl, 120 ddi_dma_bindhdl, 121 ddi_dma_unbindhdl, 122 ddi_dma_flush, 123 ddi_dma_win, 124 ddi_dma_mctl, /* bus_dma_ctl */ 125 usba_hubdi_bus_ctl, /* bus_ctl */ 126 ddi_bus_prop_op, /* bus_prop_op */ 127 hubd_busop_get_eventcookie, 128 hubd_busop_add_eventcall, 129 hubd_busop_remove_eventcall, 130 NULL, /* bus_post_event */ 131 NULL, /* bus_intr_ctl */ 132 hubd_bus_config, /* bus_config */ 133 hubd_bus_unconfig, /* bus_unconfig */ 134 NULL, /* bus_fm_init */ 135 NULL, /* bus_fm_fini */ 136 NULL, /* bus_fm_access_enter */ 137 NULL, /* bus_fm_access_exit */ 138 hubd_bus_power /* bus_power */ 139 }; 140 141 142 /* 143 * local variables 144 */ 145 static kmutex_t usba_hubdi_mutex; /* protects USBA HUB data structures */ 146 147 static usba_list_entry_t usba_hubdi_list; 148 149 usb_log_handle_t hubdi_log_handle; 150 uint_t hubdi_errlevel = USB_LOG_L4; 151 uint_t hubdi_errmask = (uint_t)-1; 152 uint8_t hubdi_min_pm_threshold = 5; /* seconds */ 153 uint8_t hubdi_reset_delay = 20; /* seconds */ 154 155 /* 156 * initialize private data 157 */ 158 void 159 usba_hubdi_initialization() 160 { 161 hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel, 162 &hubdi_errmask, NULL, 0); 163 164 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 165 "usba_hubdi_initialization"); 166 167 mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL); 168 169 usba_init_list(&usba_hubdi_list, NULL, NULL); 170 } 171 172 173 void 174 usba_hubdi_destroy() 175 { 176 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 177 "usba_hubdi_destroy"); 178 179 mutex_destroy(&usba_hubdi_mutex); 180 usba_destroy_list(&usba_hubdi_list); 181 182 usb_free_log_hdl(hubdi_log_handle); 183 } 184 185 186 /* 187 * Called by an HUB to attach an instance of the driver 188 * make this instance known to USBA 189 * the HUB should initialize usba_hubdi structure prior 190 * to calling this interface 191 */ 192 int 193 usba_hubdi_register(dev_info_t *dip, 194 uint_t flags) 195 { 196 usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP); 197 usba_device_t *usba_device = usba_get_usba_device(dip); 198 199 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 200 "usba_hubdi_register: %s", ddi_node_name(dip)); 201 202 hubdi->hubdi_dip = dip; 203 hubdi->hubdi_flags = flags; 204 205 usba_device->usb_hubdi = hubdi; 206 207 /* 208 * add this hubdi instance to the list of known hubdi's 209 */ 210 usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi, 211 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 212 hcdi_iblock_cookie); 213 mutex_enter(&usba_hubdi_mutex); 214 usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list); 215 mutex_exit(&usba_hubdi_mutex); 216 217 return (DDI_SUCCESS); 218 } 219 220 221 /* 222 * Called by an HUB to detach an instance of the driver 223 */ 224 int 225 usba_hubdi_unregister(dev_info_t *dip) 226 { 227 usba_device_t *usba_device = usba_get_usba_device(dip); 228 usba_hubdi_t *hubdi = usba_device->usb_hubdi; 229 230 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 231 "usba_hubdi_unregister: %s", ddi_node_name(dip)); 232 233 mutex_enter(&usba_hubdi_mutex); 234 (void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list); 235 mutex_exit(&usba_hubdi_mutex); 236 237 usba_destroy_list(&hubdi->hubdi_list); 238 239 kmem_free(hubdi, sizeof (usba_hubdi_t)); 240 241 return (DDI_SUCCESS); 242 } 243 244 245 /* 246 * misc bus routines currently not used 247 */ 248 /*ARGSUSED*/ 249 static int 250 usba_hubdi_map_fault(dev_info_t *dip, 251 dev_info_t *rdip, 252 struct hat *hat, 253 struct seg *seg, 254 caddr_t addr, 255 struct devpage *dp, 256 pfn_t pfn, 257 uint_t prot, 258 uint_t lock) 259 { 260 return (DDI_FAILURE); 261 } 262 263 264 /* 265 * root hub support. the root hub uses the same devi as the HCD 266 */ 267 int 268 usba_hubdi_bind_root_hub(dev_info_t *dip, 269 uchar_t *root_hub_config_descriptor, 270 size_t config_length, 271 usb_dev_descr_t *root_hub_device_descriptor) 272 { 273 usba_device_t *usba_device; 274 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip); 275 hubd_t *root_hubd; 276 usb_pipe_handle_t ph = NULL; 277 dev_info_t *child = ddi_get_child(dip); 278 279 if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 280 "root-hub") != NDI_SUCCESS) { 281 282 return (USB_FAILURE); 283 } 284 285 usba_add_root_hub(dip); 286 287 root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP); 288 289 /* 290 * create and initialize a usba_device structure 291 */ 292 usba_device = usba_alloc_usba_device(dip); 293 294 mutex_enter(&usba_device->usb_mutex); 295 usba_device->usb_hcdi_ops = hcdi->hcdi_ops; 296 usba_device->usb_cfg = root_hub_config_descriptor; 297 usba_device->usb_cfg_length = config_length; 298 usba_device->usb_dev_descr = root_hub_device_descriptor; 299 usba_device->usb_port = 1; 300 usba_device->usb_addr = ROOT_HUB_ADDR; 301 usba_device->usb_root_hubd = root_hubd; 302 usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *), 303 KM_SLEEP); 304 usba_device->usb_cfg_array_length = sizeof (uchar_t *); 305 306 usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t), 307 KM_SLEEP); 308 usba_device->usb_cfg_array_len_length = sizeof (uint16_t); 309 310 usba_device->usb_cfg_array[0] = root_hub_config_descriptor; 311 usba_device->usb_cfg_array_len[0] = 312 sizeof (root_hub_config_descriptor); 313 314 usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *), 315 KM_SLEEP); 316 usba_device->usb_n_cfgs = 1; 317 usba_device->usb_n_ifs = 1; 318 usba_device->usb_dip = dip; 319 320 usba_device->usb_client_flags = kmem_zalloc( 321 usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 322 323 usba_device->usb_client_attach_list = kmem_zalloc( 324 usba_device->usb_n_ifs * 325 sizeof (*usba_device->usb_client_attach_list), KM_SLEEP); 326 327 usba_device->usb_client_ev_cb_list = kmem_zalloc( 328 usba_device->usb_n_ifs * 329 sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP); 330 331 /* 332 * The bDeviceProtocol field of root hub device specifies, 333 * whether root hub is a High or Full speed usb device. 334 */ 335 if (root_hub_device_descriptor->bDeviceProtocol) { 336 usba_device->usb_port_status = USBA_HIGH_SPEED_DEV; 337 } else { 338 usba_device->usb_port_status = USBA_FULL_SPEED_DEV; 339 } 340 341 mutex_exit(&usba_device->usb_mutex); 342 343 usba_set_usba_device(dip, usba_device); 344 345 /* 346 * For the root hub the default pipe is not yet open 347 */ 348 if (usb_pipe_open(dip, NULL, NULL, 349 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) { 350 goto fail; 351 } 352 353 /* 354 * kill off all OBP children, they may not be fully 355 * enumerated 356 */ 357 while (child) { 358 dev_info_t *next = ddi_get_next_sibling(child); 359 (void) ddi_remove_child(child, 0); 360 child = next; 361 } 362 363 /* 364 * "attach" the root hub driver 365 */ 366 if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) { 367 goto fail; 368 } 369 370 return (USB_SUCCESS); 371 372 fail: 373 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 374 375 usba_rem_root_hub(dip); 376 377 if (ph) { 378 usb_pipe_close(dip, ph, 379 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 380 } 381 382 kmem_free(usba_device->usb_cfg_array, 383 usba_device->usb_cfg_array_length); 384 kmem_free(usba_device->usb_cfg_array_len, 385 usba_device->usb_cfg_array_len_length); 386 387 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 388 389 usba_free_usba_device(usba_device); 390 391 usba_set_usba_device(dip, NULL); 392 if (root_hubd) { 393 kmem_free(root_hubd, sizeof (hubd_t)); 394 } 395 396 return (USB_FAILURE); 397 } 398 399 400 int 401 usba_hubdi_unbind_root_hub(dev_info_t *dip) 402 { 403 usba_device_t *usba_device; 404 405 /* was root hub attached? */ 406 if (!(usba_is_root_hub(dip))) { 407 408 /* return success anyway */ 409 return (USB_SUCCESS); 410 } 411 412 /* 413 * usba_hubdi_detach also closes the default pipe 414 * and removes properties so there is no need to 415 * do it here 416 */ 417 if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) { 418 419 if (DEVI_IS_ATTACHING(dip)) { 420 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 421 "failure to unbind root hub after attach failure"); 422 } 423 424 return (USB_FAILURE); 425 } 426 427 usba_device = usba_get_usba_device(dip); 428 429 kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t)); 430 431 kmem_free(usba_device->usb_cfg_array, 432 usba_device->usb_cfg_array_length); 433 kmem_free(usba_device->usb_cfg_array_len, 434 usba_device->usb_cfg_array_len_length); 435 436 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 437 438 usba_free_usba_device(usba_device); 439 440 usba_rem_root_hub(dip); 441 442 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 443 444 return (USB_SUCCESS); 445 } 446 447 448 /* 449 * Actual Hub Driver support code: 450 * shared by root hub and non-root hubs 451 */ 452 #include <sys/usb/usba/usbai_version.h> 453 454 /* Debugging support */ 455 uint_t hubd_errlevel = USB_LOG_L4; 456 uint_t hubd_errmask = (uint_t)DPRINT_MASK_ALL; 457 uint_t hubd_instance_debug = (uint_t)-1; 458 static uint_t hubdi_bus_config_debug = 0; 459 460 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel)) 461 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask)) 462 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug)) 463 464 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 465 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 466 467 468 /* 469 * local variables: 470 * 471 * Amount of time to wait between resetting the port and accessing 472 * the device. The value is in microseconds. 473 */ 474 static uint_t hubd_device_delay = 1000000; 475 476 /* 477 * enumeration retry 478 */ 479 #define HUBD_PORT_RETRY 5 480 static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY; 481 482 /* 483 * Stale hotremoved device cleanup delay 484 */ 485 #define HUBD_STALE_DIP_CLEANUP_DELAY 5000000 486 static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY; 487 488 /* 489 * retries for USB suspend and resume 490 */ 491 #define HUBD_SUS_RES_RETRY 2 492 493 void *hubd_statep; 494 495 /* 496 * prototypes 497 */ 498 static int hubd_cleanup(dev_info_t *dip, hubd_t *hubd); 499 static int hubd_check_ports(hubd_t *hubd); 500 501 static int hubd_open_intr_pipe(hubd_t *hubd); 502 static void hubd_start_polling(hubd_t *hubd, int always); 503 static void hubd_stop_polling(hubd_t *hubd); 504 static void hubd_close_intr_pipe(hubd_t *hubd); 505 506 static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req); 507 static void hubd_exception_cb(usb_pipe_handle_t pipe, 508 usb_intr_req_t *req); 509 static void hubd_hotplug_thread(void *arg); 510 static void hubd_reset_thread(void *arg); 511 static int hubd_create_child(dev_info_t *dip, 512 hubd_t *hubd, 513 usba_device_t *usba_device, 514 usb_port_status_t port_status, 515 usb_port_t port, 516 int iteration); 517 518 static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, 519 boolean_t retry); 520 521 static int hubd_get_hub_descriptor(hubd_t *hubd); 522 523 static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status); 524 525 static int hubd_reset_port(hubd_t *hubd, usb_port_t port); 526 527 static int hubd_get_hub_status(hubd_t *hubd); 528 529 static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port); 530 531 static int hubd_disable_port(hubd_t *hubd, usb_port_t port); 532 533 static int hubd_enable_port(hubd_t *hubd, usb_port_t port); 534 static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port); 535 536 static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 537 uint16_t *status, uint16_t *change, uint_t ack_flag); 538 539 static int hubd_enable_all_port_power(hubd_t *hubd); 540 static int hubd_disable_all_port_power(hubd_t *hubd); 541 static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port); 542 static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port); 543 544 static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device); 545 546 static int hubd_can_suspend(hubd_t *hubd); 547 static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd); 548 static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port); 549 static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port); 550 551 static int hubd_register_events(hubd_t *hubd); 552 static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip, 553 ddi_eventcookie_t cookie); 554 static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type); 555 static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type); 556 static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd); 557 558 static int hubd_disconnect_event_cb(dev_info_t *dip); 559 static int hubd_reconnect_event_cb(dev_info_t *dip); 560 static int hubd_pre_suspend_event_cb(dev_info_t *dip); 561 static int hubd_post_resume_event_cb(dev_info_t *dip); 562 static int hubd_cpr_suspend(hubd_t *hubd); 563 static void hubd_cpr_resume(dev_info_t *dip); 564 static int hubd_restore_state_cb(dev_info_t *dip); 565 static int hubd_check_same_device(hubd_t *hubd, usb_port_t port); 566 567 static int hubd_init_power_budget(hubd_t *hubd); 568 569 static ndi_event_definition_t hubd_ndi_event_defs[] = { 570 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 571 NDI_EVENT_POST_TO_ALL}, 572 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 573 NDI_EVENT_POST_TO_ALL}, 574 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 575 NDI_EVENT_POST_TO_ALL}, 576 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 577 NDI_EVENT_POST_TO_ALL} 578 }; 579 580 #define HUBD_N_NDI_EVENTS \ 581 (sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t)) 582 583 static ndi_event_set_t hubd_ndi_events = { 584 NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs}; 585 586 /* events received from parent */ 587 static usb_event_t hubd_events = { 588 hubd_disconnect_event_cb, 589 hubd_reconnect_event_cb, 590 hubd_pre_suspend_event_cb, 591 hubd_post_resume_event_cb 592 }; 593 594 595 /* 596 * hubd_get_soft_state() returns the hubd soft state 597 * 598 * WUSB support extends this function to support wire adapter class 599 * devices. The hubd soft state for the wire adapter class device 600 * would be stored in usb_root_hubd field of the usba_device structure, 601 * just as the USB host controller drivers do. 602 */ 603 hubd_t * 604 hubd_get_soft_state(dev_info_t *dip) 605 { 606 if (dip == NULL) { 607 608 return (NULL); 609 } 610 611 if (usba_is_root_hub(dip) || usba_is_wa(dip)) { 612 usba_device_t *usba_device = usba_get_usba_device(dip); 613 614 return (usba_device->usb_root_hubd); 615 } else { 616 int instance = ddi_get_instance(dip); 617 618 return (ddi_get_soft_state(hubd_statep, instance)); 619 } 620 } 621 622 623 /* 624 * PM support functions: 625 */ 626 /*ARGSUSED*/ 627 static void 628 hubd_pm_busy_component(hubd_t *hubd, dev_info_t *dip, int component) 629 { 630 if (hubd->h_hubpm != NULL) { 631 hubd->h_hubpm->hubp_busy_pm++; 632 mutex_exit(HUBD_MUTEX(hubd)); 633 if (pm_busy_component(dip, 0) != DDI_SUCCESS) { 634 mutex_enter(HUBD_MUTEX(hubd)); 635 hubd->h_hubpm->hubp_busy_pm--; 636 mutex_exit(HUBD_MUTEX(hubd)); 637 } 638 mutex_enter(HUBD_MUTEX(hubd)); 639 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 640 "hubd_pm_busy_component: %d", hubd->h_hubpm->hubp_busy_pm); 641 } 642 } 643 644 645 /*ARGSUSED*/ 646 static void 647 hubd_pm_idle_component(hubd_t *hubd, dev_info_t *dip, int component) 648 { 649 if (hubd->h_hubpm != NULL) { 650 mutex_exit(HUBD_MUTEX(hubd)); 651 if (pm_idle_component(dip, 0) == DDI_SUCCESS) { 652 mutex_enter(HUBD_MUTEX(hubd)); 653 ASSERT(hubd->h_hubpm->hubp_busy_pm > 0); 654 hubd->h_hubpm->hubp_busy_pm--; 655 mutex_exit(HUBD_MUTEX(hubd)); 656 } 657 mutex_enter(HUBD_MUTEX(hubd)); 658 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 659 "hubd_pm_idle_component: %d", hubd->h_hubpm->hubp_busy_pm); 660 } 661 } 662 663 664 /* 665 * track power level changes for children of this instance 666 */ 667 static void 668 hubd_set_child_pwrlvl(hubd_t *hubd, usb_port_t port, uint8_t power) 669 { 670 int old_power, new_power, pwr; 671 usb_port_t portno; 672 hub_power_t *hubpm; 673 674 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 675 "hubd_set_child_pwrlvl: port=%d power=%d", 676 port, power); 677 678 mutex_enter(HUBD_MUTEX(hubd)); 679 hubpm = hubd->h_hubpm; 680 681 old_power = 0; 682 for (portno = 1; portno <= hubd->h_hub_descr.bNbrPorts; portno++) { 683 old_power += hubpm->hubp_child_pwrstate[portno]; 684 } 685 686 /* assign the port power */ 687 pwr = hubd->h_hubpm->hubp_child_pwrstate[port]; 688 hubd->h_hubpm->hubp_child_pwrstate[port] = power; 689 new_power = old_power - pwr + power; 690 691 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 692 "hubd_set_child_pwrlvl: new_power=%d old_power=%d", 693 new_power, old_power); 694 695 if ((new_power > 0) && (old_power == 0)) { 696 /* we have the first child coming out of low power */ 697 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 698 } else if ((new_power == 0) && (old_power > 0)) { 699 /* we have the last child going to low power */ 700 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 701 } 702 mutex_exit(HUBD_MUTEX(hubd)); 703 } 704 705 706 /* 707 * given a child dip, locate its port number 708 */ 709 static usb_port_t 710 hubd_child_dip2port(hubd_t *hubd, dev_info_t *dip) 711 { 712 usb_port_t port; 713 714 mutex_enter(HUBD_MUTEX(hubd)); 715 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 716 if (hubd->h_children_dips[port] == dip) { 717 718 break; 719 } 720 } 721 ASSERT(port <= hubd->h_hub_descr.bNbrPorts); 722 mutex_exit(HUBD_MUTEX(hubd)); 723 724 return (port); 725 } 726 727 728 /* 729 * if the hub can be put into low power mode, return success 730 * NOTE: suspend here means going to lower power, not CPR suspend. 731 */ 732 static int 733 hubd_can_suspend(hubd_t *hubd) 734 { 735 hub_power_t *hubpm; 736 int total_power = 0; 737 usb_port_t port; 738 739 hubpm = hubd->h_hubpm; 740 741 if (DEVI_IS_DETACHING(hubd->h_dip)) { 742 743 return (USB_SUCCESS); 744 } 745 746 /* 747 * Don't go to lower power if haven't been at full power for enough 748 * time to let hotplug thread kickoff. 749 */ 750 if (ddi_get_time() < (hubpm->hubp_time_at_full_power + 751 hubpm->hubp_min_pm_threshold)) { 752 753 return (USB_FAILURE); 754 } 755 756 for (port = 1; (total_power == 0) && 757 (port <= hubd->h_hub_descr.bNbrPorts); port++) { 758 total_power += hubpm->hubp_child_pwrstate[port]; 759 } 760 761 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 762 "hubd_can_suspend: %d", total_power); 763 764 return (total_power ? USB_FAILURE : USB_SUCCESS); 765 } 766 767 768 /* 769 * resume port depending on current device state 770 */ 771 static int 772 hubd_resume_port(hubd_t *hubd, usb_port_t port) 773 { 774 int rval, retry; 775 usb_cr_t completion_reason; 776 usb_cb_flags_t cb_flags; 777 uint16_t status; 778 uint16_t change; 779 int retval = USB_FAILURE; 780 781 mutex_enter(HUBD_MUTEX(hubd)); 782 783 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 784 "hubd_resume_port: port=%d state=0x%x (%s)", port, 785 hubd->h_dev_state, usb_str_dev_state(hubd->h_dev_state)); 786 787 switch (hubd->h_dev_state) { 788 case USB_DEV_HUB_CHILD_PWRLVL: 789 /* 790 * This could be a bus ctl for a port other than the one 791 * that has a remote wakeup condition. So check. 792 */ 793 if ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0) { 794 /* the port isn't suspended, so don't resume */ 795 retval = USB_SUCCESS; 796 797 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 798 "hubd_resume_port: port=%d not suspended", port); 799 800 break; 801 } 802 /* 803 * Device has initiated a wakeup. 804 * Issue a ClearFeature(PortSuspend) 805 */ 806 mutex_exit(HUBD_MUTEX(hubd)); 807 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 808 hubd->h_default_pipe, 809 HUB_HANDLE_PORT_FEATURE_TYPE, 810 USB_REQ_CLEAR_FEATURE, 811 CFS_PORT_SUSPEND, 812 port, 813 0, NULL, 0, 814 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 815 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 816 "ClearFeature(PortSuspend) fails " 817 "rval=%d cr=%d cb=0x%x", rval, 818 completion_reason, cb_flags); 819 } 820 mutex_enter(HUBD_MUTEX(hubd)); 821 822 /* either way ack changes on the port */ 823 (void) hubd_determine_port_status(hubd, port, 824 &status, &change, PORT_CHANGE_PSSC); 825 retval = USB_SUCCESS; 826 827 break; 828 case USB_DEV_HUB_STATE_RECOVER: 829 /* 830 * When hubd's connect event callback posts a connect 831 * event to its child, it results in this busctl call 832 * which is valid 833 */ 834 /* FALLTHRU */ 835 case USB_DEV_ONLINE: 836 if (((hubd->h_port_state[port] & PORT_STATUS_CCS) == 0) || 837 ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0)) { 838 /* 839 * the port isn't suspended, or connected 840 * so don't resume 841 */ 842 retval = USB_SUCCESS; 843 844 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 845 "hubd_resume_port: port=%d not suspended", port); 846 847 break; 848 } 849 /* 850 * prevent kicking off the hotplug thread 851 */ 852 hubd->h_hotplug_thread++; 853 hubd_stop_polling(hubd); 854 855 /* Now ClearFeature(PortSuspend) */ 856 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) { 857 mutex_exit(HUBD_MUTEX(hubd)); 858 rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 859 hubd->h_default_pipe, 860 HUB_HANDLE_PORT_FEATURE_TYPE, 861 USB_REQ_CLEAR_FEATURE, 862 CFS_PORT_SUSPEND, 863 port, 864 0, NULL, 0, 865 &completion_reason, &cb_flags, 0); 866 mutex_enter(HUBD_MUTEX(hubd)); 867 if (rval != USB_SUCCESS) { 868 USB_DPRINTF_L2(DPRINT_MASK_PM, 869 hubd->h_log_handle, 870 "ClearFeature(PortSuspend) fails" 871 "rval=%d cr=%d cb=0x%x", rval, 872 completion_reason, cb_flags); 873 } else { 874 /* 875 * As per spec section 11.9 and 7.1.7.7 876 * hub need to provide at least 20ms of 877 * resume signalling, and s/w provide 10ms of 878 * recovery time before accessing the port. 879 */ 880 mutex_exit(HUBD_MUTEX(hubd)); 881 delay(drv_usectohz(40000)); 882 mutex_enter(HUBD_MUTEX(hubd)); 883 (void) hubd_determine_port_status(hubd, port, 884 &status, &change, PORT_CHANGE_PSSC); 885 886 if ((status & PORT_STATUS_PSS) == 0) { 887 /* the port did finally resume */ 888 retval = USB_SUCCESS; 889 890 break; 891 } 892 } 893 } 894 895 /* allow hotplug thread again */ 896 hubd->h_hotplug_thread--; 897 hubd_start_polling(hubd, 0); 898 899 break; 900 case USB_DEV_DISCONNECTED: 901 /* Ignore - NO Operation */ 902 retval = USB_SUCCESS; 903 904 break; 905 case USB_DEV_SUSPENDED: 906 case USB_DEV_PWRED_DOWN: 907 default: 908 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 909 "Improper state for port Resume"); 910 911 break; 912 } 913 mutex_exit(HUBD_MUTEX(hubd)); 914 915 return (retval); 916 } 917 918 919 /* 920 * suspend port depending on device state 921 */ 922 static int 923 hubd_suspend_port(hubd_t *hubd, usb_port_t port) 924 { 925 int rval, retry; 926 int retval = USB_FAILURE; 927 usb_cr_t completion_reason; 928 usb_cb_flags_t cb_flags; 929 uint16_t status; 930 uint16_t change; 931 932 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 933 "hubd_suspend_port: port=%d", port); 934 935 mutex_enter(HUBD_MUTEX(hubd)); 936 937 switch (hubd->h_dev_state) { 938 case USB_DEV_HUB_STATE_RECOVER: 939 /* 940 * When hubd's connect event callback posts a connect 941 * event to its child, it results in this busctl call 942 * which is valid 943 */ 944 /* FALLTHRU */ 945 case USB_DEV_HUB_CHILD_PWRLVL: 946 /* 947 * When one child is resuming, the other could timeout 948 * and go to low power mode, which is valid 949 */ 950 /* FALLTHRU */ 951 case USB_DEV_ONLINE: 952 hubd->h_hotplug_thread++; 953 hubd_stop_polling(hubd); 954 955 /* 956 * Some devices start an unprovoked resume. According to spec, 957 * normal resume time for port is 10ms. Wait for double that 958 * time, then check to be sure port is really suspended. 959 */ 960 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) { 961 /* Now SetFeature(PortSuspend) */ 962 mutex_exit(HUBD_MUTEX(hubd)); 963 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 964 hubd->h_default_pipe, 965 HUB_HANDLE_PORT_FEATURE_TYPE, 966 USB_REQ_SET_FEATURE, 967 CFS_PORT_SUSPEND, 968 port, 969 0, NULL, 0, 970 &completion_reason, &cb_flags, 0)) != 971 USB_SUCCESS) { 972 USB_DPRINTF_L2(DPRINT_MASK_PM, 973 hubd->h_log_handle, 974 "SetFeature(PortSuspend) fails" 975 "rval=%d cr=%d cb=0x%x", 976 rval, completion_reason, cb_flags); 977 } 978 979 /* 980 * some devices start an unprovoked resume 981 * wait and check port status after some time 982 */ 983 delay(drv_usectohz(20000)); 984 985 /* either ways ack changes on the port */ 986 mutex_enter(HUBD_MUTEX(hubd)); 987 (void) hubd_determine_port_status(hubd, port, 988 &status, &change, PORT_CHANGE_PSSC); 989 if (status & PORT_STATUS_PSS) { 990 /* the port is indeed suspended */ 991 retval = USB_SUCCESS; 992 993 break; 994 } 995 } 996 997 hubd->h_hotplug_thread--; 998 hubd_start_polling(hubd, 0); 999 1000 break; 1001 1002 case USB_DEV_DISCONNECTED: 1003 /* Ignore - No Operation */ 1004 retval = USB_SUCCESS; 1005 1006 break; 1007 1008 case USB_DEV_SUSPENDED: 1009 case USB_DEV_PWRED_DOWN: 1010 default: 1011 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1012 "Improper state for port Suspend"); 1013 1014 break; 1015 } 1016 mutex_exit(HUBD_MUTEX(hubd)); 1017 1018 return (retval); 1019 } 1020 1021 1022 /* 1023 * child post attach/detach notifications 1024 */ 1025 static void 1026 hubd_post_attach(hubd_t *hubd, usb_port_t port, struct attachspec *as) 1027 { 1028 dev_info_t *dip; 1029 1030 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 1031 "hubd_post_attach: port=%d result=%d", 1032 port, as->result); 1033 1034 if (as->result == DDI_SUCCESS) { 1035 /* 1036 * Check if the child created wants to be power managed. 1037 * If yes, the childs power level gets automatically tracked 1038 * by DDI_CTLOPS_POWER busctl. 1039 * If no, we set power of the new child by default 1040 * to USB_DEV_OS_FULL_PWR. Because we should never suspend. 1041 */ 1042 mutex_enter(HUBD_MUTEX(hubd)); 1043 dip = hubd->h_children_dips[port]; 1044 mutex_exit(HUBD_MUTEX(hubd)); 1045 if (DEVI(dip)->devi_pm_info == NULL) { 1046 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_FULL_PWR); 1047 } 1048 } 1049 } 1050 1051 1052 static void 1053 hubd_post_detach(hubd_t *hubd, usb_port_t port, struct detachspec *ds) 1054 { 1055 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 1056 "hubd_post_detach: port=%d result=%d", port, ds->result); 1057 1058 /* 1059 * if the device is successfully detached and is the 1060 * last device to detach, mark component as idle 1061 */ 1062 mutex_enter(HUBD_MUTEX(hubd)); 1063 if (ds->result == DDI_SUCCESS) { 1064 usba_device_t *usba_device = hubd->h_usba_devices[port]; 1065 dev_info_t *pdip = hubd->h_dip; 1066 mutex_exit(HUBD_MUTEX(hubd)); 1067 1068 usba_hubdi_incr_power_budget(pdip, usba_device); 1069 1070 /* 1071 * We set power of the detached child 1072 * to 0, so that we can suspend if all 1073 * our children are gone 1074 */ 1075 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_PWR_OFF); 1076 1077 /* check for leaks on detaching */ 1078 if ((usba_device) && (ds->cmd == DDI_DETACH)) { 1079 usba_check_for_leaks(usba_device); 1080 } 1081 } else { 1082 mutex_exit(HUBD_MUTEX(hubd)); 1083 } 1084 } 1085 1086 1087 /* 1088 * hubd_post_power 1089 * After the child's power entry point has been called 1090 * we record its power level in our local struct. 1091 * If the device has powered off, we suspend port 1092 */ 1093 static int 1094 hubd_post_power(hubd_t *hubd, usb_port_t port, pm_bp_child_pwrchg_t *bpc, 1095 int result) 1096 { 1097 int retval = USB_SUCCESS; 1098 1099 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1100 "hubd_post_power: port=%d", port); 1101 1102 if (result == DDI_SUCCESS) { 1103 1104 /* record this power in our local struct */ 1105 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_nlevel); 1106 1107 if (bpc->bpc_nlevel == USB_DEV_OS_PWR_OFF) { 1108 1109 /* now suspend the port */ 1110 retval = hubd_suspend_port(hubd, port); 1111 } else if (bpc->bpc_nlevel == USB_DEV_OS_FULL_PWR) { 1112 1113 /* make sure the port is resumed */ 1114 retval = hubd_resume_port(hubd, port); 1115 } 1116 } else { 1117 1118 /* record old power in our local struct */ 1119 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_olevel); 1120 1121 if (bpc->bpc_olevel == USB_DEV_OS_PWR_OFF) { 1122 1123 /* 1124 * As this device failed to transition from 1125 * power off state, suspend the port again 1126 */ 1127 retval = hubd_suspend_port(hubd, port); 1128 } 1129 } 1130 1131 return (retval); 1132 } 1133 1134 1135 /* 1136 * bus ctl notifications are handled here, the rest goes up to root hub/hcd 1137 */ 1138 static int 1139 usba_hubdi_bus_ctl(dev_info_t *dip, 1140 dev_info_t *rdip, 1141 ddi_ctl_enum_t op, 1142 void *arg, 1143 void *result) 1144 { 1145 usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 1146 dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 1147 struct attachspec *as; 1148 struct detachspec *ds; 1149 hubd_t *hubd; 1150 usb_port_t port; 1151 int circ, rval; 1152 int retval = DDI_FAILURE; 1153 1154 hubd = hubd_get_soft_state(dip); 1155 1156 mutex_enter(HUBD_MUTEX(hubd)); 1157 1158 /* flag that we are currently running bus_ctl */ 1159 hubd->h_bus_ctls++; 1160 mutex_exit(HUBD_MUTEX(hubd)); 1161 1162 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1163 "usba_hubdi_bus_ctl:\n\t" 1164 "dip=0x%p, rdip=0x%p, op=0x%x, arg=0x%p", 1165 (void *)dip, (void *)rdip, op, arg); 1166 1167 switch (op) { 1168 case DDI_CTLOPS_ATTACH: 1169 as = (struct attachspec *)arg; 1170 port = hubd_child_dip2port(hubd, rdip); 1171 1172 /* there is nothing to do at resume time */ 1173 if (as->cmd == DDI_RESUME) { 1174 break; 1175 } 1176 1177 /* serialize access */ 1178 ndi_devi_enter(hubd->h_dip, &circ); 1179 1180 switch (as->when) { 1181 case DDI_PRE: 1182 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1183 "DDI_PRE DDI_CTLOPS_ATTACH: dip=%p, port=%d", 1184 (void *)rdip, port); 1185 1186 mutex_enter(HUBD_MUTEX(hubd)); 1187 hubd->h_port_state[port] |= HUBD_CHILD_ATTACHING; 1188 1189 /* Go busy here. Matching idle is DDI_POST case. */ 1190 (void) hubd_pm_busy_component(hubd, dip, 0); 1191 mutex_exit(HUBD_MUTEX(hubd)); 1192 1193 /* 1194 * if we suspended the port previously 1195 * because child went to low power state, and 1196 * someone unloaded the driver, the port would 1197 * still be suspended and needs to be resumed 1198 */ 1199 rval = hubd_resume_port(hubd, port); 1200 if (rval == USB_SUCCESS) { 1201 retval = DDI_SUCCESS; 1202 } 1203 1204 break; 1205 case DDI_POST: 1206 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1207 "DDI_POST DDI_CTLOPS_ATTACH: dip=%p, port=%d", 1208 (void *)rdip, port); 1209 1210 mutex_enter(HUBD_MUTEX(hubd)); 1211 hubd->h_port_state[port] &= ~HUBD_CHILD_ATTACHING; 1212 mutex_exit(HUBD_MUTEX(hubd)); 1213 1214 hubd_post_attach(hubd, port, (struct attachspec *)arg); 1215 retval = DDI_SUCCESS; 1216 mutex_enter(HUBD_MUTEX(hubd)); 1217 1218 /* Matching idle call for DDI_PRE busy call. */ 1219 (void) hubd_pm_idle_component(hubd, dip, 0); 1220 mutex_exit(HUBD_MUTEX(hubd)); 1221 } 1222 ndi_devi_exit(hubd->h_dip, circ); 1223 1224 break; 1225 case DDI_CTLOPS_DETACH: 1226 ds = (struct detachspec *)arg; 1227 port = hubd_child_dip2port(hubd, rdip); 1228 1229 /* there is nothing to do at suspend time */ 1230 if (ds->cmd == DDI_SUSPEND) { 1231 break; 1232 } 1233 1234 /* serialize access */ 1235 ndi_devi_enter(hubd->h_dip, &circ); 1236 1237 switch (ds->when) { 1238 case DDI_PRE: 1239 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1240 "DDI_PRE DDI_CTLOPS_DETACH: dip=%p port=%d", 1241 (void *)rdip, port); 1242 1243 mutex_enter(HUBD_MUTEX(hubd)); 1244 hubd->h_port_state[port] |= HUBD_CHILD_DETACHING; 1245 1246 /* Go busy here. Matching idle is DDI_POST case. */ 1247 (void) hubd_pm_busy_component(hubd, dip, 0); 1248 1249 mutex_exit(HUBD_MUTEX(hubd)); 1250 retval = DDI_SUCCESS; 1251 1252 break; 1253 case DDI_POST: 1254 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1255 "DDI_POST DDI_CTLOPS_DETACH: dip=%p port=%d", 1256 (void *)rdip, port); 1257 1258 mutex_enter(HUBD_MUTEX(hubd)); 1259 hubd->h_port_state[port] &= ~HUBD_CHILD_DETACHING; 1260 mutex_exit(HUBD_MUTEX(hubd)); 1261 1262 /* Matching idle call for DDI_PRE busy call. */ 1263 hubd_post_detach(hubd, port, (struct detachspec *)arg); 1264 retval = DDI_SUCCESS; 1265 mutex_enter(HUBD_MUTEX(hubd)); 1266 (void) hubd_pm_idle_component(hubd, dip, 0); 1267 mutex_exit(HUBD_MUTEX(hubd)); 1268 1269 break; 1270 } 1271 ndi_devi_exit(hubd->h_dip, circ); 1272 1273 break; 1274 default: 1275 retval = usba_bus_ctl(root_hub_dip, rdip, op, arg, result); 1276 } 1277 1278 /* decrement bus_ctls count */ 1279 mutex_enter(HUBD_MUTEX(hubd)); 1280 hubd->h_bus_ctls--; 1281 ASSERT(hubd->h_bus_ctls >= 0); 1282 mutex_exit(HUBD_MUTEX(hubd)); 1283 1284 return (retval); 1285 } 1286 1287 /* 1288 * hubd_config_one: 1289 * enumerate one child according to 'port' 1290 */ 1291 1292 static boolean_t 1293 hubd_config_one(hubd_t *hubd, int port) 1294 { 1295 uint16_t status, change; 1296 dev_info_t *hdip = hubd->h_dip; 1297 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 1298 boolean_t online_child = B_FALSE, found = B_FALSE; 1299 int prh_circ, rh_circ, circ; 1300 1301 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1302 "hubd_config_one: started, hubd_reset_port = 0x%x", port); 1303 1304 ndi_hold_devi(hdip); /* so we don't race with detach */ 1305 1306 /* 1307 * this ensures one config activity per system at a time. 1308 * we enter the parent PCI node to have this serialization. 1309 * this also excludes ioctls and deathrow thread 1310 */ 1311 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 1312 ndi_devi_enter(rh_dip, &rh_circ); 1313 1314 /* exclude other threads */ 1315 ndi_devi_enter(hdip, &circ); 1316 mutex_enter(HUBD_MUTEX(hubd)); 1317 1318 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 1319 1320 if (!hubd->h_children_dips[port]) { 1321 1322 (void) hubd_determine_port_status(hubd, port, 1323 &status, &change, HUBD_ACK_ALL_CHANGES); 1324 1325 if (status & PORT_STATUS_CCS) { 1326 online_child |= (hubd_handle_port_connect(hubd, 1327 port) == USB_SUCCESS); 1328 found = online_child; 1329 } 1330 } else { 1331 found = B_TRUE; 1332 } 1333 1334 mutex_exit(HUBD_MUTEX(hubd)); 1335 1336 ndi_devi_exit(hdip, circ); 1337 ndi_devi_exit(rh_dip, rh_circ); 1338 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 1339 1340 if (online_child) { 1341 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1342 "hubd_config_one: onlining child"); 1343 1344 (void) ndi_devi_online(hubd->h_dip, 0); 1345 } 1346 1347 mutex_enter(HUBD_MUTEX(hubd)); 1348 1349 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 1350 1351 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1352 "hubd_config_one: exit"); 1353 1354 mutex_exit(HUBD_MUTEX(hubd)); 1355 1356 ndi_rele_devi(hdip); 1357 1358 return (found); 1359 } 1360 1361 /* 1362 * bus enumeration entry points 1363 */ 1364 static int 1365 hubd_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 1366 void *arg, dev_info_t **child) 1367 { 1368 hubd_t *hubd = hubd_get_soft_state(dip); 1369 int rval, circ; 1370 long port; 1371 1372 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1373 "hubd_bus_config: op=%d", op); 1374 1375 if (hubdi_bus_config_debug) { 1376 flag |= NDI_DEVI_DEBUG; 1377 } 1378 1379 if (op == BUS_CONFIG_ONE) { 1380 boolean_t found; 1381 char cname[80]; 1382 char *name, *addr; 1383 1384 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1385 "hubd_bus_config: op=%d (BUS_CONFIG_ONE)", op); 1386 1387 (void) snprintf(cname, 80, "%s", (char *)arg); 1388 /* split name into "name@addr" parts */ 1389 i_ddi_parse_name(cname, &name, &addr, NULL); 1390 if (addr && *addr) { 1391 (void) ddi_strtol(addr, NULL, 16, &port); 1392 } else { 1393 return (NDI_FAILURE); 1394 } 1395 1396 found = hubd_config_one(hubd, port); 1397 1398 if (found == 0) { 1399 return (NDI_FAILURE); 1400 } 1401 1402 } 1403 ndi_devi_enter(hubd->h_dip, &circ); 1404 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 1405 ndi_devi_exit(hubd->h_dip, circ); 1406 1407 return (rval); 1408 } 1409 1410 1411 static int 1412 hubd_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 1413 void *arg) 1414 { 1415 hubd_t *hubd = hubd_get_soft_state(dip); 1416 dev_info_t *cdip; 1417 usb_port_t port; 1418 int circ; 1419 int rval; 1420 1421 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1422 "hubd_bus_unconfig: op=%d", op); 1423 1424 if (hubdi_bus_config_debug) { 1425 flag |= NDI_DEVI_DEBUG; 1426 } 1427 1428 if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) { 1429 flag |= NDI_DEVI_REMOVE; 1430 } 1431 1432 /* serialize access */ 1433 ndi_devi_enter(dip, &circ); 1434 1435 rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 1436 1437 /* logically zap children's list */ 1438 mutex_enter(HUBD_MUTEX(hubd)); 1439 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 1440 hubd->h_port_state[port] |= HUBD_CHILD_ZAP; 1441 } 1442 mutex_exit(HUBD_MUTEX(hubd)); 1443 1444 /* fill in what's left */ 1445 for (cdip = ddi_get_child(dip); cdip; 1446 cdip = ddi_get_next_sibling(cdip)) { 1447 usba_device_t *usba_device = usba_get_usba_device(cdip); 1448 1449 if (usba_device == NULL) { 1450 1451 continue; 1452 } 1453 mutex_enter(HUBD_MUTEX(hubd)); 1454 port = usba_device->usb_port; 1455 hubd->h_children_dips[port] = cdip; 1456 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP; 1457 mutex_exit(HUBD_MUTEX(hubd)); 1458 } 1459 1460 /* physically zap the children we didn't find */ 1461 mutex_enter(HUBD_MUTEX(hubd)); 1462 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 1463 if (hubd->h_port_state[port] & HUBD_CHILD_ZAP) { 1464 /* zap the dip and usba_device structure as well */ 1465 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 1466 hubd->h_children_dips[port] = NULL; 1467 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP; 1468 } 1469 } 1470 mutex_exit(HUBD_MUTEX(hubd)); 1471 1472 ndi_devi_exit(dip, circ); 1473 1474 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1475 "hubd_bus_unconfig: rval=%d", rval); 1476 1477 return (rval); 1478 } 1479 1480 1481 /* bus_power entry point */ 1482 static int 1483 hubd_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op, 1484 void *arg, void *result) 1485 { 1486 hubd_t *hubd; 1487 int rval, pwrup_res; 1488 usb_port_t port; 1489 int retval = DDI_FAILURE; 1490 pm_bp_child_pwrchg_t *bpc; 1491 pm_bp_nexus_pwrup_t bpn; 1492 1493 hubd = hubd_get_soft_state(dip); 1494 1495 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1496 "hubd_bus_power: dip=%p, impl_arg=%p, power_op=%d, arg=%p, " 1497 "result=%d\n", (void *)dip, impl_arg, op, arg, *(int *)result); 1498 1499 bpc = (pm_bp_child_pwrchg_t *)arg; 1500 1501 mutex_enter(HUBD_MUTEX(hubd)); 1502 hubd->h_bus_pwr++; 1503 mutex_exit(HUBD_MUTEX(hubd)); 1504 1505 switch (op) { 1506 case BUS_POWER_PRE_NOTIFICATION: 1507 port = hubd_child_dip2port(hubd, bpc->bpc_dip); 1508 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1509 "hubd_bus_power: BUS_POWER_PRE_NOTIFICATION, port=%d", 1510 port); 1511 1512 /* go to full power if we are powered down */ 1513 mutex_enter(HUBD_MUTEX(hubd)); 1514 1515 /* 1516 * If this case completes normally, idle will be in 1517 * hubd_bus_power / BUS_POWER_POST_NOTIFICATION 1518 */ 1519 hubd_pm_busy_component(hubd, dip, 0); 1520 1521 /* 1522 * raise power only if we have created the components 1523 * and are currently in low power 1524 */ 1525 if ((hubd->h_dev_state == USB_DEV_PWRED_DOWN) && 1526 hubd->h_hubpm->hubp_wakeup_enabled) { 1527 mutex_exit(HUBD_MUTEX(hubd)); 1528 1529 bpn.bpn_comp = 0; 1530 bpn.bpn_dip = dip; 1531 bpn.bpn_level = USB_DEV_OS_FULL_PWR; 1532 bpn.bpn_private = bpc->bpc_private; 1533 1534 rval = pm_busop_bus_power(dip, impl_arg, 1535 BUS_POWER_NEXUS_PWRUP, (void *)&bpn, 1536 (void *)&pwrup_res); 1537 1538 if (rval != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) { 1539 mutex_enter(HUBD_MUTEX(hubd)); 1540 hubd_pm_idle_component(hubd, dip, 0); 1541 mutex_exit(HUBD_MUTEX(hubd)); 1542 1543 break; 1544 } 1545 mutex_enter(HUBD_MUTEX(hubd)); 1546 } 1547 1548 /* indicate that child is changing power level */ 1549 hubd->h_port_state[port] |= HUBD_CHILD_PWRLVL_CHNG; 1550 mutex_exit(HUBD_MUTEX(hubd)); 1551 1552 if ((bpc->bpc_olevel == 0) && 1553 (bpc->bpc_nlevel > bpc->bpc_olevel)) { 1554 /* 1555 * this child is transitioning from power off 1556 * to power on state - resume port 1557 */ 1558 rval = hubd_resume_port(hubd, port); 1559 if (rval == USB_SUCCESS) { 1560 retval = DDI_SUCCESS; 1561 } else { 1562 /* reset this flag on failure */ 1563 mutex_enter(HUBD_MUTEX(hubd)); 1564 hubd->h_port_state[port] &= 1565 ~HUBD_CHILD_PWRLVL_CHNG; 1566 hubd_pm_idle_component(hubd, dip, 0); 1567 mutex_exit(HUBD_MUTEX(hubd)); 1568 } 1569 } else { 1570 retval = DDI_SUCCESS; 1571 } 1572 1573 break; 1574 case BUS_POWER_POST_NOTIFICATION: 1575 port = hubd_child_dip2port(hubd, bpc->bpc_dip); 1576 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1577 "hubd_bus_power: BUS_POWER_POST_NOTIFICATION, port=%d", 1578 port); 1579 1580 mutex_enter(HUBD_MUTEX(hubd)); 1581 hubd->h_port_state[port] &= ~HUBD_CHILD_PWRLVL_CHNG; 1582 mutex_exit(HUBD_MUTEX(hubd)); 1583 1584 /* record child's pwr and suspend port if required */ 1585 rval = hubd_post_power(hubd, port, bpc, *(int *)result); 1586 if (rval == USB_SUCCESS) { 1587 1588 retval = DDI_SUCCESS; 1589 } 1590 1591 mutex_enter(HUBD_MUTEX(hubd)); 1592 1593 /* 1594 * Matching idle for the busy in 1595 * hubd_bus_power / BUS_POWER_PRE_NOTIFICATION 1596 */ 1597 hubd_pm_idle_component(hubd, dip, 0); 1598 1599 mutex_exit(HUBD_MUTEX(hubd)); 1600 1601 break; 1602 default: 1603 retval = pm_busop_bus_power(dip, impl_arg, op, arg, result); 1604 1605 break; 1606 } 1607 1608 mutex_enter(HUBD_MUTEX(hubd)); 1609 hubd->h_bus_pwr--; 1610 mutex_exit(HUBD_MUTEX(hubd)); 1611 1612 return (retval); 1613 } 1614 1615 1616 /* 1617 * functions to handle power transition for OS levels 0 -> 3 1618 */ 1619 static int 1620 hubd_pwrlvl0(hubd_t *hubd) 1621 { 1622 hub_power_t *hubpm; 1623 1624 /* We can't power down if hotplug thread is running */ 1625 if (hubd->h_hotplug_thread || hubd->h_hubpm->hubp_busy_pm || 1626 (hubd_can_suspend(hubd) == USB_FAILURE)) { 1627 1628 return (USB_FAILURE); 1629 } 1630 1631 switch (hubd->h_dev_state) { 1632 case USB_DEV_ONLINE: 1633 hubpm = hubd->h_hubpm; 1634 1635 /* 1636 * To avoid race with bus_power pre_notify on check over 1637 * dev_state, we need to correctly set the dev state 1638 * before the mutex is dropped in stop polling. 1639 */ 1640 hubd->h_dev_state = USB_DEV_PWRED_DOWN; 1641 hubpm->hubp_current_power = USB_DEV_OS_PWR_OFF; 1642 1643 /* 1644 * if we are the root hub, do not stop polling 1645 * otherwise, we will never see a resume 1646 */ 1647 if (usba_is_root_hub(hubd->h_dip)) { 1648 /* place holder to implement Global Suspend */ 1649 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1650 "Global Suspend: Not Yet Implemented"); 1651 } else { 1652 hubd_stop_polling(hubd); 1653 } 1654 1655 /* Issue USB D3 command to the device here */ 1656 (void) usb_set_device_pwrlvl3(hubd->h_dip); 1657 1658 break; 1659 case USB_DEV_DISCONNECTED: 1660 case USB_DEV_SUSPENDED: 1661 case USB_DEV_PWRED_DOWN: 1662 default: 1663 1664 break; 1665 } 1666 1667 return (USB_SUCCESS); 1668 } 1669 1670 1671 /* ARGSUSED */ 1672 static int 1673 hubd_pwrlvl1(hubd_t *hubd) 1674 { 1675 /* Issue USB D2 command to the device here */ 1676 (void) usb_set_device_pwrlvl2(hubd->h_dip); 1677 1678 return (USB_FAILURE); 1679 } 1680 1681 1682 /* ARGSUSED */ 1683 static int 1684 hubd_pwrlvl2(hubd_t *hubd) 1685 { 1686 /* Issue USB D1 command to the device here */ 1687 (void) usb_set_device_pwrlvl1(hubd->h_dip); 1688 1689 return (USB_FAILURE); 1690 } 1691 1692 1693 static int 1694 hubd_pwrlvl3(hubd_t *hubd) 1695 { 1696 hub_power_t *hubpm; 1697 int rval; 1698 1699 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3"); 1700 1701 hubpm = hubd->h_hubpm; 1702 switch (hubd->h_dev_state) { 1703 case USB_DEV_PWRED_DOWN: 1704 ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF); 1705 if (usba_is_root_hub(hubd->h_dip)) { 1706 /* implement global resume here */ 1707 USB_DPRINTF_L2(DPRINT_MASK_PM, 1708 hubd->h_log_handle, 1709 "Global Resume: Not Yet Implemented"); 1710 } 1711 /* Issue USB D0 command to the device here */ 1712 rval = usb_set_device_pwrlvl0(hubd->h_dip); 1713 ASSERT(rval == USB_SUCCESS); 1714 hubd->h_dev_state = USB_DEV_ONLINE; 1715 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 1716 hubpm->hubp_time_at_full_power = ddi_get_time(); 1717 hubd_start_polling(hubd, 0); 1718 1719 /* FALLTHRU */ 1720 case USB_DEV_ONLINE: 1721 /* we are already in full power */ 1722 1723 /* FALLTHRU */ 1724 case USB_DEV_DISCONNECTED: 1725 case USB_DEV_SUSPENDED: 1726 /* 1727 * PM framework tries to put you in full power 1728 * during system shutdown. If we are disconnected 1729 * return success. Also, we should not change state 1730 * when we are disconnected or suspended or about to 1731 * transition to that state 1732 */ 1733 1734 return (USB_SUCCESS); 1735 default: 1736 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1737 "hubd_pwrlvl3: Illegal dev_state=%d", hubd->h_dev_state); 1738 1739 return (USB_FAILURE); 1740 } 1741 } 1742 1743 1744 /* power entry point */ 1745 /* ARGSUSED */ 1746 int 1747 usba_hubdi_power(dev_info_t *dip, int comp, int level) 1748 { 1749 hubd_t *hubd; 1750 hub_power_t *hubpm; 1751 int retval; 1752 int circ; 1753 1754 hubd = hubd_get_soft_state(dip); 1755 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1756 "usba_hubdi_power: level=%d", level); 1757 1758 ndi_devi_enter(dip, &circ); 1759 1760 mutex_enter(HUBD_MUTEX(hubd)); 1761 hubpm = hubd->h_hubpm; 1762 1763 /* check if we are transitioning to a legal power level */ 1764 if (USB_DEV_PWRSTATE_OK(hubpm->hubp_pwr_states, level)) { 1765 USB_DPRINTF_L2(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1766 "usba_hubdi_power: illegal power level=%d " 1767 "hubp_pwr_states=0x%x", level, hubpm->hubp_pwr_states); 1768 mutex_exit(HUBD_MUTEX(hubd)); 1769 1770 ndi_devi_exit(dip, circ); 1771 1772 return (DDI_FAILURE); 1773 } 1774 1775 switch (level) { 1776 case USB_DEV_OS_PWR_OFF: 1777 retval = hubd_pwrlvl0(hubd); 1778 1779 break; 1780 case USB_DEV_OS_PWR_1: 1781 retval = hubd_pwrlvl1(hubd); 1782 1783 break; 1784 case USB_DEV_OS_PWR_2: 1785 retval = hubd_pwrlvl2(hubd); 1786 1787 break; 1788 case USB_DEV_OS_FULL_PWR: 1789 retval = hubd_pwrlvl3(hubd); 1790 1791 break; 1792 } 1793 mutex_exit(HUBD_MUTEX(hubd)); 1794 1795 ndi_devi_exit(dip, circ); 1796 1797 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1798 } 1799 1800 1801 /* power entry point for the root hub */ 1802 int 1803 usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level) 1804 { 1805 return (usba_hubdi_power(dip, comp, level)); 1806 } 1807 1808 1809 /* 1810 * standard driver entry points support code 1811 */ 1812 int 1813 usba_hubdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1814 { 1815 int instance = ddi_get_instance(dip); 1816 hubd_t *hubd = NULL; 1817 int i, rval; 1818 int minor; 1819 uint8_t ports_count; 1820 char *log_name = NULL; 1821 const char *root_hub_drvname; 1822 usb_ep_data_t *ep_data; 1823 usba_device_t *child_ud = NULL; 1824 usb_dev_descr_t *usb_dev_descr; 1825 usb_port_status_t parent_port_status, child_port_status; 1826 1827 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubdi_log_handle, 1828 "hubd_attach instance %d, cmd=0x%x", instance, cmd); 1829 1830 switch (cmd) { 1831 case DDI_ATTACH: 1832 1833 break; 1834 case DDI_RESUME: 1835 hubd_cpr_resume(dip); 1836 1837 return (DDI_SUCCESS); 1838 default: 1839 return (DDI_FAILURE); 1840 } 1841 1842 /* 1843 * Allocate softc information. 1844 */ 1845 if (usba_is_root_hub(dip)) { 1846 /* soft state has already been allocated */ 1847 hubd = hubd_get_soft_state(dip); 1848 minor = HUBD_IS_ROOT_HUB; 1849 1850 /* generate readable labels for different root hubs */ 1851 root_hub_drvname = ddi_driver_name(dip); 1852 if (strcmp(root_hub_drvname, "ehci") == 0) { 1853 log_name = "eusb"; 1854 } else if (strcmp(root_hub_drvname, "uhci") == 0) { 1855 log_name = "uusb"; 1856 } else { 1857 /* std. for ohci */ 1858 log_name = "usb"; 1859 } 1860 } else { 1861 rval = ddi_soft_state_zalloc(hubd_statep, instance); 1862 minor = 0; 1863 1864 if (rval != DDI_SUCCESS) { 1865 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 1866 "cannot allocate soft state (%d)", instance); 1867 goto fail; 1868 } 1869 1870 hubd = hubd_get_soft_state(dip); 1871 if (hubd == NULL) { 1872 goto fail; 1873 } 1874 } 1875 1876 hubd->h_log_handle = usb_alloc_log_hdl(dip, log_name, &hubd_errlevel, 1877 &hubd_errmask, &hubd_instance_debug, 0); 1878 1879 hubd->h_usba_device = child_ud = usba_get_usba_device(dip); 1880 hubd->h_dip = dip; 1881 hubd->h_instance = instance; 1882 1883 mutex_enter(&child_ud->usb_mutex); 1884 child_port_status = child_ud->usb_port_status; 1885 usb_dev_descr = child_ud->usb_dev_descr; 1886 parent_port_status = (child_ud->usb_hs_hub_usba_dev) ? 1887 child_ud->usb_hs_hub_usba_dev->usb_port_status : 0; 1888 mutex_exit(&child_ud->usb_mutex); 1889 1890 if ((child_port_status == USBA_FULL_SPEED_DEV) && 1891 (parent_port_status == USBA_HIGH_SPEED_DEV) && 1892 (usb_dev_descr->bcdUSB == 0x100)) { 1893 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 1894 "Use of a USB1.0 hub behind a high speed port may " 1895 "cause unexpected failures"); 1896 } 1897 1898 hubd->h_pipe_policy.pp_max_async_reqs = 1; 1899 1900 /* register with USBA as client driver */ 1901 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 1902 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1903 "client attach failed"); 1904 1905 goto fail; 1906 } 1907 1908 if (usb_get_dev_data(dip, &hubd->h_dev_data, 1909 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) { 1910 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1911 "cannot get dev_data"); 1912 1913 goto fail; 1914 } 1915 1916 if ((ep_data = usb_lookup_ep_data(dip, hubd->h_dev_data, 1917 hubd->h_dev_data->dev_curr_if, 0, 0, 1918 (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) { 1919 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1920 "no interrupt IN endpoint found"); 1921 1922 goto fail; 1923 } 1924 1925 hubd->h_ep1_descr = ep_data->ep_descr; 1926 hubd->h_default_pipe = hubd->h_dev_data->dev_default_ph; 1927 1928 mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER, 1929 hubd->h_dev_data->dev_iblock_cookie); 1930 cv_init(&hubd->h_cv_reset_port, NULL, CV_DRIVER, NULL); 1931 cv_init(&hubd->h_cv_hotplug_dev, NULL, CV_DRIVER, NULL); 1932 1933 hubd->h_init_state |= HUBD_LOCKS_DONE; 1934 1935 usb_free_descr_tree(dip, hubd->h_dev_data); 1936 1937 /* 1938 * register this hub instance with usba 1939 */ 1940 rval = usba_hubdi_register(dip, 0); 1941 if (rval != USB_SUCCESS) { 1942 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1943 "usba_hubdi_register failed"); 1944 goto fail; 1945 } 1946 1947 mutex_enter(HUBD_MUTEX(hubd)); 1948 hubd->h_init_state |= HUBD_HUBDI_REGISTERED; 1949 hubd->h_dev_state = USB_DEV_ONLINE; 1950 mutex_exit(HUBD_MUTEX(hubd)); 1951 1952 /* now create components to power manage this device */ 1953 hubd_create_pm_components(dip, hubd); 1954 1955 /* 1956 * Event handling: definition and registration 1957 * 1958 * first the definition: 1959 * get event handle 1960 */ 1961 (void) ndi_event_alloc_hdl(dip, 0, &hubd->h_ndi_event_hdl, NDI_SLEEP); 1962 1963 /* bind event set to the handle */ 1964 if (ndi_event_bind_set(hubd->h_ndi_event_hdl, &hubd_ndi_events, 1965 NDI_SLEEP)) { 1966 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 1967 "binding event set failed"); 1968 1969 goto fail; 1970 } 1971 1972 /* event registration */ 1973 if (hubd_register_events(hubd) != USB_SUCCESS) { 1974 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1975 "hubd_register_events failed"); 1976 1977 goto fail; 1978 } 1979 1980 mutex_enter(HUBD_MUTEX(hubd)); 1981 hubd->h_init_state |= HUBD_EVENTS_REGISTERED; 1982 1983 if ((hubd_get_hub_descriptor(hubd)) != USB_SUCCESS) { 1984 mutex_exit(HUBD_MUTEX(hubd)); 1985 1986 goto fail; 1987 } 1988 1989 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 1990 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 1991 "hub-ignore-power-budget") == 1) { 1992 hubd->h_ignore_pwr_budget = B_TRUE; 1993 } else { 1994 hubd->h_ignore_pwr_budget = B_FALSE; 1995 1996 /* initialize hub power budget variables */ 1997 if (hubd_init_power_budget(hubd) != USB_SUCCESS) { 1998 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1999 "hubd_init_power_budget failed"); 2000 mutex_exit(HUBD_MUTEX(hubd)); 2001 2002 goto fail; 2003 } 2004 } 2005 2006 /* initialize and create children */ 2007 if (hubd_check_ports(hubd) != USB_SUCCESS) { 2008 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2009 "hubd_check_ports failed"); 2010 mutex_exit(HUBD_MUTEX(hubd)); 2011 2012 goto fail; 2013 } 2014 2015 /* 2016 * create cfgadm nodes 2017 */ 2018 hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, KM_SLEEP); 2019 hubd_get_ancestry_str(hubd); 2020 2021 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2022 "#ports=0x%x", hubd->h_hub_descr.bNbrPorts); 2023 2024 for (i = 1; i <= hubd->h_hub_descr.bNbrPorts; i++) { 2025 char ap_name[HUBD_APID_NAMELEN]; 2026 2027 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 2028 hubd->h_ancestry_str, i); 2029 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2030 "ap_name=%s", ap_name); 2031 2032 if (ddi_create_minor_node(dip, ap_name, S_IFCHR, instance, 2033 DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 2034 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2035 "cannot create attachment point node (%d)", 2036 instance); 2037 mutex_exit(HUBD_MUTEX(hubd)); 2038 2039 goto fail; 2040 } 2041 } 2042 2043 ports_count = hubd->h_hub_descr.bNbrPorts; 2044 mutex_exit(HUBD_MUTEX(hubd)); 2045 2046 /* create minor nodes */ 2047 if (ddi_create_minor_node(dip, "hubd", S_IFCHR, 2048 instance | minor, DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 2049 2050 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2051 "cannot create devctl minor node (%d)", instance); 2052 2053 goto fail; 2054 } 2055 2056 mutex_enter(HUBD_MUTEX(hubd)); 2057 hubd->h_init_state |= HUBD_MINOR_NODE_CREATED; 2058 mutex_exit(HUBD_MUTEX(hubd)); 2059 2060 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, 2061 "usb-port-count", ports_count) != DDI_PROP_SUCCESS) { 2062 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2063 "usb-port-count update failed"); 2064 } 2065 2066 /* 2067 * host controller driver has already reported this dev 2068 * if we are the root hub 2069 */ 2070 if (!usba_is_root_hub(dip)) { 2071 ddi_report_dev(dip); 2072 } 2073 2074 /* enable deathrow thread */ 2075 hubd->h_cleanup_enabled = B_TRUE; 2076 mutex_enter(HUBD_MUTEX(hubd)); 2077 hubd_pm_idle_component(hubd, dip, 0); 2078 mutex_exit(HUBD_MUTEX(hubd)); 2079 2080 return (DDI_SUCCESS); 2081 2082 fail: 2083 { 2084 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2085 2086 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 2087 "cannot attach %s", ddi_pathname(dip, pathname)); 2088 2089 kmem_free(pathname, MAXPATHLEN); 2090 } 2091 2092 mutex_enter(HUBD_MUTEX(hubd)); 2093 hubd_pm_idle_component(hubd, dip, 0); 2094 mutex_exit(HUBD_MUTEX(hubd)); 2095 2096 if (hubd) { 2097 rval = hubd_cleanup(dip, hubd); 2098 if (rval != USB_SUCCESS) { 2099 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 2100 "failure to complete cleanup after attach failure"); 2101 } 2102 } 2103 2104 return (DDI_FAILURE); 2105 } 2106 2107 2108 int 2109 usba_hubdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2110 { 2111 hubd_t *hubd = hubd_get_soft_state(dip); 2112 int rval; 2113 2114 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2115 "hubd_detach: cmd=0x%x", cmd); 2116 2117 switch (cmd) { 2118 case DDI_DETACH: 2119 rval = hubd_cleanup(dip, hubd); 2120 2121 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2122 case DDI_SUSPEND: 2123 rval = hubd_cpr_suspend(hubd); 2124 2125 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2126 default: 2127 return (DDI_FAILURE); 2128 } 2129 } 2130 2131 2132 /* 2133 * hubd_setdevaddr 2134 * set the device addrs on this port 2135 */ 2136 static int 2137 hubd_setdevaddr(hubd_t *hubd, usb_port_t port) 2138 { 2139 int rval; 2140 usb_cr_t completion_reason; 2141 usb_cb_flags_t cb_flags; 2142 usb_pipe_handle_t ph; 2143 dev_info_t *child_dip = NULL; 2144 uchar_t address = 0; 2145 usba_device_t *usba_device; 2146 int retry = 0; 2147 long time_delay; 2148 2149 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2150 "hubd_setdevaddr: port=%d", port); 2151 2152 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2153 2154 child_dip = hubd->h_children_dips[port]; 2155 address = hubd->h_usba_devices[port]->usb_addr; 2156 usba_device = hubd->h_usba_devices[port]; 2157 2158 /* close the default pipe with addr x */ 2159 mutex_exit(HUBD_MUTEX(hubd)); 2160 ph = usba_get_dflt_pipe_handle(child_dip); 2161 usb_pipe_close(child_dip, ph, 2162 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2163 mutex_enter(HUBD_MUTEX(hubd)); 2164 2165 /* 2166 * As this device has been reset, temporarily 2167 * assign the default address 2168 */ 2169 mutex_enter(&usba_device->usb_mutex); 2170 address = usba_device->usb_addr; 2171 usba_device->usb_addr = USBA_DEFAULT_ADDR; 2172 mutex_exit(&usba_device->usb_mutex); 2173 2174 mutex_exit(HUBD_MUTEX(hubd)); 2175 2176 time_delay = drv_usectohz(hubd_device_delay / 20); 2177 for (retry = 0; retry < hubd_retry_enumerate; retry++) { 2178 2179 /* open child's default pipe with USBA_DEFAULT_ADDR */ 2180 if (usb_pipe_open(child_dip, NULL, NULL, 2181 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != 2182 USB_SUCCESS) { 2183 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2184 "hubd_setdevaddr: Unable to open default pipe"); 2185 2186 break; 2187 } 2188 2189 /* Set the address of the device */ 2190 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 2191 USB_DEV_REQ_HOST_TO_DEV, 2192 USB_REQ_SET_ADDRESS, /* bRequest */ 2193 address, /* wValue */ 2194 0, /* wIndex */ 2195 0, /* wLength */ 2196 NULL, 0, 2197 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2198 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2199 "hubd_setdevaddr(%d): rval=%d cr=%d cb_fl=0x%x", 2200 retry, rval, completion_reason, cb_flags); 2201 } 2202 2203 usb_pipe_close(child_dip, ph, 2204 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2205 2206 if (rval == USB_SUCCESS) { 2207 2208 break; 2209 } 2210 2211 delay(time_delay); 2212 } 2213 2214 /* Reset to the old address */ 2215 mutex_enter(&usba_device->usb_mutex); 2216 usba_device->usb_addr = address; 2217 mutex_exit(&usba_device->usb_mutex); 2218 mutex_enter(HUBD_MUTEX(hubd)); 2219 2220 usba_clear_data_toggle(usba_device); 2221 2222 return (rval); 2223 } 2224 2225 2226 /* 2227 * hubd_setdevconfig 2228 * set the device addrs on this port 2229 */ 2230 static void 2231 hubd_setdevconfig(hubd_t *hubd, usb_port_t port) 2232 { 2233 int rval; 2234 usb_cr_t completion_reason; 2235 usb_cb_flags_t cb_flags; 2236 usb_pipe_handle_t ph; 2237 dev_info_t *child_dip = NULL; 2238 usba_device_t *usba_device = NULL; 2239 uint16_t config_value; 2240 2241 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2242 "hubd_setdevconfig: port=%d", port); 2243 2244 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2245 2246 child_dip = hubd->h_children_dips[port]; 2247 usba_device = hubd->h_usba_devices[port]; 2248 config_value = hubd->h_usba_devices[port]->usb_cfg_value; 2249 mutex_exit(HUBD_MUTEX(hubd)); 2250 2251 /* open the default control pipe */ 2252 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 2253 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) == 2254 USB_SUCCESS) { 2255 2256 /* Set the default configuration of the device */ 2257 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 2258 USB_DEV_REQ_HOST_TO_DEV, 2259 USB_REQ_SET_CFG, /* bRequest */ 2260 config_value, /* wValue */ 2261 0, /* wIndex */ 2262 0, /* wLength */ 2263 NULL, 0, 2264 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2265 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2266 "hubd_setdevconfig: set device config failed: " 2267 "cr=%d cb_fl=0x%x rval=%d", 2268 completion_reason, cb_flags, rval); 2269 } 2270 /* 2271 * After setting the configuration, we make this default 2272 * control pipe persistent, so that it gets re-opened 2273 * on posting a connect event 2274 */ 2275 usba_persistent_pipe_close(usba_device); 2276 } else { 2277 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2278 "pipe open fails: rval=%d", rval); 2279 } 2280 mutex_enter(HUBD_MUTEX(hubd)); 2281 } 2282 2283 2284 /*ARGSUSED*/ 2285 static int 2286 hubd_check_disconnected_ports(dev_info_t *dip, void *arg) 2287 { 2288 int circ; 2289 usb_port_t port; 2290 hubd_t *hubd; 2291 major_t hub_major = ddi_name_to_major("hubd"); 2292 major_t hwahc_major = ddi_name_to_major("hwahc"); 2293 major_t usbmid_major = ddi_name_to_major("usb_mid"); 2294 2295 /* 2296 * make sure dip is a usb hub, major of root hub is HCD 2297 * major 2298 */ 2299 if (!usba_is_root_hub(dip)) { 2300 if (ddi_driver_major(dip) == usbmid_major) { 2301 /* 2302 * need to walk the children since it might be a 2303 * HWA device 2304 */ 2305 2306 return (DDI_WALK_CONTINUE); 2307 } 2308 2309 /* TODO: DWA device may also need special handling */ 2310 2311 if (((ddi_driver_major(dip) != hub_major) && 2312 (ddi_driver_major(dip) != hwahc_major)) || 2313 !i_ddi_devi_attached(dip)) { 2314 2315 return (DDI_WALK_PRUNECHILD); 2316 } 2317 } 2318 2319 hubd = hubd_get_soft_state(dip); 2320 if (hubd == NULL) { 2321 2322 return (DDI_WALK_PRUNECHILD); 2323 } 2324 2325 /* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */ 2326 ndi_devi_enter(dip, &circ); 2327 2328 if (ddi_driver_major(dip) != hwahc_major) { 2329 /* for normal usb hub or root hub */ 2330 mutex_enter(HUBD_MUTEX(hubd)); 2331 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2332 dev_info_t *cdip = hubd->h_children_dips[port]; 2333 2334 if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) { 2335 2336 continue; 2337 } 2338 2339 (void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE, 2340 B_TRUE); 2341 } 2342 mutex_exit(HUBD_MUTEX(hubd)); 2343 } else { 2344 /* for HWA */ 2345 if (hubd->h_cleanup_child != NULL) { 2346 if (hubd->h_cleanup_child(dip) != USB_SUCCESS) { 2347 ndi_devi_exit(dip, circ); 2348 2349 return (DDI_WALK_PRUNECHILD); 2350 } 2351 } else { 2352 ndi_devi_exit(dip, circ); 2353 2354 return (DDI_WALK_PRUNECHILD); 2355 } 2356 } 2357 2358 ndi_devi_exit(dip, circ); 2359 2360 /* skip siblings of root hub */ 2361 if (usba_is_root_hub(dip)) { 2362 2363 return (DDI_WALK_PRUNESIB); 2364 } 2365 2366 return (DDI_WALK_CONTINUE); 2367 } 2368 2369 2370 /* 2371 * this thread will walk all children under the root hub for this 2372 * USB bus instance and attempt to remove them 2373 */ 2374 static void 2375 hubd_root_hub_cleanup_thread(void *arg) 2376 { 2377 int circ; 2378 hubd_t *root_hubd = (hubd_t *)arg; 2379 dev_info_t *rh_dip = root_hubd->h_dip; 2380 #ifndef __lock_lint 2381 callb_cpr_t cprinfo; 2382 2383 CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr, 2384 "USB root hub"); 2385 #endif 2386 2387 for (;;) { 2388 /* don't race with detach */ 2389 ndi_hold_devi(rh_dip); 2390 2391 mutex_enter(HUBD_MUTEX(root_hubd)); 2392 root_hubd->h_cleanup_needed = 0; 2393 mutex_exit(HUBD_MUTEX(root_hubd)); 2394 2395 (void) devfs_clean(rh_dip, NULL, 0); 2396 2397 ndi_devi_enter(ddi_get_parent(rh_dip), &circ); 2398 ddi_walk_devs(rh_dip, hubd_check_disconnected_ports, 2399 NULL); 2400 #ifdef __lock_lint 2401 (void) hubd_check_disconnected_ports(rh_dip, NULL); 2402 #endif 2403 ndi_devi_exit(ddi_get_parent(rh_dip), circ); 2404 2405 /* quit if we are not enabled anymore */ 2406 mutex_enter(HUBD_MUTEX(root_hubd)); 2407 if ((root_hubd->h_cleanup_enabled == B_FALSE) || 2408 (root_hubd->h_cleanup_needed == B_FALSE)) { 2409 root_hubd->h_cleanup_active = B_FALSE; 2410 mutex_exit(HUBD_MUTEX(root_hubd)); 2411 ndi_rele_devi(rh_dip); 2412 2413 break; 2414 } 2415 mutex_exit(HUBD_MUTEX(root_hubd)); 2416 ndi_rele_devi(rh_dip); 2417 2418 #ifndef __lock_lint 2419 mutex_enter(HUBD_MUTEX(root_hubd)); 2420 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2421 mutex_exit(HUBD_MUTEX(root_hubd)); 2422 2423 delay(drv_usectohz(hubd_dip_cleanup_delay)); 2424 2425 mutex_enter(HUBD_MUTEX(root_hubd)); 2426 CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd)); 2427 mutex_exit(HUBD_MUTEX(root_hubd)); 2428 #endif 2429 } 2430 2431 #ifndef __lock_lint 2432 mutex_enter(HUBD_MUTEX(root_hubd)); 2433 CALLB_CPR_EXIT(&cprinfo); 2434 #endif 2435 } 2436 2437 2438 void 2439 hubd_schedule_cleanup(dev_info_t *rh_dip) 2440 { 2441 hubd_t *root_hubd; 2442 2443 /* 2444 * The usb_root_hub_dip pointer for the child hub of the WUSB 2445 * wire adapter class device points to the wire adapter, not 2446 * the root hub. Need to find the real root hub dip so that 2447 * the cleanup thread only starts from the root hub. 2448 */ 2449 while (!usba_is_root_hub(rh_dip)) { 2450 root_hubd = hubd_get_soft_state(rh_dip); 2451 if (root_hubd != NULL) { 2452 rh_dip = root_hubd->h_usba_device->usb_root_hub_dip; 2453 if (rh_dip == NULL) { 2454 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2455 root_hubd->h_log_handle, 2456 "hubd_schedule_cleanup: null rh dip"); 2457 2458 return; 2459 } 2460 } else { 2461 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2462 root_hubd->h_log_handle, 2463 "hubd_schedule_cleanup: cannot find root hub"); 2464 2465 return; 2466 } 2467 } 2468 root_hubd = hubd_get_soft_state(rh_dip); 2469 2470 mutex_enter(HUBD_MUTEX(root_hubd)); 2471 root_hubd->h_cleanup_needed = B_TRUE; 2472 if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) { 2473 root_hubd->h_cleanup_active = B_TRUE; 2474 mutex_exit(HUBD_MUTEX(root_hubd)); 2475 (void) thread_create(NULL, 0, 2476 hubd_root_hub_cleanup_thread, 2477 (void *)root_hubd, 0, &p0, TS_RUN, 2478 minclsyspri); 2479 } else { 2480 mutex_exit(HUBD_MUTEX(root_hubd)); 2481 } 2482 } 2483 2484 2485 /* 2486 * hubd_restore_device_state: 2487 * - set config for the hub 2488 * - power cycle all the ports 2489 * - for each port that was connected 2490 * - reset port 2491 * - assign addrs to the device on this port 2492 * - restart polling 2493 * - reset suspend flag 2494 */ 2495 static void 2496 hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd) 2497 { 2498 int rval; 2499 int retry; 2500 uint_t hub_prev_state; 2501 usb_port_t port; 2502 uint16_t status; 2503 uint16_t change; 2504 dev_info_t *ch_dip; 2505 boolean_t ehci_root_hub; 2506 2507 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2508 "hubd_restore_device_state:"); 2509 2510 mutex_enter(HUBD_MUTEX(hubd)); 2511 hub_prev_state = hubd->h_dev_state; 2512 ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN); 2513 2514 /* First bring the device to full power */ 2515 (void) hubd_pm_busy_component(hubd, dip, 0); 2516 mutex_exit(HUBD_MUTEX(hubd)); 2517 2518 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2519 2520 if (!usba_is_root_hub(dip) && 2521 (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0, 2522 DPRINT_MASK_HOTPLUG, 2523 USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) { 2524 2525 /* change the device state to disconnected */ 2526 mutex_enter(HUBD_MUTEX(hubd)); 2527 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2528 (void) hubd_pm_idle_component(hubd, dip, 0); 2529 mutex_exit(HUBD_MUTEX(hubd)); 2530 2531 return; 2532 } 2533 2534 ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0); 2535 2536 mutex_enter(HUBD_MUTEX(hubd)); 2537 /* First turn off all port power */ 2538 rval = hubd_disable_all_port_power(hubd); 2539 if (rval != USB_SUCCESS) { 2540 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2541 "hubd_restore_device_state:" 2542 "turning off port power failed"); 2543 } 2544 2545 /* Settling time before turning on again */ 2546 mutex_exit(HUBD_MUTEX(hubd)); 2547 delay(drv_usectohz(hubd_device_delay / 100)); 2548 mutex_enter(HUBD_MUTEX(hubd)); 2549 2550 /* enable power on all ports so we can see connects */ 2551 if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) { 2552 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2553 "hubd_restore_device_state: turn on port power failed"); 2554 2555 /* disable whatever was enabled */ 2556 (void) hubd_disable_all_port_power(hubd); 2557 2558 (void) hubd_pm_idle_component(hubd, dip, 0); 2559 mutex_exit(HUBD_MUTEX(hubd)); 2560 2561 return; 2562 } 2563 2564 /* 2565 * wait at least 3 frames before accessing devices 2566 * (note that delay's minimal time is one clock tick which 2567 * is 10ms unless hires_tick has been changed) 2568 */ 2569 mutex_exit(HUBD_MUTEX(hubd)); 2570 delay(drv_usectohz(10000)); 2571 mutex_enter(HUBD_MUTEX(hubd)); 2572 2573 hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER; 2574 2575 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2576 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2577 "hubd_restore_device_state: port=%d", port); 2578 2579 /* 2580 * the childen_dips list may have dips that have been 2581 * already deallocated. we only get a post_detach notification 2582 * but not a destroy notification 2583 */ 2584 ch_dip = hubd->h_children_dips[port]; 2585 if (ch_dip) { 2586 /* get port status */ 2587 (void) hubd_determine_port_status(hubd, port, 2588 &status, &change, PORT_CHANGE_CSC); 2589 2590 /* check if it is truly connected */ 2591 if (status & PORT_STATUS_CCS) { 2592 /* 2593 * Now reset port and assign the device 2594 * its original address 2595 */ 2596 retry = 0; 2597 do { 2598 (void) hubd_reset_port(hubd, port); 2599 2600 /* required for ppx */ 2601 (void) hubd_enable_port(hubd, port); 2602 2603 if (retry) { 2604 mutex_exit(HUBD_MUTEX(hubd)); 2605 delay(drv_usectohz( 2606 hubd_device_delay/2)); 2607 mutex_enter(HUBD_MUTEX(hubd)); 2608 } 2609 2610 rval = hubd_setdevaddr(hubd, port); 2611 retry++; 2612 } while ((rval != USB_SUCCESS) && 2613 (retry < hubd_retry_enumerate)); 2614 2615 hubd_setdevconfig(hubd, port); 2616 2617 if (hub_prev_state == USB_DEV_DISCONNECTED) { 2618 /* post a connect event */ 2619 mutex_exit(HUBD_MUTEX(hubd)); 2620 hubd_post_event(hubd, port, 2621 USBA_EVENT_TAG_HOT_INSERTION); 2622 mutex_enter(HUBD_MUTEX(hubd)); 2623 } else { 2624 /* 2625 * Since we have this device connected 2626 * mark it reinserted to prevent 2627 * cleanup thread from stepping in. 2628 */ 2629 mutex_exit(HUBD_MUTEX(hubd)); 2630 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2631 DEVI_SET_DEVICE_REINSERTED(ch_dip); 2632 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2633 2634 /* 2635 * reopen pipes for children for 2636 * their DDI_RESUME 2637 */ 2638 rval = usba_persistent_pipe_open( 2639 usba_get_usba_device(ch_dip)); 2640 mutex_enter(HUBD_MUTEX(hubd)); 2641 ASSERT(rval == USB_SUCCESS); 2642 } 2643 } else { 2644 /* 2645 * Mark this dip for deletion as the device 2646 * is not physically present, and schedule 2647 * cleanup thread upon post resume 2648 */ 2649 mutex_exit(HUBD_MUTEX(hubd)); 2650 2651 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2652 hubd->h_log_handle, 2653 "hubd_restore_device_state: " 2654 "dip=%p on port=%d marked for cleanup", 2655 (void *)ch_dip, port); 2656 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2657 DEVI_SET_DEVICE_REMOVED(ch_dip); 2658 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2659 2660 mutex_enter(HUBD_MUTEX(hubd)); 2661 } 2662 } else if (ehci_root_hub) { 2663 /* get port status */ 2664 (void) hubd_determine_port_status(hubd, port, 2665 &status, &change, PORT_CHANGE_CSC); 2666 2667 /* check if it is truly connected */ 2668 if (status & PORT_STATUS_CCS) { 2669 /* 2670 * reset the port to find out if we have 2671 * 2.0 device connected or 1.X. A 2.0 2672 * device will still be seen as connected, 2673 * while a 1.X device will switch over to 2674 * the companion controller. 2675 */ 2676 (void) hubd_reset_port(hubd, port); 2677 2678 (void) hubd_determine_port_status(hubd, port, 2679 &status, &change, PORT_CHANGE_CSC); 2680 2681 if (status & 2682 (PORT_STATUS_CCS | PORT_STATUS_HSDA)) { 2683 /* 2684 * We have a USB 2.0 device 2685 * connected. Power cycle this port 2686 * so that hotplug thread can 2687 * enumerate this device. 2688 */ 2689 (void) hubd_toggle_port(hubd, port); 2690 } else { 2691 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2692 hubd->h_log_handle, 2693 "hubd_restore_device_state: " 2694 "device on port %d switched over", 2695 port); 2696 } 2697 } 2698 2699 } 2700 } 2701 2702 2703 /* if the device had remote wakeup earlier, enable it again */ 2704 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2705 mutex_exit(HUBD_MUTEX(hubd)); 2706 (void) usb_handle_remote_wakeup(hubd->h_dip, 2707 USB_REMOTE_WAKEUP_ENABLE); 2708 mutex_enter(HUBD_MUTEX(hubd)); 2709 } 2710 2711 hubd->h_dev_state = USB_DEV_ONLINE; 2712 hubd_start_polling(hubd, 0); 2713 (void) hubd_pm_idle_component(hubd, dip, 0); 2714 mutex_exit(HUBD_MUTEX(hubd)); 2715 } 2716 2717 2718 /* 2719 * hubd_cleanup: 2720 * cleanup hubd and deallocate. this function is called for 2721 * handling attach failures and detaching including dynamic 2722 * reconfiguration. If called from attaching, it must clean 2723 * up the whole thing and return success. 2724 */ 2725 /*ARGSUSED*/ 2726 static int 2727 hubd_cleanup(dev_info_t *dip, hubd_t *hubd) 2728 { 2729 int circ, rval, old_dev_state; 2730 hub_power_t *hubpm; 2731 #ifdef DEBUG 2732 usb_port_t port; 2733 #endif 2734 2735 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2736 "hubd_cleanup:"); 2737 2738 if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) { 2739 goto done; 2740 } 2741 2742 /* ensure we are the only one active */ 2743 ndi_devi_enter(dip, &circ); 2744 2745 mutex_enter(HUBD_MUTEX(hubd)); 2746 2747 /* Cleanup failure is only allowed if called from detach */ 2748 if (DEVI_IS_DETACHING(dip)) { 2749 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 2750 2751 /* 2752 * We are being called from detach. 2753 * Fail immediately if the hotplug thread is running 2754 * else set the dev_state to disconnected so that 2755 * hotplug thread just exits without doing anything. 2756 */ 2757 if (hubd->h_bus_ctls || hubd->h_bus_pwr || 2758 hubd->h_hotplug_thread) { 2759 mutex_exit(HUBD_MUTEX(hubd)); 2760 ndi_devi_exit(dip, circ); 2761 2762 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2763 "hubd_cleanup: hotplug thread/bus ctl active " 2764 "- failing detach"); 2765 2766 return (USB_FAILURE); 2767 } 2768 2769 /* 2770 * if the deathrow thread is still active or about 2771 * to become active, fail detach 2772 * the roothup can only be detached if nexus drivers 2773 * are unloaded or explicitly offlined 2774 */ 2775 if (rh_dip == dip) { 2776 if (hubd->h_cleanup_needed || 2777 hubd->h_cleanup_active) { 2778 mutex_exit(HUBD_MUTEX(hubd)); 2779 ndi_devi_exit(dip, circ); 2780 2781 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2782 hubd->h_log_handle, 2783 "hubd_cleanup: deathrow still active?" 2784 "- failing detach"); 2785 2786 return (USB_FAILURE); 2787 } 2788 } 2789 } 2790 2791 old_dev_state = hubd->h_dev_state; 2792 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2793 2794 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2795 "hubd_cleanup: stop polling"); 2796 hubd_close_intr_pipe(hubd); 2797 2798 ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr || 2799 hubd->h_hotplug_thread) == 0); 2800 mutex_exit(HUBD_MUTEX(hubd)); 2801 2802 /* 2803 * deallocate events, if events are still registered 2804 * (ie. children still attached) then we have to fail the detach 2805 */ 2806 if (hubd->h_ndi_event_hdl) { 2807 2808 rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl); 2809 if (DEVI_IS_ATTACHING(dip)) { 2810 2811 /* It must return success if attaching. */ 2812 ASSERT(rval == NDI_SUCCESS); 2813 2814 } else if (rval != NDI_SUCCESS) { 2815 2816 USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle, 2817 "hubd_cleanup: ndi_event_free_hdl failed"); 2818 ndi_devi_exit(dip, circ); 2819 2820 return (USB_FAILURE); 2821 2822 } 2823 } 2824 2825 mutex_enter(HUBD_MUTEX(hubd)); 2826 2827 if (hubd->h_init_state & HUBD_CHILDREN_CREATED) { 2828 #ifdef DEBUG 2829 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2830 ASSERT(hubd->h_usba_devices[port] == NULL); 2831 ASSERT(hubd->h_children_dips[port] == NULL); 2832 } 2833 #endif 2834 kmem_free(hubd->h_children_dips, hubd->h_cd_list_length); 2835 kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length); 2836 } 2837 2838 /* 2839 * Disable the event callbacks first, after this point, event 2840 * callbacks will never get called. Note we shouldn't hold 2841 * mutex while unregistering events because there may be a 2842 * competing event callback thread. Event callbacks are done 2843 * with ndi mutex held and this can cause a potential deadlock. 2844 * Note that cleanup can't fail after deregistration of events. 2845 */ 2846 if (hubd->h_init_state & HUBD_EVENTS_REGISTERED) { 2847 mutex_exit(HUBD_MUTEX(hubd)); 2848 usb_unregister_event_cbs(dip, &hubd_events); 2849 hubd_unregister_cpr_callback(hubd); 2850 mutex_enter(HUBD_MUTEX(hubd)); 2851 } 2852 2853 /* restore the old dev state so that device can be put into low power */ 2854 hubd->h_dev_state = old_dev_state; 2855 hubpm = hubd->h_hubpm; 2856 2857 if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) { 2858 (void) hubd_pm_busy_component(hubd, dip, 0); 2859 mutex_exit(HUBD_MUTEX(hubd)); 2860 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2861 /* 2862 * Bring the hub to full power before 2863 * issuing the disable remote wakeup command 2864 */ 2865 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2866 2867 if ((rval = usb_handle_remote_wakeup(hubd->h_dip, 2868 USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 2869 USB_DPRINTF_L2(DPRINT_MASK_PM, 2870 hubd->h_log_handle, 2871 "hubd_cleanup: disable remote wakeup " 2872 "fails=%d", rval); 2873 } 2874 } 2875 2876 (void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF); 2877 2878 mutex_enter(HUBD_MUTEX(hubd)); 2879 (void) hubd_pm_idle_component(hubd, dip, 0); 2880 } 2881 2882 if (hubpm) { 2883 if (hubpm->hubp_child_pwrstate) { 2884 kmem_free(hubpm->hubp_child_pwrstate, 2885 MAX_PORTS + 1); 2886 } 2887 kmem_free(hubpm, sizeof (hub_power_t)); 2888 } 2889 mutex_exit(HUBD_MUTEX(hubd)); 2890 2891 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2892 "hubd_cleanup: freeing space"); 2893 2894 if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) { 2895 rval = usba_hubdi_unregister(dip); 2896 ASSERT(rval == USB_SUCCESS); 2897 } 2898 2899 if (hubd->h_init_state & HUBD_LOCKS_DONE) { 2900 mutex_destroy(HUBD_MUTEX(hubd)); 2901 cv_destroy(&hubd->h_cv_reset_port); 2902 cv_destroy(&hubd->h_cv_hotplug_dev); 2903 } 2904 2905 ndi_devi_exit(dip, circ); 2906 2907 if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) { 2908 ddi_remove_minor_node(dip, NULL); 2909 } 2910 2911 if (usba_is_root_hub(dip)) { 2912 usb_pipe_close(dip, hubd->h_default_pipe, 2913 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2914 } 2915 2916 done: 2917 if (hubd->h_ancestry_str) { 2918 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN); 2919 } 2920 2921 usb_client_detach(dip, hubd->h_dev_data); 2922 2923 usb_free_log_hdl(hubd->h_log_handle); 2924 2925 if (!usba_is_root_hub(dip)) { 2926 ddi_soft_state_free(hubd_statep, ddi_get_instance(dip)); 2927 } 2928 2929 ddi_prop_remove_all(dip); 2930 2931 return (USB_SUCCESS); 2932 } 2933 2934 2935 /* 2936 * hubd_determine_port_connection: 2937 * Determine which port is in connect status but does not 2938 * have connect status change bit set, and mark port change 2939 * bit accordingly. 2940 * This function is applied during hub attach time. 2941 */ 2942 static usb_port_mask_t 2943 hubd_determine_port_connection(hubd_t *hubd) 2944 { 2945 usb_port_t port; 2946 usb_hub_descr_t *hub_descr; 2947 uint16_t status; 2948 uint16_t change; 2949 usb_port_mask_t port_change = 0; 2950 2951 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2952 2953 hub_descr = &hubd->h_hub_descr; 2954 2955 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 2956 2957 (void) hubd_determine_port_status(hubd, port, &status, 2958 &change, 0); 2959 2960 /* Check if port is in connect status */ 2961 if (!(status & PORT_STATUS_CCS)) { 2962 2963 continue; 2964 } 2965 2966 /* 2967 * Check if port Connect Status Change bit has been set. 2968 * If already set, the connection will be handled by 2969 * intr polling callback, not during attach. 2970 */ 2971 if (change & PORT_CHANGE_CSC) { 2972 2973 continue; 2974 } 2975 2976 port_change |= 1 << port; 2977 } 2978 2979 return (port_change); 2980 } 2981 2982 2983 /* 2984 * hubd_check_ports: 2985 * - get hub descriptor 2986 * - check initial port status 2987 * - enable power on all ports 2988 * - enable polling on ep1 2989 */ 2990 static int 2991 hubd_check_ports(hubd_t *hubd) 2992 { 2993 int rval; 2994 usb_port_mask_t port_change = 0; 2995 hubd_hotplug_arg_t *arg; 2996 2997 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2998 2999 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3000 "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip)); 3001 3002 /* 3003 * First turn off all port power 3004 */ 3005 if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) { 3006 3007 /* disable whatever was enabled */ 3008 (void) hubd_disable_all_port_power(hubd); 3009 3010 return (rval); 3011 } 3012 3013 /* 3014 * do not switch on immediately (instantly on root hub) 3015 * and allow time to settle 3016 */ 3017 mutex_exit(HUBD_MUTEX(hubd)); 3018 delay(drv_usectohz(10000)); 3019 mutex_enter(HUBD_MUTEX(hubd)); 3020 3021 /* 3022 * enable power on all ports so we can see connects 3023 */ 3024 if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) { 3025 /* disable whatever was enabled */ 3026 (void) hubd_disable_all_port_power(hubd); 3027 3028 return (rval); 3029 } 3030 3031 /* wait at least 3 frames before accessing devices */ 3032 mutex_exit(HUBD_MUTEX(hubd)); 3033 delay(drv_usectohz(10000)); 3034 mutex_enter(HUBD_MUTEX(hubd)); 3035 3036 /* 3037 * allocate arrays for saving the dips of each child per port 3038 * 3039 * ports go from 1 - n, allocate 1 more entry 3040 */ 3041 hubd->h_cd_list_length = 3042 (sizeof (dev_info_t **)) * (hubd->h_hub_descr.bNbrPorts + 1); 3043 3044 hubd->h_children_dips = (dev_info_t **)kmem_zalloc( 3045 hubd->h_cd_list_length, KM_SLEEP); 3046 hubd->h_usba_devices = (usba_device_t **)kmem_zalloc( 3047 hubd->h_cd_list_length, KM_SLEEP); 3048 3049 hubd->h_init_state |= HUBD_CHILDREN_CREATED; 3050 3051 mutex_exit(HUBD_MUTEX(hubd)); 3052 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3053 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3054 mutex_enter(HUBD_MUTEX(hubd)); 3055 3056 if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) { 3057 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3058 3059 return (rval); 3060 } 3061 3062 hubd_start_polling(hubd, 0); 3063 3064 /* 3065 * Some hub devices, like the embedded hub in the CKS ErgoMagic 3066 * keyboard, may only have connection status bit set, but not 3067 * have connect status change bit set when a device has been 3068 * connected to its downstream port before the hub is enumerated. 3069 * Then when the hub is in enumeration, the devices connected to 3070 * it cannot be detected by the intr pipe and won't be enumerated. 3071 * We need to check such situation here and enumerate the downstream 3072 * devices for such hubs. 3073 */ 3074 port_change = hubd_determine_port_connection(hubd); 3075 3076 if (port_change) { 3077 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3078 3079 arg->hubd = hubd; 3080 arg->hotplug_during_attach = B_TRUE; 3081 hubd->h_port_change |= port_change; 3082 3083 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 3084 "hubd_check_ports: port change=0x%x, need to connect", 3085 hubd->h_port_change); 3086 3087 if (usb_async_req(hubd->h_dip, hubd_hotplug_thread, 3088 (void *)arg, 0) == USB_SUCCESS) { 3089 hubd->h_hotplug_thread++; 3090 } else { 3091 /* mark this device as idle */ 3092 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3093 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3094 } 3095 } else { 3096 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3097 } 3098 3099 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3100 "hubd_check_ports done"); 3101 3102 return (USB_SUCCESS); 3103 } 3104 3105 3106 /* 3107 * hubd_get_hub_descriptor: 3108 */ 3109 static int 3110 hubd_get_hub_descriptor(hubd_t *hubd) 3111 { 3112 usb_hub_descr_t *hub_descr = &hubd->h_hub_descr; 3113 mblk_t *data = NULL; 3114 usb_cr_t completion_reason; 3115 usb_cb_flags_t cb_flags; 3116 uint16_t length; 3117 int rval; 3118 3119 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3120 "hubd_get_hub_descriptor:"); 3121 3122 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3123 ASSERT(hubd->h_default_pipe != 0); 3124 3125 /* get hub descriptor length first by requesting 8 bytes only */ 3126 mutex_exit(HUBD_MUTEX(hubd)); 3127 3128 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3129 hubd->h_default_pipe, 3130 HUB_CLASS_REQ_TYPE, 3131 USB_REQ_GET_DESCR, /* bRequest */ 3132 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3133 0, /* wIndex */ 3134 8, /* wLength */ 3135 &data, 0, 3136 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 3137 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3138 "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d", 3139 completion_reason, cb_flags, rval); 3140 freemsg(data); 3141 mutex_enter(HUBD_MUTEX(hubd)); 3142 3143 return (rval); 3144 } 3145 3146 length = *(data->b_rptr); 3147 3148 if (length > 8) { 3149 freemsg(data); 3150 data = NULL; 3151 3152 /* get complete hub descriptor */ 3153 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3154 hubd->h_default_pipe, 3155 HUB_CLASS_REQ_TYPE, 3156 USB_REQ_GET_DESCR, /* bRequest */ 3157 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3158 0, /* wIndex */ 3159 length, /* wLength */ 3160 &data, 0, 3161 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 3162 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3163 "get hub descriptor failed: " 3164 "cr=%d cb_fl=0x%x rval=%d", 3165 completion_reason, cb_flags, rval); 3166 freemsg(data); 3167 mutex_enter(HUBD_MUTEX(hubd)); 3168 3169 return (rval); 3170 } 3171 } 3172 3173 mutex_enter(HUBD_MUTEX(hubd)); 3174 3175 /* parse the hub descriptor */ 3176 /* only 32 ports are supported at present */ 3177 ASSERT(*(data->b_rptr + 2) <= 32); 3178 if (usb_parse_CV_descr("cccscccccc", 3179 data->b_rptr, MBLKL(data), 3180 (void *)hub_descr, sizeof (usb_hub_descr_t)) == 0) { 3181 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3182 "parsing hub descriptor failed"); 3183 3184 freemsg(data); 3185 3186 return (USB_FAILURE); 3187 } 3188 3189 freemsg(data); 3190 3191 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3192 "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x " 3193 "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval, 3194 hub_descr->bNbrPorts, hub_descr->wHubCharacteristics, 3195 hub_descr->bPwrOn2PwrGood, hub_descr->bHubContrCurrent); 3196 3197 if (hub_descr->bNbrPorts > MAX_PORTS) { 3198 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 3199 "Hub driver supports max of %d ports on hub. " 3200 "Hence using the first %d port of %d ports available", 3201 MAX_PORTS, MAX_PORTS, hub_descr->bNbrPorts); 3202 3203 hub_descr->bNbrPorts = MAX_PORTS; 3204 } 3205 3206 return (USB_SUCCESS); 3207 } 3208 3209 3210 /* 3211 * hubd_get_hub_status_words: 3212 */ 3213 static int 3214 hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status) 3215 { 3216 usb_cr_t completion_reason; 3217 usb_cb_flags_t cb_flags; 3218 mblk_t *data = NULL; 3219 3220 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3221 3222 mutex_exit(HUBD_MUTEX(hubd)); 3223 3224 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe, 3225 HUB_CLASS_REQ_TYPE, 3226 USB_REQ_GET_STATUS, 3227 0, 3228 0, 3229 GET_STATUS_LENGTH, 3230 &data, 0, 3231 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 3232 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3233 "get hub status failed: cr=%d cb=0x%x", 3234 completion_reason, cb_flags); 3235 3236 if (data) { 3237 freemsg(data); 3238 } 3239 3240 mutex_enter(HUBD_MUTEX(hubd)); 3241 3242 return (USB_FAILURE); 3243 } 3244 3245 mutex_enter(HUBD_MUTEX(hubd)); 3246 3247 status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 3248 status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 3249 3250 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 3251 "hub status=0x%x change=0x%x", status[0], status[1]); 3252 3253 freemsg(data); 3254 3255 return (USB_SUCCESS); 3256 } 3257 3258 3259 /* 3260 * hubd_open_intr_pipe: 3261 * we read all descriptors first for curiosity and then simply 3262 * open the pipe 3263 */ 3264 static int 3265 hubd_open_intr_pipe(hubd_t *hubd) 3266 { 3267 int rval; 3268 3269 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3270 "hubd_open_intr_pipe:"); 3271 3272 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE); 3273 3274 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING; 3275 mutex_exit(HUBD_MUTEX(hubd)); 3276 3277 if ((rval = usb_pipe_open(hubd->h_dip, 3278 &hubd->h_ep1_descr, &hubd->h_pipe_policy, 3279 0, &hubd->h_ep1_ph)) != USB_SUCCESS) { 3280 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3281 "open intr pipe failed (%d)", rval); 3282 3283 mutex_enter(HUBD_MUTEX(hubd)); 3284 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3285 3286 return (rval); 3287 } 3288 3289 mutex_enter(HUBD_MUTEX(hubd)); 3290 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3291 3292 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3293 "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph); 3294 3295 return (USB_SUCCESS); 3296 } 3297 3298 3299 /* 3300 * hubd_start_polling: 3301 * start or restart the polling 3302 */ 3303 static void 3304 hubd_start_polling(hubd_t *hubd, int always) 3305 { 3306 usb_intr_req_t *reqp; 3307 int rval; 3308 usb_pipe_state_t pipe_state; 3309 3310 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3311 "start polling: always=%d dev_state=%d pipe_state=%d\n\t" 3312 "thread=%d ep1_ph=0x%p", 3313 always, hubd->h_dev_state, hubd->h_intr_pipe_state, 3314 hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph); 3315 3316 /* 3317 * start or restart polling on the intr pipe 3318 * only if hotplug thread is not running 3319 */ 3320 if ((always == HUBD_ALWAYS_START_POLLING) || 3321 ((hubd->h_dev_state == USB_DEV_ONLINE) && 3322 (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3323 (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) { 3324 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3325 "start polling requested"); 3326 3327 reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP); 3328 3329 reqp->intr_client_private = (usb_opaque_t)hubd; 3330 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 3331 USB_ATTRS_AUTOCLEARING; 3332 reqp->intr_len = hubd->h_ep1_descr.wMaxPacketSize; 3333 reqp->intr_cb = hubd_read_cb; 3334 reqp->intr_exc_cb = hubd_exception_cb; 3335 mutex_exit(HUBD_MUTEX(hubd)); 3336 if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp, 3337 USB_FLAGS_SLEEP)) != USB_SUCCESS) { 3338 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3339 "start polling failed, rval=%d", rval); 3340 usb_free_intr_req(reqp); 3341 } 3342 3343 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3344 USB_FLAGS_SLEEP); 3345 if (pipe_state != USB_PIPE_STATE_ACTIVE) { 3346 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3347 "intr pipe state=%d, rval=%d", pipe_state, rval); 3348 } 3349 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3350 "start polling request 0x%p", (void *)reqp); 3351 3352 mutex_enter(HUBD_MUTEX(hubd)); 3353 } 3354 } 3355 3356 3357 /* 3358 * hubd_stop_polling 3359 * stop polling but do not close the pipe 3360 */ 3361 static void 3362 hubd_stop_polling(hubd_t *hubd) 3363 { 3364 int rval; 3365 usb_pipe_state_t pipe_state; 3366 3367 if (hubd->h_ep1_ph) { 3368 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3369 "hubd_stop_polling:"); 3370 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED; 3371 mutex_exit(HUBD_MUTEX(hubd)); 3372 3373 usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP); 3374 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3375 USB_FLAGS_SLEEP); 3376 3377 if (pipe_state != USB_PIPE_STATE_IDLE) { 3378 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3379 "intr pipe state=%d, rval=%d", pipe_state, rval); 3380 } 3381 mutex_enter(HUBD_MUTEX(hubd)); 3382 if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) { 3383 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3384 } 3385 } 3386 } 3387 3388 3389 /* 3390 * hubd_close_intr_pipe: 3391 * close the pipe (which also stops the polling 3392 * and wait for the hotplug thread to exit 3393 */ 3394 static void 3395 hubd_close_intr_pipe(hubd_t *hubd) 3396 { 3397 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3398 "hubd_close_intr_pipe:"); 3399 3400 /* 3401 * Now that no async operation is outstanding on pipe, 3402 * we can change the state to HUBD_INTR_PIPE_CLOSING 3403 */ 3404 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING; 3405 3406 ASSERT(hubd->h_hotplug_thread == 0); 3407 3408 if (hubd->h_ep1_ph) { 3409 mutex_exit(HUBD_MUTEX(hubd)); 3410 usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP, 3411 NULL, NULL); 3412 mutex_enter(HUBD_MUTEX(hubd)); 3413 hubd->h_ep1_ph = NULL; 3414 } 3415 3416 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3417 } 3418 3419 3420 /* 3421 * hubd_exception_cb 3422 * interrupt ep1 exception callback function. 3423 * this callback executes in taskq thread context and assumes 3424 * autoclearing 3425 */ 3426 /*ARGSUSED*/ 3427 static void 3428 hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3429 { 3430 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3431 3432 USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3433 "hubd_exception_cb: " 3434 "req=0x%p cr=%d data=0x%p cb_flags=0x%x", (void *)reqp, 3435 reqp->intr_completion_reason, (void *)reqp->intr_data, 3436 reqp->intr_cb_flags); 3437 3438 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3439 3440 mutex_enter(HUBD_MUTEX(hubd)); 3441 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3442 3443 switch (reqp->intr_completion_reason) { 3444 case USB_CR_PIPE_RESET: 3445 /* only restart polling after autoclearing */ 3446 if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3447 (hubd->h_port_reset_wait == 0)) { 3448 hubd_start_polling(hubd, 0); 3449 } 3450 3451 break; 3452 case USB_CR_DEV_NOT_RESP: 3453 case USB_CR_STOPPED_POLLING: 3454 case USB_CR_PIPE_CLOSING: 3455 case USB_CR_UNSPECIFIED_ERR: 3456 /* never restart polling on these conditions */ 3457 default: 3458 /* for all others, wait for the autoclearing PIPE_RESET cb */ 3459 3460 break; 3461 } 3462 3463 usb_free_intr_req(reqp); 3464 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3465 mutex_exit(HUBD_MUTEX(hubd)); 3466 } 3467 3468 3469 /* 3470 * helper function to convert LE bytes to a portmask 3471 */ 3472 static usb_port_mask_t 3473 hubd_mblk2portmask(mblk_t *data) 3474 { 3475 int len = min(MBLKL(data), sizeof (usb_port_mask_t)); 3476 usb_port_mask_t rval = 0; 3477 int i; 3478 3479 for (i = 0; i < len; i++) { 3480 rval |= data->b_rptr[i] << (i * 8); 3481 } 3482 3483 return (rval); 3484 } 3485 3486 3487 /* 3488 * hubd_read_cb: 3489 * interrupt ep1 callback function 3490 * 3491 * the status indicates just a change on the pipe with no indication 3492 * of what the change was 3493 * 3494 * known conditions: 3495 * - reset port completion 3496 * - connect 3497 * - disconnect 3498 * 3499 * for handling the hotplugging, create a new thread that can do 3500 * synchronous usba calls 3501 */ 3502 static void 3503 hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3504 { 3505 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3506 size_t length; 3507 mblk_t *data = reqp->intr_data; 3508 int mem_flag = 0; 3509 hubd_hotplug_arg_t *arg; 3510 3511 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3512 "hubd_read_cb: ph=0x%p req=0x%p", (void *)pipe, (void *)reqp); 3513 3514 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3515 3516 /* 3517 * At present, we are not handling notification for completion of 3518 * asynchronous pipe reset, for which this data ptr could be NULL 3519 */ 3520 3521 if (data == NULL) { 3522 usb_free_intr_req(reqp); 3523 3524 return; 3525 } 3526 3527 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3528 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3529 mem_flag = 1; 3530 3531 mutex_enter(HUBD_MUTEX(hubd)); 3532 3533 if ((hubd->h_dev_state == USB_DEV_SUSPENDED) || 3534 (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) { 3535 mutex_exit(HUBD_MUTEX(hubd)); 3536 usb_free_intr_req(reqp); 3537 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3538 3539 return; 3540 } 3541 3542 ASSERT(hubd->h_ep1_ph == pipe); 3543 3544 length = MBLKL(data); 3545 3546 /* 3547 * Only look at the data and startup the hotplug thread if 3548 * there actually is data. 3549 */ 3550 if (length != 0) { 3551 usb_port_mask_t port_change = hubd_mblk2portmask(data); 3552 3553 /* 3554 * if a port change was already reported and we are waiting for 3555 * reset port completion then wake up the hotplug thread which 3556 * should be waiting on reset port completion 3557 * 3558 * if there is disconnect event instead of reset completion, let 3559 * the hotplug thread figure this out 3560 */ 3561 3562 /* remove the reset wait bits from the status */ 3563 hubd->h_port_change |= port_change & 3564 ~