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