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