1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * USBA: Solaris USB Architecture support for the hub 29 * including root hub 30 * Most of the code for hubd resides in this file and 31 * is shared between the HCD root hub support and hubd 32 */ 33 #define USBA_FRAMEWORK 34 #include <sys/usb/usba.h> 35 #include <sys/usb/usba/usba_devdb.h> 36 #include <sys/sunndi.h> 37 #include <sys/usb/usba/usba_impl.h> 38 #include <sys/usb/usba/usba_types.h> 39 #include <sys/usb/usba/hubdi.h> 40 #include <sys/usb/usba/hcdi_impl.h> 41 #include <sys/usb/hubd/hub.h> 42 #include <sys/usb/hubd/hubdvar.h> 43 #include <sys/usb/hubd/hubd_impl.h> 44 #include <sys/kobj.h> 45 #include <sys/kobj_lex.h> 46 #include <sys/fs/dv_node.h> 47 #include <sys/strsun.h> 48 49 /* 50 * Prototypes for static functions 51 */ 52 static int usba_hubdi_bus_ctl( 53 dev_info_t *dip, 54 dev_info_t *rdip, 55 ddi_ctl_enum_t op, 56 void *arg, 57 void *result); 58 59 static int usba_hubdi_map_fault( 60 dev_info_t *dip, 61 dev_info_t *rdip, 62 struct hat *hat, 63 struct seg *seg, 64 caddr_t addr, 65 struct devpage *dp, 66 pfn_t pfn, 67 uint_t prot, 68 uint_t lock); 69 70 static int hubd_busop_get_eventcookie(dev_info_t *dip, 71 dev_info_t *rdip, 72 char *eventname, 73 ddi_eventcookie_t *cookie); 74 static int hubd_busop_add_eventcall(dev_info_t *dip, 75 dev_info_t *rdip, 76 ddi_eventcookie_t cookie, 77 void (*callback)(dev_info_t *dip, 78 ddi_eventcookie_t cookie, void *arg, 79 void *bus_impldata), 80 void *arg, ddi_callback_id_t *cb_id); 81 static int hubd_busop_remove_eventcall(dev_info_t *dip, 82 ddi_callback_id_t cb_id); 83 static int hubd_bus_config(dev_info_t *dip, 84 uint_t flag, 85 ddi_bus_config_op_t op, 86 void *arg, 87 dev_info_t **child); 88 static int hubd_bus_unconfig(dev_info_t *dip, 89 uint_t flag, 90 ddi_bus_config_op_t op, 91 void *arg); 92 static int hubd_bus_power(dev_info_t *dip, void *impl_arg, 93 pm_bus_power_op_t op, void *arg, void *result); 94 95 static usb_port_t hubd_get_port_num(hubd_t *, struct devctl_iocdata *); 96 static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t); 97 static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t); 98 static int hubd_toggle_port(hubd_t *, usb_port_t); 99 static void hubd_register_cpr_callback(hubd_t *); 100 static void hubd_unregister_cpr_callback(hubd_t *); 101 102 /* 103 * Busops vector for USB HUB's 104 */ 105 struct bus_ops usba_hubdi_busops = { 106 BUSO_REV, 107 nullbusmap, /* bus_map */ 108 NULL, /* bus_get_intrspec */ 109 NULL, /* bus_add_intrspec */ 110 NULL, /* bus_remove_intrspec */ 111 usba_hubdi_map_fault, /* bus_map_fault */ 112 ddi_dma_map, /* bus_dma_map */ 113 ddi_dma_allochdl, 114 ddi_dma_freehdl, 115 ddi_dma_bindhdl, 116 ddi_dma_unbindhdl, 117 ddi_dma_flush, 118 ddi_dma_win, 119 ddi_dma_mctl, /* bus_dma_ctl */ 120 usba_hubdi_bus_ctl, /* bus_ctl */ 121 ddi_bus_prop_op, /* bus_prop_op */ 122 hubd_busop_get_eventcookie, 123 hubd_busop_add_eventcall, 124 hubd_busop_remove_eventcall, 125 NULL, /* bus_post_event */ 126 NULL, /* bus_intr_ctl */ 127 hubd_bus_config, /* bus_config */ 128 hubd_bus_unconfig, /* bus_unconfig */ 129 NULL, /* bus_fm_init */ 130 NULL, /* bus_fm_fini */ 131 NULL, /* bus_fm_access_enter */ 132 NULL, /* bus_fm_access_exit */ 133 hubd_bus_power /* bus_power */ 134 }; 135 136 137 /* 138 * local variables 139 */ 140 static kmutex_t usba_hubdi_mutex; /* protects USBA HUB data structures */ 141 142 static usba_list_entry_t usba_hubdi_list; 143 144 usb_log_handle_t hubdi_log_handle; 145 uint_t hubdi_errlevel = USB_LOG_L4; 146 uint_t hubdi_errmask = (uint_t)-1; 147 uint8_t hubdi_min_pm_threshold = 5; /* seconds */ 148 149 /* 150 * initialize private data 151 */ 152 void 153 usba_hubdi_initialization() 154 { 155 hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel, 156 &hubdi_errmask, NULL, 0); 157 158 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 159 "usba_hubdi_initialization"); 160 161 mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL); 162 163 usba_init_list(&usba_hubdi_list, NULL, NULL); 164 } 165 166 167 void 168 usba_hubdi_destroy() 169 { 170 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 171 "usba_hubdi_destroy"); 172 173 mutex_destroy(&usba_hubdi_mutex); 174 usba_destroy_list(&usba_hubdi_list); 175 176 usb_free_log_hdl(hubdi_log_handle); 177 } 178 179 180 /* 181 * Called by an HUB to attach an instance of the driver 182 * make this instance known to USBA 183 * the HUB should initialize usba_hubdi structure prior 184 * to calling this interface 185 */ 186 int 187 usba_hubdi_register(dev_info_t *dip, 188 uint_t flags) 189 { 190 usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP); 191 usba_device_t *usba_device = usba_get_usba_device(dip); 192 193 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 194 "usba_hubdi_register: %s", ddi_node_name(dip)); 195 196 hubdi->hubdi_dip = dip; 197 hubdi->hubdi_flags = flags; 198 199 usba_device->usb_hubdi = hubdi; 200 201 /* 202 * add this hubdi instance to the list of known hubdi's 203 */ 204 usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi, 205 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 206 hcdi_iblock_cookie); 207 mutex_enter(&usba_hubdi_mutex); 208 usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list); 209 mutex_exit(&usba_hubdi_mutex); 210 211 return (DDI_SUCCESS); 212 } 213 214 215 /* 216 * Called by an HUB to detach an instance of the driver 217 */ 218 int 219 usba_hubdi_unregister(dev_info_t *dip) 220 { 221 usba_device_t *usba_device = usba_get_usba_device(dip); 222 usba_hubdi_t *hubdi = usba_device->usb_hubdi; 223 224 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 225 "usba_hubdi_unregister: %s", ddi_node_name(dip)); 226 227 mutex_enter(&usba_hubdi_mutex); 228 (void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list); 229 mutex_exit(&usba_hubdi_mutex); 230 231 usba_destroy_list(&hubdi->hubdi_list); 232 233 kmem_free(hubdi, sizeof (usba_hubdi_t)); 234 235 return (DDI_SUCCESS); 236 } 237 238 239 /* 240 * misc bus routines currently not used 241 */ 242 /*ARGSUSED*/ 243 static int 244 usba_hubdi_map_fault(dev_info_t *dip, 245 dev_info_t *rdip, 246 struct hat *hat, 247 struct seg *seg, 248 caddr_t addr, 249 struct devpage *dp, 250 pfn_t pfn, 251 uint_t prot, 252 uint_t lock) 253 { 254 return (DDI_FAILURE); 255 } 256 257 258 /* 259 * root hub support. the root hub uses the same devi as the HCD 260 */ 261 int 262 usba_hubdi_bind_root_hub(dev_info_t *dip, 263 uchar_t *root_hub_config_descriptor, 264 size_t config_length, 265 usb_dev_descr_t *root_hub_device_descriptor) 266 { 267 usba_device_t *usba_device; 268 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip); 269 hubd_t *root_hubd; 270 usb_pipe_handle_t ph = NULL; 271 dev_info_t *child = ddi_get_child(dip); 272 273 if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 274 "root-hub") != NDI_SUCCESS) { 275 276 return (USB_FAILURE); 277 } 278 279 usba_add_root_hub(dip); 280 281 root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP); 282 283 /* 284 * create and initialize a usba_device structure 285 */ 286 usba_device = usba_alloc_usba_device(dip); 287 288 mutex_enter(&usba_device->usb_mutex); 289 usba_device->usb_hcdi_ops = hcdi->hcdi_ops; 290 usba_device->usb_cfg = root_hub_config_descriptor; 291 usba_device->usb_cfg_length = config_length; 292 usba_device->usb_dev_descr = root_hub_device_descriptor; 293 usba_device->usb_port = 1; 294 usba_device->usb_addr = ROOT_HUB_ADDR; 295 usba_device->usb_root_hubd = root_hubd; 296 usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *), 297 KM_SLEEP); 298 usba_device->usb_cfg_array_length = sizeof (uchar_t *); 299 300 usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t), 301 KM_SLEEP); 302 usba_device->usb_cfg_array_len_length = sizeof (uint16_t); 303 304 usba_device->usb_cfg_array[0] = root_hub_config_descriptor; 305 usba_device->usb_cfg_array_len[0] = 306 sizeof (root_hub_config_descriptor); 307 308 usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *), 309 KM_SLEEP); 310 usba_device->usb_n_cfgs = 1; 311 usba_device->usb_n_ifs = 1; 312 usba_device->usb_dip = dip; 313 314 usba_device->usb_client_flags = kmem_zalloc( 315 usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 316 317 usba_device->usb_client_attach_list = kmem_zalloc( 318 usba_device->usb_n_ifs * 319 sizeof (*usba_device->usb_client_attach_list), KM_SLEEP); 320 321 usba_device->usb_client_ev_cb_list = kmem_zalloc( 322 usba_device->usb_n_ifs * 323 sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP); 324 325 /* 326 * The bDeviceProtocol field of root hub device specifies, 327 * whether root hub is a High or Full speed usb device. 328 */ 329 if (root_hub_device_descriptor->bDeviceProtocol) { 330 usba_device->usb_port_status = USBA_HIGH_SPEED_DEV; 331 } else { 332 usba_device->usb_port_status = USBA_FULL_SPEED_DEV; 333 } 334 335 mutex_exit(&usba_device->usb_mutex); 336 337 usba_set_usba_device(dip, usba_device); 338 339 /* 340 * For the root hub the default pipe is not yet open 341 */ 342 if (usb_pipe_open(dip, NULL, NULL, 343 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) { 344 goto fail; 345 } 346 347 /* 348 * kill off all OBP children, they may not be fully 349 * enumerated 350 */ 351 while (child) { 352 dev_info_t *next = ddi_get_next_sibling(child); 353 (void) ddi_remove_child(child, 0); 354 child = next; 355 } 356 357 /* 358 * "attach" the root hub driver 359 */ 360 if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) { 361 goto fail; 362 } 363 364 return (USB_SUCCESS); 365 366 fail: 367 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 368 369 usba_rem_root_hub(dip); 370 371 if (ph) { 372 usb_pipe_close(dip, ph, 373 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 374 } 375 376 kmem_free(usba_device->usb_cfg_array, 377 usba_device->usb_cfg_array_length); 378 kmem_free(usba_device->usb_cfg_array_len, 379 usba_device->usb_cfg_array_len_length); 380 381 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 382 383 usba_free_usba_device(usba_device); 384 385 usba_set_usba_device(dip, NULL); 386 if (root_hubd) { 387 kmem_free(root_hubd, sizeof (hubd_t)); 388 } 389 390 return (USB_FAILURE); 391 } 392 393 394 int 395 usba_hubdi_unbind_root_hub(dev_info_t *dip) 396 { 397 usba_device_t *usba_device; 398 399 /* was root hub attached? */ 400 if (!(usba_is_root_hub(dip))) { 401 402 /* return success anyway */ 403 return (USB_SUCCESS); 404 } 405 406 /* 407 * usba_hubdi_detach also closes the default pipe 408 * and removes properties so there is no need to 409 * do it here 410 */ 411 if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) { 412 413 if (DEVI_IS_ATTACHING(dip)) { 414 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 415 "failure to unbind root hub after attach failure"); 416 } 417 418 return (USB_FAILURE); 419 } 420 421 usba_device = usba_get_usba_device(dip); 422 423 kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t)); 424 425 kmem_free(usba_device->usb_cfg_array, 426 usba_device->usb_cfg_array_length); 427 kmem_free(usba_device->usb_cfg_array_len, 428 usba_device->usb_cfg_array_len_length); 429 430 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 431 432 usba_free_usba_device(usba_device); 433 434 usba_rem_root_hub(dip); 435 436 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 437 438 return (USB_SUCCESS); 439 } 440 441 442 /* 443 * Actual Hub Driver support code: 444 * shared by root hub and non-root hubs 445 */ 446 #include <sys/usb/usba/usbai_version.h> 447 448 /* Debugging support */ 449 uint_t hubd_errlevel = USB_LOG_L4; 450 uint_t hubd_errmask = (uint_t)DPRINT_MASK_ALL; 451 uint_t hubd_instance_debug = (uint_t)-1; 452 static uint_t hubdi_bus_config_debug = 0; 453 454 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel)) 455 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask)) 456 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug)) 457 458 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 459 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 460 461 462 /* 463 * local variables: 464 * 465 * Amount of time to wait between resetting the port and accessing 466 * the device. The value is in microseconds. 467 */ 468 static uint_t hubd_device_delay = 1000000; 469 470 /* 471 * enumeration retry 472 */ 473 #define HUBD_PORT_RETRY 5 474 static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY; 475 476 /* 477 * Stale hotremoved device cleanup delay 478 */ 479 #define HUBD_STALE_DIP_CLEANUP_DELAY 5000000 480 static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY; 481 482 /* 483 * retries for USB suspend and resume 484 */ 485 #define HUBD_SUS_RES_RETRY 2 486 487 void *hubd_statep; 488 489 /* 490 * prototypes 491 */ 492 static int hubd_cleanup(dev_info_t *dip, hubd_t *hubd); 493 static int hubd_check_ports(hubd_t *hubd); 494 495 static int hubd_open_intr_pipe(hubd_t *hubd); 496 static void hubd_start_polling(hubd_t *hubd, int always); 497 static void hubd_stop_polling(hubd_t *hubd); 498 static void hubd_close_intr_pipe(hubd_t *hubd); 499 500 static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req); 501 static void hubd_exception_cb(usb_pipe_handle_t pipe, 502 usb_intr_req_t *req); 503 static void hubd_hotplug_thread(void *arg); 504 static void hubd_reset_thread(void *arg); 505 static int hubd_create_child(dev_info_t *dip, 506 hubd_t *hubd, 507 usba_device_t *usba_device, 508 usb_port_status_t port_status, 509 usb_port_t port, 510 int iteration); 511 512 static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, 513 boolean_t retry); 514 515 static int hubd_get_hub_descriptor(hubd_t *hubd); 516 517 static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status); 518 519 static int hubd_reset_port(hubd_t *hubd, usb_port_t port); 520 521 static int hubd_get_hub_status(hubd_t *hubd); 522 523 static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port); 524 525 static int hubd_disable_port(hubd_t *hubd, usb_port_t port); 526 527 static int hubd_enable_port(hubd_t *hubd, usb_port_t port); 528 static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port); 529 530 static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 531 uint16_t *status, uint16_t *change, uint_t ack_flag); 532 533 static int hubd_enable_all_port_power(hubd_t *hubd); 534 static int hubd_disable_all_port_power(hubd_t *hubd); 535 static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port); 536 static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port); 537 538 static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device); 539 540 static int hubd_can_suspend(hubd_t *hubd); 541 static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd); 542 static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port); 543 static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port); 544 545 static int hubd_register_events(hubd_t *hubd); 546 static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip, 547 ddi_eventcookie_t cookie); 548 static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type); 549 static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type); 550 static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd); 551 552 static int hubd_disconnect_event_cb(dev_info_t *dip); 553 static int hubd_reconnect_event_cb(dev_info_t *dip); 554 static int hubd_pre_suspend_event_cb(dev_info_t *dip); 555 static int hubd_post_resume_event_cb(dev_info_t *dip); 556 static int hubd_cpr_suspend(hubd_t *hubd); 557 static void hubd_cpr_resume(dev_info_t *dip); 558 static int hubd_restore_state_cb(dev_info_t *dip); 559 static int hubd_check_same_device(hubd_t *hubd, usb_port_t port); 560 561 static int hubd_init_power_budget(hubd_t *hubd); 562 563 static ndi_event_definition_t hubd_ndi_event_defs[] = { 564 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 565 NDI_EVENT_POST_TO_ALL}, 566 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 567 NDI_EVENT_POST_TO_ALL}, 568 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 569 NDI_EVENT_POST_TO_ALL}, 570 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 571 NDI_EVENT_POST_TO_ALL} 572 }; 573 574 #define HUBD_N_NDI_EVENTS \ 575 (sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t)) 576 577 static ndi_event_set_t hubd_ndi_events = { 578 NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs}; 579 580 /* events received from parent */ 581 static usb_event_t hubd_events = { 582 hubd_disconnect_event_cb, 583 hubd_reconnect_event_cb, 584 hubd_pre_suspend_event_cb, 585 hubd_post_resume_event_cb 586 }; 587 588 589 /* 590 * hubd_get_soft_state() returns the hubd soft state 591 * 592 * WUSB support extends this function to support wire adapter class 593 * devices. The hubd soft state for the wire adapter class device 594 * would be stored in usb_root_hubd field of the usba_device structure, 595 * just as the USB host controller drivers do. 596 */ 597 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) || usba_is_wa(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-count 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 major_t hwahc_major = ddi_name_to_major("hwahc"); 2205 major_t usbmid_major = ddi_name_to_major("usb_mid"); 2206 2207 /* 2208 * make sure dip is a usb hub, major of root hub is HCD 2209 * major 2210 */ 2211 if (!usba_is_root_hub(dip)) { 2212 if (ddi_driver_major(dip) == usbmid_major) { 2213 /* 2214 * need to walk the children since it might be a 2215 * HWA device 2216 */ 2217 2218 return (DDI_WALK_CONTINUE); 2219 } 2220 2221 /* TODO: DWA device may also need special handling */ 2222 2223 if (((ddi_driver_major(dip) != hub_major) && 2224 (ddi_driver_major(dip) != hwahc_major)) || 2225 !i_ddi_devi_attached(dip)) { 2226 2227 return (DDI_WALK_PRUNECHILD); 2228 } 2229 } 2230 2231 hubd = hubd_get_soft_state(dip); 2232 if (hubd == NULL) { 2233 2234 return (DDI_WALK_PRUNECHILD); 2235 } 2236 2237 /* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */ 2238 ndi_devi_enter(dip, &circ); 2239 2240 if (ddi_driver_major(dip) != hwahc_major) { 2241 /* for normal usb hub or root hub */ 2242 mutex_enter(HUBD_MUTEX(hubd)); 2243 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2244 dev_info_t *cdip = hubd->h_children_dips[port]; 2245 2246 if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) { 2247 2248 continue; 2249 } 2250 2251 (void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE, 2252 B_TRUE); 2253 } 2254 mutex_exit(HUBD_MUTEX(hubd)); 2255 } else { 2256 /* for HWA */ 2257 if (hubd->h_cleanup_child != NULL) { 2258 if (hubd->h_cleanup_child(dip) != USB_SUCCESS) { 2259 ndi_devi_exit(dip, circ); 2260 2261 return (DDI_WALK_PRUNECHILD); 2262 } 2263 } else { 2264 ndi_devi_exit(dip, circ); 2265 2266 return (DDI_WALK_PRUNECHILD); 2267 } 2268 } 2269 2270 ndi_devi_exit(dip, circ); 2271 2272 /* skip siblings of root hub */ 2273 if (usba_is_root_hub(dip)) { 2274 2275 return (DDI_WALK_PRUNESIB); 2276 } 2277 2278 return (DDI_WALK_CONTINUE); 2279 } 2280 2281 2282 /* 2283 * this thread will walk all children under the root hub for this 2284 * USB bus instance and attempt to remove them 2285 */ 2286 static void 2287 hubd_root_hub_cleanup_thread(void *arg) 2288 { 2289 int circ; 2290 hubd_t *root_hubd = (hubd_t *)arg; 2291 dev_info_t *rh_dip = root_hubd->h_dip; 2292 #ifndef __lock_lint 2293 callb_cpr_t cprinfo; 2294 2295 CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr, 2296 "USB root hub"); 2297 #endif 2298 2299 for (;;) { 2300 /* don't race with detach */ 2301 ndi_hold_devi(rh_dip); 2302 2303 mutex_enter(HUBD_MUTEX(root_hubd)); 2304 root_hubd->h_cleanup_needed = 0; 2305 mutex_exit(HUBD_MUTEX(root_hubd)); 2306 2307 (void) devfs_clean(rh_dip, NULL, 0); 2308 2309 ndi_devi_enter(ddi_get_parent(rh_dip), &circ); 2310 ddi_walk_devs(rh_dip, hubd_check_disconnected_ports, 2311 NULL); 2312 #ifdef __lock_lint 2313 (void) hubd_check_disconnected_ports(rh_dip, NULL); 2314 #endif 2315 ndi_devi_exit(ddi_get_parent(rh_dip), circ); 2316 2317 /* quit if we are not enabled anymore */ 2318 mutex_enter(HUBD_MUTEX(root_hubd)); 2319 if ((root_hubd->h_cleanup_enabled == B_FALSE) || 2320 (root_hubd->h_cleanup_needed == B_FALSE)) { 2321 root_hubd->h_cleanup_active = B_FALSE; 2322 mutex_exit(HUBD_MUTEX(root_hubd)); 2323 ndi_rele_devi(rh_dip); 2324 2325 break; 2326 } 2327 mutex_exit(HUBD_MUTEX(root_hubd)); 2328 ndi_rele_devi(rh_dip); 2329 2330 #ifndef __lock_lint 2331 mutex_enter(HUBD_MUTEX(root_hubd)); 2332 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2333 mutex_exit(HUBD_MUTEX(root_hubd)); 2334 2335 delay(drv_usectohz(hubd_dip_cleanup_delay)); 2336 2337 mutex_enter(HUBD_MUTEX(root_hubd)); 2338 CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd)); 2339 mutex_exit(HUBD_MUTEX(root_hubd)); 2340 #endif 2341 } 2342 2343 #ifndef __lock_lint 2344 mutex_enter(HUBD_MUTEX(root_hubd)); 2345 CALLB_CPR_EXIT(&cprinfo); 2346 #endif 2347 } 2348 2349 2350 void 2351 hubd_schedule_cleanup(dev_info_t *rh_dip) 2352 { 2353 hubd_t *root_hubd; 2354 2355 /* 2356 * The usb_root_hub_dip pointer for the child hub of the WUSB 2357 * wire adapter class device points to the wire adapter, not 2358 * the root hub. Need to find the real root hub dip so that 2359 * the cleanup thread only starts from the root hub. 2360 */ 2361 while (!usba_is_root_hub(rh_dip)) { 2362 root_hubd = hubd_get_soft_state(rh_dip); 2363 if (root_hubd != NULL) { 2364 rh_dip = root_hubd->h_usba_device->usb_root_hub_dip; 2365 if (rh_dip == NULL) { 2366 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2367 root_hubd->h_log_handle, 2368 "hubd_schedule_cleanup: null rh dip"); 2369 2370 return; 2371 } 2372 } else { 2373 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2374 root_hubd->h_log_handle, 2375 "hubd_schedule_cleanup: cannot find root hub"); 2376 2377 return; 2378 } 2379 } 2380 root_hubd = hubd_get_soft_state(rh_dip); 2381 2382 mutex_enter(HUBD_MUTEX(root_hubd)); 2383 root_hubd->h_cleanup_needed = B_TRUE; 2384 if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) { 2385 root_hubd->h_cleanup_active = B_TRUE; 2386 mutex_exit(HUBD_MUTEX(root_hubd)); 2387 (void) thread_create(NULL, 0, 2388 hubd_root_hub_cleanup_thread, 2389 (void *)root_hubd, 0, &p0, TS_RUN, 2390 minclsyspri); 2391 } else { 2392 mutex_exit(HUBD_MUTEX(root_hubd)); 2393 } 2394 } 2395 2396 2397 /* 2398 * hubd_restore_device_state: 2399 * - set config for the hub 2400 * - power cycle all the ports 2401 * - for each port that was connected 2402 * - reset port 2403 * - assign addrs to the device on this port 2404 * - restart polling 2405 * - reset suspend flag 2406 */ 2407 static void 2408 hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd) 2409 { 2410 int rval; 2411 int retry; 2412 uint_t hub_prev_state; 2413 usb_port_t port; 2414 uint16_t status; 2415 uint16_t change; 2416 dev_info_t *ch_dip; 2417 boolean_t ehci_root_hub; 2418 2419 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2420 "hubd_restore_device_state:"); 2421 2422 mutex_enter(HUBD_MUTEX(hubd)); 2423 hub_prev_state = hubd->h_dev_state; 2424 ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN); 2425 2426 /* First bring the device to full power */ 2427 (void) hubd_pm_busy_component(hubd, dip, 0); 2428 mutex_exit(HUBD_MUTEX(hubd)); 2429 2430 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2431 2432 if (!usba_is_root_hub(dip) && 2433 (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0, 2434 DPRINT_MASK_HOTPLUG, 2435 USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) { 2436 2437 /* change the device state to disconnected */ 2438 mutex_enter(HUBD_MUTEX(hubd)); 2439 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2440 (void) hubd_pm_idle_component(hubd, dip, 0); 2441 mutex_exit(HUBD_MUTEX(hubd)); 2442 2443 return; 2444 } 2445 2446 ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0); 2447 2448 mutex_enter(HUBD_MUTEX(hubd)); 2449 /* First turn off all port power */ 2450 rval = hubd_disable_all_port_power(hubd); 2451 if (rval != USB_SUCCESS) { 2452 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2453 "hubd_restore_device_state:" 2454 "turning off port power failed"); 2455 } 2456 2457 /* Settling time before turning on again */ 2458 mutex_exit(HUBD_MUTEX(hubd)); 2459 delay(drv_usectohz(hubd_device_delay / 100)); 2460 mutex_enter(HUBD_MUTEX(hubd)); 2461 2462 /* enable power on all ports so we can see connects */ 2463 if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) { 2464 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2465 "hubd_restore_device_state: turn on port power failed"); 2466 2467 /* disable whatever was enabled */ 2468 (void) hubd_disable_all_port_power(hubd); 2469 2470 (void) hubd_pm_idle_component(hubd, dip, 0); 2471 mutex_exit(HUBD_MUTEX(hubd)); 2472 2473 return; 2474 } 2475 2476 /* 2477 * wait at least 3 frames before accessing devices 2478 * (note that delay's minimal time is one clock tick which 2479 * is 10ms unless hires_tick has been changed) 2480 */ 2481 mutex_exit(HUBD_MUTEX(hubd)); 2482 delay(drv_usectohz(10000)); 2483 mutex_enter(HUBD_MUTEX(hubd)); 2484 2485 hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER; 2486 2487 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2488 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2489 "hubd_restore_device_state: port=%d", port); 2490 2491 /* 2492 * the childen_dips list may have dips that have been 2493 * already deallocated. we only get a post_detach notification 2494 * but not a destroy notification 2495 */ 2496 ch_dip = hubd->h_children_dips[port]; 2497 if (ch_dip) { 2498 /* get port status */ 2499 (void) hubd_determine_port_status(hubd, port, 2500 &status, &change, PORT_CHANGE_CSC); 2501 2502 /* check if it is truly connected */ 2503 if (status & PORT_STATUS_CCS) { 2504 /* 2505 * Now reset port and assign the device 2506 * its original address 2507 */ 2508 retry = 0; 2509 do { 2510 (void) hubd_reset_port(hubd, port); 2511 2512 /* required for ppx */ 2513 (void) hubd_enable_port(hubd, port); 2514 2515 if (retry) { 2516 mutex_exit(HUBD_MUTEX(hubd)); 2517 delay(drv_usectohz( 2518 hubd_device_delay/2)); 2519 mutex_enter(HUBD_MUTEX(hubd)); 2520 } 2521 2522 rval = hubd_setdevaddr(hubd, port); 2523 retry++; 2524 } while ((rval != USB_SUCCESS) && 2525 (retry < hubd_retry_enumerate)); 2526 2527 hubd_setdevconfig(hubd, port); 2528 2529 if (hub_prev_state == USB_DEV_DISCONNECTED) { 2530 /* post a connect event */ 2531 mutex_exit(HUBD_MUTEX(hubd)); 2532 hubd_post_event(hubd, port, 2533 USBA_EVENT_TAG_HOT_INSERTION); 2534 mutex_enter(HUBD_MUTEX(hubd)); 2535 } else { 2536 /* 2537 * Since we have this device connected 2538 * mark it reinserted to prevent 2539 * cleanup thread from stepping in. 2540 */ 2541 mutex_exit(HUBD_MUTEX(hubd)); 2542 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2543 DEVI_SET_DEVICE_REINSERTED(ch_dip); 2544 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2545 2546 /* 2547 * reopen pipes for children for 2548 * their DDI_RESUME 2549 */ 2550 rval = usba_persistent_pipe_open( 2551 usba_get_usba_device(ch_dip)); 2552 mutex_enter(HUBD_MUTEX(hubd)); 2553 ASSERT(rval == USB_SUCCESS); 2554 } 2555 } else { 2556 /* 2557 * Mark this dip for deletion as the device 2558 * is not physically present, and schedule 2559 * cleanup thread upon post resume 2560 */ 2561 mutex_exit(HUBD_MUTEX(hubd)); 2562 2563 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2564 hubd->h_log_handle, 2565 "hubd_restore_device_state: " 2566 "dip=%p on port=%d marked for cleanup", 2567 (void *)ch_dip, port); 2568 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2569 DEVI_SET_DEVICE_REMOVED(ch_dip); 2570 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2571 2572 mutex_enter(HUBD_MUTEX(hubd)); 2573 } 2574 } else if (ehci_root_hub) { 2575 /* get port status */ 2576 (void) hubd_determine_port_status(hubd, port, 2577 &status, &change, PORT_CHANGE_CSC); 2578 2579 /* check if it is truly connected */ 2580 if (status & PORT_STATUS_CCS) { 2581 /* 2582 * reset the port to find out if we have 2583 * 2.0 device connected or 1.X. A 2.0 2584 * device will still be seen as connected, 2585 * while a 1.X device will switch over to 2586 * the companion controller. 2587 */ 2588 (void) hubd_reset_port(hubd, port); 2589 2590 (void) hubd_determine_port_status(hubd, port, 2591 &status, &change, PORT_CHANGE_CSC); 2592 2593 if (status & 2594 (PORT_STATUS_CCS | PORT_STATUS_HSDA)) { 2595 /* 2596 * We have a USB 2.0 device 2597 * connected. Power cycle this port 2598 * so that hotplug thread can 2599 * enumerate this device. 2600 */ 2601 (void) hubd_toggle_port(hubd, port); 2602 } else { 2603 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2604 hubd->h_log_handle, 2605 "hubd_restore_device_state: " 2606 "device on port %d switched over", 2607 port); 2608 } 2609 } 2610 2611 } 2612 } 2613 2614 2615 /* if the device had remote wakeup earlier, enable it again */ 2616 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2617 mutex_exit(HUBD_MUTEX(hubd)); 2618 (void) usb_handle_remote_wakeup(hubd->h_dip, 2619 USB_REMOTE_WAKEUP_ENABLE); 2620 mutex_enter(HUBD_MUTEX(hubd)); 2621 } 2622 2623 hubd->h_dev_state = USB_DEV_ONLINE; 2624 hubd_start_polling(hubd, 0); 2625 (void) hubd_pm_idle_component(hubd, dip, 0); 2626 mutex_exit(HUBD_MUTEX(hubd)); 2627 } 2628 2629 2630 /* 2631 * hubd_cleanup: 2632 * cleanup hubd and deallocate. this function is called for 2633 * handling attach failures and detaching including dynamic 2634 * reconfiguration. If called from attaching, it must clean 2635 * up the whole thing and return success. 2636 */ 2637 /*ARGSUSED*/ 2638 static int 2639 hubd_cleanup(dev_info_t *dip, hubd_t *hubd) 2640 { 2641 int circ, rval, old_dev_state; 2642 hub_power_t *hubpm; 2643 #ifdef DEBUG 2644 usb_port_t port; 2645 #endif 2646 2647 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2648 "hubd_cleanup:"); 2649 2650 if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) { 2651 goto done; 2652 } 2653 2654 /* ensure we are the only one active */ 2655 ndi_devi_enter(dip, &circ); 2656 2657 mutex_enter(HUBD_MUTEX(hubd)); 2658 2659 /* Cleanup failure is only allowed if called from detach */ 2660 if (DEVI_IS_DETACHING(dip)) { 2661 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 2662 2663 /* 2664 * We are being called from detach. 2665 * Fail immediately if the hotplug thread is running 2666 * else set the dev_state to disconnected so that 2667 * hotplug thread just exits without doing anything. 2668 */ 2669 if (hubd->h_bus_ctls || hubd->h_bus_pwr || 2670 hubd->h_hotplug_thread) { 2671 mutex_exit(HUBD_MUTEX(hubd)); 2672 ndi_devi_exit(dip, circ); 2673 2674 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2675 "hubd_cleanup: hotplug thread/bus ctl active " 2676 "- failing detach"); 2677 2678 return (USB_FAILURE); 2679 } 2680 2681 /* 2682 * if the deathrow thread is still active or about 2683 * to become active, fail detach 2684 * the roothup can only be detached if nexus drivers 2685 * are unloaded or explicitly offlined 2686 */ 2687 if (rh_dip == dip) { 2688 if (hubd->h_cleanup_needed || 2689 hubd->h_cleanup_active) { 2690 mutex_exit(HUBD_MUTEX(hubd)); 2691 ndi_devi_exit(dip, circ); 2692 2693 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2694 hubd->h_log_handle, 2695 "hubd_cleanup: deathrow still active?" 2696 "- failing detach"); 2697 2698 return (USB_FAILURE); 2699 } 2700 } 2701 } 2702 2703 old_dev_state = hubd->h_dev_state; 2704 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2705 2706 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2707 "hubd_cleanup: stop polling"); 2708 hubd_close_intr_pipe(hubd); 2709 2710 ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr || 2711 hubd->h_hotplug_thread) == 0); 2712 mutex_exit(HUBD_MUTEX(hubd)); 2713 2714 /* 2715 * deallocate events, if events are still registered 2716 * (ie. children still attached) then we have to fail the detach 2717 */ 2718 if (hubd->h_ndi_event_hdl) { 2719 2720 rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl); 2721 if (DEVI_IS_ATTACHING(dip)) { 2722 2723 /* It must return success if attaching. */ 2724 ASSERT(rval == NDI_SUCCESS); 2725 2726 } else if (rval != NDI_SUCCESS) { 2727 2728 USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle, 2729 "hubd_cleanup: ndi_event_free_hdl failed"); 2730 ndi_devi_exit(dip, circ); 2731 2732 return (USB_FAILURE); 2733 2734 } 2735 } 2736 2737 mutex_enter(HUBD_MUTEX(hubd)); 2738 2739 if (hubd->h_init_state & HUBD_CHILDREN_CREATED) { 2740 #ifdef DEBUG 2741 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2742 ASSERT(hubd->h_usba_devices[port] == NULL); 2743 ASSERT(hubd->h_children_dips[port] == NULL); 2744 } 2745 #endif 2746 kmem_free(hubd->h_children_dips, hubd->h_cd_list_length); 2747 kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length); 2748 } 2749 2750 /* 2751 * Disable the event callbacks first, after this point, event 2752 * callbacks will never get called. Note we shouldn't hold 2753 * mutex while unregistering events because there may be a 2754 * competing event callback thread. Event callbacks are done 2755 * with ndi mutex held and this can cause a potential deadlock. 2756 * Note that cleanup can't fail after deregistration of events. 2757 */ 2758 if (hubd->h_init_state & HUBD_EVENTS_REGISTERED) { 2759 mutex_exit(HUBD_MUTEX(hubd)); 2760 usb_unregister_event_cbs(dip, &hubd_events); 2761 hubd_unregister_cpr_callback(hubd); 2762 mutex_enter(HUBD_MUTEX(hubd)); 2763 } 2764 2765 /* restore the old dev state so that device can be put into low power */ 2766 hubd->h_dev_state = old_dev_state; 2767 hubpm = hubd->h_hubpm; 2768 2769 if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) { 2770 (void) hubd_pm_busy_component(hubd, dip, 0); 2771 mutex_exit(HUBD_MUTEX(hubd)); 2772 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2773 /* 2774 * Bring the hub to full power before 2775 * issuing the disable remote wakeup command 2776 */ 2777 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2778 2779 if ((rval = usb_handle_remote_wakeup(hubd->h_dip, 2780 USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 2781 USB_DPRINTF_L2(DPRINT_MASK_PM, 2782 hubd->h_log_handle, 2783 "hubd_cleanup: disable remote wakeup " 2784 "fails=%d", rval); 2785 } 2786 } 2787 2788 (void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF); 2789 2790 mutex_enter(HUBD_MUTEX(hubd)); 2791 (void) hubd_pm_idle_component(hubd, dip, 0); 2792 } 2793 2794 if (hubpm) { 2795 if (hubpm->hubp_child_pwrstate) { 2796 kmem_free(hubpm->hubp_child_pwrstate, 2797 MAX_PORTS + 1); 2798 } 2799 kmem_free(hubpm, sizeof (hub_power_t)); 2800 } 2801 mutex_exit(HUBD_MUTEX(hubd)); 2802 2803 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2804 "hubd_cleanup: freeing space"); 2805 2806 if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) { 2807 rval = usba_hubdi_unregister(dip); 2808 ASSERT(rval == USB_SUCCESS); 2809 } 2810 2811 if (hubd->h_init_state & HUBD_LOCKS_DONE) { 2812 mutex_destroy(HUBD_MUTEX(hubd)); 2813 cv_destroy(&hubd->h_cv_reset_port); 2814 cv_destroy(&hubd->h_cv_hotplug_dev); 2815 } 2816 2817 ndi_devi_exit(dip, circ); 2818 2819 if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) { 2820 ddi_remove_minor_node(dip, NULL); 2821 } 2822 2823 if (usba_is_root_hub(dip)) { 2824 usb_pipe_close(dip, hubd->h_default_pipe, 2825 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2826 } 2827 2828 done: 2829 if (hubd->h_ancestry_str) { 2830 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN); 2831 } 2832 2833 usb_client_detach(dip, hubd->h_dev_data); 2834 2835 usb_free_log_hdl(hubd->h_log_handle); 2836 2837 if (!usba_is_root_hub(dip)) { 2838 ddi_soft_state_free(hubd_statep, ddi_get_instance(dip)); 2839 } 2840 2841 ddi_prop_remove_all(dip); 2842 2843 return (USB_SUCCESS); 2844 } 2845 2846 2847 /* 2848 * hubd_determine_port_connection: 2849 * Determine which port is in connect status but does not 2850 * have connect status change bit set, and mark port change 2851 * bit accordingly. 2852 * This function is applied during hub attach time. 2853 */ 2854 static usb_port_mask_t 2855 hubd_determine_port_connection(hubd_t *hubd) 2856 { 2857 usb_port_t port; 2858 usb_hub_descr_t *hub_descr; 2859 uint16_t status; 2860 uint16_t change; 2861 usb_port_mask_t port_change = 0; 2862 2863 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2864 2865 hub_descr = &hubd->h_hub_descr; 2866 2867 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 2868 2869 (void) hubd_determine_port_status(hubd, port, &status, 2870 &change, 0); 2871 2872 /* Check if port is in connect status */ 2873 if (!(status & PORT_STATUS_CCS)) { 2874 2875 continue; 2876 } 2877 2878 /* 2879 * Check if port Connect Status Change bit has been set. 2880 * If already set, the connection will be handled by 2881 * intr polling callback, not during attach. 2882 */ 2883 if (change & PORT_CHANGE_CSC) { 2884 2885 continue; 2886 } 2887 2888 port_change |= 1 << port; 2889 } 2890 2891 return (port_change); 2892 } 2893 2894 2895 /* 2896 * hubd_check_ports: 2897 * - get hub descriptor 2898 * - check initial port status 2899 * - enable power on all ports 2900 * - enable polling on ep1 2901 */ 2902 static int 2903 hubd_check_ports(hubd_t *hubd) 2904 { 2905 int rval; 2906 usb_port_mask_t port_change = 0; 2907 hubd_hotplug_arg_t *arg; 2908 2909 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2910 2911 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 2912 "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip)); 2913 2914 /* 2915 * First turn off all port power 2916 */ 2917 if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) { 2918 2919 /* disable whatever was enabled */ 2920 (void) hubd_disable_all_port_power(hubd); 2921 2922 return (rval); 2923 } 2924 2925 /* 2926 * do not switch on immediately (instantly on root hub) 2927 * and allow time to settle 2928 */ 2929 mutex_exit(HUBD_MUTEX(hubd)); 2930 delay(drv_usectohz(10000)); 2931 mutex_enter(HUBD_MUTEX(hubd)); 2932 2933 /* 2934 * enable power on all ports so we can see connects 2935 */ 2936 if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) { 2937 /* disable whatever was enabled */ 2938 (void) hubd_disable_all_port_power(hubd); 2939 2940 return (rval); 2941 } 2942 2943 /* wait at least 3 frames before accessing devices */ 2944 mutex_exit(HUBD_MUTEX(hubd)); 2945 delay(drv_usectohz(10000)); 2946 mutex_enter(HUBD_MUTEX(hubd)); 2947 2948 /* 2949 * allocate arrays for saving the dips of each child per port 2950 * 2951 * ports go from 1 - n, allocate 1 more entry 2952 */ 2953 hubd->h_cd_list_length = 2954 (sizeof (dev_info_t **)) * (hubd->h_hub_descr.bNbrPorts + 1); 2955 2956 hubd->h_children_dips = (dev_info_t **)kmem_zalloc( 2957 hubd->h_cd_list_length, KM_SLEEP); 2958 hubd->h_usba_devices = (usba_device_t **)kmem_zalloc( 2959 hubd->h_cd_list_length, KM_SLEEP); 2960 2961 hubd->h_init_state |= HUBD_CHILDREN_CREATED; 2962 2963 mutex_exit(HUBD_MUTEX(hubd)); 2964 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 2965 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 2966 mutex_enter(HUBD_MUTEX(hubd)); 2967 2968 if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) { 2969 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 2970 2971 return (rval); 2972 } 2973 2974 hubd_start_polling(hubd, 0); 2975 2976 /* 2977 * Some hub devices, like the embedded hub in the CKS ErgoMagic 2978 * keyboard, may only have connection status bit set, but not 2979 * have connect status change bit set when a device has been 2980 * connected to its downstream port before the hub is enumerated. 2981 * Then when the hub is in enumeration, the devices connected to 2982 * it cannot be detected by the intr pipe and won't be enumerated. 2983 * We need to check such situation here and enumerate the downstream 2984 * devices for such hubs. 2985 */ 2986 port_change = hubd_determine_port_connection(hubd); 2987 2988 if (port_change) { 2989 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 2990 2991 arg->hubd = hubd; 2992 arg->hotplug_during_attach = B_TRUE; 2993 hubd->h_port_change |= port_change; 2994 2995 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 2996 "hubd_check_ports: port change=0x%x, need to connect", 2997 hubd->h_port_change); 2998 2999 if (usb_async_req(hubd->h_dip, hubd_hotplug_thread, 3000 (void *)arg, 0) == USB_SUCCESS) { 3001 hubd->h_hotplug_thread++; 3002 } else { 3003 /* mark this device as idle */ 3004 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3005 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3006 } 3007 } else { 3008 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3009 } 3010 3011 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3012 "hubd_check_ports done"); 3013 3014 return (USB_SUCCESS); 3015 } 3016 3017 3018 /* 3019 * hubd_get_hub_descriptor: 3020 */ 3021 static int 3022 hubd_get_hub_descriptor(hubd_t *hubd) 3023 { 3024 usb_hub_descr_t *hub_descr = &hubd->h_hub_descr; 3025 mblk_t *data = NULL; 3026 usb_cr_t completion_reason; 3027 usb_cb_flags_t cb_flags; 3028 uint16_t length; 3029 int rval; 3030 3031 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3032 "hubd_get_hub_descriptor:"); 3033 3034 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3035 ASSERT(hubd->h_default_pipe != 0); 3036 3037 /* get hub descriptor length first by requesting 8 bytes only */ 3038 mutex_exit(HUBD_MUTEX(hubd)); 3039 3040 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3041 hubd->h_default_pipe, 3042 HUB_CLASS_REQ_TYPE, 3043 USB_REQ_GET_DESCR, /* bRequest */ 3044 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3045 0, /* wIndex */ 3046 8, /* wLength */ 3047 &data, 0, 3048 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 3049 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3050 "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d", 3051 completion_reason, cb_flags, rval); 3052 freemsg(data); 3053 mutex_enter(HUBD_MUTEX(hubd)); 3054 3055 return (rval); 3056 } 3057 3058 length = *(data->b_rptr); 3059 3060 if (length > 8) { 3061 freemsg(data); 3062 data = NULL; 3063 3064 /* get complete hub descriptor */ 3065 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3066 hubd->h_default_pipe, 3067 HUB_CLASS_REQ_TYPE, 3068 USB_REQ_GET_DESCR, /* bRequest */ 3069 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3070 0, /* wIndex */ 3071 length, /* wLength */ 3072 &data, 0, 3073 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 3074 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3075 "get hub descriptor failed: " 3076 "cr=%d cb_fl=0x%x rval=%d", 3077 completion_reason, cb_flags, rval); 3078 freemsg(data); 3079 mutex_enter(HUBD_MUTEX(hubd)); 3080 3081 return (rval); 3082 } 3083 } 3084 3085 mutex_enter(HUBD_MUTEX(hubd)); 3086 3087 /* parse the hub descriptor */ 3088 /* only 32 ports are supported at present */ 3089 ASSERT(*(data->b_rptr + 2) <= 32); 3090 if (usb_parse_CV_descr("cccscccccc", 3091 data->b_rptr, MBLKL(data), 3092 (void *)hub_descr, sizeof (usb_hub_descr_t)) == 0) { 3093 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3094 "parsing hub descriptor failed"); 3095 3096 freemsg(data); 3097 3098 return (USB_FAILURE); 3099 } 3100 3101 freemsg(data); 3102 3103 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3104 "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x " 3105 "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval, 3106 hub_descr->bNbrPorts, hub_descr->wHubCharacteristics, 3107 hub_descr->bPwrOn2PwrGood, hub_descr->bHubContrCurrent); 3108 3109 if (hub_descr->bNbrPorts > MAX_PORTS) { 3110 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 3111 "Hub driver supports max of %d ports on hub. " 3112 "Hence using the first %d port of %d ports available", 3113 MAX_PORTS, MAX_PORTS, hub_descr->bNbrPorts); 3114 3115 hub_descr->bNbrPorts = MAX_PORTS; 3116 } 3117 3118 return (USB_SUCCESS); 3119 } 3120 3121 3122 /* 3123 * hubd_get_hub_status_words: 3124 */ 3125 static int 3126 hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status) 3127 { 3128 usb_cr_t completion_reason; 3129 usb_cb_flags_t cb_flags; 3130 mblk_t *data = NULL; 3131 3132 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3133 3134 mutex_exit(HUBD_MUTEX(hubd)); 3135 3136 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe, 3137 HUB_CLASS_REQ_TYPE, 3138 USB_REQ_GET_STATUS, 3139 0, 3140 0, 3141 GET_STATUS_LENGTH, 3142 &data, 0, 3143 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 3144 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3145 "get hub status failed: cr=%d cb=0x%x", 3146 completion_reason, cb_flags); 3147 3148 if (data) { 3149 freemsg(data); 3150 } 3151 3152 mutex_enter(HUBD_MUTEX(hubd)); 3153 3154 return (USB_FAILURE); 3155 } 3156 3157 mutex_enter(HUBD_MUTEX(hubd)); 3158 3159 status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 3160 status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 3161 3162 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 3163 "hub status=0x%x change=0x%x", status[0], status[1]); 3164 3165 freemsg(data); 3166 3167 return (USB_SUCCESS); 3168 } 3169 3170 3171 /* 3172 * hubd_open_intr_pipe: 3173 * we read all descriptors first for curiosity and then simply 3174 * open the pipe 3175 */ 3176 static int 3177 hubd_open_intr_pipe(hubd_t *hubd) 3178 { 3179 int rval; 3180 3181 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3182 "hubd_open_intr_pipe:"); 3183 3184 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE); 3185 3186 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING; 3187 mutex_exit(HUBD_MUTEX(hubd)); 3188 3189 if ((rval = usb_pipe_open(hubd->h_dip, 3190 &hubd->h_ep1_descr, &hubd->h_pipe_policy, 3191 0, &hubd->h_ep1_ph)) != USB_SUCCESS) { 3192 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3193 "open intr pipe failed (%d)", rval); 3194 3195 mutex_enter(HUBD_MUTEX(hubd)); 3196 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3197 3198 return (rval); 3199 } 3200 3201 mutex_enter(HUBD_MUTEX(hubd)); 3202 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3203 3204 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3205 "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph); 3206 3207 return (USB_SUCCESS); 3208 } 3209 3210 3211 /* 3212 * hubd_start_polling: 3213 * start or restart the polling 3214 */ 3215 static void 3216 hubd_start_polling(hubd_t *hubd, int always) 3217 { 3218 usb_intr_req_t *reqp; 3219 int rval; 3220 usb_pipe_state_t pipe_state; 3221 3222 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3223 "start polling: always=%d dev_state=%d pipe_state=%d\n\t" 3224 "thread=%d ep1_ph=0x%p", 3225 always, hubd->h_dev_state, hubd->h_intr_pipe_state, 3226 hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph); 3227 3228 /* 3229 * start or restart polling on the intr pipe 3230 * only if hotplug thread is not running 3231 */ 3232 if ((always == HUBD_ALWAYS_START_POLLING) || 3233 ((hubd->h_dev_state == USB_DEV_ONLINE) && 3234 (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3235 (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) { 3236 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3237 "start polling requested"); 3238 3239 reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP); 3240 3241 reqp->intr_client_private = (usb_opaque_t)hubd; 3242 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 3243 USB_ATTRS_AUTOCLEARING; 3244 reqp->intr_len = hubd->h_ep1_descr.wMaxPacketSize; 3245 reqp->intr_cb = hubd_read_cb; 3246 reqp->intr_exc_cb = hubd_exception_cb; 3247 mutex_exit(HUBD_MUTEX(hubd)); 3248 if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp, 3249 USB_FLAGS_SLEEP)) != USB_SUCCESS) { 3250 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3251 "start polling failed, rval=%d", rval); 3252 usb_free_intr_req(reqp); 3253 } 3254 3255 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3256 USB_FLAGS_SLEEP); 3257 if (pipe_state != USB_PIPE_STATE_ACTIVE) { 3258 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3259 "intr pipe state=%d, rval=%d", pipe_state, rval); 3260 } 3261 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3262 "start polling request 0x%p", (void *)reqp); 3263 3264 mutex_enter(HUBD_MUTEX(hubd)); 3265 } 3266 } 3267 3268 3269 /* 3270 * hubd_stop_polling 3271 * stop polling but do not close the pipe 3272 */ 3273 static void 3274 hubd_stop_polling(hubd_t *hubd) 3275 { 3276 int rval; 3277 usb_pipe_state_t pipe_state; 3278 3279 if (hubd->h_ep1_ph) { 3280 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3281 "hubd_stop_polling:"); 3282 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED; 3283 mutex_exit(HUBD_MUTEX(hubd)); 3284 3285 usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP); 3286 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3287 USB_FLAGS_SLEEP); 3288 3289 if (pipe_state != USB_PIPE_STATE_IDLE) { 3290 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3291 "intr pipe state=%d, rval=%d", pipe_state, rval); 3292 } 3293 mutex_enter(HUBD_MUTEX(hubd)); 3294 if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) { 3295 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3296 } 3297 } 3298 } 3299 3300 3301 /* 3302 * hubd_close_intr_pipe: 3303 * close the pipe (which also stops the polling 3304 * and wait for the hotplug thread to exit 3305 */ 3306 static void 3307 hubd_close_intr_pipe(hubd_t *hubd) 3308 { 3309 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3310 "hubd_close_intr_pipe:"); 3311 3312 /* 3313 * Now that no async operation is outstanding on pipe, 3314 * we can change the state to HUBD_INTR_PIPE_CLOSING 3315 */ 3316 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING; 3317 3318 ASSERT(hubd->h_hotplug_thread == 0); 3319 3320 if (hubd->h_ep1_ph) { 3321 mutex_exit(HUBD_MUTEX(hubd)); 3322 usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP, 3323 NULL, NULL); 3324 mutex_enter(HUBD_MUTEX(hubd)); 3325 hubd->h_ep1_ph = NULL; 3326 } 3327 3328 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3329 } 3330 3331 3332 /* 3333 * hubd_exception_cb 3334 * interrupt ep1 exception callback function. 3335 * this callback executes in taskq thread context and assumes 3336 * autoclearing 3337 */ 3338 /*ARGSUSED*/ 3339 static void 3340 hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3341 { 3342 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3343 3344 USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3345 "hubd_exception_cb: " 3346 "req=0x%p cr=%d data=0x%p cb_flags=0x%x", (void *)reqp, 3347 reqp->intr_completion_reason, (void *)reqp->intr_data, 3348 reqp->intr_cb_flags); 3349 3350 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3351 3352 mutex_enter(HUBD_MUTEX(hubd)); 3353 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3354 3355 switch (reqp->intr_completion_reason) { 3356 case USB_CR_PIPE_RESET: 3357 /* only restart polling after autoclearing */ 3358 if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3359 (hubd->h_port_reset_wait == 0)) { 3360 hubd_start_polling(hubd, 0); 3361 } 3362 3363 break; 3364 case USB_CR_DEV_NOT_RESP: 3365 case USB_CR_STOPPED_POLLING: 3366 case USB_CR_PIPE_CLOSING: 3367 case USB_CR_UNSPECIFIED_ERR: 3368 /* never restart polling on these conditions */ 3369 default: 3370 /* for all others, wait for the autoclearing PIPE_RESET cb */ 3371 3372 break; 3373 } 3374 3375 usb_free_intr_req(reqp); 3376 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3377 mutex_exit(HUBD_MUTEX(hubd)); 3378 } 3379 3380 3381 /* 3382 * helper function to convert LE bytes to a portmask 3383 */ 3384 static usb_port_mask_t 3385 hubd_mblk2portmask(mblk_t *data) 3386 { 3387 int len = min(MBLKL(data), sizeof (usb_port_mask_t)); 3388 usb_port_mask_t rval = 0; 3389 int i; 3390 3391 for (i = 0; i < len; i++) { 3392 rval |= data->b_rptr[i] << (i * 8); 3393 } 3394 3395 return (rval); 3396 } 3397 3398 3399 /* 3400 * hubd_read_cb: 3401 * interrupt ep1 callback function 3402 * 3403 * the status indicates just a change on the pipe with no indication 3404 * of what the change was 3405 * 3406 * known conditions: 3407 * - reset port completion 3408 * - connect 3409 * - disconnect 3410 * 3411 * for handling the hotplugging, create a new thread that can do 3412 * synchronous usba calls 3413 */ 3414 static void 3415 hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3416 { 3417 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3418 size_t length; 3419 mblk_t *data = reqp->intr_data; 3420 int mem_flag = 0; 3421 hubd_hotplug_arg_t *arg; 3422 3423 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3424 "hubd_read_cb: ph=0x%p req=0x%p", (void *)pipe, (void *)reqp); 3425 3426 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3427 3428 /* 3429 * At present, we are not handling notification for completion of 3430 * asynchronous pipe reset, for which this data ptr could be NULL 3431 */ 3432 3433 if (data == NULL) { 3434 usb_free_intr_req(reqp); 3435 3436 return; 3437 } 3438 3439 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3440 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3441 mem_flag = 1; 3442 3443 mutex_enter(HUBD_MUTEX(hubd)); 3444 3445 if ((hubd->h_dev_state == USB_DEV_SUSPENDED) || 3446 (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) { 3447 mutex_exit(HUBD_MUTEX(hubd)); 3448 usb_free_intr_req(reqp); 3449 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3450 3451 return; 3452 } 3453 3454 ASSERT(hubd->h_ep1_ph == pipe); 3455 3456 length = MBLKL(data); 3457 3458 /* 3459 * Only look at the data and startup the hotplug thread if 3460 * there actually is data. 3461 */ 3462 if (length != 0) { 3463 usb_port_mask_t port_change = hubd_mblk2portmask(data); 3464 3465 /* 3466 * if a port change was already reported and we are waiting for 3467 * reset port completion then wake up the hotplug thread which 3468 * should be waiting on reset port completion 3469 * 3470 * if there is disconnect event instead of reset completion, let 3471 * the hotplug thread figure this out 3472 */ 3473 3474 /* remove the reset wait bits from the status */ 3475 hubd->h_port_change |= port_change & 3476 ~hubd->h_port_reset_wait; 3477 3478 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3479 "port change=0x%x port_reset_wait=0x%x", 3480 hubd->h_port_change, hubd->h_port_reset_wait); 3481 3482 /* there should be only one reset bit active at the time */ 3483 if (hubd->h_port_reset_wait & port_change) { 3484 hubd->h_port_reset_wait = 0; 3485 cv_signal(&hubd->h_cv_reset_port); 3486 } 3487 3488 /* 3489 * kick off the thread only if device is ONLINE and it is not 3490 * during attaching or detaching 3491 */ 3492 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 3493 (!DEVI_IS_ATTACHING(hubd->h_dip)) && 3494 (!DEVI_IS_DETACHING(hubd->h_dip)) && 3495 (hubd->h_port_change) && 3496 (hubd->h_hotplug_thread == 0)) { 3497 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3498 "creating hotplug thread: " 3499 "dev_state=%d", hubd->h_dev_state); 3500 3501 /* 3502 * Mark this device as busy. The will be marked idle 3503 * if the async req fails or at the exit of hotplug 3504 * thread 3505 */ 3506 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3507 3508 arg->hubd = hubd; 3509 arg->hotplug_during_attach = B_FALSE; 3510 3511 if (usb_async_req(hubd->h_dip, 3512 hubd_hotplug_thread, 3513 (void *)arg, 0) == USB_SUCCESS) { 3514 hubd->h_hotplug_thread++; 3515 mem_flag = 0; 3516 } else { 3517 /* mark this device as idle */ 3518 (void) hubd_pm_idle_component(hubd, 3519 hubd->h_dip, 0); 3520 } 3521 } 3522 } 3523 mutex_exit(HUBD_MUTEX(hubd)); 3524 3525 if (mem_flag == 1) { 3526 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3527 } 3528 3529 usb_free_intr_req(reqp); 3530 } 3531 3532 3533 /* 3534 * hubd_hotplug_thread: 3535 * handles resetting of port, and creating children 3536 * 3537 * the ports to check are indicated in h_port_change bit mask 3538 * XXX note that one time poll doesn't work on the root hub 3539 */ 3540 static void 3541 hubd_hotplug_thread(void *arg) 3542 { 3543 hubd_hotplug_arg_t *hd_arg = (hubd_hotplug_arg_t *)arg; 3544 hubd_t *hubd = hd_arg->hubd; 3545 boolean_t attach_flg = hd_arg->hotplug_during_attach; 3546 usb_port_t port; 3547 uint16_t nports; 3548 uint16_t status, change; 3549 hub_power_t *hubpm; 3550 dev_info_t *hdip = hubd->h_dip; 3551 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 3552 dev_info_t *child_dip; 3553 boolean_t online_child = B_FALSE; 3554 boolean_t offline_child = B_FALSE; 3555 boolean_t pwrup_child = B_FALSE; 3556 int prh_circ, rh_circ, chld_circ, circ, old_state; 3557 3558 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3559 "hubd_hotplug_thread: started"); 3560 3561 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3562 3563 /* 3564 * if our bus power entry point is active, process the change 3565 * on the next notification of interrupt pipe 3566 */ 3567 mutex_enter(HUBD_MUTEX(hubd)); 3568 if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) { 3569