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