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