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