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