1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 24 */ 25 26 /* 27 * USBA: Solaris USB Architecture support for the hub 28 * including root hub 29 * Most of the code for hubd resides in this file and 30 * is shared between the HCD root hub support and hubd 31 */ 32 #define USBA_FRAMEWORK 33 #include <sys/usb/usba.h> 34 #include <sys/usb/usba/usba_devdb.h> 35 #include <sys/sunndi.h> 36 #include <sys/usb/usba/usba_impl.h> 37 #include <sys/usb/usba/usba_types.h> 38 #include <sys/usb/usba/hubdi.h> 39 #include <sys/usb/usba/hcdi_impl.h> 40 #include <sys/usb/hubd/hub.h> 41 #include <sys/usb/hubd/hubdvar.h> 42 #include <sys/usb/hubd/hubd_impl.h> 43 #include <sys/kobj.h> 44 #include <sys/kobj_lex.h> 45 #include <sys/fs/dv_node.h> 46 #include <sys/strsun.h> 47 48 /* 49 * External functions 50 */ 51 extern boolean_t consconfig_console_is_ready(void); 52 53 /* 54 * Prototypes for static functions 55 */ 56 static int usba_hubdi_bus_ctl( 57 dev_info_t *dip, 58 dev_info_t *rdip, 59 ddi_ctl_enum_t op, 60 void *arg, 61 void *result); 62 63 static int usba_hubdi_map_fault( 64 dev_info_t *dip, 65 dev_info_t *rdip, 66 struct hat *hat, 67 struct seg *seg, 68 caddr_t addr, 69 struct devpage *dp, 70 pfn_t pfn, 71 uint_t prot, 72 uint_t lock); 73 74 static int hubd_busop_get_eventcookie(dev_info_t *dip, 75 dev_info_t *rdip, 76 char *eventname, 77 ddi_eventcookie_t *cookie); 78 static int hubd_busop_add_eventcall(dev_info_t *dip, 79 dev_info_t *rdip, 80 ddi_eventcookie_t cookie, 81 void (*callback)(dev_info_t *dip, 82 ddi_eventcookie_t cookie, void *arg, 83 void *bus_impldata), 84 void *arg, ddi_callback_id_t *cb_id); 85 static int hubd_busop_remove_eventcall(dev_info_t *dip, 86 ddi_callback_id_t cb_id); 87 static int hubd_bus_config(dev_info_t *dip, 88 uint_t flag, 89 ddi_bus_config_op_t op, 90 void *arg, 91 dev_info_t **child); 92 static int hubd_bus_unconfig(dev_info_t *dip, 93 uint_t flag, 94 ddi_bus_config_op_t op, 95 void *arg); 96 static int hubd_bus_power(dev_info_t *dip, void *impl_arg, 97 pm_bus_power_op_t op, void *arg, void *result); 98 99 static usb_port_t hubd_get_port_num(hubd_t *, struct devctl_iocdata *); 100 static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t); 101 static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t); 102 static int hubd_toggle_port(hubd_t *, usb_port_t); 103 static void hubd_register_cpr_callback(hubd_t *); 104 static void hubd_unregister_cpr_callback(hubd_t *); 105 106 /* 107 * Busops vector for USB HUB's 108 */ 109 struct bus_ops usba_hubdi_busops = { 110 BUSO_REV, 111 nullbusmap, /* bus_map */ 112 NULL, /* bus_get_intrspec */ 113 NULL, /* bus_add_intrspec */ 114 NULL, /* bus_remove_intrspec */ 115 usba_hubdi_map_fault, /* bus_map_fault */ 116 NULL, /* bus_dma_map */ 117 ddi_dma_allochdl, 118 ddi_dma_freehdl, 119 ddi_dma_bindhdl, 120 ddi_dma_unbindhdl, 121 ddi_dma_flush, 122 ddi_dma_win, 123 ddi_dma_mctl, /* bus_dma_ctl */ 124 usba_hubdi_bus_ctl, /* bus_ctl */ 125 ddi_bus_prop_op, /* bus_prop_op */ 126 hubd_busop_get_eventcookie, 127 hubd_busop_add_eventcall, 128 hubd_busop_remove_eventcall, 129 NULL, /* bus_post_event */ 130 NULL, /* bus_intr_ctl */ 131 hubd_bus_config, /* bus_config */ 132 hubd_bus_unconfig, /* bus_unconfig */ 133 NULL, /* bus_fm_init */ 134 NULL, /* bus_fm_fini */ 135 NULL, /* bus_fm_access_enter */ 136 NULL, /* bus_fm_access_exit */ 137 hubd_bus_power /* bus_power */ 138 }; 139 140 #define USB_HUB_INTEL_VID 0x8087 141 #define USB_HUB_INTEL_PID 0x0020 142 143 /* 144 * local variables 145 */ 146 static kmutex_t usba_hubdi_mutex; /* protects USBA HUB data structures */ 147 148 static usba_list_entry_t usba_hubdi_list; 149 150 usb_log_handle_t hubdi_log_handle; 151 uint_t hubdi_errlevel = USB_LOG_L4; 152 uint_t hubdi_errmask = (uint_t)-1; 153 uint8_t hubdi_min_pm_threshold = 5; /* seconds */ 154 uint8_t hubdi_reset_delay = 20; /* seconds */ 155 extern int modrootloaded; 156 157 /* 158 * initialize private data 159 */ 160 void 161 usba_hubdi_initialization() 162 { 163 hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel, 164 &hubdi_errmask, NULL, 0); 165 166 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 167 "usba_hubdi_initialization"); 168 169 mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL); 170 171 usba_init_list(&usba_hubdi_list, NULL, NULL); 172 } 173 174 175 void 176 usba_hubdi_destroy() 177 { 178 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 179 "usba_hubdi_destroy"); 180 181 mutex_destroy(&usba_hubdi_mutex); 182 usba_destroy_list(&usba_hubdi_list); 183 184 usb_free_log_hdl(hubdi_log_handle); 185 } 186 187 188 /* 189 * Called by an HUB to attach an instance of the driver 190 * make this instance known to USBA 191 * the HUB should initialize usba_hubdi structure prior 192 * to calling this interface 193 */ 194 int 195 usba_hubdi_register(dev_info_t *dip, 196 uint_t flags) 197 { 198 usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP); 199 usba_device_t *usba_device = usba_get_usba_device(dip); 200 201 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 202 "usba_hubdi_register: %s", ddi_node_name(dip)); 203 204 hubdi->hubdi_dip = dip; 205 hubdi->hubdi_flags = flags; 206 207 usba_device->usb_hubdi = hubdi; 208 209 /* 210 * add this hubdi instance to the list of known hubdi's 211 */ 212 usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi, 213 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 214 hcdi_iblock_cookie); 215 mutex_enter(&usba_hubdi_mutex); 216 usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list); 217 mutex_exit(&usba_hubdi_mutex); 218 219 return (DDI_SUCCESS); 220 } 221 222 223 /* 224 * Called by an HUB to detach an instance of the driver 225 */ 226 int 227 usba_hubdi_unregister(dev_info_t *dip) 228 { 229 usba_device_t *usba_device = usba_get_usba_device(dip); 230 usba_hubdi_t *hubdi = usba_device->usb_hubdi; 231 232 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle, 233 "usba_hubdi_unregister: %s", ddi_node_name(dip)); 234 235 mutex_enter(&usba_hubdi_mutex); 236 (void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list); 237 mutex_exit(&usba_hubdi_mutex); 238 239 usba_destroy_list(&hubdi->hubdi_list); 240 241 kmem_free(hubdi, sizeof (usba_hubdi_t)); 242 243 return (DDI_SUCCESS); 244 } 245 246 247 /* 248 * misc bus routines currently not used 249 */ 250 /*ARGSUSED*/ 251 static int 252 usba_hubdi_map_fault(dev_info_t *dip, 253 dev_info_t *rdip, 254 struct hat *hat, 255 struct seg *seg, 256 caddr_t addr, 257 struct devpage *dp, 258 pfn_t pfn, 259 uint_t prot, 260 uint_t lock) 261 { 262 return (DDI_FAILURE); 263 } 264 265 266 /* 267 * root hub support. the root hub uses the same devi as the HCD 268 */ 269 int 270 usba_hubdi_bind_root_hub(dev_info_t *dip, 271 uchar_t *root_hub_config_descriptor, 272 size_t config_length, 273 usb_dev_descr_t *root_hub_device_descriptor) 274 { 275 usba_device_t *usba_device; 276 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip); 277 hubd_t *root_hubd; 278 usb_pipe_handle_t ph = NULL; 279 dev_info_t *child = ddi_get_child(dip); 280 281 if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 282 "root-hub") != NDI_SUCCESS) { 283 284 return (USB_FAILURE); 285 } 286 287 usba_add_root_hub(dip); 288 289 root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP); 290 291 /* 292 * create and initialize a usba_device structure 293 */ 294 usba_device = usba_alloc_usba_device(dip); 295 296 mutex_enter(&usba_device->usb_mutex); 297 usba_device->usb_hcdi_ops = hcdi->hcdi_ops; 298 usba_device->usb_cfg = root_hub_config_descriptor; 299 usba_device->usb_cfg_length = config_length; 300 usba_device->usb_dev_descr = root_hub_device_descriptor; 301 usba_device->usb_port = 1; 302 usba_device->usb_addr = ROOT_HUB_ADDR; 303 usba_device->usb_root_hubd = root_hubd; 304 usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *), 305 KM_SLEEP); 306 usba_device->usb_cfg_array_length = sizeof (uchar_t *); 307 308 usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t), 309 KM_SLEEP); 310 usba_device->usb_cfg_array_len_length = sizeof (uint16_t); 311 312 usba_device->usb_cfg_array[0] = root_hub_config_descriptor; 313 usba_device->usb_cfg_array_len[0] = 314 sizeof (root_hub_config_descriptor); 315 316 usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *), 317 KM_SLEEP); 318 usba_device->usb_n_cfgs = 1; 319 usba_device->usb_n_ifs = 1; 320 usba_device->usb_dip = dip; 321 322 usba_device->usb_client_flags = kmem_zalloc( 323 usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 324 325 usba_device->usb_client_attach_list = kmem_zalloc( 326 usba_device->usb_n_ifs * 327 sizeof (*usba_device->usb_client_attach_list), KM_SLEEP); 328 329 usba_device->usb_client_ev_cb_list = kmem_zalloc( 330 usba_device->usb_n_ifs * 331 sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP); 332 333 /* 334 * The bDeviceProtocol field of root hub device specifies, 335 * whether root hub is a High or Full speed usb device. 336 */ 337 if (root_hub_device_descriptor->bDeviceProtocol) { 338 usba_device->usb_port_status = USBA_HIGH_SPEED_DEV; 339 } else { 340 usba_device->usb_port_status = USBA_FULL_SPEED_DEV; 341 } 342 343 mutex_exit(&usba_device->usb_mutex); 344 345 usba_set_usba_device(dip, usba_device); 346 347 /* 348 * For the root hub the default pipe is not yet open 349 */ 350 if (usb_pipe_open(dip, NULL, NULL, 351 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) { 352 goto fail; 353 } 354 355 /* 356 * kill off all OBP children, they may not be fully 357 * enumerated 358 */ 359 while (child) { 360 dev_info_t *next = ddi_get_next_sibling(child); 361 (void) ddi_remove_child(child, 0); 362 child = next; 363 } 364 365 /* 366 * "attach" the root hub driver 367 */ 368 if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) { 369 goto fail; 370 } 371 372 return (USB_SUCCESS); 373 374 fail: 375 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 376 377 usba_rem_root_hub(dip); 378 379 if (ph) { 380 usb_pipe_close(dip, ph, 381 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 382 } 383 384 kmem_free(usba_device->usb_cfg_array, 385 usba_device->usb_cfg_array_length); 386 kmem_free(usba_device->usb_cfg_array_len, 387 usba_device->usb_cfg_array_len_length); 388 389 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 390 391 usba_free_usba_device(usba_device); 392 393 usba_set_usba_device(dip, NULL); 394 if (root_hubd) { 395 kmem_free(root_hubd, sizeof (hubd_t)); 396 } 397 398 return (USB_FAILURE); 399 } 400 401 402 int 403 usba_hubdi_unbind_root_hub(dev_info_t *dip) 404 { 405 usba_device_t *usba_device; 406 407 /* was root hub attached? */ 408 if (!(usba_is_root_hub(dip))) { 409 410 /* return success anyway */ 411 return (USB_SUCCESS); 412 } 413 414 /* 415 * usba_hubdi_detach also closes the default pipe 416 * and removes properties so there is no need to 417 * do it here 418 */ 419 if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) { 420 421 if (DEVI_IS_ATTACHING(dip)) { 422 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 423 "failure to unbind root hub after attach failure"); 424 } 425 426 return (USB_FAILURE); 427 } 428 429 usba_device = usba_get_usba_device(dip); 430 431 kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t)); 432 433 kmem_free(usba_device->usb_cfg_array, 434 usba_device->usb_cfg_array_length); 435 kmem_free(usba_device->usb_cfg_array_len, 436 usba_device->usb_cfg_array_len_length); 437 438 kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *)); 439 440 usba_free_usba_device(usba_device); 441 442 usba_rem_root_hub(dip); 443 444 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub"); 445 446 return (USB_SUCCESS); 447 } 448 449 450 /* 451 * Actual Hub Driver support code: 452 * shared by root hub and non-root hubs 453 */ 454 #include <sys/usb/usba/usbai_version.h> 455 456 /* Debugging support */ 457 uint_t hubd_errlevel = USB_LOG_L4; 458 uint_t hubd_errmask = (uint_t)DPRINT_MASK_ALL; 459 uint_t hubd_instance_debug = (uint_t)-1; 460 static uint_t hubdi_bus_config_debug = 0; 461 462 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel)) 463 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask)) 464 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug)) 465 466 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 467 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 468 469 470 /* 471 * local variables: 472 * 473 * Amount of time to wait between resetting the port and accessing 474 * the device. The value is in microseconds. 475 */ 476 static uint_t hubd_device_delay = 1000000; 477 478 /* 479 * enumeration retry 480 */ 481 #define HUBD_PORT_RETRY 5 482 static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY; 483 484 /* 485 * Stale hotremoved device cleanup delay 486 */ 487 #define HUBD_STALE_DIP_CLEANUP_DELAY 5000000 488 static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY; 489 490 /* 491 * retries for USB suspend and resume 492 */ 493 #define HUBD_SUS_RES_RETRY 2 494 495 void *hubd_statep; 496 497 /* 498 * prototypes 499 */ 500 static int hubd_cleanup(dev_info_t *dip, hubd_t *hubd); 501 static int hubd_check_ports(hubd_t *hubd); 502 503 static int hubd_open_intr_pipe(hubd_t *hubd); 504 static void hubd_start_polling(hubd_t *hubd, int always); 505 static void hubd_stop_polling(hubd_t *hubd); 506 static void hubd_close_intr_pipe(hubd_t *hubd); 507 508 static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req); 509 static void hubd_exception_cb(usb_pipe_handle_t pipe, 510 usb_intr_req_t *req); 511 static void hubd_hotplug_thread(void *arg); 512 static void hubd_reset_thread(void *arg); 513 static int hubd_create_child(dev_info_t *dip, 514 hubd_t *hubd, 515 usba_device_t *usba_device, 516 usb_port_status_t port_status, 517 usb_port_t port, 518 int iteration); 519 520 static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, 521 boolean_t retry); 522 523 static int hubd_get_hub_descriptor(hubd_t *hubd); 524 525 static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status); 526 527 static int hubd_reset_port(hubd_t *hubd, usb_port_t port); 528 529 static int hubd_get_hub_status(hubd_t *hubd); 530 531 static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port); 532 533 static int hubd_disable_port(hubd_t *hubd, usb_port_t port); 534 535 static int hubd_enable_port(hubd_t *hubd, usb_port_t port); 536 static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port); 537 538 static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 539 uint16_t *status, uint16_t *change, uint_t ack_flag); 540 541 static int hubd_enable_all_port_power(hubd_t *hubd); 542 static int hubd_disable_all_port_power(hubd_t *hubd); 543 static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port); 544 static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port); 545 546 static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device); 547 548 static int hubd_can_suspend(hubd_t *hubd); 549 static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd); 550 static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port); 551 static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port); 552 553 static int hubd_register_events(hubd_t *hubd); 554 static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip, 555 ddi_eventcookie_t cookie); 556 static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type); 557 static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type); 558 static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd); 559 560 static int hubd_disconnect_event_cb(dev_info_t *dip); 561 static int hubd_reconnect_event_cb(dev_info_t *dip); 562 static int hubd_pre_suspend_event_cb(dev_info_t *dip); 563 static int hubd_post_resume_event_cb(dev_info_t *dip); 564 static int hubd_cpr_suspend(hubd_t *hubd); 565 static void hubd_cpr_resume(dev_info_t *dip); 566 static int hubd_restore_state_cb(dev_info_t *dip); 567 static int hubd_check_same_device(hubd_t *hubd, usb_port_t port); 568 569 static int hubd_init_power_budget(hubd_t *hubd); 570 571 static ndi_event_definition_t hubd_ndi_event_defs[] = { 572 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 573 NDI_EVENT_POST_TO_ALL}, 574 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 575 NDI_EVENT_POST_TO_ALL}, 576 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 577 NDI_EVENT_POST_TO_ALL}, 578 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 579 NDI_EVENT_POST_TO_ALL} 580 }; 581 582 #define HUBD_N_NDI_EVENTS \ 583 (sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t)) 584 585 static ndi_event_set_t hubd_ndi_events = { 586 NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs}; 587 588 /* events received from parent */ 589 static usb_event_t hubd_events = { 590 hubd_disconnect_event_cb, 591 hubd_reconnect_event_cb, 592 hubd_pre_suspend_event_cb, 593 hubd_post_resume_event_cb 594 }; 595 596 597 /* 598 * hubd_get_soft_state() returns the hubd soft state 599 * 600 * WUSB support extends this function to support wire adapter class 601 * devices. The hubd soft state for the wire adapter class device 602 * would be stored in usb_root_hubd field of the usba_device structure, 603 * just as the USB host controller drivers do. 604 */ 605 hubd_t * 606 hubd_get_soft_state(dev_info_t *dip) 607 { 608 if (dip == NULL) { 609 610 return (NULL); 611 } 612 613 if (usba_is_root_hub(dip) || usba_is_wa(dip)) { 614 usba_device_t *usba_device = usba_get_usba_device(dip); 615 616 return (usba_device->usb_root_hubd); 617 } else { 618 int instance = ddi_get_instance(dip); 619 620 return (ddi_get_soft_state(hubd_statep, instance)); 621 } 622 } 623 624 625 /* 626 * PM support functions: 627 */ 628 /*ARGSUSED*/ 629 static void 630 hubd_pm_busy_component(hubd_t *hubd, dev_info_t *dip, int component) 631 { 632 if (hubd->h_hubpm != NULL) { 633 hubd->h_hubpm->hubp_busy_pm++; 634 mutex_exit(HUBD_MUTEX(hubd)); 635 if (pm_busy_component(dip, 0) != DDI_SUCCESS) { 636 mutex_enter(HUBD_MUTEX(hubd)); 637 hubd->h_hubpm->hubp_busy_pm--; 638 mutex_exit(HUBD_MUTEX(hubd)); 639 } 640 mutex_enter(HUBD_MUTEX(hubd)); 641 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 642 "hubd_pm_busy_component: %d", hubd->h_hubpm->hubp_busy_pm); 643 } 644 } 645 646 647 /*ARGSUSED*/ 648 static void 649 hubd_pm_idle_component(hubd_t *hubd, dev_info_t *dip, int component) 650 { 651 if (hubd->h_hubpm != NULL) { 652 mutex_exit(HUBD_MUTEX(hubd)); 653 if (pm_idle_component(dip, 0) == DDI_SUCCESS) { 654 mutex_enter(HUBD_MUTEX(hubd)); 655 ASSERT(hubd->h_hubpm->hubp_busy_pm > 0); 656 hubd->h_hubpm->hubp_busy_pm--; 657 mutex_exit(HUBD_MUTEX(hubd)); 658 } 659 mutex_enter(HUBD_MUTEX(hubd)); 660 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 661 "hubd_pm_idle_component: %d", hubd->h_hubpm->hubp_busy_pm); 662 } 663 } 664 665 666 /* 667 * track power level changes for children of this instance 668 */ 669 static void 670 hubd_set_child_pwrlvl(hubd_t *hubd, usb_port_t port, uint8_t power) 671 { 672 int old_power, new_power, pwr; 673 usb_port_t portno; 674 hub_power_t *hubpm; 675 676 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 677 "hubd_set_child_pwrlvl: port=%d power=%d", 678 port, power); 679 680 mutex_enter(HUBD_MUTEX(hubd)); 681 hubpm = hubd->h_hubpm; 682 683 old_power = 0; 684 for (portno = 1; portno <= hubd->h_hub_descr.bNbrPorts; portno++) { 685 old_power += hubpm->hubp_child_pwrstate[portno]; 686 } 687 688 /* assign the port power */ 689 pwr = hubd->h_hubpm->hubp_child_pwrstate[port]; 690 hubd->h_hubpm->hubp_child_pwrstate[port] = power; 691 new_power = old_power - pwr + power; 692 693 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 694 "hubd_set_child_pwrlvl: new_power=%d old_power=%d", 695 new_power, old_power); 696 697 if ((new_power > 0) && (old_power == 0)) { 698 /* we have the first child coming out of low power */ 699 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 700 } else if ((new_power == 0) && (old_power > 0)) { 701 /* we have the last child going to low power */ 702 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 703 } 704 mutex_exit(HUBD_MUTEX(hubd)); 705 } 706 707 708 /* 709 * given a child dip, locate its port number 710 */ 711 static usb_port_t 712 hubd_child_dip2port(hubd_t *hubd, dev_info_t *dip) 713 { 714 usb_port_t port; 715 716 mutex_enter(HUBD_MUTEX(hubd)); 717 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 718 if (hubd->h_children_dips[port] == dip) { 719 720 break; 721 } 722 } 723 ASSERT(port <= hubd->h_hub_descr.bNbrPorts); 724 mutex_exit(HUBD_MUTEX(hubd)); 725 726 return (port); 727 } 728 729 730 /* 731 * if the hub can be put into low power mode, return success 732 * NOTE: suspend here means going to lower power, not CPR suspend. 733 */ 734 static int 735 hubd_can_suspend(hubd_t *hubd) 736 { 737 hub_power_t *hubpm; 738 int total_power = 0; 739 usb_port_t port; 740 741 hubpm = hubd->h_hubpm; 742 743 if (DEVI_IS_DETACHING(hubd->h_dip)) { 744 745 return (USB_SUCCESS); 746 } 747 748 /* 749 * Don't go to lower power if haven't been at full power for enough 750 * time to let hotplug thread kickoff. 751 */ 752 if (ddi_get_time() < (hubpm->hubp_time_at_full_power + 753 hubpm->hubp_min_pm_threshold)) { 754 755 return (USB_FAILURE); 756 } 757 758 for (port = 1; (total_power == 0) && 759 (port <= hubd->h_hub_descr.bNbrPorts); port++) { 760 total_power += hubpm->hubp_child_pwrstate[port]; 761 } 762 763 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 764 "hubd_can_suspend: %d", total_power); 765 766 return (total_power ? USB_FAILURE : USB_SUCCESS); 767 } 768 769 770 /* 771 * resume port depending on current device state 772 */ 773 static int 774 hubd_resume_port(hubd_t *hubd, usb_port_t port) 775 { 776 int rval, retry; 777 usb_cr_t completion_reason; 778 usb_cb_flags_t cb_flags; 779 uint16_t status; 780 uint16_t change; 781 int retval = USB_FAILURE; 782 783 mutex_enter(HUBD_MUTEX(hubd)); 784 785 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 786 "hubd_resume_port: port=%d state=0x%x (%s)", port, 787 hubd->h_dev_state, usb_str_dev_state(hubd->h_dev_state)); 788 789 switch (hubd->h_dev_state) { 790 case USB_DEV_HUB_CHILD_PWRLVL: 791 /* 792 * This could be a bus ctl for a port other than the one 793 * that has a remote wakeup condition. So check. 794 */ 795 if ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0) { 796 /* the port isn't suspended, so don't resume */ 797 retval = USB_SUCCESS; 798 799 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 800 "hubd_resume_port: port=%d not suspended", port); 801 802 break; 803 } 804 /* 805 * Device has initiated a wakeup. 806 * Issue a ClearFeature(PortSuspend) 807 */ 808 mutex_exit(HUBD_MUTEX(hubd)); 809 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 810 hubd->h_default_pipe, 811 HUB_HANDLE_PORT_FEATURE_TYPE, 812 USB_REQ_CLEAR_FEATURE, 813 CFS_PORT_SUSPEND, 814 port, 815 0, NULL, 0, 816 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 817 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 818 "ClearFeature(PortSuspend) fails " 819 "rval=%d cr=%d cb=0x%x", rval, 820 completion_reason, cb_flags); 821 } 822 mutex_enter(HUBD_MUTEX(hubd)); 823 824 /* either way ack changes on the port */ 825 (void) hubd_determine_port_status(hubd, port, 826 &status, &change, PORT_CHANGE_PSSC); 827 retval = USB_SUCCESS; 828 829 break; 830 case USB_DEV_HUB_STATE_RECOVER: 831 /* 832 * When hubd's connect event callback posts a connect 833 * event to its child, it results in this busctl call 834 * which is valid 835 */ 836 /* FALLTHRU */ 837 case USB_DEV_ONLINE: 838 if (((hubd->h_port_state[port] & PORT_STATUS_CCS) == 0) || 839 ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0)) { 840 /* 841 * the port isn't suspended, or connected 842 * so don't resume 843 */ 844 retval = USB_SUCCESS; 845 846 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 847 "hubd_resume_port: port=%d not suspended", port); 848 849 break; 850 } 851 /* 852 * prevent kicking off the hotplug thread 853 */ 854 hubd->h_hotplug_thread++; 855 hubd_stop_polling(hubd); 856 857 /* Now ClearFeature(PortSuspend) */ 858 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) { 859 mutex_exit(HUBD_MUTEX(hubd)); 860 rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 861 hubd->h_default_pipe, 862 HUB_HANDLE_PORT_FEATURE_TYPE, 863 USB_REQ_CLEAR_FEATURE, 864 CFS_PORT_SUSPEND, 865 port, 866 0, NULL, 0, 867 &completion_reason, &cb_flags, 0); 868 mutex_enter(HUBD_MUTEX(hubd)); 869 if (rval != USB_SUCCESS) { 870 USB_DPRINTF_L2(DPRINT_MASK_PM, 871 hubd->h_log_handle, 872 "ClearFeature(PortSuspend) fails" 873 "rval=%d cr=%d cb=0x%x", rval, 874 completion_reason, cb_flags); 875 } else { 876 /* 877 * As per spec section 11.9 and 7.1.7.7 878 * hub need to provide at least 20ms of 879 * resume signalling, and s/w provide 10ms of 880 * recovery time before accessing the port. 881 */ 882 mutex_exit(HUBD_MUTEX(hubd)); 883 delay(drv_usectohz(40000)); 884 mutex_enter(HUBD_MUTEX(hubd)); 885 (void) hubd_determine_port_status(hubd, port, 886 &status, &change, PORT_CHANGE_PSSC); 887 888 if ((status & PORT_STATUS_PSS) == 0) { 889 /* the port did finally resume */ 890 retval = USB_SUCCESS; 891 892 break; 893 } 894 } 895 } 896 897 /* allow hotplug thread again */ 898 hubd->h_hotplug_thread--; 899 hubd_start_polling(hubd, 0); 900 901 break; 902 case USB_DEV_DISCONNECTED: 903 /* Ignore - NO Operation */ 904 retval = USB_SUCCESS; 905 906 break; 907 case USB_DEV_SUSPENDED: 908 case USB_DEV_PWRED_DOWN: 909 default: 910 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 911 "Improper state for port Resume"); 912 913 break; 914 } 915 mutex_exit(HUBD_MUTEX(hubd)); 916 917 return (retval); 918 } 919 920 921 /* 922 * suspend port depending on device state 923 */ 924 static int 925 hubd_suspend_port(hubd_t *hubd, usb_port_t port) 926 { 927 int rval, retry; 928 int retval = USB_FAILURE; 929 usb_cr_t completion_reason; 930 usb_cb_flags_t cb_flags; 931 uint16_t status; 932 uint16_t change; 933 934 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 935 "hubd_suspend_port: port=%d", port); 936 937 mutex_enter(HUBD_MUTEX(hubd)); 938 939 switch (hubd->h_dev_state) { 940 case USB_DEV_HUB_STATE_RECOVER: 941 /* 942 * When hubd's connect event callback posts a connect 943 * event to its child, it results in this busctl call 944 * which is valid 945 */ 946 /* FALLTHRU */ 947 case USB_DEV_HUB_CHILD_PWRLVL: 948 /* 949 * When one child is resuming, the other could timeout 950 * and go to low power mode, which is valid 951 */ 952 /* FALLTHRU */ 953 case USB_DEV_ONLINE: 954 hubd->h_hotplug_thread++; 955 hubd_stop_polling(hubd); 956 957 /* 958 * Some devices start an unprovoked resume. According to spec, 959 * normal resume time for port is 10ms. Wait for double that 960 * time, then check to be sure port is really suspended. 961 */ 962 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) { 963 /* Now SetFeature(PortSuspend) */ 964 mutex_exit(HUBD_MUTEX(hubd)); 965 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 966 hubd->h_default_pipe, 967 HUB_HANDLE_PORT_FEATURE_TYPE, 968 USB_REQ_SET_FEATURE, 969 CFS_PORT_SUSPEND, 970 port, 971 0, NULL, 0, 972 &completion_reason, &cb_flags, 0)) != 973 USB_SUCCESS) { 974 USB_DPRINTF_L2(DPRINT_MASK_PM, 975 hubd->h_log_handle, 976 "SetFeature(PortSuspend) fails" 977 "rval=%d cr=%d cb=0x%x", 978 rval, completion_reason, cb_flags); 979 } 980 981 /* 982 * some devices start an unprovoked resume 983 * wait and check port status after some time 984 */ 985 delay(drv_usectohz(20000)); 986 987 /* either ways ack changes on the port */ 988 mutex_enter(HUBD_MUTEX(hubd)); 989 (void) hubd_determine_port_status(hubd, port, 990 &status, &change, PORT_CHANGE_PSSC); 991 if (status & PORT_STATUS_PSS) { 992 /* the port is indeed suspended */ 993 retval = USB_SUCCESS; 994 995 break; 996 } else { 997 USB_DPRINTF_L0(DPRINT_MASK_PM, 998 hubd->h_log_handle, 999 "hubdi: port%d failed to be suspended!", 1000 port); 1001 } 1002 } 1003 1004 hubd->h_hotplug_thread--; 1005 hubd_start_polling(hubd, 0); 1006 1007 break; 1008 1009 case USB_DEV_DISCONNECTED: 1010 /* Ignore - No Operation */ 1011 retval = USB_SUCCESS; 1012 1013 break; 1014 1015 case USB_DEV_SUSPENDED: 1016 case USB_DEV_PWRED_DOWN: 1017 default: 1018 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1019 "Improper state for port Suspend"); 1020 1021 break; 1022 } 1023 mutex_exit(HUBD_MUTEX(hubd)); 1024 1025 return (retval); 1026 } 1027 1028 1029 /* 1030 * child post attach/detach notifications 1031 */ 1032 static void 1033 hubd_post_attach(hubd_t *hubd, usb_port_t port, struct attachspec *as) 1034 { 1035 dev_info_t *dip; 1036 1037 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 1038 "hubd_post_attach: port=%d result=%d", 1039 port, as->result); 1040 1041 if (as->result == DDI_SUCCESS) { 1042 /* 1043 * Check if the child created wants to be power managed. 1044 * If yes, the childs power level gets automatically tracked 1045 * by DDI_CTLOPS_POWER busctl. 1046 * If no, we set power of the new child by default 1047 * to USB_DEV_OS_FULL_PWR. Because we should never suspend. 1048 */ 1049 mutex_enter(HUBD_MUTEX(hubd)); 1050 dip = hubd->h_children_dips[port]; 1051 mutex_exit(HUBD_MUTEX(hubd)); 1052 if (DEVI(dip)->devi_pm_info == NULL) { 1053 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_FULL_PWR); 1054 } 1055 } 1056 } 1057 1058 1059 static void 1060 hubd_post_detach(hubd_t *hubd, usb_port_t port, struct detachspec *ds) 1061 { 1062 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 1063 "hubd_post_detach: port=%d result=%d", port, ds->result); 1064 1065 /* 1066 * if the device is successfully detached and is the 1067 * last device to detach, mark component as idle 1068 */ 1069 mutex_enter(HUBD_MUTEX(hubd)); 1070 if (ds->result == DDI_SUCCESS) { 1071 usba_device_t *usba_device = hubd->h_usba_devices[port]; 1072 dev_info_t *pdip = hubd->h_dip; 1073 mutex_exit(HUBD_MUTEX(hubd)); 1074 1075 usba_hubdi_incr_power_budget(pdip, usba_device); 1076 1077 /* 1078 * We set power of the detached child 1079 * to 0, so that we can suspend if all 1080 * our children are gone 1081 */ 1082 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_PWR_OFF); 1083 1084 /* check for leaks on detaching */ 1085 if ((usba_device) && (ds->cmd == DDI_DETACH)) { 1086 usba_check_for_leaks(usba_device); 1087 } 1088 } else { 1089 mutex_exit(HUBD_MUTEX(hubd)); 1090 } 1091 } 1092 1093 1094 /* 1095 * hubd_post_power 1096 * After the child's power entry point has been called 1097 * we record its power level in our local struct. 1098 * If the device has powered off, we suspend port 1099 */ 1100 static int 1101 hubd_post_power(hubd_t *hubd, usb_port_t port, pm_bp_child_pwrchg_t *bpc, 1102 int result) 1103 { 1104 int retval = USB_SUCCESS; 1105 1106 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1107 "hubd_post_power: port=%d", port); 1108 1109 if (result == DDI_SUCCESS) { 1110 1111 /* record this power in our local struct */ 1112 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_nlevel); 1113 1114 if (bpc->bpc_nlevel == USB_DEV_OS_PWR_OFF) { 1115 1116 /* now suspend the port */ 1117 retval = hubd_suspend_port(hubd, port); 1118 } else if (bpc->bpc_nlevel == USB_DEV_OS_FULL_PWR) { 1119 1120 /* make sure the port is resumed */ 1121 retval = hubd_resume_port(hubd, port); 1122 } 1123 } else { 1124 1125 /* record old power in our local struct */ 1126 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_olevel); 1127 1128 if (bpc->bpc_olevel == USB_DEV_OS_PWR_OFF) { 1129 1130 /* 1131 * As this device failed to transition from 1132 * power off state, suspend the port again 1133 */ 1134 retval = hubd_suspend_port(hubd, port); 1135 } 1136 } 1137 1138 return (retval); 1139 } 1140 1141 1142 /* 1143 * bus ctl notifications are handled here, the rest goes up to root hub/hcd 1144 */ 1145 static int 1146 usba_hubdi_bus_ctl(dev_info_t *dip, 1147 dev_info_t *rdip, 1148 ddi_ctl_enum_t op, 1149 void *arg, 1150 void *result) 1151 { 1152 usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 1153 dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 1154 struct attachspec *as; 1155 struct detachspec *ds; 1156 hubd_t *hubd; 1157 usb_port_t port; 1158 int circ, rval; 1159 int retval = DDI_FAILURE; 1160 1161 hubd = hubd_get_soft_state(dip); 1162 1163 mutex_enter(HUBD_MUTEX(hubd)); 1164 1165 /* flag that we are currently running bus_ctl */ 1166 hubd->h_bus_ctls++; 1167 mutex_exit(HUBD_MUTEX(hubd)); 1168 1169 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1170 "usba_hubdi_bus_ctl:\n\t" 1171 "dip=0x%p, rdip=0x%p, op=0x%x, arg=0x%p", 1172 (void *)dip, (void *)rdip, op, arg); 1173 1174 switch (op) { 1175 case DDI_CTLOPS_ATTACH: 1176 as = (struct attachspec *)arg; 1177 port = hubd_child_dip2port(hubd, rdip); 1178 1179 /* there is nothing to do at resume time */ 1180 if (as->cmd == DDI_RESUME) { 1181 break; 1182 } 1183 1184 /* serialize access */ 1185 ndi_devi_enter(hubd->h_dip, &circ); 1186 1187 switch (as->when) { 1188 case DDI_PRE: 1189 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1190 "DDI_PRE DDI_CTLOPS_ATTACH: dip=%p, port=%d", 1191 (void *)rdip, port); 1192 1193 mutex_enter(HUBD_MUTEX(hubd)); 1194 hubd->h_port_state[port] |= HUBD_CHILD_ATTACHING; 1195 1196 /* Go busy here. Matching idle is DDI_POST case. */ 1197 (void) hubd_pm_busy_component(hubd, dip, 0); 1198 mutex_exit(HUBD_MUTEX(hubd)); 1199 1200 /* 1201 * if we suspended the port previously 1202 * because child went to low power state, and 1203 * someone unloaded the driver, the port would 1204 * still be suspended and needs to be resumed 1205 */ 1206 rval = hubd_resume_port(hubd, port); 1207 if (rval == USB_SUCCESS) { 1208 retval = DDI_SUCCESS; 1209 } 1210 1211 break; 1212 case DDI_POST: 1213 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1214 "DDI_POST DDI_CTLOPS_ATTACH: dip=%p, port=%d", 1215 (void *)rdip, port); 1216 1217 mutex_enter(HUBD_MUTEX(hubd)); 1218 hubd->h_port_state[port] &= ~HUBD_CHILD_ATTACHING; 1219 mutex_exit(HUBD_MUTEX(hubd)); 1220 1221 hubd_post_attach(hubd, port, (struct attachspec *)arg); 1222 retval = DDI_SUCCESS; 1223 mutex_enter(HUBD_MUTEX(hubd)); 1224 1225 /* Matching idle call for DDI_PRE busy call. */ 1226 (void) hubd_pm_idle_component(hubd, dip, 0); 1227 mutex_exit(HUBD_MUTEX(hubd)); 1228 } 1229 ndi_devi_exit(hubd->h_dip, circ); 1230 1231 break; 1232 case DDI_CTLOPS_DETACH: 1233 ds = (struct detachspec *)arg; 1234 port = hubd_child_dip2port(hubd, rdip); 1235 1236 /* there is nothing to do at suspend time */ 1237 if (ds->cmd == DDI_SUSPEND) { 1238 break; 1239 } 1240 1241 /* serialize access */ 1242 ndi_devi_enter(hubd->h_dip, &circ); 1243 1244 switch (ds->when) { 1245 case DDI_PRE: 1246 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1247 "DDI_PRE DDI_CTLOPS_DETACH: dip=%p port=%d", 1248 (void *)rdip, port); 1249 1250 mutex_enter(HUBD_MUTEX(hubd)); 1251 hubd->h_port_state[port] |= HUBD_CHILD_DETACHING; 1252 1253 /* Go busy here. Matching idle is DDI_POST case. */ 1254 (void) hubd_pm_busy_component(hubd, dip, 0); 1255 1256 mutex_exit(HUBD_MUTEX(hubd)); 1257 retval = DDI_SUCCESS; 1258 1259 break; 1260 case DDI_POST: 1261 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1262 "DDI_POST DDI_CTLOPS_DETACH: dip=%p port=%d", 1263 (void *)rdip, port); 1264 1265 mutex_enter(HUBD_MUTEX(hubd)); 1266 hubd->h_port_state[port] &= ~HUBD_CHILD_DETACHING; 1267 mutex_exit(HUBD_MUTEX(hubd)); 1268 1269 /* Matching idle call for DDI_PRE busy call. */ 1270 hubd_post_detach(hubd, port, (struct detachspec *)arg); 1271 retval = DDI_SUCCESS; 1272 mutex_enter(HUBD_MUTEX(hubd)); 1273 (void) hubd_pm_idle_component(hubd, dip, 0); 1274 mutex_exit(HUBD_MUTEX(hubd)); 1275 1276 break; 1277 } 1278 ndi_devi_exit(hubd->h_dip, circ); 1279 1280 break; 1281 default: 1282 retval = usba_bus_ctl(root_hub_dip, rdip, op, arg, result); 1283 } 1284 1285 /* decrement bus_ctls count */ 1286 mutex_enter(HUBD_MUTEX(hubd)); 1287 hubd->h_bus_ctls--; 1288 ASSERT(hubd->h_bus_ctls >= 0); 1289 mutex_exit(HUBD_MUTEX(hubd)); 1290 1291 return (retval); 1292 } 1293 1294 /* 1295 * hubd_config_one: 1296 * enumerate one child according to 'port' 1297 */ 1298 1299 static boolean_t 1300 hubd_config_one(hubd_t *hubd, int port) 1301 { 1302 uint16_t status, change; 1303 dev_info_t *hdip = hubd->h_dip; 1304 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 1305 boolean_t online_child = B_FALSE, found = B_FALSE; 1306 int prh_circ, rh_circ, circ; 1307 1308 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1309 "hubd_config_one: started, hubd_reset_port = 0x%x", port); 1310 1311 ndi_hold_devi(hdip); /* so we don't race with detach */ 1312 1313 /* 1314 * this ensures one config activity per system at a time. 1315 * we enter the parent PCI node to have this serialization. 1316 * this also excludes ioctls and deathrow thread 1317 */ 1318 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 1319 ndi_devi_enter(rh_dip, &rh_circ); 1320 1321 /* exclude other threads */ 1322 ndi_devi_enter(hdip, &circ); 1323 mutex_enter(HUBD_MUTEX(hubd)); 1324 1325 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 1326 1327 if (!hubd->h_children_dips[port]) { 1328 1329 (void) hubd_determine_port_status(hubd, port, 1330 &status, &change, HUBD_ACK_ALL_CHANGES); 1331 1332 if (status & PORT_STATUS_CCS) { 1333 online_child |= (hubd_handle_port_connect(hubd, 1334 port) == USB_SUCCESS); 1335 found = online_child; 1336 } 1337 } else { 1338 found = B_TRUE; 1339 } 1340 1341 mutex_exit(HUBD_MUTEX(hubd)); 1342 1343 ndi_devi_exit(hdip, circ); 1344 ndi_devi_exit(rh_dip, rh_circ); 1345 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 1346 1347 if (online_child) { 1348 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1349 "hubd_config_one: onlining child"); 1350 1351 (void) ndi_devi_online(hubd->h_dip, 0); 1352 } 1353 1354 mutex_enter(HUBD_MUTEX(hubd)); 1355 1356 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 1357 1358 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 1359 "hubd_config_one: exit"); 1360 1361 mutex_exit(HUBD_MUTEX(hubd)); 1362 1363 ndi_rele_devi(hdip); 1364 1365 return (found); 1366 } 1367 1368 /* 1369 * bus enumeration entry points 1370 */ 1371 static int 1372 hubd_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 1373 void *arg, dev_info_t **child) 1374 { 1375 hubd_t *hubd = hubd_get_soft_state(dip); 1376 int rval, circ; 1377 long port; 1378 1379 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1380 "hubd_bus_config: op=%d", op); 1381 1382 if (hubdi_bus_config_debug) { 1383 flag |= NDI_DEVI_DEBUG; 1384 } 1385 1386 if (op == BUS_CONFIG_ONE) { 1387 boolean_t found; 1388 char cname[80]; 1389 char *name, *addr; 1390 1391 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1392 "hubd_bus_config: op=%d (BUS_CONFIG_ONE)", op); 1393 1394 (void) snprintf(cname, 80, "%s", (char *)arg); 1395 /* split name into "name@addr" parts */ 1396 i_ddi_parse_name(cname, &name, &addr, NULL); 1397 if (addr && *addr) { 1398 (void) ddi_strtol(addr, NULL, 16, &port); 1399 } else { 1400 return (NDI_FAILURE); 1401 } 1402 1403 found = hubd_config_one(hubd, port); 1404 1405 if (found == 0) { 1406 return (NDI_FAILURE); 1407 } 1408 1409 } 1410 ndi_devi_enter(hubd->h_dip, &circ); 1411 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 1412 ndi_devi_exit(hubd->h_dip, circ); 1413 1414 return (rval); 1415 } 1416 1417 1418 static int 1419 hubd_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 1420 void *arg) 1421 { 1422 hubd_t *hubd = hubd_get_soft_state(dip); 1423 dev_info_t *cdip; 1424 usb_port_t port; 1425 int circ; 1426 int rval; 1427 1428 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1429 "hubd_bus_unconfig: op=%d", op); 1430 1431 if (hubdi_bus_config_debug) { 1432 flag |= NDI_DEVI_DEBUG; 1433 } 1434 1435 if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) { 1436 flag |= NDI_DEVI_REMOVE; 1437 } 1438 1439 /* serialize access */ 1440 ndi_devi_enter(dip, &circ); 1441 1442 rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 1443 1444 /* logically zap children's list */ 1445 mutex_enter(HUBD_MUTEX(hubd)); 1446 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 1447 hubd->h_port_state[port] |= HUBD_CHILD_ZAP; 1448 } 1449 mutex_exit(HUBD_MUTEX(hubd)); 1450 1451 /* fill in what's left */ 1452 for (cdip = ddi_get_child(dip); cdip; 1453 cdip = ddi_get_next_sibling(cdip)) { 1454 usba_device_t *usba_device = usba_get_usba_device(cdip); 1455 1456 if (usba_device == NULL) { 1457 1458 continue; 1459 } 1460 mutex_enter(HUBD_MUTEX(hubd)); 1461 port = usba_device->usb_port; 1462 hubd->h_children_dips[port] = cdip; 1463 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP; 1464 mutex_exit(HUBD_MUTEX(hubd)); 1465 } 1466 1467 /* physically zap the children we didn't find */ 1468 mutex_enter(HUBD_MUTEX(hubd)); 1469 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 1470 if (hubd->h_port_state[port] & HUBD_CHILD_ZAP) { 1471 /* zap the dip and usba_device structure as well */ 1472 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 1473 hubd->h_children_dips[port] = NULL; 1474 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP; 1475 } 1476 } 1477 mutex_exit(HUBD_MUTEX(hubd)); 1478 1479 ndi_devi_exit(dip, circ); 1480 1481 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 1482 "hubd_bus_unconfig: rval=%d", rval); 1483 1484 return (rval); 1485 } 1486 1487 1488 /* bus_power entry point */ 1489 static int 1490 hubd_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op, 1491 void *arg, void *result) 1492 { 1493 hubd_t *hubd; 1494 int rval, pwrup_res; 1495 usb_port_t port; 1496 int retval = DDI_FAILURE; 1497 pm_bp_child_pwrchg_t *bpc; 1498 pm_bp_nexus_pwrup_t bpn; 1499 1500 hubd = hubd_get_soft_state(dip); 1501 1502 USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1503 "hubd_bus_power: dip=%p, impl_arg=%p, power_op=%d, arg=%p, " 1504 "result=%d\n", (void *)dip, impl_arg, op, arg, *(int *)result); 1505 1506 bpc = (pm_bp_child_pwrchg_t *)arg; 1507 1508 mutex_enter(HUBD_MUTEX(hubd)); 1509 hubd->h_bus_pwr++; 1510 mutex_exit(HUBD_MUTEX(hubd)); 1511 1512 switch (op) { 1513 case BUS_POWER_PRE_NOTIFICATION: 1514 port = hubd_child_dip2port(hubd, bpc->bpc_dip); 1515 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1516 "hubd_bus_power: BUS_POWER_PRE_NOTIFICATION, port=%d", 1517 port); 1518 1519 /* go to full power if we are powered down */ 1520 mutex_enter(HUBD_MUTEX(hubd)); 1521 1522 /* 1523 * If this case completes normally, idle will be in 1524 * hubd_bus_power / BUS_POWER_POST_NOTIFICATION 1525 */ 1526 hubd_pm_busy_component(hubd, dip, 0); 1527 1528 /* 1529 * raise power only if we have created the components 1530 * and are currently in low power 1531 */ 1532 if ((hubd->h_dev_state == USB_DEV_PWRED_DOWN) && 1533 hubd->h_hubpm->hubp_wakeup_enabled) { 1534 mutex_exit(HUBD_MUTEX(hubd)); 1535 1536 bpn.bpn_comp = 0; 1537 bpn.bpn_dip = dip; 1538 bpn.bpn_level = USB_DEV_OS_FULL_PWR; 1539 bpn.bpn_private = bpc->bpc_private; 1540 1541 rval = pm_busop_bus_power(dip, impl_arg, 1542 BUS_POWER_NEXUS_PWRUP, (void *)&bpn, 1543 (void *)&pwrup_res); 1544 1545 if (rval != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) { 1546 mutex_enter(HUBD_MUTEX(hubd)); 1547 hubd_pm_idle_component(hubd, dip, 0); 1548 mutex_exit(HUBD_MUTEX(hubd)); 1549 1550 break; 1551 } 1552 mutex_enter(HUBD_MUTEX(hubd)); 1553 } 1554 1555 /* indicate that child is changing power level */ 1556 hubd->h_port_state[port] |= HUBD_CHILD_PWRLVL_CHNG; 1557 mutex_exit(HUBD_MUTEX(hubd)); 1558 1559 if ((bpc->bpc_olevel == 0) && 1560 (bpc->bpc_nlevel > bpc->bpc_olevel)) { 1561 /* 1562 * this child is transitioning from power off 1563 * to power on state - resume port 1564 */ 1565 rval = hubd_resume_port(hubd, port); 1566 if (rval == USB_SUCCESS) { 1567 retval = DDI_SUCCESS; 1568 } else { 1569 /* reset this flag on failure */ 1570 mutex_enter(HUBD_MUTEX(hubd)); 1571 hubd->h_port_state[port] &= 1572 ~HUBD_CHILD_PWRLVL_CHNG; 1573 hubd_pm_idle_component(hubd, dip, 0); 1574 mutex_exit(HUBD_MUTEX(hubd)); 1575 } 1576 } else { 1577 retval = DDI_SUCCESS; 1578 } 1579 1580 break; 1581 case BUS_POWER_POST_NOTIFICATION: 1582 port = hubd_child_dip2port(hubd, bpc->bpc_dip); 1583 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1584 "hubd_bus_power: BUS_POWER_POST_NOTIFICATION, port=%d", 1585 port); 1586 1587 mutex_enter(HUBD_MUTEX(hubd)); 1588 hubd->h_port_state[port] &= ~HUBD_CHILD_PWRLVL_CHNG; 1589 mutex_exit(HUBD_MUTEX(hubd)); 1590 1591 /* record child's pwr and suspend port if required */ 1592 rval = hubd_post_power(hubd, port, bpc, *(int *)result); 1593 if (rval == USB_SUCCESS) { 1594 1595 retval = DDI_SUCCESS; 1596 } 1597 1598 mutex_enter(HUBD_MUTEX(hubd)); 1599 1600 /* 1601 * Matching idle for the busy in 1602 * hubd_bus_power / BUS_POWER_PRE_NOTIFICATION 1603 */ 1604 hubd_pm_idle_component(hubd, dip, 0); 1605 1606 mutex_exit(HUBD_MUTEX(hubd)); 1607 1608 break; 1609 default: 1610 retval = pm_busop_bus_power(dip, impl_arg, op, arg, result); 1611 1612 break; 1613 } 1614 1615 mutex_enter(HUBD_MUTEX(hubd)); 1616 hubd->h_bus_pwr--; 1617 mutex_exit(HUBD_MUTEX(hubd)); 1618 1619 return (retval); 1620 } 1621 1622 1623 /* 1624 * functions to handle power transition for OS levels 0 -> 3 1625 */ 1626 static int 1627 hubd_pwrlvl0(hubd_t *hubd) 1628 { 1629 hub_power_t *hubpm; 1630 1631 /* We can't power down if hotplug thread is running */ 1632 if (hubd->h_hotplug_thread || hubd->h_hubpm->hubp_busy_pm || 1633 (hubd_can_suspend(hubd) == USB_FAILURE)) { 1634 1635 return (USB_FAILURE); 1636 } 1637 1638 switch (hubd->h_dev_state) { 1639 case USB_DEV_ONLINE: 1640 hubpm = hubd->h_hubpm; 1641 1642 /* 1643 * To avoid race with bus_power pre_notify on check over 1644 * dev_state, we need to correctly set the dev state 1645 * before the mutex is dropped in stop polling. 1646 */ 1647 hubd->h_dev_state = USB_DEV_PWRED_DOWN; 1648 hubpm->hubp_current_power = USB_DEV_OS_PWR_OFF; 1649 1650 /* 1651 * if we are the root hub, do not stop polling 1652 * otherwise, we will never see a resume 1653 */ 1654 if (usba_is_root_hub(hubd->h_dip)) { 1655 /* place holder to implement Global Suspend */ 1656 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1657 "Global Suspend: Not Yet Implemented"); 1658 } else { 1659 hubd_stop_polling(hubd); 1660 } 1661 1662 /* Issue USB D3 command to the device here */ 1663 (void) usb_set_device_pwrlvl3(hubd->h_dip); 1664 1665 break; 1666 case USB_DEV_DISCONNECTED: 1667 case USB_DEV_SUSPENDED: 1668 case USB_DEV_PWRED_DOWN: 1669 default: 1670 1671 break; 1672 } 1673 1674 return (USB_SUCCESS); 1675 } 1676 1677 1678 /* ARGSUSED */ 1679 static int 1680 hubd_pwrlvl1(hubd_t *hubd) 1681 { 1682 /* Issue USB D2 command to the device here */ 1683 (void) usb_set_device_pwrlvl2(hubd->h_dip); 1684 1685 return (USB_FAILURE); 1686 } 1687 1688 1689 /* ARGSUSED */ 1690 static int 1691 hubd_pwrlvl2(hubd_t *hubd) 1692 { 1693 /* Issue USB D1 command to the device here */ 1694 (void) usb_set_device_pwrlvl1(hubd->h_dip); 1695 1696 return (USB_FAILURE); 1697 } 1698 1699 1700 static int 1701 hubd_pwrlvl3(hubd_t *hubd) 1702 { 1703 hub_power_t *hubpm; 1704 int rval; 1705 1706 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3"); 1707 1708 hubpm = hubd->h_hubpm; 1709 switch (hubd->h_dev_state) { 1710 case USB_DEV_PWRED_DOWN: 1711 ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF); 1712 if (usba_is_root_hub(hubd->h_dip)) { 1713 /* implement global resume here */ 1714 USB_DPRINTF_L2(DPRINT_MASK_PM, 1715 hubd->h_log_handle, 1716 "Global Resume: Not Yet Implemented"); 1717 } 1718 /* Issue USB D0 command to the device here */ 1719 rval = usb_set_device_pwrlvl0(hubd->h_dip); 1720 ASSERT(rval == USB_SUCCESS); 1721 hubd->h_dev_state = USB_DEV_ONLINE; 1722 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 1723 hubpm->hubp_time_at_full_power = ddi_get_time(); 1724 hubd_start_polling(hubd, 0); 1725 1726 /* FALLTHRU */ 1727 case USB_DEV_ONLINE: 1728 /* we are already in full power */ 1729 1730 /* FALLTHRU */ 1731 case USB_DEV_DISCONNECTED: 1732 case USB_DEV_SUSPENDED: 1733 /* 1734 * PM framework tries to put you in full power 1735 * during system shutdown. If we are disconnected 1736 * return success. Also, we should not change state 1737 * when we are disconnected or suspended or about to 1738 * transition to that state 1739 */ 1740 1741 return (USB_SUCCESS); 1742 default: 1743 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 1744 "hubd_pwrlvl3: Illegal dev_state=%d", hubd->h_dev_state); 1745 1746 return (USB_FAILURE); 1747 } 1748 } 1749 1750 1751 /* power entry point */ 1752 /* ARGSUSED */ 1753 int 1754 usba_hubdi_power(dev_info_t *dip, int comp, int level) 1755 { 1756 hubd_t *hubd; 1757 hub_power_t *hubpm; 1758 int retval; 1759 int circ; 1760 1761 hubd = hubd_get_soft_state(dip); 1762 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1763 "usba_hubdi_power: level=%d", level); 1764 1765 ndi_devi_enter(dip, &circ); 1766 1767 mutex_enter(HUBD_MUTEX(hubd)); 1768 hubpm = hubd->h_hubpm; 1769 1770 /* check if we are transitioning to a legal power level */ 1771 if (USB_DEV_PWRSTATE_OK(hubpm->hubp_pwr_states, level)) { 1772 USB_DPRINTF_L2(DPRINT_MASK_HUBDI, hubd->h_log_handle, 1773 "usba_hubdi_power: illegal power level=%d " 1774 "hubp_pwr_states=0x%x", level, hubpm->hubp_pwr_states); 1775 mutex_exit(HUBD_MUTEX(hubd)); 1776 1777 ndi_devi_exit(dip, circ); 1778 1779 return (DDI_FAILURE); 1780 } 1781 1782 switch (level) { 1783 case USB_DEV_OS_PWR_OFF: 1784 retval = hubd_pwrlvl0(hubd); 1785 1786 break; 1787 case USB_DEV_OS_PWR_1: 1788 retval = hubd_pwrlvl1(hubd); 1789 1790 break; 1791 case USB_DEV_OS_PWR_2: 1792 retval = hubd_pwrlvl2(hubd); 1793 1794 break; 1795 case USB_DEV_OS_FULL_PWR: 1796 retval = hubd_pwrlvl3(hubd); 1797 1798 break; 1799 } 1800 mutex_exit(HUBD_MUTEX(hubd)); 1801 1802 ndi_devi_exit(dip, circ); 1803 1804 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1805 } 1806 1807 1808 /* power entry point for the root hub */ 1809 int 1810 usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level) 1811 { 1812 return (usba_hubdi_power(dip, comp, level)); 1813 } 1814 1815 1816 /* 1817 * standard driver entry points support code 1818 */ 1819 int 1820 usba_hubdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1821 { 1822 int instance = ddi_get_instance(dip); 1823 hubd_t *hubd = NULL; 1824 int i, rval; 1825 int minor; 1826 uint8_t ports_count; 1827 char *log_name = NULL; 1828 const char *root_hub_drvname; 1829 usb_ep_data_t *ep_data; 1830 usba_device_t *child_ud = NULL; 1831 usb_dev_descr_t *usb_dev_descr; 1832 usb_port_status_t parent_port_status, child_port_status; 1833 1834 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubdi_log_handle, 1835 "hubd_attach instance %d, cmd=0x%x", instance, cmd); 1836 1837 switch (cmd) { 1838 case DDI_ATTACH: 1839 1840 break; 1841 case DDI_RESUME: 1842 hubd_cpr_resume(dip); 1843 1844 return (DDI_SUCCESS); 1845 default: 1846 return (DDI_FAILURE); 1847 } 1848 1849 /* 1850 * Allocate softc information. 1851 */ 1852 if (usba_is_root_hub(dip)) { 1853 /* soft state has already been allocated */ 1854 hubd = hubd_get_soft_state(dip); 1855 minor = HUBD_IS_ROOT_HUB; 1856 1857 /* generate readable labels for different root hubs */ 1858 root_hub_drvname = ddi_driver_name(dip); 1859 if (strcmp(root_hub_drvname, "ehci") == 0) { 1860 log_name = "eusb"; 1861 } else if (strcmp(root_hub_drvname, "uhci") == 0) { 1862 log_name = "uusb"; 1863 } else { 1864 /* std. for ohci */ 1865 log_name = "usb"; 1866 } 1867 } else { 1868 rval = ddi_soft_state_zalloc(hubd_statep, instance); 1869 minor = 0; 1870 1871 if (rval != DDI_SUCCESS) { 1872 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 1873 "cannot allocate soft state (%d)", instance); 1874 goto fail; 1875 } 1876 1877 hubd = hubd_get_soft_state(dip); 1878 if (hubd == NULL) { 1879 goto fail; 1880 } 1881 } 1882 1883 hubd->h_log_handle = usb_alloc_log_hdl(dip, log_name, &hubd_errlevel, 1884 &hubd_errmask, &hubd_instance_debug, 0); 1885 1886 hubd->h_usba_device = child_ud = usba_get_usba_device(dip); 1887 hubd->h_dip = dip; 1888 hubd->h_instance = instance; 1889 1890 mutex_enter(&child_ud->usb_mutex); 1891 child_port_status = child_ud->usb_port_status; 1892 usb_dev_descr = child_ud->usb_dev_descr; 1893 parent_port_status = (child_ud->usb_hs_hub_usba_dev) ? 1894 child_ud->usb_hs_hub_usba_dev->usb_port_status : 0; 1895 mutex_exit(&child_ud->usb_mutex); 1896 1897 if ((child_port_status == USBA_FULL_SPEED_DEV) && 1898 (parent_port_status == USBA_HIGH_SPEED_DEV) && 1899 (usb_dev_descr->bcdUSB == 0x100)) { 1900 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 1901 "Use of a USB1.0 hub behind a high speed port may " 1902 "cause unexpected failures"); 1903 } 1904 1905 hubd->h_pipe_policy.pp_max_async_reqs = 1; 1906 1907 /* register with USBA as client driver */ 1908 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 1909 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1910 "client attach failed"); 1911 1912 goto fail; 1913 } 1914 1915 if (usb_get_dev_data(dip, &hubd->h_dev_data, 1916 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) { 1917 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1918 "cannot get dev_data"); 1919 1920 goto fail; 1921 } 1922 1923 if ((ep_data = usb_lookup_ep_data(dip, hubd->h_dev_data, 1924 hubd->h_dev_data->dev_curr_if, 0, 0, 1925 (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) { 1926 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1927 "no interrupt IN endpoint found"); 1928 1929 goto fail; 1930 } 1931 1932 hubd->h_ep1_descr = ep_data->ep_descr; 1933 hubd->h_default_pipe = hubd->h_dev_data->dev_default_ph; 1934 1935 mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER, 1936 hubd->h_dev_data->dev_iblock_cookie); 1937 cv_init(&hubd->h_cv_reset_port, NULL, CV_DRIVER, NULL); 1938 cv_init(&hubd->h_cv_hotplug_dev, NULL, CV_DRIVER, NULL); 1939 1940 hubd->h_init_state |= HUBD_LOCKS_DONE; 1941 1942 usb_free_descr_tree(dip, hubd->h_dev_data); 1943 1944 /* 1945 * register this hub instance with usba 1946 */ 1947 rval = usba_hubdi_register(dip, 0); 1948 if (rval != USB_SUCCESS) { 1949 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1950 "usba_hubdi_register failed"); 1951 goto fail; 1952 } 1953 1954 mutex_enter(HUBD_MUTEX(hubd)); 1955 hubd->h_init_state |= HUBD_HUBDI_REGISTERED; 1956 hubd->h_dev_state = USB_DEV_ONLINE; 1957 mutex_exit(HUBD_MUTEX(hubd)); 1958 1959 /* now create components to power manage this device */ 1960 hubd_create_pm_components(dip, hubd); 1961 1962 /* 1963 * Event handling: definition and registration 1964 * 1965 * first the definition: 1966 * get event handle 1967 */ 1968 (void) ndi_event_alloc_hdl(dip, 0, &hubd->h_ndi_event_hdl, NDI_SLEEP); 1969 1970 /* bind event set to the handle */ 1971 if (ndi_event_bind_set(hubd->h_ndi_event_hdl, &hubd_ndi_events, 1972 NDI_SLEEP)) { 1973 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 1974 "binding event set failed"); 1975 1976 goto fail; 1977 } 1978 1979 /* event registration */ 1980 if (hubd_register_events(hubd) != USB_SUCCESS) { 1981 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 1982 "hubd_register_events failed"); 1983 1984 goto fail; 1985 } 1986 1987 mutex_enter(HUBD_MUTEX(hubd)); 1988 hubd->h_init_state |= HUBD_EVENTS_REGISTERED; 1989 1990 if ((hubd_get_hub_descriptor(hubd)) != USB_SUCCESS) { 1991 mutex_exit(HUBD_MUTEX(hubd)); 1992 1993 goto fail; 1994 } 1995 1996 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 1997 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 1998 "hub-ignore-power-budget") == 1) { 1999 hubd->h_ignore_pwr_budget = B_TRUE; 2000 } else { 2001 hubd->h_ignore_pwr_budget = B_FALSE; 2002 2003 /* initialize hub power budget variables */ 2004 if (hubd_init_power_budget(hubd) != USB_SUCCESS) { 2005 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2006 "hubd_init_power_budget failed"); 2007 mutex_exit(HUBD_MUTEX(hubd)); 2008 2009 goto fail; 2010 } 2011 } 2012 2013 /* initialize and create children */ 2014 if (hubd_check_ports(hubd) != USB_SUCCESS) { 2015 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2016 "hubd_check_ports failed"); 2017 mutex_exit(HUBD_MUTEX(hubd)); 2018 2019 goto fail; 2020 } 2021 2022 /* 2023 * create cfgadm nodes 2024 */ 2025 hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, KM_SLEEP); 2026 hubd_get_ancestry_str(hubd); 2027 2028 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2029 "#ports=0x%x", hubd->h_hub_descr.bNbrPorts); 2030 2031 for (i = 1; i <= hubd->h_hub_descr.bNbrPorts; i++) { 2032 char ap_name[HUBD_APID_NAMELEN]; 2033 2034 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 2035 hubd->h_ancestry_str, i); 2036 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2037 "ap_name=%s", ap_name); 2038 2039 if (ddi_create_minor_node(dip, ap_name, S_IFCHR, instance, 2040 DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 2041 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2042 "cannot create attachment point node (%d)", 2043 instance); 2044 mutex_exit(HUBD_MUTEX(hubd)); 2045 2046 goto fail; 2047 } 2048 } 2049 2050 ports_count = hubd->h_hub_descr.bNbrPorts; 2051 mutex_exit(HUBD_MUTEX(hubd)); 2052 2053 /* create minor nodes */ 2054 if (ddi_create_minor_node(dip, "hubd", S_IFCHR, 2055 instance | minor, DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 2056 2057 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2058 "cannot create devctl minor node (%d)", instance); 2059 2060 goto fail; 2061 } 2062 2063 mutex_enter(HUBD_MUTEX(hubd)); 2064 hubd->h_init_state |= HUBD_MINOR_NODE_CREATED; 2065 mutex_exit(HUBD_MUTEX(hubd)); 2066 2067 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, 2068 "usb-port-count", ports_count) != DDI_PROP_SUCCESS) { 2069 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2070 "usb-port-count update failed"); 2071 } 2072 2073 /* 2074 * host controller driver has already reported this dev 2075 * if we are the root hub 2076 */ 2077 if (!usba_is_root_hub(dip)) { 2078 ddi_report_dev(dip); 2079 } 2080 2081 /* enable deathrow thread */ 2082 hubd->h_cleanup_enabled = B_TRUE; 2083 mutex_enter(HUBD_MUTEX(hubd)); 2084 hubd_pm_idle_component(hubd, dip, 0); 2085 mutex_exit(HUBD_MUTEX(hubd)); 2086 2087 return (DDI_SUCCESS); 2088 2089 fail: 2090 { 2091 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2092 2093 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 2094 "cannot attach %s", ddi_pathname(dip, pathname)); 2095 2096 kmem_free(pathname, MAXPATHLEN); 2097 } 2098 2099 mutex_enter(HUBD_MUTEX(hubd)); 2100 hubd_pm_idle_component(hubd, dip, 0); 2101 mutex_exit(HUBD_MUTEX(hubd)); 2102 2103 if (hubd) { 2104 rval = hubd_cleanup(dip, hubd); 2105 if (rval != USB_SUCCESS) { 2106 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 2107 "failure to complete cleanup after attach failure"); 2108 } 2109 } 2110 2111 return (DDI_FAILURE); 2112 } 2113 2114 2115 int 2116 usba_hubdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2117 { 2118 hubd_t *hubd = hubd_get_soft_state(dip); 2119 int rval; 2120 2121 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2122 "hubd_detach: cmd=0x%x", cmd); 2123 2124 switch (cmd) { 2125 case DDI_DETACH: 2126 rval = hubd_cleanup(dip, hubd); 2127 2128 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2129 case DDI_SUSPEND: 2130 rval = hubd_cpr_suspend(hubd); 2131 2132 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 2133 default: 2134 return (DDI_FAILURE); 2135 } 2136 } 2137 2138 2139 /* 2140 * hubd_setdevaddr 2141 * set the device addrs on this port 2142 */ 2143 static int 2144 hubd_setdevaddr(hubd_t *hubd, usb_port_t port) 2145 { 2146 int rval; 2147 usb_cr_t completion_reason; 2148 usb_cb_flags_t cb_flags; 2149 usb_pipe_handle_t ph; 2150 dev_info_t *child_dip = NULL; 2151 uchar_t address = 0; 2152 usba_device_t *usba_device; 2153 int retry = 0; 2154 long time_delay; 2155 2156 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2157 "hubd_setdevaddr: port=%d", port); 2158 2159 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2160 2161 child_dip = hubd->h_children_dips[port]; 2162 address = hubd->h_usba_devices[port]->usb_addr; 2163 usba_device = hubd->h_usba_devices[port]; 2164 2165 /* close the default pipe with addr x */ 2166 mutex_exit(HUBD_MUTEX(hubd)); 2167 ph = usba_get_dflt_pipe_handle(child_dip); 2168 usb_pipe_close(child_dip, ph, 2169 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2170 mutex_enter(HUBD_MUTEX(hubd)); 2171 2172 /* 2173 * As this device has been reset, temporarily 2174 * assign the default address 2175 */ 2176 mutex_enter(&usba_device->usb_mutex); 2177 address = usba_device->usb_addr; 2178 usba_device->usb_addr = USBA_DEFAULT_ADDR; 2179 mutex_exit(&usba_device->usb_mutex); 2180 2181 mutex_exit(HUBD_MUTEX(hubd)); 2182 2183 time_delay = drv_usectohz(hubd_device_delay / 20); 2184 for (retry = 0; retry < hubd_retry_enumerate; retry++) { 2185 2186 /* open child's default pipe with USBA_DEFAULT_ADDR */ 2187 if (usb_pipe_open(child_dip, NULL, NULL, 2188 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != 2189 USB_SUCCESS) { 2190 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2191 "hubd_setdevaddr: Unable to open default pipe"); 2192 2193 break; 2194 } 2195 2196 /* Set the address of the device */ 2197 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 2198 USB_DEV_REQ_HOST_TO_DEV, 2199 USB_REQ_SET_ADDRESS, /* bRequest */ 2200 address, /* wValue */ 2201 0, /* wIndex */ 2202 0, /* wLength */ 2203 NULL, 0, 2204 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2205 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2206 "hubd_setdevaddr(%d): rval=%d cr=%d cb_fl=0x%x", 2207 retry, rval, completion_reason, cb_flags); 2208 } 2209 2210 usb_pipe_close(child_dip, ph, 2211 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2212 2213 if (rval == USB_SUCCESS) { 2214 2215 break; 2216 } 2217 2218 delay(time_delay); 2219 } 2220 2221 /* Reset to the old address */ 2222 mutex_enter(&usba_device->usb_mutex); 2223 usba_device->usb_addr = address; 2224 mutex_exit(&usba_device->usb_mutex); 2225 mutex_enter(HUBD_MUTEX(hubd)); 2226 2227 usba_clear_data_toggle(usba_device); 2228 2229 return (rval); 2230 } 2231 2232 2233 /* 2234 * hubd_setdevconfig 2235 * set the device addrs on this port 2236 */ 2237 static void 2238 hubd_setdevconfig(hubd_t *hubd, usb_port_t port) 2239 { 2240 int rval; 2241 usb_cr_t completion_reason; 2242 usb_cb_flags_t cb_flags; 2243 usb_pipe_handle_t ph; 2244 dev_info_t *child_dip = NULL; 2245 usba_device_t *usba_device = NULL; 2246 uint16_t config_value; 2247 2248 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2249 "hubd_setdevconfig: port=%d", port); 2250 2251 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2252 2253 child_dip = hubd->h_children_dips[port]; 2254 usba_device = hubd->h_usba_devices[port]; 2255 config_value = hubd->h_usba_devices[port]->usb_cfg_value; 2256 mutex_exit(HUBD_MUTEX(hubd)); 2257 2258 /* open the default control pipe */ 2259 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 2260 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) == 2261 USB_SUCCESS) { 2262 2263 /* Set the default configuration of the device */ 2264 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 2265 USB_DEV_REQ_HOST_TO_DEV, 2266 USB_REQ_SET_CFG, /* bRequest */ 2267 config_value, /* wValue */ 2268 0, /* wIndex */ 2269 0, /* wLength */ 2270 NULL, 0, 2271 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2272 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2273 "hubd_setdevconfig: set device config failed: " 2274 "cr=%d cb_fl=0x%x rval=%d", 2275 completion_reason, cb_flags, rval); 2276 } 2277 /* 2278 * After setting the configuration, we make this default 2279 * control pipe persistent, so that it gets re-opened 2280 * on posting a connect event 2281 */ 2282 usba_persistent_pipe_close(usba_device); 2283 } else { 2284 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2285 "pipe open fails: rval=%d", rval); 2286 } 2287 mutex_enter(HUBD_MUTEX(hubd)); 2288 } 2289 2290 2291 /*ARGSUSED*/ 2292 static int 2293 hubd_check_disconnected_ports(dev_info_t *dip, void *arg) 2294 { 2295 int circ; 2296 usb_port_t port; 2297 hubd_t *hubd; 2298 major_t hub_major = ddi_name_to_major("hubd"); 2299 major_t hwahc_major = ddi_name_to_major("hwahc"); 2300 major_t usbmid_major = ddi_name_to_major("usb_mid"); 2301 2302 /* 2303 * make sure dip is a usb hub, major of root hub is HCD 2304 * major 2305 */ 2306 if (!usba_is_root_hub(dip)) { 2307 if (ddi_driver_major(dip) == usbmid_major) { 2308 /* 2309 * need to walk the children since it might be a 2310 * HWA device 2311 */ 2312 2313 return (DDI_WALK_CONTINUE); 2314 } 2315 2316 /* TODO: DWA device may also need special handling */ 2317 2318 if (((ddi_driver_major(dip) != hub_major) && 2319 (ddi_driver_major(dip) != hwahc_major)) || 2320 !i_ddi_devi_attached(dip)) { 2321 2322 return (DDI_WALK_PRUNECHILD); 2323 } 2324 } 2325 2326 hubd = hubd_get_soft_state(dip); 2327 if (hubd == NULL) { 2328 2329 return (DDI_WALK_PRUNECHILD); 2330 } 2331 2332 /* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */ 2333 ndi_devi_enter(dip, &circ); 2334 2335 if (ddi_driver_major(dip) != hwahc_major) { 2336 /* for normal usb hub or root hub */ 2337 mutex_enter(HUBD_MUTEX(hubd)); 2338 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2339 dev_info_t *cdip = hubd->h_children_dips[port]; 2340 2341 if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) { 2342 2343 continue; 2344 } 2345 2346 (void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE, 2347 B_TRUE); 2348 } 2349 mutex_exit(HUBD_MUTEX(hubd)); 2350 } else { 2351 /* for HWA */ 2352 if (hubd->h_cleanup_child != NULL) { 2353 if (hubd->h_cleanup_child(dip) != USB_SUCCESS) { 2354 ndi_devi_exit(dip, circ); 2355 2356 return (DDI_WALK_PRUNECHILD); 2357 } 2358 } else { 2359 ndi_devi_exit(dip, circ); 2360 2361 return (DDI_WALK_PRUNECHILD); 2362 } 2363 } 2364 2365 ndi_devi_exit(dip, circ); 2366 2367 /* skip siblings of root hub */ 2368 if (usba_is_root_hub(dip)) { 2369 2370 return (DDI_WALK_PRUNESIB); 2371 } 2372 2373 return (DDI_WALK_CONTINUE); 2374 } 2375 2376 2377 /* 2378 * this thread will walk all children under the root hub for this 2379 * USB bus instance and attempt to remove them 2380 */ 2381 static void 2382 hubd_root_hub_cleanup_thread(void *arg) 2383 { 2384 int circ; 2385 hubd_t *root_hubd = (hubd_t *)arg; 2386 dev_info_t *rh_dip = root_hubd->h_dip; 2387 #ifndef __lock_lint 2388 callb_cpr_t cprinfo; 2389 2390 CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr, 2391 "USB root hub"); 2392 #endif 2393 2394 for (;;) { 2395 /* don't race with detach */ 2396 ndi_hold_devi(rh_dip); 2397 2398 mutex_enter(HUBD_MUTEX(root_hubd)); 2399 root_hubd->h_cleanup_needed = 0; 2400 mutex_exit(HUBD_MUTEX(root_hubd)); 2401 2402 (void) devfs_clean(rh_dip, NULL, 0); 2403 2404 ndi_devi_enter(ddi_get_parent(rh_dip), &circ); 2405 ddi_walk_devs(rh_dip, hubd_check_disconnected_ports, 2406 NULL); 2407 #ifdef __lock_lint 2408 (void) hubd_check_disconnected_ports(rh_dip, NULL); 2409 #endif 2410 ndi_devi_exit(ddi_get_parent(rh_dip), circ); 2411 2412 /* quit if we are not enabled anymore */ 2413 mutex_enter(HUBD_MUTEX(root_hubd)); 2414 if ((root_hubd->h_cleanup_enabled == B_FALSE) || 2415 (root_hubd->h_cleanup_needed == B_FALSE)) { 2416 root_hubd->h_cleanup_active = B_FALSE; 2417 mutex_exit(HUBD_MUTEX(root_hubd)); 2418 ndi_rele_devi(rh_dip); 2419 2420 break; 2421 } 2422 mutex_exit(HUBD_MUTEX(root_hubd)); 2423 ndi_rele_devi(rh_dip); 2424 2425 #ifndef __lock_lint 2426 mutex_enter(HUBD_MUTEX(root_hubd)); 2427 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2428 mutex_exit(HUBD_MUTEX(root_hubd)); 2429 2430 delay(drv_usectohz(hubd_dip_cleanup_delay)); 2431 2432 mutex_enter(HUBD_MUTEX(root_hubd)); 2433 CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd)); 2434 mutex_exit(HUBD_MUTEX(root_hubd)); 2435 #endif 2436 } 2437 2438 #ifndef __lock_lint 2439 mutex_enter(HUBD_MUTEX(root_hubd)); 2440 CALLB_CPR_EXIT(&cprinfo); 2441 #endif 2442 } 2443 2444 2445 void 2446 hubd_schedule_cleanup(dev_info_t *rh_dip) 2447 { 2448 hubd_t *root_hubd; 2449 2450 /* 2451 * The usb_root_hub_dip pointer for the child hub of the WUSB 2452 * wire adapter class device points to the wire adapter, not 2453 * the root hub. Need to find the real root hub dip so that 2454 * the cleanup thread only starts from the root hub. 2455 */ 2456 while (!usba_is_root_hub(rh_dip)) { 2457 root_hubd = hubd_get_soft_state(rh_dip); 2458 if (root_hubd != NULL) { 2459 rh_dip = root_hubd->h_usba_device->usb_root_hub_dip; 2460 if (rh_dip == NULL) { 2461 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2462 root_hubd->h_log_handle, 2463 "hubd_schedule_cleanup: null rh dip"); 2464 2465 return; 2466 } 2467 } else { 2468 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2469 root_hubd->h_log_handle, 2470 "hubd_schedule_cleanup: cannot find root hub"); 2471 2472 return; 2473 } 2474 } 2475 root_hubd = hubd_get_soft_state(rh_dip); 2476 2477 mutex_enter(HUBD_MUTEX(root_hubd)); 2478 root_hubd->h_cleanup_needed = B_TRUE; 2479 if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) { 2480 root_hubd->h_cleanup_active = B_TRUE; 2481 mutex_exit(HUBD_MUTEX(root_hubd)); 2482 (void) thread_create(NULL, 0, 2483 hubd_root_hub_cleanup_thread, 2484 (void *)root_hubd, 0, &p0, TS_RUN, 2485 minclsyspri); 2486 } else { 2487 mutex_exit(HUBD_MUTEX(root_hubd)); 2488 } 2489 } 2490 2491 2492 /* 2493 * hubd_restore_device_state: 2494 * - set config for the hub 2495 * - power cycle all the ports 2496 * - for each port that was connected 2497 * - reset port 2498 * - assign addrs to the device on this port 2499 * - restart polling 2500 * - reset suspend flag 2501 */ 2502 static void 2503 hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd) 2504 { 2505 int rval; 2506 int retry; 2507 uint_t hub_prev_state; 2508 usb_port_t port; 2509 uint16_t status; 2510 uint16_t change; 2511 dev_info_t *ch_dip; 2512 boolean_t ehci_root_hub; 2513 2514 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2515 "hubd_restore_device_state:"); 2516 2517 mutex_enter(HUBD_MUTEX(hubd)); 2518 hub_prev_state = hubd->h_dev_state; 2519 ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN); 2520 2521 /* First bring the device to full power */ 2522 (void) hubd_pm_busy_component(hubd, dip, 0); 2523 mutex_exit(HUBD_MUTEX(hubd)); 2524 2525 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2526 2527 if (!usba_is_root_hub(dip) && 2528 (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0, 2529 DPRINT_MASK_HOTPLUG, 2530 USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) { 2531 2532 /* change the device state to disconnected */ 2533 mutex_enter(HUBD_MUTEX(hubd)); 2534 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2535 (void) hubd_pm_idle_component(hubd, dip, 0); 2536 mutex_exit(HUBD_MUTEX(hubd)); 2537 2538 return; 2539 } 2540 2541 ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0); 2542 2543 mutex_enter(HUBD_MUTEX(hubd)); 2544 /* First turn off all port power */ 2545 rval = hubd_disable_all_port_power(hubd); 2546 if (rval != USB_SUCCESS) { 2547 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2548 "hubd_restore_device_state:" 2549 "turning off port power failed"); 2550 } 2551 2552 /* Settling time before turning on again */ 2553 mutex_exit(HUBD_MUTEX(hubd)); 2554 delay(drv_usectohz(hubd_device_delay / 100)); 2555 mutex_enter(HUBD_MUTEX(hubd)); 2556 2557 /* enable power on all ports so we can see connects */ 2558 if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) { 2559 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2560 "hubd_restore_device_state: turn on port power failed"); 2561 2562 /* disable whatever was enabled */ 2563 (void) hubd_disable_all_port_power(hubd); 2564 2565 (void) hubd_pm_idle_component(hubd, dip, 0); 2566 mutex_exit(HUBD_MUTEX(hubd)); 2567 2568 return; 2569 } 2570 2571 /* 2572 * wait at least 3 frames before accessing devices 2573 * (note that delay's minimal time is one clock tick which 2574 * is 10ms unless hires_tick has been changed) 2575 */ 2576 mutex_exit(HUBD_MUTEX(hubd)); 2577 delay(drv_usectohz(10000)); 2578 mutex_enter(HUBD_MUTEX(hubd)); 2579 2580 hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER; 2581 2582 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2583 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 2584 "hubd_restore_device_state: port=%d", port); 2585 2586 /* 2587 * the childen_dips list may have dips that have been 2588 * already deallocated. we only get a post_detach notification 2589 * but not a destroy notification 2590 */ 2591 ch_dip = hubd->h_children_dips[port]; 2592 if (ch_dip) { 2593 /* get port status */ 2594 (void) hubd_determine_port_status(hubd, port, 2595 &status, &change, PORT_CHANGE_CSC); 2596 2597 /* check if it is truly connected */ 2598 if (status & PORT_STATUS_CCS) { 2599 /* 2600 * Now reset port and assign the device 2601 * its original address 2602 */ 2603 retry = 0; 2604 do { 2605 (void) hubd_reset_port(hubd, port); 2606 2607 /* required for ppx */ 2608 (void) hubd_enable_port(hubd, port); 2609 2610 if (retry) { 2611 mutex_exit(HUBD_MUTEX(hubd)); 2612 delay(drv_usectohz( 2613 hubd_device_delay/2)); 2614 mutex_enter(HUBD_MUTEX(hubd)); 2615 } 2616 2617 rval = hubd_setdevaddr(hubd, port); 2618 retry++; 2619 } while ((rval != USB_SUCCESS) && 2620 (retry < hubd_retry_enumerate)); 2621 2622 hubd_setdevconfig(hubd, port); 2623 2624 if (hub_prev_state == USB_DEV_DISCONNECTED) { 2625 /* post a connect event */ 2626 mutex_exit(HUBD_MUTEX(hubd)); 2627 hubd_post_event(hubd, port, 2628 USBA_EVENT_TAG_HOT_INSERTION); 2629 mutex_enter(HUBD_MUTEX(hubd)); 2630 } else { 2631 /* 2632 * Since we have this device connected 2633 * mark it reinserted to prevent 2634 * cleanup thread from stepping in. 2635 */ 2636 mutex_exit(HUBD_MUTEX(hubd)); 2637 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2638 DEVI_SET_DEVICE_REINSERTED(ch_dip); 2639 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2640 2641 /* 2642 * reopen pipes for children for 2643 * their DDI_RESUME 2644 */ 2645 rval = usba_persistent_pipe_open( 2646 usba_get_usba_device(ch_dip)); 2647 mutex_enter(HUBD_MUTEX(hubd)); 2648 ASSERT(rval == USB_SUCCESS); 2649 } 2650 } else { 2651 /* 2652 * Mark this dip for deletion as the device 2653 * is not physically present, and schedule 2654 * cleanup thread upon post resume 2655 */ 2656 mutex_exit(HUBD_MUTEX(hubd)); 2657 2658 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2659 hubd->h_log_handle, 2660 "hubd_restore_device_state: " 2661 "dip=%p on port=%d marked for cleanup", 2662 (void *)ch_dip, port); 2663 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2664 DEVI_SET_DEVICE_REMOVED(ch_dip); 2665 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2666 2667 mutex_enter(HUBD_MUTEX(hubd)); 2668 } 2669 } else if (ehci_root_hub) { 2670 /* get port status */ 2671 (void) hubd_determine_port_status(hubd, port, 2672 &status, &change, PORT_CHANGE_CSC); 2673 2674 /* check if it is truly connected */ 2675 if (status & PORT_STATUS_CCS) { 2676 /* 2677 * reset the port to find out if we have 2678 * 2.0 device connected or 1.X. A 2.0 2679 * device will still be seen as connected, 2680 * while a 1.X device will switch over to 2681 * the companion controller. 2682 */ 2683 (void) hubd_reset_port(hubd, port); 2684 2685 (void) hubd_determine_port_status(hubd, port, 2686 &status, &change, PORT_CHANGE_CSC); 2687 2688 if (status & 2689 (PORT_STATUS_CCS | PORT_STATUS_HSDA)) { 2690 /* 2691 * We have a USB 2.0 device 2692 * connected. Power cycle this port 2693 * so that hotplug thread can 2694 * enumerate this device. 2695 */ 2696 (void) hubd_toggle_port(hubd, port); 2697 } else { 2698 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2699 hubd->h_log_handle, 2700 "hubd_restore_device_state: " 2701 "device on port %d switched over", 2702 port); 2703 } 2704 } 2705 2706 } 2707 } 2708 2709 2710 /* if the device had remote wakeup earlier, enable it again */ 2711 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2712 mutex_exit(HUBD_MUTEX(hubd)); 2713 (void) usb_handle_remote_wakeup(hubd->h_dip, 2714 USB_REMOTE_WAKEUP_ENABLE); 2715 mutex_enter(HUBD_MUTEX(hubd)); 2716 } 2717 2718 hubd->h_dev_state = USB_DEV_ONLINE; 2719 hubd_start_polling(hubd, 0); 2720 (void) hubd_pm_idle_component(hubd, dip, 0); 2721 mutex_exit(HUBD_MUTEX(hubd)); 2722 } 2723 2724 2725 /* 2726 * hubd_cleanup: 2727 * cleanup hubd and deallocate. this function is called for 2728 * handling attach failures and detaching including dynamic 2729 * reconfiguration. If called from attaching, it must clean 2730 * up the whole thing and return success. 2731 */ 2732 /*ARGSUSED*/ 2733 static int 2734 hubd_cleanup(dev_info_t *dip, hubd_t *hubd) 2735 { 2736 int circ, rval, old_dev_state; 2737 hub_power_t *hubpm; 2738 #ifdef DEBUG 2739 usb_port_t port; 2740 #endif 2741 2742 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2743 "hubd_cleanup:"); 2744 2745 if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) { 2746 goto done; 2747 } 2748 2749 /* ensure we are the only one active */ 2750 ndi_devi_enter(dip, &circ); 2751 2752 mutex_enter(HUBD_MUTEX(hubd)); 2753 2754 /* Cleanup failure is only allowed if called from detach */ 2755 if (DEVI_IS_DETACHING(dip)) { 2756 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 2757 2758 /* 2759 * We are being called from detach. 2760 * Fail immediately if the hotplug thread is running 2761 * else set the dev_state to disconnected so that 2762 * hotplug thread just exits without doing anything. 2763 */ 2764 if (hubd->h_bus_ctls || hubd->h_bus_pwr || 2765 hubd->h_hotplug_thread) { 2766 mutex_exit(HUBD_MUTEX(hubd)); 2767 ndi_devi_exit(dip, circ); 2768 2769 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2770 "hubd_cleanup: hotplug thread/bus ctl active " 2771 "- failing detach"); 2772 2773 return (USB_FAILURE); 2774 } 2775 2776 /* 2777 * if the deathrow thread is still active or about 2778 * to become active, fail detach 2779 * the roothup can only be detached if nexus drivers 2780 * are unloaded or explicitly offlined 2781 */ 2782 if (rh_dip == dip) { 2783 if (hubd->h_cleanup_needed || 2784 hubd->h_cleanup_active) { 2785 mutex_exit(HUBD_MUTEX(hubd)); 2786 ndi_devi_exit(dip, circ); 2787 2788 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2789 hubd->h_log_handle, 2790 "hubd_cleanup: deathrow still active?" 2791 "- failing detach"); 2792 2793 return (USB_FAILURE); 2794 } 2795 } 2796 } 2797 2798 old_dev_state = hubd->h_dev_state; 2799 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2800 2801 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2802 "hubd_cleanup: stop polling"); 2803 hubd_close_intr_pipe(hubd); 2804 2805 ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr || 2806 hubd->h_hotplug_thread) == 0); 2807 mutex_exit(HUBD_MUTEX(hubd)); 2808 2809 /* 2810 * deallocate events, if events are still registered 2811 * (ie. children still attached) then we have to fail the detach 2812 */ 2813 if (hubd->h_ndi_event_hdl) { 2814 2815 rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl); 2816 if (DEVI_IS_ATTACHING(dip)) { 2817 2818 /* It must return success if attaching. */ 2819 ASSERT(rval == NDI_SUCCESS); 2820 2821 } else if (rval != NDI_SUCCESS) { 2822 2823 USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle, 2824 "hubd_cleanup: ndi_event_free_hdl failed"); 2825 ndi_devi_exit(dip, circ); 2826 2827 return (USB_FAILURE); 2828 2829 } 2830 } 2831 2832 mutex_enter(HUBD_MUTEX(hubd)); 2833 2834 if (hubd->h_init_state & HUBD_CHILDREN_CREATED) { 2835 #ifdef DEBUG 2836 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2837 ASSERT(hubd->h_usba_devices[port] == NULL); 2838 ASSERT(hubd->h_children_dips[port] == NULL); 2839 } 2840 #endif 2841 kmem_free(hubd->h_children_dips, hubd->h_cd_list_length); 2842 kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length); 2843 } 2844 2845 /* 2846 * Disable the event callbacks first, after this point, event 2847 * callbacks will never get called. Note we shouldn't hold 2848 * mutex while unregistering events because there may be a 2849 * competing event callback thread. Event callbacks are done 2850 * with ndi mutex held and this can cause a potential deadlock. 2851 * Note that cleanup can't fail after deregistration of events. 2852 */ 2853 if (hubd->h_init_state & HUBD_EVENTS_REGISTERED) { 2854 mutex_exit(HUBD_MUTEX(hubd)); 2855 usb_unregister_event_cbs(dip, &hubd_events); 2856 hubd_unregister_cpr_callback(hubd); 2857 mutex_enter(HUBD_MUTEX(hubd)); 2858 } 2859 2860 /* restore the old dev state so that device can be put into low power */ 2861 hubd->h_dev_state = old_dev_state; 2862 hubpm = hubd->h_hubpm; 2863 2864 if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) { 2865 (void) hubd_pm_busy_component(hubd, dip, 0); 2866 mutex_exit(HUBD_MUTEX(hubd)); 2867 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2868 /* 2869 * Bring the hub to full power before 2870 * issuing the disable remote wakeup command 2871 */ 2872 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2873 2874 if ((rval = usb_handle_remote_wakeup(hubd->h_dip, 2875 USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 2876 USB_DPRINTF_L2(DPRINT_MASK_PM, 2877 hubd->h_log_handle, 2878 "hubd_cleanup: disable remote wakeup " 2879 "fails=%d", rval); 2880 } 2881 } 2882 2883 (void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF); 2884 2885 mutex_enter(HUBD_MUTEX(hubd)); 2886 (void) hubd_pm_idle_component(hubd, dip, 0); 2887 } 2888 2889 if (hubpm) { 2890 if (hubpm->hubp_child_pwrstate) { 2891 kmem_free(hubpm->hubp_child_pwrstate, 2892 MAX_PORTS + 1); 2893 } 2894 kmem_free(hubpm, sizeof (hub_power_t)); 2895 } 2896 mutex_exit(HUBD_MUTEX(hubd)); 2897 2898 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2899 "hubd_cleanup: freeing space"); 2900 2901 if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) { 2902 rval = usba_hubdi_unregister(dip); 2903 ASSERT(rval == USB_SUCCESS); 2904 } 2905 2906 if (hubd->h_init_state & HUBD_LOCKS_DONE) { 2907 mutex_destroy(HUBD_MUTEX(hubd)); 2908 cv_destroy(&hubd->h_cv_reset_port); 2909 cv_destroy(&hubd->h_cv_hotplug_dev); 2910 } 2911 2912 ndi_devi_exit(dip, circ); 2913 2914 if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) { 2915 ddi_remove_minor_node(dip, NULL); 2916 } 2917 2918 if (usba_is_root_hub(dip)) { 2919 usb_pipe_close(dip, hubd->h_default_pipe, 2920 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2921 } 2922 2923 done: 2924 if (hubd->h_ancestry_str) { 2925 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN); 2926 } 2927 2928 usb_client_detach(dip, hubd->h_dev_data); 2929 2930 usb_free_log_hdl(hubd->h_log_handle); 2931 2932 if (!usba_is_root_hub(dip)) { 2933 ddi_soft_state_free(hubd_statep, ddi_get_instance(dip)); 2934 } 2935 2936 ddi_prop_remove_all(dip); 2937 2938 return (USB_SUCCESS); 2939 } 2940 2941 2942 /* 2943 * hubd_determine_port_connection: 2944 * Determine which port is in connect status but does not 2945 * have connect status change bit set, and mark port change 2946 * bit accordingly. 2947 * This function is applied during hub attach time. 2948 */ 2949 static usb_port_mask_t 2950 hubd_determine_port_connection(hubd_t *hubd) 2951 { 2952 usb_port_t port; 2953 usb_hub_descr_t *hub_descr; 2954 uint16_t status; 2955 uint16_t change; 2956 usb_port_mask_t port_change = 0; 2957 2958 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2959 2960 hub_descr = &hubd->h_hub_descr; 2961 2962 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 2963 2964 (void) hubd_determine_port_status(hubd, port, &status, 2965 &change, 0); 2966 2967 /* Check if port is in connect status */ 2968 if (!(status & PORT_STATUS_CCS)) { 2969 2970 continue; 2971 } 2972 2973 /* 2974 * Check if port Connect Status Change bit has been set. 2975 * If already set, the connection will be handled by 2976 * intr polling callback, not during attach. 2977 */ 2978 if (change & PORT_CHANGE_CSC) { 2979 2980 continue; 2981 } 2982 2983 port_change |= 1 << port; 2984 } 2985 2986 return (port_change); 2987 } 2988 2989 2990 /* 2991 * hubd_check_ports: 2992 * - get hub descriptor 2993 * - check initial port status 2994 * - enable power on all ports 2995 * - enable polling on ep1 2996 */ 2997 static int 2998 hubd_check_ports(hubd_t *hubd) 2999 { 3000 int rval; 3001 usb_port_mask_t port_change = 0; 3002 hubd_hotplug_arg_t *arg; 3003 3004 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3005 3006 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3007 "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip)); 3008 3009 /* 3010 * First turn off all port power 3011 */ 3012 if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) { 3013 3014 /* disable whatever was enabled */ 3015 (void) hubd_disable_all_port_power(hubd); 3016 3017 return (rval); 3018 } 3019 3020 /* 3021 * do not switch on immediately (instantly on root hub) 3022 * and allow time to settle 3023 */ 3024 mutex_exit(HUBD_MUTEX(hubd)); 3025 delay(drv_usectohz(10000)); 3026 mutex_enter(HUBD_MUTEX(hubd)); 3027 3028 /* 3029 * enable power on all ports so we can see connects 3030 */ 3031 if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) { 3032 /* disable whatever was enabled */ 3033 (void) hubd_disable_all_port_power(hubd); 3034 3035 return (rval); 3036 } 3037 3038 /* wait at least 3 frames before accessing devices */ 3039 mutex_exit(HUBD_MUTEX(hubd)); 3040 delay(drv_usectohz(10000)); 3041 mutex_enter(HUBD_MUTEX(hubd)); 3042 3043 /* 3044 * allocate arrays for saving the dips of each child per port 3045 * 3046 * ports go from 1 - n, allocate 1 more entry 3047 */ 3048 hubd->h_cd_list_length = 3049 (sizeof (dev_info_t **)) * (hubd->h_hub_descr.bNbrPorts + 1); 3050 3051 hubd->h_children_dips = (dev_info_t **)kmem_zalloc( 3052 hubd->h_cd_list_length, KM_SLEEP); 3053 hubd->h_usba_devices = (usba_device_t **)kmem_zalloc( 3054 hubd->h_cd_list_length, KM_SLEEP); 3055 3056 hubd->h_init_state |= HUBD_CHILDREN_CREATED; 3057 3058 mutex_exit(HUBD_MUTEX(hubd)); 3059 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3060 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3061 mutex_enter(HUBD_MUTEX(hubd)); 3062 3063 if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) { 3064 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3065 3066 return (rval); 3067 } 3068 3069 hubd_start_polling(hubd, 0); 3070 3071 /* 3072 * Some hub devices, like the embedded hub in the CKS ErgoMagic 3073 * keyboard, may only have connection status bit set, but not 3074 * have connect status change bit set when a device has been 3075 * connected to its downstream port before the hub is enumerated. 3076 * Then when the hub is in enumeration, the devices connected to 3077 * it cannot be detected by the intr pipe and won't be enumerated. 3078 * We need to check such situation here and enumerate the downstream 3079 * devices for such hubs. 3080 */ 3081 port_change = hubd_determine_port_connection(hubd); 3082 3083 if (port_change) { 3084 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3085 3086 arg->hubd = hubd; 3087 arg->hotplug_during_attach = B_TRUE; 3088 hubd->h_port_change |= port_change; 3089 3090 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 3091 "hubd_check_ports: port change=0x%x, need to connect", 3092 hubd->h_port_change); 3093 3094 if (usb_async_req(hubd->h_dip, hubd_hotplug_thread, 3095 (void *)arg, 0) == USB_SUCCESS) { 3096 hubd->h_hotplug_thread++; 3097 } else { 3098 /* mark this device as idle */ 3099 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3100 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3101 } 3102 } else { 3103 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3104 } 3105 3106 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3107 "hubd_check_ports done"); 3108 3109 return (USB_SUCCESS); 3110 } 3111 3112 3113 /* 3114 * hubd_get_hub_descriptor: 3115 */ 3116 static int 3117 hubd_get_hub_descriptor(hubd_t *hubd) 3118 { 3119 usb_hub_descr_t *hub_descr = &hubd->h_hub_descr; 3120 mblk_t *data = NULL; 3121 usb_cr_t completion_reason; 3122 usb_cb_flags_t cb_flags; 3123 uint16_t length; 3124 int rval; 3125 usb_req_attrs_t attr = 0; 3126 3127 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3128 "hubd_get_hub_descriptor:"); 3129 3130 if ((hubd->h_dev_data->dev_descr->idVendor == USB_HUB_INTEL_VID) && 3131 (hubd->h_dev_data->dev_descr->idProduct == USB_HUB_INTEL_PID)) { 3132 attr = USB_ATTRS_SHORT_XFER_OK; 3133 } 3134 3135 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3136 ASSERT(hubd->h_default_pipe != 0); 3137 3138 /* get hub descriptor length first by requesting 8 bytes only */ 3139 mutex_exit(HUBD_MUTEX(hubd)); 3140 3141 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3142 hubd->h_default_pipe, 3143 HUB_CLASS_REQ_TYPE, 3144 USB_REQ_GET_DESCR, /* bRequest */ 3145 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3146 0, /* wIndex */ 3147 8, /* wLength */ 3148 &data, 0, 3149 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 3150 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3151 "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d", 3152 completion_reason, cb_flags, rval); 3153 freemsg(data); 3154 mutex_enter(HUBD_MUTEX(hubd)); 3155 3156 return (rval); 3157 } 3158 3159 length = *(data->b_rptr); 3160 3161 if (length > 8) { 3162 freemsg(data); 3163 data = NULL; 3164 3165 /* get complete hub descriptor */ 3166 rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 3167 hubd->h_default_pipe, 3168 HUB_CLASS_REQ_TYPE, 3169 USB_REQ_GET_DESCR, /* bRequest */ 3170 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 3171 0, /* wIndex */ 3172 length, /* wLength */ 3173 &data, attr, 3174 &completion_reason, &cb_flags, 0); 3175 3176 /* 3177 * Hub descriptor data less than 9 bytes is not valid and 3178 * may cause trouble if we use it. See USB2.0 Tab11-13. 3179 */ 3180 if ((rval != USB_SUCCESS) || (MBLKL(data) <= 8)) { 3181 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3182 "get hub descriptor failed: " 3183 "cr=%d cb_fl=0x%x rval=%d, len=%ld", 3184 completion_reason, cb_flags, rval, 3185 (data)?MBLKL(data):0); 3186 freemsg(data); 3187 mutex_enter(HUBD_MUTEX(hubd)); 3188 3189 return (rval); 3190 } 3191 } 3192 3193 mutex_enter(HUBD_MUTEX(hubd)); 3194 3195 /* parse the hub descriptor */ 3196 /* only 32 ports are supported at present */ 3197 ASSERT(*(data->b_rptr + 2) <= 32); 3198 if (usb_parse_CV_descr("cccscccccc", 3199 data->b_rptr, MBLKL(data), 3200 (void *)hub_descr, sizeof (usb_hub_descr_t)) == 0) { 3201 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 3202 "parsing hub descriptor failed"); 3203 3204 freemsg(data); 3205 3206 return (USB_FAILURE); 3207 } 3208 3209 freemsg(data); 3210 3211 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 3212 "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x " 3213 "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval, 3214 hub_descr->bNbrPorts, hub_descr->wHubCharacteristics, 3215 hub_descr->bPwrOn2PwrGood, hub_descr->bHubContrCurrent); 3216 3217 if (hub_descr->bNbrPorts > MAX_PORTS) { 3218 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 3219 "Hub driver supports max of %d ports on hub. " 3220 "Hence using the first %d port of %d ports available", 3221 MAX_PORTS, MAX_PORTS, hub_descr->bNbrPorts); 3222 3223 hub_descr->bNbrPorts = MAX_PORTS; 3224 } 3225 3226 return (USB_SUCCESS); 3227 } 3228 3229 3230 /* 3231 * hubd_get_hub_status_words: 3232 */ 3233 static int 3234 hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status) 3235 { 3236 usb_cr_t completion_reason; 3237 usb_cb_flags_t cb_flags; 3238 mblk_t *data = NULL; 3239 3240 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 3241 3242 mutex_exit(HUBD_MUTEX(hubd)); 3243 3244 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe, 3245 HUB_CLASS_REQ_TYPE, 3246 USB_REQ_GET_STATUS, 3247 0, 3248 0, 3249 GET_STATUS_LENGTH, 3250 &data, 0, 3251 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 3252 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3253 "get hub status failed: cr=%d cb=0x%x", 3254 completion_reason, cb_flags); 3255 3256 if (data) { 3257 freemsg(data); 3258 } 3259 3260 mutex_enter(HUBD_MUTEX(hubd)); 3261 3262 return (USB_FAILURE); 3263 } 3264 3265 mutex_enter(HUBD_MUTEX(hubd)); 3266 3267 status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 3268 status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 3269 3270 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 3271 "hub status=0x%x change=0x%x", status[0], status[1]); 3272 3273 freemsg(data); 3274 3275 return (USB_SUCCESS); 3276 } 3277 3278 3279 /* 3280 * hubd_open_intr_pipe: 3281 * we read all descriptors first for curiosity and then simply 3282 * open the pipe 3283 */ 3284 static int 3285 hubd_open_intr_pipe(hubd_t *hubd) 3286 { 3287 int rval; 3288 3289 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3290 "hubd_open_intr_pipe:"); 3291 3292 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE); 3293 3294 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING; 3295 mutex_exit(HUBD_MUTEX(hubd)); 3296 3297 if ((rval = usb_pipe_open(hubd->h_dip, 3298 &hubd->h_ep1_descr, &hubd->h_pipe_policy, 3299 0, &hubd->h_ep1_ph)) != USB_SUCCESS) { 3300 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3301 "open intr pipe failed (%d)", rval); 3302 3303 mutex_enter(HUBD_MUTEX(hubd)); 3304 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3305 3306 return (rval); 3307 } 3308 3309 mutex_enter(HUBD_MUTEX(hubd)); 3310 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3311 3312 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3313 "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph); 3314 3315 return (USB_SUCCESS); 3316 } 3317 3318 3319 /* 3320 * hubd_start_polling: 3321 * start or restart the polling 3322 */ 3323 static void 3324 hubd_start_polling(hubd_t *hubd, int always) 3325 { 3326 usb_intr_req_t *reqp; 3327 int rval; 3328 usb_pipe_state_t pipe_state; 3329 3330 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3331 "start polling: always=%d dev_state=%d pipe_state=%d\n\t" 3332 "thread=%d ep1_ph=0x%p", 3333 always, hubd->h_dev_state, hubd->h_intr_pipe_state, 3334 hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph); 3335 3336 /* 3337 * start or restart polling on the intr pipe 3338 * only if hotplug thread is not running 3339 */ 3340 if ((always == HUBD_ALWAYS_START_POLLING) || 3341 ((hubd->h_dev_state == USB_DEV_ONLINE) && 3342 (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3343 (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) { 3344 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3345 "start polling requested"); 3346 3347 reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP); 3348 3349 reqp->intr_client_private = (usb_opaque_t)hubd; 3350 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 3351 USB_ATTRS_AUTOCLEARING; 3352 reqp->intr_len = hubd->h_ep1_descr.wMaxPacketSize; 3353 reqp->intr_cb = hubd_read_cb; 3354 reqp->intr_exc_cb = hubd_exception_cb; 3355 mutex_exit(HUBD_MUTEX(hubd)); 3356 if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp, 3357 USB_FLAGS_SLEEP)) != USB_SUCCESS) { 3358 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 3359 "start polling failed, rval=%d", rval); 3360 usb_free_intr_req(reqp); 3361 } 3362 3363 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3364 USB_FLAGS_SLEEP); 3365 if (pipe_state != USB_PIPE_STATE_ACTIVE) { 3366 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3367 "intr pipe state=%d, rval=%d", pipe_state, rval); 3368 } 3369 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3370 "start polling request 0x%p", (void *)reqp); 3371 3372 mutex_enter(HUBD_MUTEX(hubd)); 3373 } 3374 } 3375 3376 3377 /* 3378 * hubd_stop_polling 3379 * stop polling but do not close the pipe 3380 */ 3381 static void 3382 hubd_stop_polling(hubd_t *hubd) 3383 { 3384 int rval; 3385 usb_pipe_state_t pipe_state; 3386 3387 if (hubd->h_ep1_ph) { 3388 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3389 "hubd_stop_polling:"); 3390 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED; 3391 mutex_exit(HUBD_MUTEX(hubd)); 3392 3393 usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP); 3394 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3395 USB_FLAGS_SLEEP); 3396 3397 if (pipe_state != USB_PIPE_STATE_IDLE) { 3398 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3399 "intr pipe state=%d, rval=%d", pipe_state, rval); 3400 } 3401 mutex_enter(HUBD_MUTEX(hubd)); 3402 if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) { 3403 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3404 } 3405 } 3406 } 3407 3408 3409 /* 3410 * hubd_close_intr_pipe: 3411 * close the pipe (which also stops the polling 3412 * and wait for the hotplug thread to exit 3413 */ 3414 static void 3415 hubd_close_intr_pipe(hubd_t *hubd) 3416 { 3417 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3418 "hubd_close_intr_pipe:"); 3419 3420 /* 3421 * Now that no async operation is outstanding on pipe, 3422 * we can change the state to HUBD_INTR_PIPE_CLOSING 3423 */ 3424 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING; 3425 3426 ASSERT(hubd->h_hotplug_thread == 0); 3427 3428 if (hubd->h_ep1_ph) { 3429 mutex_exit(HUBD_MUTEX(hubd)); 3430 usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP, 3431 NULL, NULL); 3432 mutex_enter(HUBD_MUTEX(hubd)); 3433 hubd->h_ep1_ph = NULL; 3434 } 3435 3436 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3437 } 3438 3439 3440 /* 3441 * hubd_exception_cb 3442 * interrupt ep1 exception callback function. 3443 * this callback executes in taskq thread context and assumes 3444 * autoclearing 3445 */ 3446 /*ARGSUSED*/ 3447 static void 3448 hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3449 { 3450 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3451 3452 USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3453 "hubd_exception_cb: " 3454 "req=0x%p cr=%d data=0x%p cb_flags=0x%x", (void *)reqp, 3455 reqp->intr_completion_reason, (void *)reqp->intr_data, 3456 reqp->intr_cb_flags); 3457 3458 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3459 3460 mutex_enter(HUBD_MUTEX(hubd)); 3461 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3462 3463 switch (reqp->intr_completion_reason) { 3464 case USB_CR_PIPE_RESET: 3465 /* only restart polling after autoclearing */ 3466 if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3467 (hubd->h_port_reset_wait == 0)) { 3468 hubd_start_polling(hubd, 0); 3469 } 3470 3471 break; 3472 case USB_CR_DEV_NOT_RESP: 3473 case USB_CR_STOPPED_POLLING: 3474 case USB_CR_PIPE_CLOSING: 3475 case USB_CR_UNSPECIFIED_ERR: 3476 /* never restart polling on these conditions */ 3477 default: 3478 /* for all others, wait for the autoclearing PIPE_RESET cb */ 3479 3480 break; 3481 } 3482 3483 usb_free_intr_req(reqp); 3484 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3485 mutex_exit(HUBD_MUTEX(hubd)); 3486 } 3487 3488 3489 /* 3490 * helper function to convert LE bytes to a portmask 3491 */ 3492 static usb_port_mask_t 3493 hubd_mblk2portmask(mblk_t *data) 3494 { 3495 int len = min(MBLKL(data), sizeof (usb_port_mask_t)); 3496 usb_port_mask_t rval = 0; 3497 int i; 3498 3499 for (i = 0; i < len; i++) { 3500 rval |= data->b_rptr[i] << (i * 8); 3501 } 3502 3503 return (rval); 3504 } 3505 3506 3507 /* 3508 * hubd_read_cb: 3509 * interrupt ep1 callback function 3510 * 3511 * the status indicates just a change on the pipe with no indication 3512 * of what the change was 3513 * 3514 * known conditions: 3515 * - reset port completion 3516 * - connect 3517 * - disconnect 3518 * 3519 * for handling the hotplugging, create a new thread that can do 3520 * synchronous usba calls 3521 */ 3522 static void 3523 hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3524 { 3525 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3526 size_t length; 3527 mblk_t *data = reqp->intr_data; 3528 int mem_flag = 0; 3529 hubd_hotplug_arg_t *arg; 3530 3531 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3532 "hubd_read_cb: ph=0x%p req=0x%p", (void *)pipe, (void *)reqp); 3533 3534 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3535 3536 /* 3537 * At present, we are not handling notification for completion of 3538 * asynchronous pipe reset, for which this data ptr could be NULL 3539 */ 3540 3541 if (data == NULL) { 3542 usb_free_intr_req(reqp); 3543 3544 return; 3545 } 3546 3547 arg = (hubd_hotplug_arg_t *)kmem_zalloc( 3548 sizeof (hubd_hotplug_arg_t), KM_SLEEP); 3549 mem_flag = 1; 3550 3551 mutex_enter(HUBD_MUTEX(hubd)); 3552 3553 if ((hubd->h_dev_state == USB_DEV_SUSPENDED) || 3554 (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) { 3555 mutex_exit(HUBD_MUTEX(hubd)); 3556 usb_free_intr_req(reqp); 3557 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3558 3559 return; 3560 } 3561 3562 ASSERT(hubd->h_ep1_ph == pipe); 3563 3564 length = MBLKL(data); 3565 3566 /* 3567 * Only look at the data and startup the hotplug thread if 3568 * there actually is data. 3569 */ 3570 if (length != 0) { 3571 usb_port_mask_t port_change = hubd_mblk2portmask(data); 3572 3573 /* 3574 * if a port change was already reported and we are waiting for 3575 * reset port completion then wake up the hotplug thread which 3576 * should be waiting on reset port completion 3577 * 3578 * if there is disconnect event instead of reset completion, let 3579 * the hotplug thread figure this out 3580 */ 3581 3582 /* remove the reset wait bits from the status */ 3583 hubd->h_port_change |= port_change & 3584 ~hubd->h_port_reset_wait; 3585 3586 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3587 "port change=0x%x port_reset_wait=0x%x", 3588 hubd->h_port_change, hubd->h_port_reset_wait); 3589 3590 /* there should be only one reset bit active at the time */ 3591 if (hubd->h_port_reset_wait & port_change) { 3592 hubd->h_port_reset_wait = 0; 3593 cv_signal(&hubd->h_cv_reset_port); 3594 } 3595 3596 /* 3597 * kick off the thread only if device is ONLINE and it is not 3598 * during attaching or detaching 3599 */ 3600 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 3601 (!DEVI_IS_ATTACHING(hubd->h_dip)) && 3602 (!DEVI_IS_DETACHING(hubd->h_dip)) && 3603 (hubd->h_port_change) && 3604 (hubd->h_hotplug_thread == 0)) { 3605 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3606 "creating hotplug thread: " 3607 "dev_state=%d", hubd->h_dev_state); 3608 3609 /* 3610 * Mark this device as busy. The will be marked idle 3611 * if the async req fails or at the exit of hotplug 3612 * thread 3613 */ 3614 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3615 3616 arg->hubd = hubd; 3617 arg->hotplug_during_attach = B_FALSE; 3618 3619 if (usb_async_req(hubd->h_dip, 3620 hubd_hotplug_thread, 3621 (void *)arg, 0) == USB_SUCCESS) { 3622 hubd->h_hotplug_thread++; 3623 mem_flag = 0; 3624 } else { 3625 /* mark this device as idle */ 3626 (void) hubd_pm_idle_component(hubd, 3627 hubd->h_dip, 0); 3628 } 3629 } 3630 } 3631 mutex_exit(HUBD_MUTEX(hubd)); 3632 3633 if (mem_flag == 1) { 3634 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3635 } 3636 3637 usb_free_intr_req(reqp); 3638 } 3639 3640 3641 /* 3642 * hubd_hotplug_thread: 3643 * handles resetting of port, and creating children 3644 * 3645 * the ports to check are indicated in h_port_change bit mask 3646 * XXX note that one time poll doesn't work on the root hub 3647 */ 3648 static void 3649 hubd_hotplug_thread(void *arg) 3650 { 3651 hubd_hotplug_arg_t *hd_arg = (hubd_hotplug_arg_t *)arg; 3652 hubd_t *hubd = hd_arg->hubd; 3653 boolean_t attach_flg = hd_arg->hotplug_during_attach; 3654 usb_port_t port; 3655 uint16_t nports; 3656 uint16_t status, change; 3657 hub_power_t *hubpm; 3658 dev_info_t *hdip = hubd->h_dip; 3659 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 3660 dev_info_t *child_dip; 3661 boolean_t online_child = B_FALSE; 3662 boolean_t offline_child = B_FALSE; 3663 boolean_t pwrup_child = B_FALSE; 3664 int prh_circ, rh_circ, chld_circ, circ, old_state; 3665 3666 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3667 "hubd_hotplug_thread: started"); 3668 3669 /* 3670 * Before console is init'd, we temporarily block the hotplug 3671 * threads so that BUS_CONFIG_ONE through hubd_bus_config() can be 3672 * processed quickly. This reduces the time needed for vfs_mountroot() 3673 * to mount the root FS from a USB disk. And on SPARC platform, 3674 * in order to load 'consconfig' successfully after OBP is gone, 3675 * we need to check 'modrootloaded' to make sure root filesystem is 3676 * available. 3677 */ 3678 while (!modrootloaded || !consconfig_console_is_ready()) { 3679 delay(drv_usectohz(10000)); 3680 } 3681 3682 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3683 3684 /* 3685 * if our bus power entry point is active, process the change 3686 * on the next notification of interrupt pipe 3687 */ 3688 mutex_enter(HUBD_MUTEX(hubd)); 3689 if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) { 3690 hubd->h_hotplug_thread--; 3691 3692 /* mark this device as idle */ 3693 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3694 mutex_exit(HUBD_MUTEX(hubd)); 3695 3696 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3697 "hubd_hotplug_thread: " 3698 "bus_power in progress/hotplugging undesirable - quit"); 3699 3700 return; 3701 } 3702 mutex_exit(HUBD_MUTEX(hubd)); 3703 3704 ndi_hold_devi(hdip); /* so we don't race with detach */ 3705 3706 mutex_enter(HUBD_MUTEX(hubd)); 3707 3708 /* is this the root hub? */ 3709 if (hdip == rh_dip) { 3710 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) { 3711 hubpm = hubd->h_hubpm; 3712 3713 /* mark the root hub as full power */ 3714 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 3715 hubpm->hubp_time_at_full_power = ddi_get_time(); 3716 mutex_exit(HUBD_MUTEX(hubd)); 3717 3718 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3719 "hubd_hotplug_thread: call pm_power_has_changed"); 3720 3721 (void) pm_power_has_changed(hdip, 0, 3722 USB_DEV_OS_FULL_PWR); 3723 3724 mutex_enter(HUBD_MUTEX(hubd)); 3725 hubd->h_dev_state = USB_DEV_ONLINE; 3726 } 3727 3728 } else { 3729 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3730 "hubd_hotplug_thread: not root hub"); 3731 } 3732 3733 mutex_exit(HUBD_MUTEX(hubd)); 3734 3735 /* 3736 * this ensures one hotplug activity per system at a time. 3737 * we enter the parent PCI node to have this serialization. 3738 * this also excludes ioctls and deathrow thread 3739 * (a bit crude but easier to debug) 3740 */ 3741 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 3742 ndi_devi_enter(rh_dip, &rh_circ); 3743 3744 /* exclude other threads */ 3745 ndi_devi_enter(hdip, &circ); 3746 mutex_enter(HUBD_MUTEX(hubd)); 3747 3748 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE); 3749 3750 nports = hubd->h_hub_descr.bNbrPorts; 3751 3752 hubd_stop_polling(hubd); 3753 3754 while ((hubd->h_dev_state == USB_DEV_ONLINE) && 3755 (hubd->h_port_change)) { 3756 /* 3757 * The 0th bit is the hub status change bit. 3758 * handle loss of local power here 3759 */ 3760 if (hubd->h_port_change & HUB_CHANGE_STATUS) { 3761 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3762 "hubd_hotplug_thread: hub status change!"); 3763 3764 /* 3765 * This should be handled properly. For now, 3766 * mask off the bit. 3767 */ 3768 hubd->h_port_change &= ~HUB_CHANGE_STATUS; 3769 3770 /* 3771 * check and ack hub status 3772 * this causes stall conditions 3773 * when local power is removed 3774 */ 3775 (void) hubd_get_hub_status(hubd); 3776 } 3777 3778 for (port = 1; port <= nports; port++) { 3779 usb_port_mask_t port_mask; 3780 boolean_t was_connected; 3781 3782 port_mask = 1 << port; 3783 was_connected = 3784 (hubd->h_port_state[port] & PORT_STATUS_CCS) && 3785 (hubd->h_children_dips[port]); 3786 3787 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3788 "hubd_hotplug_thread: " 3789 "port %d mask=0x%x change=0x%x connected=0x%x", 3790 port, port_mask, hubd->h_port_change, 3791 was_connected); 3792 3793 /* 3794 * is this a port connection that changed? 3795 */ 3796 if ((hubd->h_port_change & port_mask) == 0) { 3797 3798 continue; 3799 } 3800 hubd->h_port_change &= ~port_mask; 3801 3802 /* ack all changes */ 3803 (void) hubd_determine_port_status(hubd, port, 3804 &status, &change, HUBD_ACK_ALL_CHANGES); 3805 3806 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3807 "handle port %d:\n\t" 3808 "new status=0x%x change=0x%x was_conn=0x%x ", 3809 port, status, change, was_connected); 3810 3811 /* Recover a disabled port */ 3812 if (change & PORT_CHANGE_PESC) { 3813 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 3814 hubd->h_log_handle, 3815 "port%d Disabled - " 3816 "status=0x%x, change=0x%x", 3817 port, status, change); 3818 3819 /* 3820 * if the port was connected and is still 3821 * connected, recover the port 3822 */ 3823 if (was_connected && (status & 3824 PORT_STATUS_CCS)) { 3825 online_child |= 3826 (hubd_recover_disabled_port(hubd, 3827 port) == USB_SUCCESS); 3828 } 3829 } 3830 3831 /* 3832 * Now check what changed on the port 3833 */ 3834 if ((change & PORT_CHANGE_CSC) || attach_flg) { 3835 if ((status & PORT_STATUS_CCS) && 3836 (!was_connected)) { 3837 /* new device plugged in */ 3838 online_child |= 3839 (hubd_handle_port_connect(hubd, 3840 port) == USB_SUCCESS); 3841 3842 } else if ((status & PORT_STATUS_CCS) && 3843 was_connected) { 3844 /* 3845 * In this case we can never be sure 3846 * if the device indeed got hotplugged 3847 * or the hub is falsely reporting the 3848 * change. 3849 */ 3850 child_dip = hubd->h_children_dips[port]; 3851 3852 mutex_exit(HUBD_MUTEX(hubd)); 3853 /* 3854 * this ensures we do not race with 3855 * other threads which are detaching 3856 * the child driver at the same time. 3857 */ 3858 ndi_devi_enter(child_dip, &chld_circ); 3859 /* 3860 * Now check if the driver remains 3861 * attached. 3862 */ 3863 if (i_ddi_devi_attached(child_dip)) { 3864 /* 3865 * first post a disconnect event 3866 * to the child. 3867 */ 3868 hubd_post_event(hubd, port, 3869 USBA_EVENT_TAG_HOT_REMOVAL); 3870 mutex_enter(HUBD_MUTEX(hubd)); 3871 3872 /* 3873 * then reset the port and 3874 * recover the device 3875 */ 3876 online_child |= 3877 (hubd_handle_port_connect( 3878 hubd, port) == USB_SUCCESS); 3879 3880 mutex_exit(HUBD_MUTEX(hubd)); 3881 } 3882 3883 ndi_devi_exit(child_dip, chld_circ); 3884 mutex_enter(HUBD_MUTEX(hubd)); 3885 } else if (was_connected) { 3886 /* this is a disconnect */ 3887 mutex_exit(HUBD_MUTEX(hubd)); 3888 hubd_post_event(hubd, port, 3889 USBA_EVENT_TAG_HOT_REMOVAL); 3890 mutex_enter(HUBD_MUTEX(hubd)); 3891 3892 offline_child = B_TRUE; 3893 } 3894 } 3895 3896 /* 3897 * Check if any port is coming out of suspend 3898 */ 3899 if (change & PORT_CHANGE_PSSC) { 3900 /* a resuming device could have disconnected */ 3901 if (was_connected && 3902 hubd->h_children_dips[port]) { 3903 3904 /* device on this port resuming */ 3905 dev_info_t *dip; 3906 3907 dip = hubd->h_children_dips[port]; 3908 3909 /* 3910 * Don't raise power on detaching child 3911 */ 3912 if (!DEVI_IS_DETACHING(dip)) { 3913 /* 3914 * As this child is not 3915 * detaching, we set this 3916 * flag, causing bus_ctls 3917 * to stall detach till 3918 * pm_raise_power returns 3919 * and flag it for a deferred 3920 * raise_power. 3921 * 3922 * pm_raise_power is deferred 3923 * because we need to release 3924 * the locks first. 3925 */ 3926 hubd->h_port_state[port] |= 3927 HUBD_CHILD_RAISE_POWER; 3928 pwrup_child = B_TRUE; 3929 mutex_exit(HUBD_MUTEX(hubd)); 3930 3931 /* 3932 * make sure that child 3933 * doesn't disappear 3934 */ 3935 ndi_hold_devi(dip); 3936 3937 mutex_enter(HUBD_MUTEX(hubd)); 3938 } 3939 } 3940 } 3941 3942 /* 3943 * Check if the port is over-current 3944 */ 3945 if (change & PORT_CHANGE_OCIC) { 3946 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 3947 hubd->h_log_handle, 3948 "Port%d in over current condition, " 3949 "please check the attached device to " 3950 "clear the condition. The system will " 3951 "try to recover the port, but if not " 3952 "successful, you need to re-connect " 3953 "the hub or reboot the system to bring " 3954 "the port back to work", port); 3955 3956 if (!(status & PORT_STATUS_PPS)) { 3957 /* 3958 * Try to enable port power, but 3959 * possibly fail. Ignore failure 3960 */ 3961 (void) hubd_enable_port_power(hubd, 3962 port); 3963 3964 /* 3965 * Delay some time to avoid 3966 * over-current event to happen 3967 * too frequently in some cases 3968 */ 3969 mutex_exit(HUBD_MUTEX(hubd)); 3970 delay(drv_usectohz(500000)); 3971 mutex_enter(HUBD_MUTEX(hubd)); 3972 } 3973 } 3974 } 3975 } 3976 3977 /* release locks so we can do a devfs_clean */ 3978 mutex_exit(HUBD_MUTEX(hubd)); 3979 3980 /* delete cached dv_node's but drop locks first */ 3981 ndi_devi_exit(hdip, circ); 3982 ndi_devi_exit(rh_dip, rh_circ); 3983 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 3984 3985 (void) devfs_clean(rh_dip, NULL, 0); 3986 3987 /* now check if any children need onlining */ 3988 if (online_child) { 3989 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3990 "hubd_hotplug_thread: onlining children"); 3991 3992 (void) ndi_devi_online(hubd->h_dip, 0); 3993 } 3994 3995 /* now check if any disconnected devices need to be cleaned up */ 3996 if (offline_child) { 3997 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3998 "hubd_hotplug_thread: scheduling cleanup"); 3999 4000 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 4001 } 4002 4003 mutex_enter(HUBD_MUTEX(hubd)); 4004 4005 /* now raise power on the children that have woken up */ 4006 if (pwrup_child) { 4007 old_state = hubd->h_dev_state; 4008 hubd->h_dev_state = USB_DEV_HUB_CHILD_PWRLVL; 4009 for (port = 1; port <= nports; port++) { 4010 if (hubd->h_port_state[port] & HUBD_CHILD_RAISE_POWER) { 4011 dev_info_t *dip = hubd->h_children_dips[port]; 4012 4013 mutex_exit(HUBD_MUTEX(hubd)); 4014 4015 /* Get the device to full power */ 4016 (void) pm_busy_component(dip, 0); 4017 (void) pm_raise_power(dip, 0, 4018 USB_DEV_OS_FULL_PWR); 4019 (void) pm_idle_component(dip, 0); 4020 4021 /* release the hold on the child */ 4022 ndi_rele_devi(dip); 4023 mutex_enter(HUBD_MUTEX(hubd)); 4024 hubd->h_port_state[port] &= 4025 ~HUBD_CHILD_RAISE_POWER; 4026 } 4027 } 4028 /* 4029 * make sure that we don't accidentally 4030 * over write the disconnect state 4031 */ 4032 if (hubd->h_dev_state == USB_DEV_HUB_CHILD_PWRLVL) { 4033 hubd->h_dev_state = old_state; 4034 } 4035 } 4036 4037 /* 4038 * start polling can immediately kick off read callback 4039 * we need to set the h_hotplug_thread to 0 so that 4040 * the callback is not dropped 4041 * 4042 * if there is device during reset, still stop polling to avoid the 4043 * read callback interrupting the reset, the polling will be started 4044 * in hubd_reset_thread. 4045 */ 4046 for (port = 1; port <= MAX_PORTS; port++) { 4047 if (hubd->h_reset_port[port]) { 4048 4049 break; 4050 } 4051 } 4052 if (port > MAX_PORTS) { 4053 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 4054 } 4055 4056 /* 4057 * Earlier we would set the h_hotplug_thread = 0 before 4058 * polling was restarted so that 4059 * if there is any root hub status change interrupt, we can still kick 4060 * off the hotplug thread. This was valid when this interrupt was 4061 * delivered in hardware, and only ONE interrupt would be delivered. 4062 * Now that we poll on the root hub looking for status change in 4063 * software, this assignment is no longer required. 4064 */ 4065 hubd->h_hotplug_thread--; 4066 4067 /* mark this device as idle */ 4068 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 4069 4070 cv_broadcast(&hubd->h_cv_hotplug_dev); 4071 4072 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4073 "hubd_hotplug_thread: exit"); 4074 4075 mutex_exit(HUBD_MUTEX(hubd)); 4076 4077 ndi_rele_devi(hdip); 4078 } 4079 4080 4081 /* 4082 * hubd_handle_port_connect: 4083 * Transition a port from Disabled to Enabled. Ensure that the 4084 * port is in the correct state before attempting to 4085 * access the device. 4086 */ 4087 static int 4088 hubd_handle_port_connect(hubd_t *hubd, usb_port_t port) 4089 { 4090 int rval; 4091 int retry; 4092 long time_delay; 4093 long settling_time; 4094 uint16_t status; 4095 uint16_t change; 4096 usb_addr_t hubd_usb_addr; 4097 usba_device_t *usba_device; 4098 usb_port_status_t port_status = 0; 4099 usb_port_status_t hub_port_status = 0; 4100 4101 /* Get the hub address and port status */ 4102 usba_device = hubd->h_usba_device; 4103 mutex_enter(&usba_device->usb_mutex); 4104 hubd_usb_addr = usba_device->usb_addr; 4105 hub_port_status = usba_device->usb_port_status; 4106 mutex_exit(&usba_device->usb_mutex); 4107 4108 /* 4109 * If a device is connected, transition the 4110 * port from Disabled to the Enabled state. 4111 * The device will receive downstream packets 4112 * in the Enabled state. 4113 * 4114 * reset port and wait for the hub to report 4115 * completion 4116 */ 4117 change = status = 0; 4118 4119 /* 4120 * According to section 9.1.2 of USB 2.0 spec, the host should 4121 * wait for atleast 100ms to allow completion of an insertion 4122 * process and for power at the device to become stable. 4123 * We wait for 200 ms 4124 */ 4125 settling_time = drv_usectohz(hubd_device_delay / 5); 4126 mutex_exit(HUBD_MUTEX(hubd)); 4127 delay(settling_time); 4128 mutex_enter(HUBD_MUTEX(hubd)); 4129 4130 /* calculate 600 ms delay time */ 4131 time_delay = (6 * drv_usectohz(hubd_device_delay)) / 10; 4132 4133 for (retry = 0; (hubd->h_dev_state == USB_DEV_ONLINE) && 4134 (retry < hubd_retry_enumerate); retry++) { 4135 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4136 "resetting port%d, retry=%d", port, retry); 4137 4138 if ((rval = hubd_reset_port(hubd, port)) != USB_SUCCESS) { 4139 (void) hubd_determine_port_status(hubd, 4140 port, &status, &change, 0); 4141 4142 /* continue only if port is still connected */ 4143 if (status & PORT_STATUS_CCS) { 4144 continue; 4145 } 4146 4147 /* carry on regardless */ 4148 } 4149 4150 /* 4151 * according to USB 2.0 spec section 11.24.2.7.1.2 4152 * at the end of port reset, the hub enables the port. 4153 * But for some strange reasons, uhci port remains disabled. 4154 * And because the port remains disabled for the settling 4155 * time below, the device connected to the port gets wedged 4156 * - fails to enumerate (device not responding) 4157 * Hence, we enable it here immediately and later again after 4158 * the delay 4159 */ 4160 (void) hubd_enable_port(hubd, port); 4161 4162 /* we skip this delay in the first iteration */ 4163 if (retry) { 4164 /* 4165 * delay for device to signal disconnect/connect so 4166 * that hub properly recognizes the speed of the device 4167 */ 4168 mutex_exit(HUBD_MUTEX(hubd)); 4169 delay(settling_time); 4170 mutex_enter(HUBD_MUTEX(hubd)); 4171 4172 /* 4173 * When a low speed device is connected to any port of 4174 * PPX it has to be explicitly enabled 4175 * Also, if device intentionally signals 4176 * disconnect/connect, it will disable the port. 4177 * So enable it again. 4178 */ 4179 (void) hubd_enable_port(hubd, port); 4180 } 4181 4182 if ((rval = hubd_determine_port_status(hubd, port, &status, 4183 &change, 0)) != USB_SUCCESS) { 4184 4185 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4186 "getting status failed (%d)", rval); 4187 4188 (void) hubd_disable_port(hubd, port); 4189 4190 continue; 4191 } 4192 4193 if (status & PORT_STATUS_POCI) { 4194 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4195 "port %d overcurrent", port); 4196 4197 (void) hubd_disable_port(hubd, port); 4198 4199 /* ack changes */ 4200 (void) hubd_determine_port_status(hubd, 4201 port, &status, &change, PORT_CHANGE_OCIC); 4202 4203 continue; 4204 } 4205 4206 /* is status really OK? */ 4207 if ((status & PORT_STATUS_OK) != PORT_STATUS_OK) { 4208 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4209 "port %d status (0x%x) not OK on retry %d", 4210 port, status, retry); 4211 4212 /* check if we still have the connection */ 4213 if (!(status & PORT_STATUS_CCS)) { 4214 /* lost connection, set exit condition */ 4215 retry = hubd_retry_enumerate; 4216 4217 break; 4218 } 4219 } else { 4220 /* 4221 * Determine if the device is high or full 4222 * or low speed. 4223 */ 4224 if (status & PORT_STATUS_LSDA) { 4225 port_status = USBA_LOW_SPEED_DEV; 4226 } else if (status & PORT_STATUS_HSDA) { 4227 port_status = USBA_HIGH_SPEED_DEV; 4228 } else { 4229 port_status = USBA_FULL_SPEED_DEV; 4230 } 4231 4232 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4233 "creating child port%d, status=0x%x " 4234 "port status=0x%x", 4235 port, status, port_status); 4236 4237 /* 4238 * if the child already exists, set addrs and config 4239 * to the device post connect event to the child 4240 */ 4241 if (hubd->h_children_dips[port]) { 4242 /* set addrs to this device */ 4243 rval = hubd_setdevaddr(hubd, port); 4244 4245 /* 4246 * This delay is important for the CATC hub 4247 * to enumerate. But, avoid delay in the first 4248 * iteration 4249 */ 4250 if (retry) { 4251 mutex_exit(HUBD_MUTEX(hubd)); 4252 delay(drv_usectohz( 4253 hubd_device_delay/100)); 4254 mutex_enter(HUBD_MUTEX(hubd)); 4255 } 4256 4257 if (rval == USB_SUCCESS) { 4258 /* 4259 * if the port is resetting, check if 4260 * device's descriptors have changed. 4261 */ 4262 if ((hubd->h_reset_port[port]) && 4263 (hubd_check_same_device(hubd, 4264 port) != USB_SUCCESS)) { 4265 retry = hubd_retry_enumerate; 4266 4267 break; 4268 } 4269 4270 /* 4271 * set the default config for 4272 * this device 4273 */ 4274 hubd_setdevconfig(hubd, port); 4275 4276 /* 4277 * if we are doing Default reset, do 4278 * not post reconnect event since we 4279 * don't know where reset function is 4280 * called. 4281 */ 4282 if (hubd->h_reset_port[port]) { 4283 4284 return (USB_SUCCESS); 4285 } 4286 4287 /* 4288 * indicate to the child that 4289 * it is online again 4290 */ 4291 mutex_exit(HUBD_MUTEX(hubd)); 4292 hubd_post_event(hubd, port, 4293 USBA_EVENT_TAG_HOT_INSERTION); 4294 mutex_enter(HUBD_MUTEX(hubd)); 4295 4296 return (USB_SUCCESS); 4297 } 4298 } else { 4299 /* 4300 * We need to release access here 4301 * so that busctls on other ports can 4302 * continue and don't cause a deadlock 4303 * when busctl and removal of prom node 4304 * takes concurrently. This also ensures 4305 * busctls for attach of successfully 4306 * enumerated devices on other ports can 4307 * continue concurrently with the process 4308 * of enumerating the new devices. This 4309 * reduces the overall boot time of the system. 4310 */ 4311 rval = hubd_create_child(hubd->h_dip, 4312 hubd, 4313 hubd->h_usba_device, 4314 port_status, port, 4315 retry); 4316 if (rval == USB_SUCCESS) { 4317 usba_update_hotplug_stats(hubd->h_dip, 4318 USBA_TOTAL_HOTPLUG_SUCCESS| 4319 USBA_HOTPLUG_SUCCESS); 4320 hubd->h_total_hotplug_success++; 4321 4322 if (retry > 0) { 4323 USB_DPRINTF_L2( 4324 DPRINT_MASK_HOTPLUG, 4325 hubd->h_log_handle, 4326 "device on port %d " 4327 "enumerated after %d %s", 4328 port, retry, 4329 (retry > 1) ? "retries" : 4330 "retry"); 4331 4332 } 4333 4334 return (USB_SUCCESS); 4335 } 4336 } 4337 } 4338 4339 /* wait a while until it settles? */ 4340 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4341 "disabling port %d again", port); 4342 4343 (void) hubd_disable_port(hubd, port); 4344 if (retry) { 4345 mutex_exit(HUBD_MUTEX(hubd)); 4346 delay(time_delay); 4347 mutex_enter(HUBD_MUTEX(hubd)); 4348 } 4349 4350 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4351 "retrying on port %d", port); 4352 } 4353 4354 if (retry >= hubd_retry_enumerate) { 4355 /* 4356 * If it is a High Speed Root Hub and connected device 4357 * Is a Low/Full Speed, it will be handled by USB 1.1 4358 * Host Controller. In this case, USB 2.0 Host Controller 4359 * will transfer the ownership of this port to USB 1.1 4360 * Host Controller. So don't display any error message on 4361 * the console. 4362 */ 4363 if ((hubd_usb_addr == ROOT_HUB_ADDR) && 4364 (hub_port_status == USBA_HIGH_SPEED_DEV) && 4365 (port_status != USBA_HIGH_SPEED_DEV)) { 4366 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4367 hubd->h_log_handle, 4368 "hubd_handle_port_connect: Low/Full speed " 4369 "device is connected to High Speed root hub"); 4370 } else { 4371 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4372 hubd->h_log_handle, 4373 "Connecting device on port %d failed", port); 4374 } 4375 4376 (void) hubd_disable_port(hubd, port); 4377 usba_update_hotplug_stats(hubd->h_dip, 4378 USBA_TOTAL_HOTPLUG_FAILURE|USBA_HOTPLUG_FAILURE); 4379 hubd->h_total_hotplug_failure++; 4380 4381 /* 4382 * the port should be automagically 4383 * disabled but just in case, we do 4384 * it here 4385 */ 4386 (void) hubd_disable_port(hubd, port); 4387 4388 /* ack all changes because we disabled this port */ 4389 (void) hubd_determine_port_status(hubd, 4390 port, &status, &change, HUBD_ACK_ALL_CHANGES); 4391 4392 } 4393 4394 return (USB_FAILURE); 4395 } 4396 4397 4398 /* 4399 * hubd_get_hub_status: 4400 */ 4401 static int 4402 hubd_get_hub_status(hubd_t *hubd) 4403 { 4404 int rval; 4405 usb_cr_t completion_reason; 4406 usb_cb_flags_t cb_flags; 4407 uint16_t stword[2]; 4408 uint16_t status; 4409 uint16_t change; 4410 usb_cfg_descr_t cfg_descr; 4411 size_t cfg_length; 4412 uchar_t *usb_cfg; 4413 uint8_t MaxPower; 4414 usb_hub_descr_t *hub_descr; 4415 usb_port_t port; 4416 4417 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4418 "hubd_get_hub_status:"); 4419 4420 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4421 4422 if ((hubd_get_hub_status_words(hubd, stword)) != USB_SUCCESS) { 4423 4424 return (USB_FAILURE); 4425 } 4426 status = stword[0]; 4427 change = stword[1]; 4428 4429 mutex_exit(HUBD_MUTEX(hubd)); 4430 4431 /* Obtain the raw configuration descriptor */ 4432 usb_cfg = usb_get_raw_cfg_data(hubd->h_dip, &cfg_length); 4433 4434 /* get configuration descriptor */ 4435 rval = usb_parse_cfg_descr(usb_cfg, cfg_length, 4436 &cfg_descr, USB_CFG_DESCR_SIZE); 4437 4438 if (rval != USB_CFG_DESCR_SIZE) { 4439 4440 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4441 "get hub configuration descriptor failed."); 4442 4443 mutex_enter(HUBD_MUTEX(hubd)); 4444 4445 return (USB_FAILURE); 4446 } else { 4447 MaxPower = cfg_descr.bMaxPower; 4448 } 4449 4450 /* check if local power status changed. */ 4451 if (change & C_HUB_LOCAL_POWER_STATUS) { 4452 4453 /* 4454 * local power has been lost, check the maximum 4455 * power consumption of current configuration. 4456 * see USB2.0 spec Table 11-12. 4457 */ 4458 if (status & HUB_LOCAL_POWER_STATUS) { 4459 4460 if (MaxPower == 0) { 4461 4462 /* 4463 * Self-powered only hub. Because it could 4464 * not draw any power from USB bus. 4465 * It can't work well on this condition. 4466 */ 4467 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 4468 hubd->h_log_handle, 4469 "local power has been lost, " 4470 "please disconnect hub"); 4471 } else { 4472 4473 /* 4474 * Bus-powered only or self/bus-powered hub. 4475 */ 4476 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 4477 hubd->h_log_handle, 4478 "local power has been lost," 4479 "the hub could draw %d" 4480 " mA power from the USB bus.", 4481 2*MaxPower); 4482 } 4483 4484 } 4485 4486 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4487 "clearing feature C_HUB_LOCAL_POWER "); 4488 4489 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4490 hubd->h_default_pipe, 4491 HUB_HANDLE_HUB_FEATURE_TYPE, 4492 USB_REQ_CLEAR_FEATURE, 4493 CFS_C_HUB_LOCAL_POWER, 4494 0, 4495 0, 4496 NULL, 0, 4497 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4498 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4499 hubd->h_log_handle, 4500 "clear feature C_HUB_LOCAL_POWER " 4501 "failed (%d 0x%x %d)", 4502 rval, completion_reason, cb_flags); 4503 } 4504 4505 } 4506 4507 if (change & C_HUB_OVER_CURRENT) { 4508 4509 if (status & HUB_OVER_CURRENT) { 4510 4511 if (usba_is_root_hub(hubd->h_dip)) { 4512 /* 4513 * The root hub should be automatically 4514 * recovered when over-current condition is 4515 * cleared. But there might be exception and 4516 * need user interaction to recover. 4517 */ 4518 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4519 hubd->h_log_handle, 4520 "Root hub over current condition, " 4521 "please check your system to clear the " 4522 "condition as soon as possible. And you " 4523 "may need to reboot the system to bring " 4524 "the root hub back to work if it cannot " 4525 "recover automatically"); 4526 } else { 4527 /* 4528 * The driver would try to recover port power 4529 * on over current condition. When the recovery 4530 * fails, the user may still need to offline 4531 * this hub in order to recover. 4532 * The port power is automatically disabled, 4533 * so we won't see disconnects. 4534 */ 4535 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4536 hubd->h_log_handle, 4537 "Hub global over current condition, " 4538 "please disconnect the devices connected " 4539 "to the hub to clear the condition. And " 4540 "you may need to re-connect the hub if " 4541 "the ports do not work"); 4542 } 4543 } 4544 4545 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4546 "clearing feature C_HUB_OVER_CURRENT"); 4547 4548 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4549 hubd->h_default_pipe, 4550 HUB_HANDLE_HUB_FEATURE_TYPE, 4551 USB_REQ_CLEAR_FEATURE, 4552 CFS_C_HUB_OVER_CURRENT, 4553 0, 4554 0, 4555 NULL, 0, 4556 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4557 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4558 hubd->h_log_handle, 4559 "clear feature C_HUB_OVER_CURRENT " 4560 "failed (%d 0x%x %d)", 4561 rval, completion_reason, cb_flags); 4562 } 4563 4564 /* 4565 * Try to recover all port power if they are turned off. 4566 * Don't do this for root hub, but rely on the root hub 4567 * to recover itself. 4568 */ 4569 if (!usba_is_root_hub(hubd->h_dip)) { 4570 4571 mutex_enter(HUBD_MUTEX(hubd)); 4572 4573 /* 4574 * Only check the power status of the 1st port 4575 * since all port power status should be the same. 4576 */ 4577 (void) hubd_determine_port_status(hubd, 1, &status, 4578 &change, 0); 4579 4580 if (status & PORT_STATUS_PPS) { 4581 4582 return (USB_SUCCESS); 4583 } 4584 4585 hub_descr = &hubd->h_hub_descr; 4586 4587 for (port = 1; port <= hub_descr->bNbrPorts; 4588 port++) { 4589 4590 (void) hubd_enable_port_power(hubd, port); 4591 } 4592 4593 mutex_exit(HUBD_MUTEX(hubd)); 4594 4595 /* 4596 * Delay some time to avoid over-current event 4597 * to happen too frequently in some cases 4598 */ 4599 delay(drv_usectohz(500000)); 4600 } 4601 } 4602 4603 mutex_enter(HUBD_MUTEX(hubd)); 4604 4605 return (USB_SUCCESS); 4606 } 4607 4608 4609 /* 4610 * hubd_reset_port: 4611 */ 4612 static int 4613 hubd_reset_port(hubd_t *hubd, usb_port_t port) 4614 { 4615 int rval; 4616 usb_cr_t completion_reason; 4617 usb_cb_flags_t cb_flags; 4618 usb_port_mask_t port_mask = 1 << port; 4619 mblk_t *data; 4620 uint16_t status; 4621 uint16_t change; 4622 int i; 4623 clock_t delta; 4624 4625 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4626 "hubd_reset_port: port=%d", port); 4627 4628 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4629 4630 hubd->h_port_reset_wait |= port_mask; 4631 4632 mutex_exit(HUBD_MUTEX(hubd)); 4633 4634 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4635 hubd->h_default_pipe, 4636 HUB_HANDLE_PORT_FEATURE_TYPE, 4637 USB_REQ_SET_FEATURE, 4638 CFS_PORT_RESET, 4639 port, 4640 0, 4641 NULL, 0, 4642 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4643 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4644 "reset port%d failed (%d 0x%x %d)", 4645 port, completion_reason, cb_flags, rval); 4646 4647 mutex_enter(HUBD_MUTEX(hubd)); 4648 4649 return (USB_FAILURE); 4650 } 4651 4652 mutex_enter(HUBD_MUTEX(hubd)); 4653 4654 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4655 "waiting on cv for reset completion"); 4656 4657 /* 4658 * wait for port status change event 4659 */ 4660 delta = drv_usectohz(hubd_device_delay / 10); 4661 for (i = 0; i < hubd_retry_enumerate; i++) { 4662 /* 4663 * start polling ep1 for receiving notification on 4664 * reset completion 4665 */ 4666 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 4667 4668 /* 4669 * sleep a max of 100ms for reset completion 4670 * notification to be received 4671 */ 4672 if (hubd->h_port_reset_wait & port_mask) { 4673 rval = cv_reltimedwait(&hubd->h_cv_reset_port, 4674 &hubd->h_mutex, delta, TR_CLOCK_TICK); 4675 if ((rval <= 0) && 4676 (hubd->h_port_reset_wait & port_mask)) { 4677 /* we got woken up because of a timeout */ 4678 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4679 hubd->h_log_handle, 4680 "timeout: reset port=%d failed", port); 4681 4682 hubd->h_port_reset_wait &= ~port_mask; 4683 4684 hubd_stop_polling(hubd); 4685 4686 return (USB_FAILURE); 4687 } 4688 } 4689 4690 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4691 "reset completion received"); 4692 4693 hubd_stop_polling(hubd); 4694 4695 data = NULL; 4696 4697 /* check status to determine whether reset completed */ 4698 mutex_exit(HUBD_MUTEX(hubd)); 4699 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4700 hubd->h_default_pipe, 4701 HUB_GET_PORT_STATUS_TYPE, 4702 USB_REQ_GET_STATUS, 4703 0, 4704 port, 4705 GET_STATUS_LENGTH, 4706 &data, 0, 4707 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4708 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4709 hubd->h_log_handle, 4710 "get status port%d failed (%d 0x%x %d)", 4711 port, completion_reason, cb_flags, rval); 4712 4713 if (data) { 4714 freemsg(data); 4715 data = NULL; 4716 } 4717 mutex_enter(HUBD_MUTEX(hubd)); 4718 4719 continue; 4720 } 4721 4722 status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4723 change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4724 4725 freemsg(data); 4726 4727 /* continue only if port is still connected */ 4728 if (!(status & PORT_STATUS_CCS)) { 4729 4730 /* lost connection, set exit condition */ 4731 i = hubd_retry_enumerate; 4732 4733 mutex_enter(HUBD_MUTEX(hubd)); 4734 4735 break; 4736 } 4737 4738 if (status & PORT_STATUS_PRS) { 4739 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4740 "port%d reset active", port); 4741 mutex_enter(HUBD_MUTEX(hubd)); 4742 4743 continue; 4744 } else { 4745 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4746 "port%d reset inactive", port); 4747 } 4748 4749 if (change & PORT_CHANGE_PRSC) { 4750 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4751 "clearing feature CFS_C_PORT_RESET"); 4752 4753 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4754 hubd->h_default_pipe, 4755 HUB_HANDLE_PORT_FEATURE_TYPE, 4756 USB_REQ_CLEAR_FEATURE, 4757 CFS_C_PORT_RESET, 4758 port, 4759 0, 4760 NULL, 0, 4761 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 4762 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4763 hubd->h_log_handle, 4764 "clear feature CFS_C_PORT_RESET" 4765 " port%d failed (%d 0x%x %d)", 4766 port, completion_reason, cb_flags, rval); 4767 } 4768 } 4769 mutex_enter(HUBD_MUTEX(hubd)); 4770 4771 break; 4772 } 4773 4774 if (i >= hubd_retry_enumerate) { 4775 /* port reset has failed */ 4776 rval = USB_FAILURE; 4777 } 4778 4779 return (rval); 4780 } 4781 4782 4783 /* 4784 * hubd_enable_port: 4785 * this may fail if the hub as been disconnected 4786 */ 4787 static int 4788 hubd_enable_port(hubd_t *hubd, usb_port_t port) 4789 { 4790 int rval; 4791 usb_cr_t completion_reason; 4792 usb_cb_flags_t cb_flags; 4793 4794 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4795 "hubd_enable_port: port=%d", port); 4796 4797 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4798 4799 mutex_exit(HUBD_MUTEX(hubd)); 4800 4801 /* Do not issue a SetFeature(PORT_ENABLE) on external hubs */ 4802 if (!usba_is_root_hub(hubd->h_dip)) { 4803 mutex_enter(HUBD_MUTEX(hubd)); 4804 4805 return (USB_SUCCESS); 4806 } 4807 4808 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4809 hubd->h_default_pipe, 4810 HUB_HANDLE_PORT_FEATURE_TYPE, 4811 USB_REQ_SET_FEATURE, 4812 CFS_PORT_ENABLE, 4813 port, 4814 0, 4815 NULL, 0, 4816 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4817 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4818 "enable port%d failed (%d 0x%x %d)", 4819 port, completion_reason, cb_flags, rval); 4820 } 4821 4822 mutex_enter(HUBD_MUTEX(hubd)); 4823 4824 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4825 "enabling port done"); 4826 4827 return (rval); 4828 } 4829 4830 4831 /* 4832 * hubd_disable_port 4833 */ 4834 static int 4835 hubd_disable_port(hubd_t *hubd, usb_port_t port) 4836 { 4837 int rval; 4838 usb_cr_t completion_reason; 4839 usb_cb_flags_t cb_flags; 4840 4841 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4842 "hubd_disable_port: port=%d", port); 4843 4844 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4845 4846 mutex_exit(HUBD_MUTEX(hubd)); 4847 4848 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4849 hubd->h_default_pipe, 4850 HUB_HANDLE_PORT_FEATURE_TYPE, 4851 USB_REQ_CLEAR_FEATURE, 4852 CFS_PORT_ENABLE, 4853 port, 4854 0, 4855 NULL, 0, 4856 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4857 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4858 "disable port%d failed (%d 0x%x %d)", port, 4859 completion_reason, cb_flags, rval); 4860 mutex_enter(HUBD_MUTEX(hubd)); 4861 4862 return (USB_FAILURE); 4863 } 4864 4865 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4866 "clearing feature CFS_C_PORT_ENABLE"); 4867 4868 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4869 hubd->h_default_pipe, 4870 HUB_HANDLE_PORT_FEATURE_TYPE, 4871 USB_REQ_CLEAR_FEATURE, 4872 CFS_C_PORT_ENABLE, 4873 port, 4874 0, 4875 NULL, 0, 4876 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4877 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4878 hubd->h_log_handle, 4879 "clear feature CFS_C_PORT_ENABLE port%d failed " 4880 "(%d 0x%x %d)", 4881 port, completion_reason, cb_flags, rval); 4882 4883 mutex_enter(HUBD_MUTEX(hubd)); 4884 4885 return (USB_FAILURE); 4886 } 4887 4888 mutex_enter(HUBD_MUTEX(hubd)); 4889 4890 return (USB_SUCCESS); 4891 } 4892 4893 4894 /* 4895 * hubd_determine_port_status: 4896 */ 4897 static int 4898 hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 4899 uint16_t *status, uint16_t *change, uint_t ack_flag) 4900 { 4901 int rval; 4902 mblk_t *data = NULL; 4903 usb_cr_t completion_reason; 4904 usb_cb_flags_t cb_flags; 4905 4906 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4907 "hubd_determine_port_status: port=%d, state=0x%x ack=0x%x", port, 4908 hubd->h_port_state[port], ack_flag); 4909 4910 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4911 4912 mutex_exit(HUBD_MUTEX(hubd)); 4913 4914 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4915 hubd->h_default_pipe, 4916 HUB_GET_PORT_STATUS_TYPE, 4917 USB_REQ_GET_STATUS, 4918 0, 4919 port, 4920 GET_STATUS_LENGTH, 4921 &data, 0, 4922 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4923 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4924 "port=%d get status failed (%d 0x%x %d)", 4925 port, completion_reason, cb_flags, rval); 4926 4927 if (data) { 4928 freemsg(data); 4929 } 4930 4931 *status = *change = 0; 4932 mutex_enter(HUBD_MUTEX(hubd)); 4933 4934 return (rval); 4935 } 4936 4937 mutex_enter(HUBD_MUTEX(hubd)); 4938 if (MBLKL(data) != GET_STATUS_LENGTH) { 4939 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4940 "port %d: length incorrect %ld", 4941 port, MBLKL(data)); 4942 freemsg(data); 4943 *status = *change = 0; 4944 4945 return (rval); 4946 } 4947 4948 4949 *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4950 *change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4951 4952 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4953 "port%d status=0x%x, change=0x%x", port, *status, *change); 4954 4955 freemsg(data); 4956 4957 if (*status & PORT_STATUS_CCS) { 4958 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4959 "port%d connected", port); 4960 4961 hubd->h_port_state[port] |= (PORT_STATUS_CCS & ack_flag); 4962 } else { 4963 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4964 "port%d disconnected", port); 4965 4966 hubd->h_port_state[port] &= ~(PORT_STATUS_CCS & ack_flag); 4967 } 4968 4969 if (*status & PORT_STATUS_PES) { 4970 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4971 "port%d enabled", port); 4972 4973 hubd->h_port_state[port] |= (PORT_STATUS_PES & ack_flag); 4974 } else { 4975 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4976 "port%d disabled", port); 4977 4978 hubd->h_port_state[port] &= ~(PORT_STATUS_PES & ack_flag); 4979 } 4980 4981 if (*status & PORT_STATUS_PSS) { 4982 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4983 "port%d suspended", port); 4984 4985 hubd->h_port_state[port] |= (PORT_STATUS_PSS & ack_flag); 4986 } else { 4987 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4988 "port%d not suspended", port); 4989 4990 hubd->h_port_state[port] &= ~(PORT_STATUS_PSS & ack_flag); 4991 } 4992 4993 if (*change & PORT_CHANGE_PRSC) { 4994 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4995 "port%d reset completed", port); 4996 4997 hubd->h_port_state[port] |= (PORT_CHANGE_PRSC & ack_flag); 4998 } else { 4999 5000 hubd->h_port_state[port] &= ~(PORT_CHANGE_PRSC & ack_flag); 5001 } 5002 5003 if (*status & PORT_STATUS_POCI) { 5004 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5005 "port%d overcurrent!", port); 5006 5007 hubd->h_port_state[port] |= (PORT_STATUS_POCI & ack_flag); 5008 } else { 5009 5010 hubd->h_port_state[port] &= ~(PORT_STATUS_POCI & ack_flag); 5011 } 5012 5013 if (*status & PORT_STATUS_PRS) { 5014 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5015 "port%d reset active", port); 5016 5017 hubd->h_port_state[port] |= (PORT_STATUS_PRS & ack_flag); 5018 } else { 5019 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5020 "port%d reset inactive", port); 5021 5022 hubd->h_port_state[port] &= ~(PORT_STATUS_PRS & ack_flag); 5023 } 5024 if (*status & PORT_STATUS_PPS) { 5025 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5026 "port%d power on", port); 5027 5028 hubd->h_port_state[port] |= (PORT_STATUS_PPS & ack_flag); 5029 } else { 5030 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5031 "port%d power off", port); 5032 5033 hubd->h_port_state[port] &= ~(PORT_STATUS_PPS & ack_flag); 5034 } 5035 if (*status & PORT_STATUS_LSDA) { 5036 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5037 "port%d low speed", port); 5038 5039 hubd->h_port_state[port] |= (PORT_STATUS_LSDA & ack_flag); 5040 } else { 5041 hubd->h_port_state[port] &= ~(PORT_STATUS_LSDA & ack_flag); 5042 if (*status & PORT_STATUS_HSDA) { 5043 USB_DPRINTF_L3(DPRINT_MASK_PORT, 5044 hubd->h_log_handle, "port%d " 5045 "high speed", port); 5046 5047 hubd->h_port_state[port] |= 5048 (PORT_STATUS_HSDA & ack_flag); 5049 } else { 5050 USB_DPRINTF_L3(DPRINT_MASK_PORT, 5051 hubd->h_log_handle, "port%d " 5052 "full speed", port); 5053 5054 hubd->h_port_state[port] &= 5055 ~(PORT_STATUS_HSDA & ack_flag); 5056 } 5057 } 5058 5059 /* 5060 * Acknowledge connection, enable, reset status 5061 */ 5062 if (ack_flag) { 5063 mutex_exit(HUBD_MUTEX(hubd)); 5064 if (*change & PORT_CHANGE_CSC & ack_flag) { 5065 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5066 "clearing feature CFS_C_PORT_CONNECTION"); 5067 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5068 hubd->h_default_pipe, 5069 HUB_HANDLE_PORT_FEATURE_TYPE, 5070 USB_REQ_CLEAR_FEATURE, 5071 CFS_C_PORT_CONNECTION, 5072 port, 5073 0, NULL, 0, 5074 &completion_reason, &cb_flags, 0)) != 5075 USB_SUCCESS) { 5076 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5077 hubd->h_log_handle, 5078 "clear feature CFS_C_PORT_CONNECTION" 5079 " port%d failed (%d 0x%x %d)", 5080 port, completion_reason, cb_flags, rval); 5081 } 5082 } 5083 if (*change & PORT_CHANGE_PESC & ack_flag) { 5084 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5085 "clearing feature CFS_C_PORT_ENABLE"); 5086 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5087 hubd->h_default_pipe, 5088 HUB_HANDLE_PORT_FEATURE_TYPE, 5089 USB_REQ_CLEAR_FEATURE, 5090 CFS_C_PORT_ENABLE, 5091 port, 5092 0, NULL, 0, 5093 &completion_reason, &cb_flags, 0)) != 5094 USB_SUCCESS) { 5095 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5096 hubd->h_log_handle, 5097 "clear feature CFS_C_PORT_ENABLE" 5098 " port%d failed (%d 0x%x %d)", 5099 port, completion_reason, cb_flags, rval); 5100 } 5101 } 5102 if (*change & PORT_CHANGE_PSSC & ack_flag) { 5103 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5104 "clearing feature CFS_C_PORT_SUSPEND"); 5105 5106 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5107 hubd->h_default_pipe, 5108 HUB_HANDLE_PORT_FEATURE_TYPE, 5109 USB_REQ_CLEAR_FEATURE, 5110 CFS_C_PORT_SUSPEND, 5111 port, 5112 0, NULL, 0, 5113 &completion_reason, &cb_flags, 0)) != 5114 USB_SUCCESS) { 5115 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5116 hubd->h_log_handle, 5117 "clear feature CFS_C_PORT_SUSPEND" 5118 " port%d failed (%d 0x%x %d)", 5119 port, completion_reason, cb_flags, rval); 5120 } 5121 } 5122 if (*change & PORT_CHANGE_OCIC & ack_flag) { 5123 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5124 "clearing feature CFS_C_PORT_OVER_CURRENT"); 5125 5126 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5127 hubd->h_default_pipe, 5128 HUB_HANDLE_PORT_FEATURE_TYPE, 5129 USB_REQ_CLEAR_FEATURE, 5130 CFS_C_PORT_OVER_CURRENT, 5131 port, 5132 0, NULL, 0, 5133 &completion_reason, &cb_flags, 0)) != 5134 USB_SUCCESS) { 5135 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5136 hubd->h_log_handle, 5137 "clear feature CFS_C_PORT_OVER_CURRENT" 5138 " port%d failed (%d 0x%x %d)", 5139 port, completion_reason, cb_flags, rval); 5140 } 5141 } 5142 if (*change & PORT_CHANGE_PRSC & ack_flag) { 5143 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 5144 "clearing feature CFS_C_PORT_RESET"); 5145 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5146 hubd->h_default_pipe, 5147 HUB_HANDLE_PORT_FEATURE_TYPE, 5148 USB_REQ_CLEAR_FEATURE, 5149 CFS_C_PORT_RESET, 5150 port, 5151 0, NULL, 0, 5152 &completion_reason, &cb_flags, 0)) != 5153 USB_SUCCESS) { 5154 USB_DPRINTF_L2(DPRINT_MASK_PORT, 5155 hubd->h_log_handle, 5156 "clear feature CFS_C_PORT_RESET" 5157 " port%d failed (%d 0x%x %d)", 5158 port, completion_reason, cb_flags, rval); 5159 } 5160 } 5161 mutex_enter(HUBD_MUTEX(hubd)); 5162 } 5163 5164 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5165 "new port%d state 0x%x", port, hubd->h_port_state[port]); 5166 5167 5168 return (USB_SUCCESS); 5169 } 5170 5171 5172 /* 5173 * hubd_recover_disabled_port 5174 * if the port got disabled because of an error 5175 * enable it. If hub doesn't suport enable port, 5176 * reset the port to bring the device to life again 5177 */ 5178 static int 5179 hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port) 5180 { 5181 uint16_t status; 5182 uint16_t change; 5183 int rval = USB_FAILURE; 5184 5185 /* first try enabling the port */ 5186 (void) hubd_enable_port(hubd, port); 5187 5188 /* read the port status */ 5189 (void) hubd_determine_port_status(hubd, port, &status, &change, 5190 PORT_CHANGE_PESC); 5191 5192 if (status & PORT_STATUS_PES) { 5193 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5194 "Port%d now Enabled", port); 5195 } else if (status & PORT_STATUS_CCS) { 5196 /* first post a disconnect event to the child */ 5197 mutex_exit(HUBD_MUTEX(hubd)); 5198 hubd_post_event(hubd, port, USBA_EVENT_TAG_HOT_REMOVAL); 5199 mutex_enter(HUBD_MUTEX(hubd)); 5200 5201 /* then reset the port and recover the device */ 5202 rval = hubd_handle_port_connect(hubd, port); 5203 5204 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5205 "Port%d now Enabled by force", port); 5206 } 5207 5208 return (rval); 5209 } 5210 5211 5212 /* 5213 * hubd_enable_all_port_power: 5214 */ 5215 static int 5216 hubd_enable_all_port_power(hubd_t *hubd) 5217 { 5218 usb_hub_descr_t *hub_descr; 5219 int wait; 5220 usb_port_t port; 5221 uint_t retry; 5222 uint16_t status; 5223 uint16_t change; 5224 5225 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5226 "hubd_enable_all_port_power"); 5227 5228 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5229 5230 hub_descr = &hubd->h_hub_descr; 5231 5232 /* 5233 * According to section 11.11 of USB, for hubs with no power 5234 * switches, bPwrOn2PwrGood is zero. But we wait for some 5235 * arbitrary time to enable power to become stable. 5236 * 5237 * If an hub supports port power switching, we need to wait 5238 * at least 20ms before accessing corresponding usb port. 5239 */ 5240 if ((hub_descr->wHubCharacteristics & 5241 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 5242 wait = hubd_device_delay / 10; 5243 } else { 5244 wait = max(HUB_DEFAULT_POPG, 5245 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 5246 } 5247 5248 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5249 "hubd_enable_all_port_power: popg=%d wait=%d", 5250 hub_descr->bPwrOn2PwrGood, wait); 5251 5252 /* 5253 * Enable power per port. we ignore gang power and power mask 5254 * and always enable all ports one by one. 5255 */ 5256 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 5257 /* 5258 * Transition the port from the Powered Off to the 5259 * Disconnected state by supplying power to the port. 5260 */ 5261 USB_DPRINTF_L4(DPRINT_MASK_PORT, 5262 hubd->h_log_handle, 5263 "hubd_enable_all_port_power: power port=%d", port); 5264 5265 (void) hubd_enable_port_power(hubd, port); 5266 } 5267 5268 mutex_exit(HUBD_MUTEX(hubd)); 5269 delay(drv_usectohz(wait)); 5270 mutex_enter(HUBD_MUTEX(hubd)); 5271 5272 /* For retry if any, use some extra delay */ 5273 wait = max(wait, hubd_device_delay / 10); 5274 5275 /* Check each port power status for a given usb hub */ 5276 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 5277 5278 /* Get port status */ 5279 (void) hubd_determine_port_status(hubd, port, 5280 &status, &change, 0); 5281 5282 for (retry = 0; ((!(status & PORT_STATUS_PPS)) && 5283 (retry < HUBD_PORT_RETRY)); retry++) { 5284 5285 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5286 "Retry is in progress %d: port %d status %d", 5287 retry, port, status); 5288 5289 (void) hubd_enable_port_power(hubd, port); 5290 5291 mutex_exit(HUBD_MUTEX(hubd)); 5292 delay(drv_usectohz(wait)); 5293 mutex_enter(HUBD_MUTEX(hubd)); 5294 5295 /* Get port status */ 5296 (void) hubd_determine_port_status(hubd, port, 5297 &status, &change, 0); 5298 } 5299 5300 /* Print warning message if port has no power */ 5301 if (!(status & PORT_STATUS_PPS)) { 5302 5303 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5304 "hubd_enable_all_port_power: port %d power-on " 5305 "failed, port status 0x%x", port, status); 5306 } 5307 } 5308 5309 return (USB_SUCCESS); 5310 } 5311 5312 5313 /* 5314 * hubd_enable_port_power: 5315 * enable individual port power 5316 */ 5317 static int 5318 hubd_enable_port_power(hubd_t *hubd, usb_port_t port) 5319 { 5320 int rval; 5321 usb_cr_t completion_reason; 5322 usb_cb_flags_t cb_flags; 5323 5324 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5325 "hubd_enable_port_power: port=%d", port); 5326 5327 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5328 ASSERT(hubd->h_default_pipe != 0); 5329 5330 mutex_exit(HUBD_MUTEX(hubd)); 5331 5332 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5333 hubd->h_default_pipe, 5334 HUB_HANDLE_PORT_FEATURE_TYPE, 5335 USB_REQ_SET_FEATURE, 5336 CFS_PORT_POWER, 5337 port, 5338 0, NULL, 0, 5339 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5340 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5341 "set port power failed (%d 0x%x %d)", 5342 completion_reason, cb_flags, rval); 5343 mutex_enter(HUBD_MUTEX(hubd)); 5344 5345 return (USB_FAILURE); 5346 } else { 5347 mutex_enter(HUBD_MUTEX(hubd)); 5348 hubd->h_port_state[port] |= PORT_STATUS_PPS; 5349 5350 return (USB_SUCCESS); 5351 } 5352 } 5353 5354 5355 /* 5356 * hubd_disable_all_port_power: 5357 */ 5358 static int 5359 hubd_disable_all_port_power(hubd_t *hubd) 5360 { 5361 usb_port_t port; 5362 5363 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5364 "hubd_disable_all_port_power"); 5365 5366 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5367 5368 /* 5369 * disable power per port, ignore gang power and power mask 5370 */ 5371 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 5372 (void) hubd_disable_port_power(hubd, port); 5373 } 5374 5375 return (USB_SUCCESS); 5376 } 5377 5378 5379 /* 5380 * hubd_disable_port_power: 5381 * disable individual port power 5382 */ 5383 static int 5384 hubd_disable_port_power(hubd_t *hubd, usb_port_t port) 5385 { 5386 int rval; 5387 usb_cr_t completion_reason; 5388 usb_cb_flags_t cb_flags; 5389 5390 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5391 "hubd_disable_port_power: port=%d", port); 5392 5393 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5394 5395 mutex_exit(HUBD_MUTEX(hubd)); 5396 5397 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5398 hubd->h_default_pipe, 5399 HUB_HANDLE_PORT_FEATURE_TYPE, 5400 USB_REQ_CLEAR_FEATURE, 5401 CFS_PORT_POWER, 5402 port, 5403 0, NULL, 0, 5404 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5405 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5406 "clearing port%d power failed (%d 0x%x %d)", 5407 port, completion_reason, cb_flags, rval); 5408 5409 mutex_enter(HUBD_MUTEX(hubd)); 5410 5411 return (USB_FAILURE); 5412 } else { 5413 5414 mutex_enter(HUBD_MUTEX(hubd)); 5415 ASSERT(completion_reason == 0); 5416 hubd->h_port_state[port] &= ~PORT_STATUS_PPS; 5417 5418 return (USB_SUCCESS); 5419 } 5420 } 5421 5422 5423 /* 5424 * Search the database of user preferences and find out the preferred 5425 * configuration for this new device 5426 */ 5427 int 5428 hubd_select_device_configuration(hubd_t *hubd, usb_port_t port, 5429 dev_info_t *child_dip, usba_device_t *child_ud) 5430 { 5431 char *pathname = NULL; 5432 char *tmp_path = NULL; 5433 int user_conf; 5434 int pathlen; 5435 usb_dev_descr_t *usbdev_ptr; 5436 usba_configrec_t *user_pref; 5437 5438 mutex_enter(&child_ud->usb_mutex); 5439 usbdev_ptr = child_ud->usb_dev_descr; 5440 mutex_exit(&child_ud->usb_mutex); 5441 5442 /* try to get pathname for this device */ 5443 tmp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5444 (void) ddi_pathname(child_dip, tmp_path); 5445 5446 pathlen = strlen(tmp_path) + 32; 5447 pathname = kmem_zalloc(pathlen, KM_SLEEP); 5448 5449 /* 5450 * We haven't initialized the node and it doesn't have an address 5451 * yet. Append port number to the physical pathname 5452 */ 5453 (void) sprintf(pathname, "%s@%d", tmp_path, port); 5454 5455 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5456 "hubd_select_device_configuration: Device=%s\n\t" 5457 "Child path=%s", 5458 usba_get_mfg_prod_sn_str(child_dip, tmp_path, MAXPATHLEN), 5459 pathname); 5460 kmem_free(tmp_path, MAXPATHLEN); 5461 5462 5463 /* database search for user preferences */ 5464 user_pref = usba_devdb_get_user_preferences(usbdev_ptr->idVendor, 5465 usbdev_ptr->idProduct, child_ud->usb_serialno_str, pathname); 5466 5467 if (user_pref) { 5468 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5469 "hubd_select_device_configuration: " 5470 "usba_devdb_get_user_preferences " 5471 "return user_conf=%d\npreferred driver=%s path=%s", 5472 user_pref->cfg_index, user_pref->driver, 5473 user_pref->pathname); 5474 5475 user_conf = user_pref->cfg_index; 5476 5477 if (user_pref->driver) { 5478 mutex_enter(&child_ud->usb_mutex); 5479 child_ud->usb_preferred_driver = user_pref->driver; 5480 mutex_exit(&child_ud->usb_mutex); 5481 } 5482 } else { 5483 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5484 "hubd_select_device_configuration: No match found"); 5485 5486 /* select default configuration for this device */ 5487 user_conf = USBA_DEV_CONFIG_INDEX_UNDEFINED; 5488 } 5489 kmem_free(pathname, pathlen); 5490 5491 /* if the device has just one configuration, set default value */ 5492 if (usbdev_ptr->bNumConfigurations == 1) { 5493 user_conf = USB_DEV_DEFAULT_CONFIG_INDEX; 5494 } 5495 5496 return (user_conf); 5497 } 5498 5499 5500 /* 5501 * Retrieves config cloud for this configuration 5502 */ 5503 int 5504 hubd_get_this_config_cloud(hubd_t *hubd, dev_info_t *dip, 5505 usba_device_t *child_ud, uint16_t conf_index) 5506 { 5507 usb_cfg_descr_t *confdescr; 5508 mblk_t *pdata = NULL; 5509 int rval; 5510 size_t size; 5511 char *tmpbuf; 5512 usb_cr_t completion_reason; 5513 usb_cb_flags_t cb_flags; 5514 usb_pipe_handle_t def_ph; 5515 5516 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5517 "hubd_get_this_config_cloud: conf_index=%d", conf_index); 5518 5519 5520 /* alloc temporary space for config descriptor */ 5521 confdescr = (usb_cfg_descr_t *)kmem_zalloc(USB_CFG_DESCR_SIZE, 5522 KM_SLEEP); 5523 5524 /* alloc temporary space for string descriptor */ 5525 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 5526 5527 def_ph = usba_get_dflt_pipe_handle(dip); 5528 5529 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5530 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5531 USB_REQ_GET_DESCR, 5532 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5533 0, 5534 USB_CFG_DESCR_SIZE, 5535 &pdata, 5536 0, 5537 &completion_reason, 5538 &cb_flags, 5539 0)) == USB_SUCCESS) { 5540 5541 /* this must be true since we didn't allow data underruns */ 5542 if (MBLKL(pdata) != USB_CFG_DESCR_SIZE) { 5543 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5544 "device returned incorrect configuration " 5545 "descriptor size."); 5546 5547 rval = USB_FAILURE; 5548 goto done; 5549 } 5550 5551 /* 5552 * Parse the configuration descriptor 5553 */ 5554 size = usb_parse_cfg_descr(pdata->b_rptr, 5555 MBLKL(pdata), confdescr, 5556 USB_CFG_DESCR_SIZE); 5557 5558 /* if parse cfg descr error, it should return failure */ 5559 if (size == USB_PARSE_ERROR) { 5560 5561 if (pdata->b_rptr[1] != USB_DESCR_TYPE_CFG) { 5562 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5563 hubd->h_log_handle, 5564 "device returned incorrect " 5565 "configuration descriptor type."); 5566 } 5567 rval = USB_FAILURE; 5568 goto done; 5569 } 5570 5571 if (confdescr->wTotalLength < USB_CFG_DESCR_SIZE) { 5572 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5573 hubd->h_log_handle, 5574 "device returned incorrect " 5575 "configuration descriptor size."); 5576 5577 rval = USB_FAILURE; 5578 goto done; 5579 } 5580 5581 freemsg(pdata); 5582 pdata = NULL; 5583 5584 /* Now fetch the complete config cloud */ 5585 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5586 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5587 USB_REQ_GET_DESCR, 5588 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5589 0, 5590 confdescr->wTotalLength, 5591 &pdata, 5592 0, 5593 &completion_reason, 5594 &cb_flags, 5595 0)) == USB_SUCCESS) { 5596 5597 if (MBLKL(pdata) != 5598 confdescr->wTotalLength) { 5599 5600 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5601 hubd->h_log_handle, 5602 "device returned incorrect " 5603 "configuration descriptor."); 5604 5605 rval = USB_FAILURE; 5606 goto done; 5607 } 5608 5609 /* 5610 * copy config descriptor into usba_device 5611 */ 5612 mutex_enter(&child_ud->usb_mutex); 5613 child_ud->usb_cfg_array[conf_index] = 5614 kmem_alloc(confdescr->wTotalLength, KM_SLEEP); 5615 child_ud->usb_cfg_array_len[conf_index] = 5616 confdescr->wTotalLength; 5617 bcopy((caddr_t)pdata->b_rptr, 5618 (caddr_t)child_ud->usb_cfg_array[conf_index], 5619 confdescr->wTotalLength); 5620 mutex_exit(&child_ud->usb_mutex); 5621 5622 /* 5623 * retrieve string descriptor describing this 5624 * configuration 5625 */ 5626 if (confdescr->iConfiguration) { 5627 5628 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 5629 hubd->h_log_handle, 5630 "Get conf str descr for config_index=%d", 5631 conf_index); 5632 5633 /* 5634 * Now fetch the string descriptor describing 5635 * this configuration 5636 */ 5637 if ((rval = usb_get_string_descr(dip, 5638 USB_LANG_ID, confdescr->iConfiguration, 5639 tmpbuf, USB_MAXSTRINGLEN)) == 5640 USB_SUCCESS) { 5641 size = strlen(tmpbuf); 5642 if (size > 0) { 5643 child_ud->usb_cfg_str_descr 5644 [conf_index] = (char *) 5645 kmem_zalloc(size + 1, 5646 KM_SLEEP); 5647 (void) strcpy( 5648 child_ud->usb_cfg_str_descr 5649 [conf_index], tmpbuf); 5650 } 5651 } else { 5652 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5653 hubd->h_log_handle, 5654 "hubd_get_this_config_cloud: " 5655 "getting config string (%d) " 5656 "failed", 5657 confdescr->iConfiguration); 5658 5659 /* ignore this error */ 5660 rval = USB_SUCCESS; 5661 } 5662 } 5663 } 5664 } 5665 5666 done: 5667 if (rval != USB_SUCCESS) { 5668 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5669 "hubd_get_this_config_cloud: " 5670 "error in retrieving config descriptor for " 5671 "config index=%d rval=%d cr=%d", 5672 conf_index, rval, completion_reason); 5673 } 5674 5675 if (pdata) { 5676 freemsg(pdata); 5677 pdata = NULL; 5678 } 5679 5680 kmem_free(confdescr, USB_CFG_DESCR_SIZE); 5681 kmem_free(tmpbuf, USB_MAXSTRINGLEN); 5682 5683 return (rval); 5684 } 5685 5686 5687 /* 5688 * Retrieves the entire config cloud for all configurations of the device 5689 */ 5690 int 5691 hubd_get_all_device_config_cloud(hubd_t *hubd, dev_info_t *dip, 5692 usba_device_t *child_ud) 5693 { 5694 int rval = USB_SUCCESS; 5695 int ncfgs; 5696 uint16_t size; 5697 uint16_t conf_index; 5698 uchar_t **cfg_array; 5699 uint16_t *cfg_array_len; 5700 char **str_descr; 5701 5702 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5703 "hubd_get_all_device_config_cloud: Start"); 5704 5705 /* alloc pointer array for conf. descriptors */ 5706 mutex_enter(&child_ud->usb_mutex); 5707 ncfgs = child_ud->usb_n_cfgs; 5708 mutex_exit(&child_ud->usb_mutex); 5709 5710 size = sizeof (uchar_t *) * ncfgs; 5711 cfg_array = kmem_zalloc(size, KM_SLEEP); 5712 cfg_array_len = kmem_zalloc(ncfgs * sizeof (uint16_t), KM_SLEEP); 5713 str_descr = kmem_zalloc(size, KM_SLEEP); 5714 5715 mutex_enter(&child_ud->usb_mutex); 5716 child_ud->usb_cfg_array = cfg_array; 5717 child_ud->usb_cfg_array_len = cfg_array_len; 5718 child_ud->usb_cfg_array_length = size; 5719 child_ud->usb_cfg_array_len_length = ncfgs * sizeof (uint16_t); 5720 child_ud->usb_cfg_str_descr = str_descr; 5721 mutex_exit(&child_ud->usb_mutex); 5722 5723 /* Get configuration descriptor for each configuration */ 5724 for (conf_index = 0; (conf_index < ncfgs) && 5725 (rval == USB_SUCCESS); conf_index++) { 5726 5727 rval = hubd_get_this_config_cloud(hubd, dip, child_ud, 5728 conf_index); 5729 } 5730 5731 return (rval); 5732 } 5733 5734 5735 /* 5736 * hubd_ready_device: 5737 * Update the usba_device structure 5738 * Set the given configuration 5739 * Prepares the device node for driver to online. If an existing 5740 * OBP node is found, it will switch to the OBP node. 5741 */ 5742 dev_info_t * 5743 hubd_ready_device(hubd_t *hubd, dev_info_t *child_dip, usba_device_t *child_ud, 5744 uint_t config_index) 5745 { 5746 usb_cr_t completion_reason; 5747 usb_cb_flags_t cb_flags; 5748 size_t size; 5749 usb_cfg_descr_t config_descriptor; 5750 usb_pipe_handle_t def_ph; 5751 usba_pipe_handle_data_t *ph; 5752 5753 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5754 "hubd_ready_device: dip=0x%p, user_conf_index=%d", 5755 (void *)child_dip, config_index); 5756 5757 size = usb_parse_cfg_descr( 5758 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 5759 &config_descriptor, USB_CFG_DESCR_SIZE); 5760 ASSERT(size == USB_CFG_DESCR_SIZE); 5761 5762 def_ph = usba_get_dflt_pipe_handle(child_dip); 5763 5764 /* Set the configuration */ 5765 (void) usb_pipe_sync_ctrl_xfer(child_dip, def_ph, 5766 USB_DEV_REQ_HOST_TO_DEV, 5767 USB_REQ_SET_CFG, /* bRequest */ 5768 config_descriptor.bConfigurationValue, /* wValue */ 5769 0, /* wIndex */ 5770 0, /* wLength */ 5771 NULL, 5772 0, 5773 &completion_reason, 5774 &cb_flags, 5775 0); 5776 5777 mutex_enter(&child_ud->usb_mutex); 5778 child_ud->usb_active_cfg_ndx = config_index; 5779 child_ud->usb_cfg = child_ud->usb_cfg_array[config_index]; 5780 child_ud->usb_cfg_length = config_descriptor.wTotalLength; 5781 child_ud->usb_cfg_value = config_descriptor.bConfigurationValue; 5782 child_ud->usb_n_ifs = config_descriptor.bNumInterfaces; 5783 child_ud->usb_dip = child_dip; 5784 5785 child_ud->usb_client_flags = kmem_zalloc( 5786 child_ud->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 5787 5788 child_ud->usb_client_attach_list = kmem_zalloc( 5789 child_ud->usb_n_ifs * 5790 sizeof (*child_ud->usb_client_attach_list), KM_SLEEP); 5791 5792 child_ud->usb_client_ev_cb_list = kmem_zalloc( 5793 child_ud->usb_n_ifs * 5794 sizeof (*child_ud->usb_client_ev_cb_list), KM_SLEEP); 5795 5796 mutex_exit(&child_ud->usb_mutex); 5797 5798 /* ready the device node */ 5799 child_dip = usba_ready_device_node(child_dip); 5800 5801 /* set owner of default pipe to child dip */ 5802 ph = usba_get_ph_data(def_ph); 5803 mutex_enter(&ph->p_mutex); 5804 mutex_enter(&ph->p_ph_impl->usba_ph_mutex); 5805 ph->p_ph_impl->usba_ph_dip = ph->p_dip = child_dip; 5806 mutex_exit(&ph->p_ph_impl->usba_ph_mutex); 5807 mutex_exit(&ph->p_mutex); 5808 5809 return (child_dip); 5810 } 5811 5812 5813 /* 5814 * hubd_create_child 5815 * - create child dip 5816 * - open default pipe 5817 * - get device descriptor 5818 * - set the address 5819 * - get device string descriptors 5820 * - get the entire config cloud (all configurations) of the device 5821 * - set user preferred configuration 5822 * - close default pipe 5823 * - load appropriate driver(s) 5824 */ 5825 static int 5826 hubd_create_child(dev_info_t *dip, 5827 hubd_t *hubd, 5828 usba_device_t *hubd_ud, 5829 usb_port_status_t port_status, 5830 usb_port_t port, 5831 int iteration) 5832 { 5833 dev_info_t *child_dip = NULL; 5834 usb_dev_descr_t usb_dev_descr; 5835 int rval; 5836 usba_device_t *child_ud = NULL; 5837 usba_device_t *parent_ud = NULL; 5838 usb_pipe_handle_t ph = NULL; /* default pipe handle */ 5839 mblk_t *pdata = NULL; 5840 usb_cr_t completion_reason; 5841 int user_conf_index; 5842 uint_t config_index; 5843 usb_cb_flags_t cb_flags; 5844 uchar_t address = 0; 5845 uint16_t length; 5846 size_t size; 5847 usb_addr_t parent_usb_addr; 5848 usb_port_t parent_usb_port; 5849 usba_device_t *parent_usba_dev; 5850 usb_port_status_t parent_port_status; 5851 5852 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5853 "hubd_create_child: port=%d", port); 5854 5855 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5856 ASSERT(hubd->h_usba_devices[port] == NULL); 5857 5858 mutex_exit(HUBD_MUTEX(hubd)); 5859 5860 /* 5861 * create a dip which can be used to open the pipe. we set 5862 * the name after getting the descriptors from the device 5863 */ 5864 rval = usba_create_child_devi(dip, 5865 "device", /* driver name */ 5866 hubd_ud->usb_hcdi_ops, /* usba_hcdi ops */ 5867 hubd_ud->usb_root_hub_dip, 5868 port_status, /* low speed device */ 5869 child_ud, 5870 &child_dip); 5871 5872 if (rval != USB_SUCCESS) { 5873 5874 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5875 "usb_create_child_devi failed (%d)", rval); 5876 5877 goto fail_cleanup; 5878 } 5879 5880 child_ud = usba_get_usba_device(child_dip); 5881 ASSERT(child_ud != NULL); 5882 5883 parent_ud = hubd->h_usba_device; 5884 mutex_enter(&parent_ud->usb_mutex); 5885 parent_port_status = parent_ud->usb_port_status; 5886 5887 /* 5888 * To support split transactions, update address and port 5889 * of high speed hub to which given device is connected. 5890 */ 5891 if (parent_port_status == USBA_HIGH_SPEED_DEV) { 5892 parent_usba_dev = parent_ud; 5893 parent_usb_addr = parent_ud->usb_addr; 5894 parent_usb_port = port; 5895 } else { 5896 parent_usba_dev = parent_ud->usb_hs_hub_usba_dev; 5897 parent_usb_addr = parent_ud->usb_hs_hub_addr; 5898 parent_usb_port = parent_ud->usb_hs_hub_port; 5899 } 5900 mutex_exit(&parent_ud->usb_mutex); 5901 5902 mutex_enter(&child_ud->usb_mutex); 5903 address = child_ud->usb_addr; 5904 child_ud->usb_addr = 0; 5905 child_ud->usb_dev_descr = kmem_alloc(sizeof (usb_dev_descr_t), 5906 KM_SLEEP); 5907 bzero(&usb_dev_descr, sizeof (usb_dev_descr_t)); 5908 usb_dev_descr.bMaxPacketSize0 = 5909 (port_status == USBA_LOW_SPEED_DEV) ? 8 : 64; 5910 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5911 sizeof (usb_dev_descr_t)); 5912 child_ud->usb_port = port; 5913 child_ud->usb_hs_hub_usba_dev = parent_usba_dev; 5914 child_ud->usb_hs_hub_addr = parent_usb_addr; 5915 child_ud->usb_hs_hub_port = parent_usb_port; 5916 mutex_exit(&child_ud->usb_mutex); 5917 5918 /* Open the default pipe */ 5919 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5920 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 5921 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5922 "usb_pipe_open failed (%d)", rval); 5923 5924 goto fail_cleanup; 5925 } 5926 5927 /* 5928 * get device descriptor 5929 */ 5930 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5931 "hubd_create_child: get device descriptor: 64 bytes"); 5932 5933 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5934 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5935 USB_REQ_GET_DESCR, /* bRequest */ 5936 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5937 0, /* wIndex */ 5938 64, /* wLength */ 5939 &pdata, USB_ATTRS_SHORT_XFER_OK, 5940 &completion_reason, &cb_flags, 0); 5941 5942 if ((rval != USB_SUCCESS) && 5943 (!((completion_reason == USB_CR_DATA_OVERRUN) && pdata))) { 5944 5945 /* 5946 * rval != USB_SUCCESS AND 5947 * completion_reason != USB_CR_DATA_OVERRUN 5948 * pdata could be != NULL. 5949 * Free pdata now to prevent memory leak. 5950 */ 5951 freemsg(pdata); 5952 pdata = NULL; 5953 5954 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5955 "hubd_create_child: get device descriptor: 8 bytes"); 5956 5957 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5958 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5959 USB_REQ_GET_DESCR, /* bRequest */ 5960 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5961 0, /* wIndex */ 5962 8, /* wLength */ 5963 &pdata, USB_ATTRS_NONE, 5964 &completion_reason, &cb_flags, 0); 5965 5966 if (rval != USB_SUCCESS) { 5967 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5968 "getting device descriptor failed (%s 0x%x %d)", 5969 usb_str_cr(completion_reason), cb_flags, rval); 5970 goto fail_cleanup; 5971 } 5972 } else { 5973 ASSERT(completion_reason == USB_CR_OK); 5974 } 5975 5976 ASSERT(pdata != NULL); 5977 5978 size = usb_parse_dev_descr( 5979 pdata->b_rptr, 5980 MBLKL(pdata), 5981 &usb_dev_descr, 5982 sizeof (usb_dev_descr_t)); 5983 5984 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5985 "parsing device descriptor returned %lu", size); 5986 5987 length = *(pdata->b_rptr); 5988 freemsg(pdata); 5989 pdata = NULL; 5990 if (size < 8) { 5991 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5992 "get device descriptor returned %lu bytes", size); 5993 5994 goto fail_cleanup; 5995 } 5996 5997 if (length < 8) { 5998 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5999 "fail enumeration: bLength=%d", length); 6000 6001 goto fail_cleanup; 6002 } 6003 6004 /* Set the address of the device */ 6005 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6006 USB_DEV_REQ_HOST_TO_DEV, 6007 USB_REQ_SET_ADDRESS, /* bRequest */ 6008 address, /* wValue */ 6009 0, /* wIndex */ 6010 0, /* wLength */ 6011 NULL, 0, 6012 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 6013 char buffer[64]; 6014 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6015 "setting address failed (cr=%s cb_flags=%s rval=%d)", 6016 usb_str_cr(completion_reason), 6017 usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)), 6018 rval); 6019 6020 goto fail_cleanup; 6021 } 6022 6023 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6024 "set address 0x%x done", address); 6025 6026 /* now close the pipe for addr 0 */ 6027 usb_pipe_close(child_dip, ph, 6028 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 6029 6030 /* 6031 * This delay is important for the CATC hub to enumerate 6032 * But, avoid delay in the first iteration 6033 */ 6034 if (iteration) { 6035 delay(drv_usectohz(hubd_device_delay/100)); 6036 } 6037 6038 /* assign the address in the usba_device structure */ 6039 mutex_enter(&child_ud->usb_mutex); 6040 child_ud->usb_addr = address; 6041 child_ud->usb_no_cpr = 0; 6042 child_ud->usb_port_status = port_status; 6043 /* save this device descriptor */ 6044 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 6045 sizeof (usb_dev_descr_t)); 6046 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 6047 mutex_exit(&child_ud->usb_mutex); 6048 6049 /* re-open the pipe for the device with the new address */ 6050 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 6051 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 6052 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6053 "usb_pipe_open failed (%d)", rval); 6054 6055 goto fail_cleanup; 6056 } 6057 6058 /* 6059 * Get full device descriptor only if we have not received full 6060 * device descriptor earlier. 6061 */ 6062 if (size < length) { 6063 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6064 "hubd_create_child: get full device descriptor: " 6065 "%d bytes", length); 6066 6067 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6068 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 6069 USB_REQ_GET_DESCR, /* bRequest */ 6070 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 6071 0, /* wIndex */ 6072 length, /* wLength */ 6073 &pdata, 0, 6074 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 6075 freemsg(pdata); 6076 pdata = NULL; 6077 6078 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 6079 hubd->h_log_handle, 6080 "hubd_create_child: get full device descriptor: " 6081 "64 bytes"); 6082 6083 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6084 USB_DEV_REQ_DEV_TO_HOST | 6085 USB_DEV_REQ_TYPE_STANDARD, 6086 USB_REQ_GET_DESCR, /* bRequest */ 6087 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 6088 0, /* wIndex */ 6089 64, /* wLength */ 6090 &pdata, USB_ATTRS_SHORT_XFER_OK, 6091 &completion_reason, &cb_flags, 0); 6092 6093 /* we have to trust the data now */ 6094 if (pdata) { 6095 int len = *(pdata->b_rptr); 6096 6097 length = MBLKL(pdata); 6098 if (length < len) { 6099 6100 goto fail_cleanup; 6101 } 6102 } else if (rval != USB_SUCCESS) { 6103 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6104 hubd->h_log_handle, 6105 "getting device descriptor failed " 6106 "(%d 0x%x %d)", 6107 completion_reason, cb_flags, rval); 6108 6109 goto fail_cleanup; 6110 } 6111 } 6112 6113 size = usb_parse_dev_descr( 6114 pdata->b_rptr, 6115 MBLKL(pdata), 6116 &usb_dev_descr, 6117 sizeof (usb_dev_descr_t)); 6118 6119 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6120 "parsing device descriptor returned %lu", size); 6121 6122 /* 6123 * For now, free the data 6124 * eventually, each configuration may need to be looked at 6125 */ 6126 freemsg(pdata); 6127 pdata = NULL; 6128 6129 if (size != USB_DEV_DESCR_SIZE) { 6130 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6131 "fail enumeration: descriptor size=%lu " 6132 "expected size=%u", size, USB_DEV_DESCR_SIZE); 6133 6134 goto fail_cleanup; 6135 } 6136 6137 /* 6138 * save the device descriptor in usba_device since it is needed 6139 * later on again 6140 */ 6141 mutex_enter(&child_ud->usb_mutex); 6142 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 6143 sizeof (usb_dev_descr_t)); 6144 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 6145 mutex_exit(&child_ud->usb_mutex); 6146 } 6147 6148 if (usb_dev_descr.bNumConfigurations == 0) { 6149 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6150 "device descriptor:\n\t" 6151 "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t" 6152 "protocol=0x%x maxpktsize=0x%x " 6153 "Vid=0x%x Pid=0x%x rel=0x%x\n\t" 6154 "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x", 6155 usb_dev_descr.bLength, usb_dev_descr.bDescriptorType, 6156 usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass, 6157 usb_dev_descr.bDeviceSubClass, 6158 usb_dev_descr.bDeviceProtocol, 6159 usb_dev_descr.bMaxPacketSize0, 6160 usb_dev_descr.idVendor, 6161 usb_dev_descr.idProduct, usb_dev_descr.bcdDevice, 6162 usb_dev_descr.iManufacturer, usb_dev_descr.iProduct, 6163 usb_dev_descr.iSerialNumber, 6164 usb_dev_descr.bNumConfigurations); 6165 goto fail_cleanup; 6166 } 6167 6168 6169 /* get the device string descriptor(s) */ 6170 usba_get_dev_string_descrs(child_dip, child_ud); 6171 6172 /* retrieve config cloud for all configurations */ 6173 rval = hubd_get_all_device_config_cloud(hubd, child_dip, child_ud); 6174 if (rval != USB_SUCCESS) { 6175 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6176 "failed to get configuration descriptor(s)"); 6177 6178 goto fail_cleanup; 6179 } 6180 6181 /* get the preferred configuration for this device */ 6182 user_conf_index = hubd_select_device_configuration(hubd, port, 6183 child_dip, child_ud); 6184 6185 /* Check if the user selected configuration index is in range */ 6186 if ((user_conf_index >= usb_dev_descr.bNumConfigurations) || 6187 (user_conf_index < 0)) { 6188 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6189 "Configuration index for device idVendor=%d " 6190 "idProduct=%d is=%d, and is out of range[0..%d]", 6191 usb_dev_descr.idVendor, usb_dev_descr.idProduct, 6192 user_conf_index, usb_dev_descr.bNumConfigurations - 1); 6193 6194 /* treat this as user didn't specify configuration */ 6195 user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED; 6196 } 6197 6198 6199 /* 6200 * Warn users of a performance hit if connecting a 6201 * High Speed behind a 1.1 hub, which is behind a 6202 * 2.0 port. 6203 */ 6204 if ((parent_port_status != USBA_HIGH_SPEED_DEV) && 6205 !(usba_is_root_hub(parent_ud->usb_dip)) && 6206 (parent_usb_addr)) { 6207 6208 /* 6209 * Now that we know the root port is a high speed port 6210 * and that the parent port is not a high speed port, 6211 * let's find out if the device itself is a high speed 6212 * device. If it is a high speed device, 6213 * USB_DESCR_TYPE_SETUP_DEV_QLF should return a value, 6214 * otherwise the command will fail. 6215 */ 6216 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 6217 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 6218 USB_REQ_GET_DESCR, /* bRequest */ 6219 USB_DESCR_TYPE_SETUP_DEV_QLF, /* wValue */ 6220 0, /* wIndex */ 6221 10, /* wLength */ 6222 &pdata, USB_ATTRS_SHORT_XFER_OK, 6223 &completion_reason, &cb_flags, 0); 6224 6225 if (pdata) { 6226 freemsg(pdata); 6227 pdata = NULL; 6228 } 6229 6230 /* 6231 * USB_DESCR_TYPE_SETUP_DEV_QLF query was successful 6232 * that means this is a high speed device behind a 6233 * high speed root hub, but running at full speed 6234 * because there is a full speed hub in the middle. 6235 */ 6236 if (rval == USB_SUCCESS) { 6237 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 6238 hubd->h_log_handle, 6239 "Connecting a high speed device to a " 6240 "non high speed hub (port %d) will result " 6241 "in a loss of performance. Please connect " 6242 "the device to a high speed hub to get " 6243 "the maximum performance.", 6244 port); 6245 } 6246 } 6247 6248 /* 6249 * Now we try to online the device by attaching a driver 6250 * The following truth table illustrates the logic:- 6251 * Cfgndx Driver Action 6252 * 0 0 loop all configs for driver with full 6253 * compatible properties. 6254 * 0 1 set first configuration, 6255 * compatible prop = drivername. 6256 * 1 0 Set config, full compatible prop 6257 * 1 1 Set config, compatible prop = drivername. 6258 * 6259 * Note: 6260 * cfgndx = user_conf_index 6261 * Driver = usb_preferred_driver 6262 */ 6263 if (user_conf_index == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 6264 if (child_ud->usb_preferred_driver) { 6265 /* 6266 * It is the job of the "preferred driver" to put the 6267 * device in the desired configuration. Till then 6268 * put the device in config index 0. 6269 */ 6270 if ((rval = usba_hubdi_check_power_budget(dip, child_ud, 6271 USB_DEV_DEFAULT_CONFIG_INDEX)) != USB_SUCCESS) { 6272 6273 goto fail_cleanup; 6274 } 6275 6276 child_dip = hubd_ready_device(hubd, child_dip, 6277 child_ud, USB_DEV_DEFAULT_CONFIG_INDEX); 6278 6279 /* 6280 * Assign the dip before onlining to avoid race 6281 * with busctl 6282 */ 6283 mutex_enter(HUBD_MUTEX(hubd)); 6284 hubd->h_children_dips[port] = child_dip; 6285 mutex_exit(HUBD_MUTEX(hubd)); 6286 6287 (void) usba_bind_driver(child_dip); 6288 } else { 6289 /* 6290 * loop through all the configurations to see if we 6291 * can find a driver for any one config. If not, set 6292 * the device in config_index 0 6293 */ 6294 rval = USB_FAILURE; 6295 for (config_index = 0; 6296 (config_index < usb_dev_descr.bNumConfigurations) && 6297 (rval != USB_SUCCESS); config_index++) { 6298 6299 child_dip = hubd_ready_device(hubd, child_dip, 6300 child_ud, config_index); 6301 6302 /* 6303 * Assign the dip before onlining to avoid race 6304 * with busctl 6305 */ 6306 mutex_enter(HUBD_MUTEX(hubd)); 6307 hubd->h_children_dips[port] = child_dip; 6308 mutex_exit(HUBD_MUTEX(hubd)); 6309 6310 rval = usba_bind_driver(child_dip); 6311 6312 /* 6313 * Normally power budget should be checked 6314 * before device is configured. A failure in 6315 * power budget checking will stop the device 6316 * from being configured with current 6317 * config_index and may enable the device to 6318 * be configured in another configuration. 6319 * This may break the user experience that a 6320 * device which previously worked in config 6321 * A now works in config B after power budget 6322 * control is enabled. To avoid such situation, 6323 * power budget checking is moved here and will 6324 * fail the child creation directly if config 6325 * A exceeds the power available. 6326 */ 6327 if (rval == USB_SUCCESS) { 6328 if ((usba_hubdi_check_power_budget(dip, 6329 child_ud, config_index)) != 6330 USB_SUCCESS) { 6331 6332 goto fail_cleanup; 6333 } 6334 } 6335 } 6336 if (rval != USB_SUCCESS) { 6337 6338 if ((usba_hubdi_check_power_budget(dip, 6339 child_ud, 0)) != USB_SUCCESS) { 6340 6341 goto fail_cleanup; 6342 } 6343 6344 child_dip = hubd_ready_device(hubd, child_dip, 6345 child_ud, 0); 6346 mutex_enter(HUBD_MUTEX(hubd)); 6347 hubd->h_children_dips[port] = child_dip; 6348 mutex_exit(HUBD_MUTEX(hubd)); 6349 } 6350 } /* end else loop all configs */ 6351 } else { 6352 6353 if ((usba_hubdi_check_power_budget(dip, child_ud, 6354 (uint_t)user_conf_index)) != USB_SUCCESS) { 6355 6356 goto fail_cleanup; 6357 } 6358 6359 child_dip = hubd_ready_device(hubd, child_dip, 6360 child_ud, (uint_t)user_conf_index); 6361 6362 /* 6363 * Assign the dip before onlining to avoid race 6364 * with busctl 6365 */ 6366 mutex_enter(HUBD_MUTEX(hubd)); 6367 hubd->h_children_dips[port] = child_dip; 6368 mutex_exit(HUBD_MUTEX(hubd)); 6369 6370 (void) usba_bind_driver(child_dip); 6371 } 6372 6373 usba_hubdi_decr_power_budget(dip, child_ud); 6374 6375 mutex_enter(HUBD_MUTEX(hubd)); 6376 if (hubd->h_usba_devices[port] == NULL) { 6377 hubd->h_usba_devices[port] = usba_get_usba_device(child_dip); 6378 } else { 6379 ASSERT(hubd->h_usba_devices[port] == 6380 usba_get_usba_device(child_dip)); 6381 } 6382 6383 return (USB_SUCCESS); 6384 6385 6386 fail_cleanup: 6387 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6388 "hubd_create_child: fail_cleanup"); 6389 6390 mutex_enter(HUBD_MUTEX(hubd)); 6391 hubd->h_children_dips[port] = NULL; 6392 mutex_exit(HUBD_MUTEX(hubd)); 6393 6394 if (pdata) { 6395 freemsg(pdata); 6396 } 6397 6398 if (ph) { 6399 usb_pipe_close(child_dip, ph, 6400 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 6401 } 6402 6403 if (child_dip) { 6404 int rval = usba_destroy_child_devi(child_dip, 6405 NDI_DEVI_REMOVE); 6406 if (rval != USB_SUCCESS) { 6407 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6408 "failure to remove child node"); 6409 } 6410 } 6411 6412 if (child_ud) { 6413 /* to make sure we free the address */ 6414 mutex_enter(&child_ud->usb_mutex); 6415 child_ud->usb_addr = address; 6416 ASSERT(child_ud->usb_ref_count == 0); 6417 mutex_exit(&child_ud->usb_mutex); 6418 6419 mutex_enter(HUBD_MUTEX(hubd)); 6420 if (hubd->h_usba_devices[port] == NULL) { 6421 mutex_exit(HUBD_MUTEX(hubd)); 6422 usba_free_usba_device(child_ud); 6423 } else { 6424 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 6425 mutex_exit(HUBD_MUTEX(hubd)); 6426 } 6427 } 6428 6429 mutex_enter(HUBD_MUTEX(hubd)); 6430 6431 return (USB_FAILURE); 6432 } 6433 6434 6435 /* 6436 * hubd_delete_child: 6437 * - free usb address 6438 * - lookup child dips, there may be multiple on this port 6439 * - offline each child devi 6440 */ 6441 static int 6442 hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, boolean_t retry) 6443 { 6444 dev_info_t *child_dip; 6445 usba_device_t *usba_device; 6446 int rval = USB_SUCCESS; 6447 6448 child_dip = hubd->h_children_dips[port]; 6449 usba_device = hubd->h_usba_devices[port]; 6450 6451 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6452 "hubd_delete_child: port=%d, dip=0x%p usba_device=0x%p", 6453 port, (void *)child_dip, (void *)usba_device); 6454 6455 mutex_exit(HUBD_MUTEX(hubd)); 6456 if (child_dip) { 6457 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6458 "hubd_delete_child:\n\t" 6459 "dip = 0x%p (%s) at port %d", 6460 (void *)child_dip, ddi_node_name(child_dip), port); 6461 6462 if (usba_device) { 6463 usba_hubdi_incr_power_budget(hubd->h_dip, usba_device); 6464 } 6465 6466 rval = usba_destroy_child_devi(child_dip, flag); 6467 6468 if ((rval != USB_SUCCESS) && usba_is_hwa(child_dip)) { 6469 /* 6470 * This is only useful for HWA device node. 6471 * Since hwahc interface must hold hwarc interface 6472 * open until hwahc is detached, the first call to 6473 * ndi_devi_unconfig_one() can only offline hwahc 6474 * driver but not hwarc driver. Need to make a second 6475 * call to ndi_devi_unconfig_one() to make the hwarc 6476 * driver detach. 6477 */ 6478 rval = usba_destroy_child_devi(child_dip, flag); 6479 } 6480 6481 if ((rval == USB_SUCCESS) && (flag & NDI_DEVI_REMOVE)) { 6482 /* 6483 * if the child was still < DS_INITIALIZED 6484 * then our bus_unconfig was not called and 6485 * we have to zap the child here 6486 */ 6487 mutex_enter(HUBD_MUTEX(hubd)); 6488 if (hubd->h_children_dips[port] == child_dip) { 6489 usba_device_t *ud = 6490 hubd->h_usba_devices[port]; 6491 hubd->h_children_dips[port] = NULL; 6492 if (ud) { 6493 mutex_exit(HUBD_MUTEX(hubd)); 6494 6495 mutex_enter(&ud->usb_mutex); 6496 ud->usb_ref_count = 0; 6497 mutex_exit(&ud->usb_mutex); 6498 6499 usba_free_usba_device(ud); 6500 mutex_enter(HUBD_MUTEX(hubd)); 6501 hubd->h_usba_devices[port] = NULL; 6502 } 6503 } 6504 mutex_exit(HUBD_MUTEX(hubd)); 6505 } 6506 } 6507 6508 if ((rval != USB_SUCCESS) && retry) { 6509 6510 hubd_schedule_cleanup(usba_device->usb_root_hub_dip); 6511 } 6512 mutex_enter(HUBD_MUTEX(hubd)); 6513 6514 return (rval); 6515 } 6516 6517 6518 /* 6519 * hubd_free_usba_device: 6520 * free usb device structure unless it is associated with 6521 * the root hub which is handled differently 6522 */ 6523 static void 6524 hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device) 6525 { 6526 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6527 "hubd_free_usba_device: hubd=0x%p, usba_device=0x%p", 6528 (void *)hubd, (void *)usba_device); 6529 6530 if (usba_device && (usba_device->usb_addr != ROOT_HUB_ADDR)) { 6531 usb_port_t port = usba_device->usb_port; 6532 dev_info_t *dip = hubd->h_children_dips[port]; 6533 6534 #ifdef DEBUG 6535 if (dip) { 6536 ASSERT(i_ddi_node_state(dip) < DS_INITIALIZED); 6537 } 6538 #endif 6539 6540 port = usba_device->usb_port; 6541 hubd->h_usba_devices[port] = NULL; 6542 6543 mutex_exit(HUBD_MUTEX(hubd)); 6544 usba_free_usba_device(usba_device); 6545 mutex_enter(HUBD_MUTEX(hubd)); 6546 } 6547 } 6548 6549 6550 /* 6551 * event support 6552 * 6553 * busctl event support 6554 */ 6555 static int 6556 hubd_busop_get_eventcookie(dev_info_t *dip, 6557 dev_info_t *rdip, 6558 char *eventname, 6559 ddi_eventcookie_t *cookie) 6560 { 6561 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6562 6563 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6564 "hubd_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 6565 "event=%s", (void *)dip, (void *)rdip, eventname); 6566 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6567 "(dip=%s%d, rdip=%s%d)", 6568 ddi_driver_name(dip), ddi_get_instance(dip), 6569 ddi_driver_name(rdip), ddi_get_instance(rdip)); 6570 6571 /* return event cookie, iblock cookie, and level */ 6572 return (ndi_event_retrieve_cookie(hubd->h_ndi_event_hdl, 6573 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 6574 } 6575 6576 6577 static int 6578 hubd_busop_add_eventcall(dev_info_t *dip, 6579 dev_info_t *rdip, 6580 ddi_eventcookie_t cookie, 6581 void (*callback)(dev_info_t *dip, 6582 ddi_eventcookie_t cookie, void *arg, 6583 void *bus_impldata), 6584 void *arg, ddi_callback_id_t *cb_id) 6585 { 6586 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6587 usb_port_t port = hubd_child_dip2port(hubd, rdip); 6588 6589 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6590 "hubd_busop_add_eventcall: dip=0x%p, rdip=0x%p " 6591 "cookie=0x%p, cb=0x%p, arg=0x%p", 6592 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 6593 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6594 "(dip=%s%d, rdip=%s%d, event=%s)", 6595 ddi_driver_name(dip), ddi_get_instance(dip), 6596 ddi_driver_name(rdip), ddi_get_instance(rdip), 6597 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, cookie)); 6598 6599 /* Set flag on children registering events */ 6600 switch (ndi_event_cookie_to_tag(hubd->h_ndi_event_hdl, cookie)) { 6601 case USBA_EVENT_TAG_HOT_REMOVAL: 6602 mutex_enter(HUBD_MUTEX(hubd)); 6603 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6604 mutex_exit(HUBD_MUTEX(hubd)); 6605 6606 break; 6607 case USBA_EVENT_TAG_PRE_SUSPEND: 6608 mutex_enter(HUBD_MUTEX(hubd)); 6609 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6610 mutex_exit(HUBD_MUTEX(hubd)); 6611 6612 break; 6613 default: 6614 6615 break; 6616 } 6617 6618 /* add callback to our event set */ 6619 return (ndi_event_add_callback(hubd->h_ndi_event_hdl, 6620 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 6621 } 6622 6623 6624 static int 6625 hubd_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 6626 { 6627 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6628 ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id; 6629 6630 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6631 "hubd_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 6632 "cookie=0x%p", (void *)dip, (void *)id->ndi_evtcb_dip, 6633 (void *)id->ndi_evtcb_cookie); 6634 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6635 "(dip=%s%d, rdip=%s%d, event=%s)", 6636 ddi_driver_name(dip), ddi_get_instance(dip), 6637 ddi_driver_name(id->ndi_evtcb_dip), 6638 ddi_get_instance(id->ndi_evtcb_dip), 6639 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, 6640 id->ndi_evtcb_cookie)); 6641 6642 /* remove event registration from our event set */ 6643 return (ndi_event_remove_callback(hubd->h_ndi_event_hdl, cb_id)); 6644 } 6645 6646 6647 /* 6648 * event distribution 6649 * 6650 * hubd_do_callback: 6651 * Post this event to the specified child 6652 */ 6653 static void 6654 hubd_do_callback(hubd_t *hubd, dev_info_t *cdip, ddi_eventcookie_t cookie) 6655 { 6656 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6657 "hubd_do_callback"); 6658 6659 (void) ndi_event_do_callback(hubd->h_ndi_event_hdl, cdip, cookie, NULL); 6660 } 6661 6662 6663 /* 6664 * hubd_run_callbacks: 6665 * Send this event to all children 6666 */ 6667 static void 6668 hubd_run_callbacks(hubd_t *hubd, usba_event_t type) 6669 { 6670 usb_port_t port; 6671 6672 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6673 "hubd_run_callbacks"); 6674 6675 mutex_enter(HUBD_MUTEX(hubd)); 6676 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 6677 /* 6678 * the childen_dips list may have dips that have been 6679 * already deallocated. we only get a post_detach notification 6680 * but not a destroy notification 6681 */ 6682 if (hubd->h_children_dips[port]) { 6683 mutex_exit(HUBD_MUTEX(hubd)); 6684 hubd_post_event(hubd, port, type); 6685 mutex_enter(HUBD_MUTEX(hubd)); 6686 } 6687 } 6688 mutex_exit(HUBD_MUTEX(hubd)); 6689 } 6690 6691 6692 /* 6693 * hubd_post_event 6694 * post event to a child on the port depending on the type 6695 */ 6696 static void 6697 hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type) 6698 { 6699 int rval; 6700 dev_info_t *dip; 6701 usba_device_t *usba_device; 6702 ddi_eventcookie_t cookie, rm_cookie, suspend_cookie; 6703 6704 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6705 "hubd_post_event: port=%d event=%s", port, 6706 ndi_event_tag_to_name(hubd->h_ndi_event_hdl, type)); 6707 6708 cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, type); 6709 rm_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6710 USBA_EVENT_TAG_HOT_REMOVAL); 6711 suspend_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6712 USBA_EVENT_TAG_PRE_SUSPEND); 6713 6714 /* 6715 * Hotplug daemon may be attaching a driver that may be registering 6716 * event callbacks. So it already has got the device tree lock and 6717 * event handle mutex. So to prevent a deadlock while posting events, 6718 * we grab and release the locks in the same order. 6719 */ 6720 mutex_enter(HUBD_MUTEX(hubd)); 6721 dip = hubd->h_children_dips[port]; 6722 usba_device = hubd->h_usba_devices[port]; 6723 mutex_exit(HUBD_MUTEX(hubd)); 6724 6725 switch (type) { 6726 case USBA_EVENT_TAG_HOT_REMOVAL: 6727 /* Clear the registered event flag */ 6728 mutex_enter(HUBD_MUTEX(hubd)); 6729 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_DISCONNECT; 6730 mutex_exit(HUBD_MUTEX(hubd)); 6731 6732 hubd_do_callback(hubd, dip, cookie); 6733 usba_persistent_pipe_close(usba_device); 6734 6735 /* 6736 * Mark the dip for deletion only after the driver has 6737 * seen the disconnect event to prevent cleanup thread 6738 * from stepping in between. 6739 */ 6740 mutex_enter(&(DEVI(dip)->devi_lock)); 6741 DEVI_SET_DEVICE_REMOVED(dip); 6742 mutex_exit(&(DEVI(dip)->devi_lock)); 6743 6744 break; 6745 case USBA_EVENT_TAG_PRE_SUSPEND: 6746 mutex_enter(HUBD_MUTEX(hubd)); 6747 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_PRESUSPEND; 6748 mutex_exit(HUBD_MUTEX(hubd)); 6749 6750 hubd_do_callback(hubd, dip, cookie); 6751 /* 6752 * persistent pipe close for this event is taken care by the 6753 * caller after verfying that all children can suspend 6754 */ 6755 6756 break; 6757 case USBA_EVENT_TAG_HOT_INSERTION: 6758 /* 6759 * Check if this child has missed the disconnect event before 6760 * it registered for event callbacks 6761 */ 6762 mutex_enter(HUBD_MUTEX(hubd)); 6763 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_DISCONNECT) { 6764 /* clear the flag and post disconnect event */ 6765 hubd->h_child_events[port] &= 6766 ~HUBD_CHILD_EVENT_DISCONNECT; 6767 mutex_exit(HUBD_MUTEX(hubd)); 6768 hubd_do_callback(hubd, dip, rm_cookie); 6769 usba_persistent_pipe_close(usba_device); 6770 mutex_enter(HUBD_MUTEX(hubd)); 6771 } 6772 mutex_exit(HUBD_MUTEX(hubd)); 6773 6774 /* 6775 * Mark the dip as reinserted to prevent cleanup thread 6776 * from stepping in. 6777 */ 6778 mutex_enter(&(DEVI(dip)->devi_lock)); 6779 DEVI_SET_DEVICE_REINSERTED(dip); 6780 mutex_exit(&(DEVI(dip)->devi_lock)); 6781 6782 rval = usba_persistent_pipe_open(usba_device); 6783 if (rval != USB_SUCCESS) { 6784 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6785 hubd->h_log_handle, 6786 "failed to reopen all pipes on reconnect"); 6787 } 6788 6789 hubd_do_callback(hubd, dip, cookie); 6790 6791 /* 6792 * We might see a connect event only if hotplug thread for 6793 * disconnect event don't run in time. 6794 * Set the flag again, so we don't miss posting a 6795 * disconnect event. 6796 */ 6797 mutex_enter(HUBD_MUTEX(hubd)); 6798 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6799 mutex_exit(HUBD_MUTEX(hubd)); 6800 6801 break; 6802 case USBA_EVENT_TAG_POST_RESUME: 6803 /* 6804 * Check if this child has missed the pre-suspend event before 6805 * it registered for event callbacks 6806 */ 6807 mutex_enter(HUBD_MUTEX(hubd)); 6808 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_PRESUSPEND) { 6809 /* clear the flag and post pre_suspend event */ 6810 hubd->h_port_state[port] &= 6811 ~HUBD_CHILD_EVENT_PRESUSPEND; 6812 mutex_exit(HUBD_MUTEX(hubd)); 6813 hubd_do_callback(hubd, dip, suspend_cookie); 6814 mutex_enter(HUBD_MUTEX(hubd)); 6815 } 6816 mutex_exit(HUBD_MUTEX(hubd)); 6817 6818 mutex_enter(&usba_device->usb_mutex); 6819 usba_device->usb_no_cpr = 0; 6820 mutex_exit(&usba_device->usb_mutex); 6821 6822 /* 6823 * Since the pipe has already been opened by hub 6824 * at DDI_RESUME time, there is no need for a 6825 * persistent pipe open 6826 */ 6827 hubd_do_callback(hubd, dip, cookie); 6828 6829 /* 6830 * Set the flag again, so we don't miss posting a 6831 * pre-suspend event. This enforces a tighter 6832 * dev_state model. 6833 */ 6834 mutex_enter(HUBD_MUTEX(hubd)); 6835 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6836 mutex_exit(HUBD_MUTEX(hubd)); 6837 break; 6838 } 6839 } 6840 6841 6842 /* 6843 * handling of events coming from above 6844 */ 6845 static int 6846 hubd_disconnect_event_cb(dev_info_t *dip) 6847 { 6848 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6849 usb_port_t port, nports; 6850 usba_device_t *usba_dev; 6851 usba_event_t tag = USBA_EVENT_TAG_HOT_REMOVAL; 6852 int circ; 6853 6854 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6855 "hubd_disconnect_event_cb: tag=%d", tag); 6856 6857 ndi_devi_enter(dip, &circ); 6858 6859 mutex_enter(HUBD_MUTEX(hubd)); 6860 switch (hubd->h_dev_state) { 6861 case USB_DEV_ONLINE: 6862 case USB_DEV_PWRED_DOWN: 6863 hubd->h_dev_state = USB_DEV_DISCONNECTED; 6864 /* stop polling on the interrupt pipe */ 6865 hubd_stop_polling(hubd); 6866 6867 /* FALLTHROUGH */ 6868 case USB_DEV_SUSPENDED: 6869 /* we remain in this state */ 6870 mutex_exit(HUBD_MUTEX(hubd)); 6871 hubd_run_callbacks(hubd, tag); 6872 mutex_enter(HUBD_MUTEX(hubd)); 6873 6874 /* close all the open pipes of our children */ 6875 nports = hubd->h_hub_descr.bNbrPorts; 6876 for (port = 1; port <= nports; port++) { 6877 usba_dev = hubd->h_usba_devices[port]; 6878 if (usba_dev != NULL) { 6879 mutex_exit(HUBD_MUTEX(hubd)); 6880 usba_persistent_pipe_close(usba_dev); 6881 mutex_enter(HUBD_MUTEX(hubd)); 6882 } 6883 } 6884 6885 break; 6886 case USB_DEV_DISCONNECTED: 6887 /* avoid passing multiple disconnects to children */ 6888 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6889 "hubd_disconnect_event_cb: Already disconnected"); 6890 6891 break; 6892 default: 6893 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6894 "hubd_disconnect_event_cb: Illegal devstate=%d", 6895 hubd->h_dev_state); 6896 6897 break; 6898 } 6899 mutex_exit(HUBD_MUTEX(hubd)); 6900 6901 ndi_devi_exit(dip, circ); 6902 6903 return (USB_SUCCESS); 6904 } 6905 6906 6907 static int 6908 hubd_reconnect_event_cb(dev_info_t *dip) 6909 { 6910 int rval, circ; 6911 6912 ndi_devi_enter(dip, &circ); 6913 rval = hubd_restore_state_cb(dip); 6914 ndi_devi_exit(dip, circ); 6915 6916 return (rval); 6917 } 6918 6919 6920 /* 6921 * hubd_pre_suspend_event_cb 6922 * propogate event for binary compatibility of old drivers 6923 */ 6924 static int 6925 hubd_pre_suspend_event_cb(dev_info_t *dip) 6926 { 6927 int circ; 6928 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6929 6930 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6931 "hubd_pre_suspend_event_cb"); 6932 6933 /* disable hotplug thread */ 6934 mutex_enter(HUBD_MUTEX(hubd)); 6935 hubd->h_hotplug_thread++; 6936 hubd_stop_polling(hubd); 6937 6938 /* keep PM out till we see a cpr resume */ 6939 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6940 mutex_exit(HUBD_MUTEX(hubd)); 6941 6942 ndi_devi_enter(dip, &circ); 6943 hubd_run_callbacks(hubd, USBA_EVENT_TAG_PRE_SUSPEND); 6944 ndi_devi_exit(dip, circ); 6945 6946 return (USB_SUCCESS); 6947 } 6948 6949 6950 /* 6951 * hubd_post_resume_event_cb 6952 * propogate event for binary compatibility of old drivers 6953 */ 6954 static int 6955 hubd_post_resume_event_cb(dev_info_t *dip) 6956 { 6957 int circ; 6958 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6959 6960 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6961 "hubd_post_resume_event_cb"); 6962 6963 ndi_devi_enter(dip, &circ); 6964 hubd_run_callbacks(hubd, USBA_EVENT_TAG_POST_RESUME); 6965 ndi_devi_exit(dip, circ); 6966 6967 mutex_enter(HUBD_MUTEX(hubd)); 6968 6969 /* enable PM */ 6970 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6971 6972 /* allow hotplug thread */ 6973 hubd->h_hotplug_thread--; 6974 6975 /* start polling */ 6976 hubd_start_polling(hubd, 0); 6977 mutex_exit(HUBD_MUTEX(hubd)); 6978 6979 return (USB_SUCCESS); 6980 } 6981 6982 6983 /* 6984 * hubd_cpr_suspend 6985 * save the current state of the driver/device 6986 */ 6987 static int 6988 hubd_cpr_suspend(hubd_t *hubd) 6989 { 6990 usb_port_t port, nports; 6991 usba_device_t *usba_dev; 6992 uchar_t no_cpr = 0; 6993 int rval = USB_FAILURE; 6994 6995 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6996 "hubd_cpr_suspend: Begin"); 6997 6998 /* Make sure device is powered up to save state. */ 6999 mutex_enter(HUBD_MUTEX(hubd)); 7000 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7001 mutex_exit(HUBD_MUTEX(hubd)); 7002 7003 /* bring the device to full power */ 7004 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7005 mutex_enter(HUBD_MUTEX(hubd)); 7006 7007 switch (hubd->h_dev_state) { 7008 case USB_DEV_ONLINE: 7009 case USB_DEV_PWRED_DOWN: 7010 case USB_DEV_DISCONNECTED: 7011 /* find out if all our children have been quiesced */ 7012 nports = hubd->h_hub_descr.bNbrPorts; 7013 for (port = 1; (no_cpr == 0) && (port <= nports); port++) { 7014 usba_dev = hubd->h_usba_devices[port]; 7015 if (usba_dev != NULL) { 7016 mutex_enter(&usba_dev->usb_mutex); 7017 no_cpr += usba_dev->usb_no_cpr; 7018 mutex_exit(&usba_dev->usb_mutex); 7019 } 7020 } 7021 if (no_cpr > 0) { 7022 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7023 "Children busy - can't checkpoint"); 7024 /* remain in same state to fail checkpoint */ 7025 7026 break; 7027 } else { 7028 /* 7029 * do not suspend if our hotplug thread 7030 * or the deathrow thread is active 7031 */ 7032 if ((hubd->h_hotplug_thread > 1) || 7033 (hubd->h_cleanup_active == B_TRUE)) { 7034 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 7035 hubd->h_log_handle, 7036 "hotplug thread active - can't cpr"); 7037 /* remain in same state to fail checkpoint */ 7038 7039 break; 7040 } 7041 7042 /* quiesce ourselves now */ 7043 hubd_stop_polling(hubd); 7044 7045 /* close all the open pipes of our children */ 7046 for (port = 1; port <= nports; port++) { 7047 usba_dev = hubd->h_usba_devices[port]; 7048 if (usba_dev != NULL) { 7049 mutex_exit(HUBD_MUTEX(hubd)); 7050 usba_persistent_pipe_close(usba_dev); 7051 if (hubd_suspend_port(hubd, port)) { 7052 USB_DPRINTF_L0( 7053 DPRINT_MASK_HOTPLUG, 7054 hubd->h_log_handle, 7055 "suspending port %d failed", 7056 port); 7057 } 7058 mutex_enter(HUBD_MUTEX(hubd)); 7059 } 7060 7061 } 7062 hubd->h_dev_state = USB_DEV_SUSPENDED; 7063 7064 /* 7065 * if we are the root hub, we close our pipes 7066 * ourselves. 7067 */ 7068 if (usba_is_root_hub(hubd->h_dip)) { 7069 mutex_exit(HUBD_MUTEX(hubd)); 7070 usba_persistent_pipe_close( 7071 usba_get_usba_device(hubd->h_dip)); 7072 mutex_enter(HUBD_MUTEX(hubd)); 7073 } 7074 rval = USB_SUCCESS; 7075 7076 break; 7077 } 7078 case USB_DEV_SUSPENDED: 7079 default: 7080 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7081 "hubd_cpr_suspend: Illegal dev state=%d", 7082 hubd->h_dev_state); 7083 7084 break; 7085 } 7086 7087 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7088 mutex_exit(HUBD_MUTEX(hubd)); 7089 7090 return (rval); 7091 } 7092 7093 static void 7094 hubd_cpr_resume(dev_info_t *dip) 7095 { 7096 int rval, circ; 7097 7098 ndi_devi_enter(dip, &circ); 7099 /* 7100 * if we are the root hub, we open our pipes 7101 * ourselves. 7102 */ 7103 if (usba_is_root_hub(dip)) { 7104 rval = usba_persistent_pipe_open( 7105 usba_get_usba_device(dip)); 7106 ASSERT(rval == USB_SUCCESS); 7107 } 7108 (void) hubd_restore_state_cb(dip); 7109 ndi_devi_exit(dip, circ); 7110 } 7111 7112 7113 /* 7114 * hubd_restore_state_cb 7115 * Event callback to restore device state 7116 */ 7117 static int 7118 hubd_restore_state_cb(dev_info_t *dip) 7119 { 7120 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 7121 7122 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 7123 "hubd_restore_state_cb: Begin"); 7124 7125 /* restore the state of this device */ 7126 hubd_restore_device_state(dip, hubd); 7127 7128 return (USB_SUCCESS); 7129 } 7130 7131 7132 /* 7133 * registering for events 7134 */ 7135 static int 7136 hubd_register_events(hubd_t *hubd) 7137 { 7138 int rval = USB_SUCCESS; 7139 7140 if (usba_is_root_hub(hubd->h_dip)) { 7141 hubd_register_cpr_callback(hubd); 7142 } else { 7143 rval = usb_register_event_cbs(hubd->h_dip, &hubd_events, 0); 7144 } 7145 7146 return (rval); 7147 } 7148 7149 7150 /* 7151 * hubd cpr callback related functions 7152 * 7153 * hubd_cpr_post_user_callb: 7154 * This function is called during checkpoint & resume - 7155 * 1. after user threads are stopped during checkpoint 7156 * 2. after kernel threads are resumed during resume 7157 */ 7158 /* ARGSUSED */ 7159 static boolean_t 7160 hubd_cpr_post_user_callb(void *arg, int code) 7161 { 7162 hubd_cpr_t *cpr_cb = (hubd_cpr_t *)arg; 7163 hubd_t *hubd = cpr_cb->statep; 7164 int retry = 0; 7165 7166 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7167 "hubd_cpr_post_user_callb"); 7168 7169 switch (code) { 7170 case CB_CODE_CPR_CHKPT: 7171 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7172 "hubd_cpr_post_user_callb: CB_CODE_CPR_CHKPT"); 7173 7174 mutex_enter(HUBD_MUTEX(hubd)); 7175 7176 /* turn off deathrow thread */ 7177 hubd->h_cleanup_enabled = B_FALSE; 7178 7179 /* give up if deathrow thread doesn't exit */ 7180 while ((hubd->h_cleanup_active == B_TRUE) && (retry++ < 3)) { 7181 mutex_exit(HUBD_MUTEX(hubd)); 7182 delay(drv_usectohz(hubd_dip_cleanup_delay)); 7183 7184 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7185 "hubd_cpr_post_user_callb, waiting for " 7186 "deathrow thread to exit"); 7187 mutex_enter(HUBD_MUTEX(hubd)); 7188 } 7189 7190 mutex_exit(HUBD_MUTEX(hubd)); 7191 7192 /* save the state of the device */ 7193 (void) hubd_pre_suspend_event_cb(hubd->h_dip); 7194 7195 return (B_TRUE); 7196 case CB_CODE_CPR_RESUME: 7197 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7198 "hubd_cpr_post_user_callb: CB_CODE_CPR_RESUME"); 7199 7200 /* restore the state of the device */ 7201 (void) hubd_post_resume_event_cb(hubd->h_dip); 7202 7203 /* turn on deathrow thread */ 7204 mutex_enter(HUBD_MUTEX(hubd)); 7205 hubd->h_cleanup_enabled = B_TRUE; 7206 mutex_exit(HUBD_MUTEX(hubd)); 7207 7208 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 7209 7210 return (B_TRUE); 7211 default: 7212 7213 return (B_FALSE); 7214 } 7215 7216 } 7217 7218 7219 /* register callback with cpr framework */ 7220 void 7221 hubd_register_cpr_callback(hubd_t *hubd) 7222 { 7223 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7224 "hubd_register_cpr_callback"); 7225 7226 mutex_enter(HUBD_MUTEX(hubd)); 7227 hubd->h_cpr_cb = 7228 (hubd_cpr_t *)kmem_zalloc(sizeof (hubd_cpr_t), KM_SLEEP); 7229 mutex_exit(HUBD_MUTEX(hubd)); 7230 mutex_init(&hubd->h_cpr_cb->lockp, NULL, MUTEX_DRIVER, 7231 hubd->h_dev_data->dev_iblock_cookie); 7232 hubd->h_cpr_cb->statep = hubd; 7233 hubd->h_cpr_cb->cpr.cc_lockp = &hubd->h_cpr_cb->lockp; 7234 hubd->h_cpr_cb->cpr.cc_id = callb_add(hubd_cpr_post_user_callb, 7235 (void *)hubd->h_cpr_cb, CB_CL_CPR_POST_USER, "hubd"); 7236 } 7237 7238 7239 /* unregister callback with cpr framework */ 7240 void 7241 hubd_unregister_cpr_callback(hubd_t *hubd) 7242 { 7243 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 7244 "hubd_unregister_cpr_callback"); 7245 7246 if (hubd->h_cpr_cb) { 7247 (void) callb_delete(hubd->h_cpr_cb->cpr.cc_id); 7248 mutex_destroy(&hubd->h_cpr_cb->lockp); 7249 mutex_enter(HUBD_MUTEX(hubd)); 7250 kmem_free(hubd->h_cpr_cb, sizeof (hubd_cpr_t)); 7251 mutex_exit(HUBD_MUTEX(hubd)); 7252 } 7253 } 7254 7255 7256 /* 7257 * Power management 7258 * 7259 * create the pm components required for power management 7260 */ 7261 static void 7262 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd) 7263 { 7264 hub_power_t *hubpm; 7265 7266 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7267 "hubd_create_pm_components: Begin"); 7268 7269 /* Allocate the state structure */ 7270 hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP); 7271 7272 hubd->h_hubpm = hubpm; 7273 hubpm->hubp_hubd = hubd; 7274 hubpm->hubp_pm_capabilities = 0; 7275 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 7276 hubpm->hubp_time_at_full_power = ddi_get_time(); 7277 hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold; 7278 7279 /* alloc memory to save power states of children */ 7280 hubpm->hubp_child_pwrstate = (uint8_t *) 7281 kmem_zalloc(MAX_PORTS + 1, KM_SLEEP); 7282 7283 /* 7284 * if the enable remote wakeup fails 7285 * we still want to enable 7286 * parent notification so we can PM the children 7287 */ 7288 usb_enable_parent_notification(dip); 7289 7290 if (usb_handle_remote_wakeup(dip, 7291 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 7292 uint_t pwr_states; 7293 7294 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 7295 "hubd_create_pm_components: " 7296 "Remote Wakeup Enabled"); 7297 7298 if (usb_create_pm_components(dip, &pwr_states) == 7299 USB_SUCCESS) { 7300 mutex_enter(HUBD_MUTEX(hubd)); 7301 hubpm->hubp_wakeup_enabled = 1; 7302 hubpm->hubp_pwr_states = (uint8_t)pwr_states; 7303 7304 /* we are busy now till end of the attach */ 7305 hubd_pm_busy_component(hubd, dip, 0); 7306 mutex_exit(HUBD_MUTEX(hubd)); 7307 7308 /* bring the device to full power */ 7309 (void) pm_raise_power(dip, 0, 7310 USB_DEV_OS_FULL_PWR); 7311 } 7312 } 7313 7314 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7315 "hubd_create_pm_components: END"); 7316 } 7317 7318 7319 /* 7320 * Attachment point management 7321 */ 7322 /* ARGSUSED */ 7323 int 7324 usba_hubdi_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, 7325 cred_t *credp) 7326 { 7327 hubd_t *hubd; 7328 7329 if (otyp != OTYP_CHR) 7330 return (EINVAL); 7331 7332 hubd = hubd_get_soft_state(dip); 7333 if (hubd == NULL) { 7334 return (ENXIO); 7335 } 7336 7337 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7338 "hubd_open:"); 7339 7340 mutex_enter(HUBD_MUTEX(hubd)); 7341 if ((flags & FEXCL) && (hubd->h_softstate & HUBD_SS_ISOPEN)) { 7342 mutex_exit(HUBD_MUTEX(hubd)); 7343 7344 return (EBUSY); 7345 } 7346 7347 hubd->h_softstate |= HUBD_SS_ISOPEN; 7348 mutex_exit(HUBD_MUTEX(hubd)); 7349 7350 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "opened"); 7351 7352 return (0); 7353 } 7354 7355 7356 /* ARGSUSED */ 7357 int 7358 usba_hubdi_close(dev_info_t *dip, dev_t dev, int flag, int otyp, 7359 cred_t *credp) 7360 { 7361 hubd_t *hubd; 7362 7363 if (otyp != OTYP_CHR) { 7364 return (EINVAL); 7365 } 7366 7367 hubd = hubd_get_soft_state(dip); 7368 7369 if (hubd == NULL) { 7370 return (ENXIO); 7371 } 7372 7373 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "hubd_close:"); 7374 7375 mutex_enter(HUBD_MUTEX(hubd)); 7376 hubd->h_softstate &= ~HUBD_SS_ISOPEN; 7377 mutex_exit(HUBD_MUTEX(hubd)); 7378 7379 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "closed"); 7380 7381 return (0); 7382 } 7383 7384 7385 /* 7386 * hubd_ioctl: cfgadm controls 7387 */ 7388 /* ARGSUSED */ 7389 int 7390 usba_hubdi_ioctl(dev_info_t *self, dev_t dev, int cmd, intptr_t arg, 7391 int mode, cred_t *credp, int *rvalp) 7392 { 7393 int rv = 0; 7394 char *msg; /* for messages */ 7395 hubd_t *hubd; 7396 usb_port_t port = 0; 7397 dev_info_t *child_dip = NULL; 7398 dev_info_t *rh_dip; 7399 devctl_ap_state_t ap_state; 7400 struct devctl_iocdata *dcp = NULL; 7401 usb_pipe_state_t prev_pipe_state = 0; 7402 int circ, rh_circ, prh_circ; 7403 7404 if ((hubd = hubd_get_soft_state(self)) == NULL) { 7405 7406 return (ENXIO); 7407 } 7408 7409 rh_dip = hubd->h_usba_device->usb_root_hub_dip; 7410 7411 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7412 "usba_hubdi_ioctl: " 7413 "cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx", 7414 cmd, arg, mode, (void *)credp, (void *)rvalp, dev); 7415 7416 /* read devctl ioctl data */ 7417 if ((cmd != DEVCTL_AP_CONTROL) && 7418 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 7419 7420 return (EFAULT); 7421 } 7422 7423 /* 7424 * make sure the hub is connected before trying any 7425 * of the following operations: 7426 * configure, connect, disconnect 7427 */ 7428 mutex_enter(HUBD_MUTEX(hubd)); 7429 7430 switch (cmd) { 7431 case DEVCTL_AP_DISCONNECT: 7432 case DEVCTL_AP_UNCONFIGURE: 7433 case DEVCTL_AP_CONFIGURE: 7434 if (hubd->h_dev_state == USB_DEV_DISCONNECTED) { 7435 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7436 "hubd: already gone"); 7437 mutex_exit(HUBD_MUTEX(hubd)); 7438 if (dcp) { 7439 ndi_dc_freehdl(dcp); 7440 } 7441 7442 return (EIO); 7443 } 7444 7445 /* FALLTHROUGH */ 7446 case DEVCTL_AP_GETSTATE: 7447 if ((port = hubd_get_port_num(hubd, dcp)) == 0) { 7448 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7449 "hubd: bad port"); 7450 mutex_exit(HUBD_MUTEX(hubd)); 7451 if (dcp) { 7452 ndi_dc_freehdl(dcp); 7453 } 7454 7455 return (EINVAL); 7456 } 7457 break; 7458 7459 case DEVCTL_AP_CONTROL: 7460 7461 break; 7462 default: 7463 mutex_exit(HUBD_MUTEX(hubd)); 7464 if (dcp) { 7465 ndi_dc_freehdl(dcp); 7466 } 7467 7468 return (ENOTTY); 7469 } 7470 7471 /* should not happen, just in case */ 7472 if (hubd->h_dev_state == USB_DEV_SUSPENDED) { 7473 mutex_exit(HUBD_MUTEX(hubd)); 7474 if (dcp) { 7475 ndi_dc_freehdl(dcp); 7476 } 7477 7478 return (EIO); 7479 } 7480 7481 if (hubd->h_reset_port[port]) { 7482 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7483 "This port is resetting, just return"); 7484 mutex_exit(HUBD_MUTEX(hubd)); 7485 if (dcp) { 7486 ndi_dc_freehdl(dcp); 7487 } 7488 7489 return (EIO); 7490 } 7491 7492 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7493 mutex_exit(HUBD_MUTEX(hubd)); 7494 7495 /* go full power */ 7496 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7497 7498 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 7499 ndi_devi_enter(rh_dip, &rh_circ); 7500 ndi_devi_enter(hubd->h_dip, &circ); 7501 7502 mutex_enter(HUBD_MUTEX(hubd)); 7503 7504 hubd->h_hotplug_thread++; 7505 7506 /* stop polling if it was active */ 7507 if (hubd->h_ep1_ph) { 7508 mutex_exit(HUBD_MUTEX(hubd)); 7509 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 7510 USB_FLAGS_SLEEP); 7511 mutex_enter(HUBD_MUTEX(hubd)); 7512 7513 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 7514 hubd_stop_polling(hubd); 7515 } 7516 } 7517 7518 switch (cmd) { 7519 case DEVCTL_AP_DISCONNECT: 7520 if (hubd_delete_child(hubd, port, 7521 NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS) { 7522 rv = EIO; 7523 } 7524 7525 break; 7526 case DEVCTL_AP_UNCONFIGURE: 7527 if (hubd_delete_child(hubd, port, 7528 NDI_UNCONFIG, B_FALSE) != USB_SUCCESS) { 7529 rv = EIO; 7530 } 7531 7532 break; 7533 case DEVCTL_AP_CONFIGURE: 7534 /* toggle port */ 7535 if (hubd_toggle_port(hubd, port) != USB_SUCCESS) { 7536 rv = EIO; 7537 7538 break; 7539 } 7540 7541 (void) hubd_handle_port_connect(hubd, port); 7542 child_dip = hubd_get_child_dip(hubd, port); 7543 mutex_exit(HUBD_MUTEX(hubd)); 7544 7545 ndi_devi_exit(hubd->h_dip, circ); 7546 ndi_devi_exit(rh_dip, rh_circ); 7547 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 7548 if (child_dip == NULL) { 7549 rv = EIO; 7550 } else { 7551 ndi_hold_devi(child_dip); 7552 if (ndi_devi_online(child_dip, 0) != NDI_SUCCESS) 7553 rv = EIO; 7554 ndi_rele_devi(child_dip); 7555 } 7556 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 7557 ndi_devi_enter(rh_dip, &rh_circ); 7558 ndi_devi_enter(hubd->h_dip, &circ); 7559 7560 mutex_enter(HUBD_MUTEX(hubd)); 7561 7562 break; 7563 case DEVCTL_AP_GETSTATE: 7564 switch (hubd_cfgadm_state(hubd, port)) { 7565 case HUBD_CFGADM_DISCONNECTED: 7566 /* port previously 'disconnected' by cfgadm */ 7567 ap_state.ap_rstate = AP_RSTATE_DISCONNECTED; 7568 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7569 ap_state.ap_condition = AP_COND_OK; 7570 7571 break; 7572 case HUBD_CFGADM_UNCONFIGURED: 7573 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7574 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7575 ap_state.ap_condition = AP_COND_OK; 7576 7577 break; 7578 case HUBD_CFGADM_CONFIGURED: 7579 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7580 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7581 ap_state.ap_condition = AP_COND_OK; 7582 7583 break; 7584 case HUBD_CFGADM_STILL_REFERENCED: 7585 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7586 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7587 ap_state.ap_condition = AP_COND_UNUSABLE; 7588 7589 break; 7590 case HUBD_CFGADM_EMPTY: 7591 default: 7592 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7593 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7594 ap_state.ap_condition = AP_COND_OK; 7595 7596 break; 7597 } 7598 7599 ap_state.ap_last_change = (time_t)-1; 7600 ap_state.ap_error_code = 0; 7601 ap_state.ap_in_transition = 0; 7602 7603 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7604 "DEVCTL_AP_GETSTATE: " 7605 "ostate=0x%x, rstate=0x%x, condition=0x%x", 7606 ap_state.ap_ostate, 7607 ap_state.ap_rstate, ap_state.ap_condition); 7608 7609 /* copy the return-AP-state information to the user space */ 7610 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 7611 rv = EFAULT; 7612 } 7613 7614 break; 7615 case DEVCTL_AP_CONTROL: 7616 { 7617 /* 7618 * Generic devctl for hardware-specific functionality. 7619 * For list of sub-commands see hubd_impl.h 7620 */ 7621 hubd_ioctl_data_t ioc; /* for 64 byte copies */ 7622 7623 /* copy user ioctl data in first */ 7624 #ifdef _MULTI_DATAMODEL 7625 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 7626 hubd_ioctl_data_32_t ioc32; 7627 7628 if (ddi_copyin((void *)arg, (void *)&ioc32, 7629 sizeof (ioc32), mode) != 0) { 7630 rv = EFAULT; 7631 7632 break; 7633 } 7634 ioc.cmd = (uint_t)ioc32.cmd; 7635 ioc.port = (uint_t)ioc32.port; 7636 ioc.get_size = (uint_t)ioc32.get_size; 7637 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 7638 ioc.bufsiz = (uint_t)ioc32.bufsiz; 7639 ioc.misc_arg = (uint_t)ioc32.misc_arg; 7640 } else 7641 #endif /* _MULTI_DATAMODEL */ 7642 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc), 7643 mode) != 0) { 7644 rv = EFAULT; 7645 7646 break; 7647 } 7648 7649 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7650 "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d" 7651 "\n\tbuf=0x%p, bufsiz=%d, misc_arg=%d", ioc.cmd, 7652 ioc.port, ioc.get_size, (void *)ioc.buf, ioc.bufsiz, 7653 ioc.misc_arg); 7654 7655 /* 7656 * To avoid BE/LE and 32/64 issues, a get_size always 7657 * returns a 32-bit number. 7658 */ 7659 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) { 7660 rv = EINVAL; 7661 7662 break; 7663 } 7664 7665 switch (ioc.cmd) { 7666 case USB_DESCR_TYPE_DEV: 7667 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC"; 7668 if (ioc.get_size) { 7669 /* uint32 so this works 32/64 */ 7670 uint32_t size = sizeof (usb_dev_descr_t); 7671 7672 if (ddi_copyout((void *)&size, ioc.buf, 7673 ioc.bufsiz, mode) != 0) { 7674 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7675 hubd->h_log_handle, 7676 "%s: get_size copyout failed", msg); 7677 rv = EIO; 7678 7679 break; 7680 } 7681 } else { /* send out the actual descr */ 7682 usb_dev_descr_t *dev_descrp; 7683 7684 /* check child_dip */ 7685 if ((child_dip = hubd_get_child_dip(hubd, 7686 ioc.port)) == NULL) { 7687 rv = EINVAL; 7688 7689 break; 7690 } 7691 7692 dev_descrp = usb_get_dev_descr(child_dip); 7693 if (ioc.bufsiz != sizeof (*dev_descrp)) { 7694 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7695 hubd->h_log_handle, 7696 "%s: bufsize passed (%d) != sizeof " 7697 "usba_device_descr_t (%d)", msg, 7698 ioc.bufsiz, dev_descrp->bLength); 7699 rv = EINVAL; 7700 7701 break; 7702 } 7703 7704 if (ddi_copyout((void *)dev_descrp, 7705 ioc.buf, ioc.bufsiz, mode) != 0) { 7706 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7707 hubd->h_log_handle, 7708 "%s: copyout failed.", msg); 7709 rv = EIO; 7710 7711 break; 7712 } 7713 } 7714 break; 7715 case USB_DESCR_TYPE_STRING: 7716 { 7717 char *str; 7718 uint32_t size; 7719 usba_device_t *usba_device; 7720 7721 msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR"; 7722 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7723 "%s: string request: %d", msg, ioc.misc_arg); 7724 7725 /* recheck */ 7726 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7727 NULL) { 7728 rv = EINVAL; 7729 7730 break; 7731 } 7732 usba_device = usba_get_usba_device(child_dip); 7733 7734 switch (ioc.misc_arg) { 7735 case HUBD_MFG_STR: 7736 str = usba_device->usb_mfg_str; 7737 7738 break; 7739 case HUBD_PRODUCT_STR: 7740 str = usba_device->usb_product_str; 7741 7742 break; 7743 case HUBD_SERIALNO_STR: 7744 str = usba_device->usb_serialno_str; 7745 7746 break; 7747 case HUBD_CFG_DESCR_STR: 7748 mutex_enter(&usba_device->usb_mutex); 7749 str = usba_device->usb_cfg_str_descr[ 7750 usba_device->usb_active_cfg_ndx]; 7751 mutex_exit(&usba_device->usb_mutex); 7752 7753 break; 7754 default: 7755 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7756 hubd->h_log_handle, 7757 "%s: Invalid string request", msg); 7758 rv = EINVAL; 7759 7760 break; 7761 } /* end of switch */ 7762 7763 if (rv != 0) { 7764 7765 break; 7766 } 7767 7768 size = (str != NULL) ? strlen(str) + 1 : 0; 7769 if (ioc.get_size) { 7770 if (ddi_copyout((void *)&size, ioc.buf, 7771 ioc.bufsiz, mode) != 0) { 7772 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7773 hubd->h_log_handle, 7774 "%s: copyout of size failed.", msg); 7775 rv = EIO; 7776 7777 break; 7778 } 7779 } else { 7780 if (size == 0) { 7781 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, 7782 hubd->h_log_handle, 7783 "%s: String is NULL", msg); 7784 rv = EINVAL; 7785 7786 break; 7787 } 7788 7789 if (ioc.bufsiz != size) { 7790 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7791 hubd->h_log_handle, 7792 "%s: string buf size wrong", msg); 7793 rv = EINVAL; 7794 7795 break; 7796 } 7797 7798 if (ddi_copyout((void *)str, ioc.buf, 7799 ioc.bufsiz, mode) != 0) { 7800 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7801 hubd->h_log_handle, 7802 "%s: copyout failed.", msg); 7803 rv = EIO; 7804 7805 break; 7806 } 7807 } 7808 break; 7809 } 7810 case HUBD_GET_CFGADM_NAME: 7811 { 7812 uint32_t name_len; 7813 const char *name; 7814 7815 /* recheck */ 7816 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7817 NULL) { 7818 rv = EINVAL; 7819 7820 break; 7821 } 7822 name = ddi_node_name(child_dip); 7823 if (name == NULL) { 7824 name = "unsupported"; 7825 } 7826 name_len = strlen(name) + 1; 7827 7828 msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME"; 7829 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7830 "%s: name=%s name_len=%d", msg, name, name_len); 7831 7832 if (ioc.get_size) { 7833 if (ddi_copyout((void *)&name_len, 7834 ioc.buf, ioc.bufsiz, mode) != 0) { 7835 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7836 hubd->h_log_handle, 7837 "%s: copyout of size failed", msg); 7838 rv = EIO; 7839 7840 break; 7841 } 7842 } else { 7843 if (ioc.bufsiz != name_len) { 7844 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7845 hubd->h_log_handle, 7846 "%s: string buf length wrong", msg); 7847 rv = EINVAL; 7848 7849 break; 7850 } 7851 7852 if (ddi_copyout((void *)name, ioc.buf, 7853 ioc.bufsiz, mode) != 0) { 7854 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7855 hubd->h_log_handle, 7856 "%s: copyout failed.", msg); 7857 rv = EIO; 7858 7859 break; 7860 } 7861 } 7862 7863 break; 7864 } 7865 7866 /* 7867 * Return the config index for the currently-configured 7868 * configuration. 7869 */ 7870 case HUBD_GET_CURRENT_CONFIG: 7871 { 7872 uint_t config_index; 7873 uint32_t size = sizeof (config_index); 7874 usba_device_t *usba_device; 7875 7876 msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG"; 7877 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7878 "%s", msg); 7879 7880 /* 7881 * Return the config index for the configuration 7882 * currently in use. 7883 * Recheck if child_dip exists 7884 */ 7885 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7886 NULL) { 7887 rv = EINVAL; 7888 7889 break; 7890 } 7891 7892 usba_device = usba_get_usba_device(child_dip); 7893 mutex_enter(&usba_device->usb_mutex); 7894 config_index = usba_device->usb_active_cfg_ndx; 7895 mutex_exit(&usba_device->usb_mutex); 7896 7897 if (ioc.get_size) { 7898 if (ddi_copyout((void *)&size, 7899 ioc.buf, ioc.bufsiz, mode) != 0) { 7900 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7901 hubd->h_log_handle, 7902 "%s: copyout of size failed.", msg); 7903 rv = EIO; 7904 7905 break; 7906 } 7907 } else { 7908 if (ioc.bufsiz != size) { 7909 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7910 hubd->h_log_handle, 7911 "%s: buffer size wrong", msg); 7912 rv = EINVAL; 7913 7914 break; 7915 } 7916 if (ddi_copyout((void *)&config_index, 7917 ioc.buf, ioc.bufsiz, mode) != 0) { 7918 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7919 hubd->h_log_handle, 7920 "%s: copyout failed", msg); 7921 rv = EIO; 7922 } 7923 } 7924 7925 break; 7926 } 7927 case HUBD_GET_DEVICE_PATH: 7928 { 7929 char *path; 7930 uint32_t size; 7931 7932 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH"; 7933 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7934 "%s", msg); 7935 7936 /* Recheck if child_dip exists */ 7937 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7938 NULL) { 7939 rv = EINVAL; 7940 7941 break; 7942 } 7943 7944 /* ddi_pathname doesn't supply /devices, so we do. */ 7945 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7946 (void) strcpy(path, "/devices"); 7947 (void) ddi_pathname(child_dip, path + strlen(path)); 7948 size = strlen(path) + 1; 7949 7950 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7951 "%s: device path=%s size=%d", msg, path, size); 7952 7953 if (ioc.get_size) { 7954 if (ddi_copyout((void *)&size, 7955 ioc.buf, ioc.bufsiz, mode) != 0) { 7956 7957 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7958 hubd->h_log_handle, 7959 "%s: copyout of size failed.", msg); 7960 rv = EIO; 7961 } 7962 } else { 7963 if (ioc.bufsiz != size) { 7964 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7965 hubd->h_log_handle, 7966 "%s: buffer wrong size.", msg); 7967 rv = EINVAL; 7968 } else if (ddi_copyout((void *)path, 7969 ioc.buf, ioc.bufsiz, mode) != 0) { 7970 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7971 hubd->h_log_handle, 7972 "%s: copyout failed.", msg); 7973 rv = EIO; 7974 } 7975 } 7976 kmem_free(path, MAXPATHLEN); 7977 7978 break; 7979 } 7980 case HUBD_REFRESH_DEVDB: 7981 msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB"; 7982 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7983 "%s", msg); 7984 7985 if ((rv = usba_devdb_refresh()) != USB_SUCCESS) { 7986 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7987 hubd->h_log_handle, 7988 "%s: Failed: %d", msg, rv); 7989 rv = EIO; 7990 } 7991 7992 break; 7993 default: 7994 rv = ENOTSUP; 7995 } /* end switch */ 7996 7997 break; 7998 } 7999 8000 default: 8001 rv = ENOTTY; 8002 } 8003 8004 if (dcp) { 8005 ndi_dc_freehdl(dcp); 8006 } 8007 8008 /* allow hotplug thread now */ 8009 hubd->h_hotplug_thread--; 8010 8011 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 8012 hubd->h_ep1_ph && (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 8013 hubd_start_polling(hubd, 0); 8014 } 8015 mutex_exit(HUBD_MUTEX(hubd)); 8016 8017 ndi_devi_exit(hubd->h_dip, circ); 8018 ndi_devi_exit(rh_dip, rh_circ); 8019 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 8020 8021 mutex_enter(HUBD_MUTEX(hubd)); 8022 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 8023 mutex_exit(HUBD_MUTEX(hubd)); 8024 8025 return (rv); 8026 } 8027 8028 8029 /* 8030 * Helper func used only to help construct the names for the attachment point 8031 * minor nodes. Used only in usba_hubdi_attach. 8032 * Returns whether it found ancestry or not (USB_SUCCESS if yes). 8033 * ports between the root hub and the device represented by dip. 8034 * E.g., "2.4.3.1" means this device is 8035 * plugged into port 1 of a hub that is 8036 * plugged into port 3 of a hub that is 8037 * plugged into port 4 of a hub that is 8038 * plugged into port 2 of the root hub. 8039 * NOTE: Max ap_id path len is HUBD_APID_NAMELEN (32 chars), which is 8040 * more than sufficient (as hubs are a max 6 levels deep, port needs 3 8041 * chars plus NULL each) 8042 */ 8043 void 8044 hubd_get_ancestry_str(hubd_t *hubd) 8045 { 8046 char ap_name[HUBD_APID_NAMELEN]; 8047 dev_info_t *pdip; 8048 hubd_t *phubd; 8049 usb_port_t port; 8050 8051 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8052 "hubd_get_ancestry_str: hubd=0x%p", (void *)hubd); 8053 8054 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8055 8056 /* 8057 * The function is extended to support wire adapter class 8058 * devices introduced by WUSB spec. The node name is no 8059 * longer "hub" only. 8060 * Generate the ap_id str based on the parent and child 8061 * relationship instead of retrieving it from the hub 8062 * device path, which simplifies the algorithm. 8063 */ 8064 if (usba_is_root_hub(hubd->h_dip)) { 8065 hubd->h_ancestry_str[0] = '\0'; 8066 } else { 8067 port = hubd->h_usba_device->usb_port; 8068 mutex_exit(HUBD_MUTEX(hubd)); 8069 8070 pdip = ddi_get_parent(hubd->h_dip); 8071 /* 8072 * The parent of wire adapter device might be usb_mid. 8073 * Need to look further up for hub device 8074 */ 8075 if (strcmp(ddi_driver_name(pdip), "usb_mid") == 0) { 8076 pdip = ddi_get_parent(pdip); 8077 ASSERT(pdip != NULL); 8078 } 8079 8080 phubd = hubd_get_soft_state(pdip); 8081 8082 mutex_enter(HUBD_MUTEX(phubd)); 8083 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 8084 phubd->h_ancestry_str, port); 8085 mutex_exit(HUBD_MUTEX(phubd)); 8086 8087 mutex_enter(HUBD_MUTEX(hubd)); 8088 (void) strcpy(hubd->h_ancestry_str, ap_name); 8089 (void) strcat(hubd->h_ancestry_str, "."); 8090 } 8091 } 8092 8093 8094 /* Get which port to operate on. */ 8095 static usb_port_t 8096 hubd_get_port_num(hubd_t *hubd, struct devctl_iocdata *dcp) 8097 { 8098 int32_t port; 8099 8100 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8101 8102 /* Get which port to operate on. */ 8103 if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) { 8104 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8105 "hubd_get_port_num: port lookup failed"); 8106 port = 0; 8107 } 8108 8109 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8110 "hubd_get_port_num: hubd=0x%p, port=%d", (void *)hubd, port); 8111 8112 return ((usb_port_t)port); 8113 } 8114 8115 8116 /* check if child still exists */ 8117 static dev_info_t * 8118 hubd_get_child_dip(hubd_t *hubd, usb_port_t port) 8119 { 8120 dev_info_t *child_dip = hubd->h_children_dips[port]; 8121 8122 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8123 "hubd_get_child_dip: hubd=0x%p, port=%d", (void *)hubd, port); 8124 8125 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8126 8127 return (child_dip); 8128 } 8129 8130 8131 /* 8132 * hubd_cfgadm_state: 8133 * 8134 * child_dip list port_state cfgadm_state 8135 * -------------- ---------- ------------ 8136 * != NULL connected configured or 8137 * unconfigured 8138 * != NULL not connected disconnect but 8139 * busy/still referenced 8140 * NULL connected logically disconnected 8141 * NULL not connected empty 8142 */ 8143 static uint_t 8144 hubd_cfgadm_state(hubd_t *hubd, usb_port_t port) 8145 { 8146 uint_t state; 8147 dev_info_t *child_dip = hubd_get_child_dip(hubd, port); 8148 8149 if (child_dip) { 8150 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 8151 /* 8152 * connected, now check if driver exists 8153 */ 8154 if (DEVI_IS_DEVICE_OFFLINE(child_dip) || 8155 !i_ddi_devi_attached(child_dip)) { 8156 state = HUBD_CFGADM_UNCONFIGURED; 8157 } else { 8158 state = HUBD_CFGADM_CONFIGURED; 8159 } 8160 } else { 8161 /* 8162 * this means that the dip is around for 8163 * a device that is still referenced but 8164 * has been yanked out. So the cfgadm info 8165 * for this state should be EMPTY (port empty) 8166 * and CONFIGURED (dip still valid). 8167 */ 8168 state = HUBD_CFGADM_STILL_REFERENCED; 8169 } 8170 } else { 8171 /* connected but no child dip */ 8172 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 8173 /* logically disconnected */ 8174 state = HUBD_CFGADM_DISCONNECTED; 8175 } else { 8176 /* physically disconnected */ 8177 state = HUBD_CFGADM_EMPTY; 8178 } 8179 } 8180 8181 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8182 "hubd_cfgadm_state: hubd=0x%p, port=%d state=0x%x", 8183 (void *)hubd, port, state); 8184 8185 return (state); 8186 } 8187 8188 8189 /* 8190 * hubd_toggle_port: 8191 */ 8192 static int 8193 hubd_toggle_port(hubd_t *hubd, usb_port_t port) 8194 { 8195 usb_hub_descr_t *hub_descr; 8196 int wait; 8197 uint_t retry; 8198 uint16_t status; 8199 uint16_t change; 8200 8201 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 8202 "hubd_toggle_port: hubd=0x%p, port=%d", (void *)hubd, port); 8203 8204 if ((hubd_disable_port_power(hubd, port)) != USB_SUCCESS) { 8205 8206 return (USB_FAILURE); 8207 } 8208 8209 /* 8210 * see hubd_enable_all_port_power() which 8211 * requires longer delay for hubs. 8212 */ 8213 mutex_exit(HUBD_MUTEX(hubd)); 8214 delay(drv_usectohz(hubd_device_delay / 10)); 8215 mutex_enter(HUBD_MUTEX(hubd)); 8216 8217 hub_descr = &hubd->h_hub_descr; 8218 8219 /* 8220 * According to section 11.11 of USB, for hubs with no power 8221 * switches, bPwrOn2PwrGood is zero. But we wait for some 8222 * arbitrary time to enable power to become stable. 8223 * 8224 * If an hub supports port power swicthing, we need to wait 8225 * at least 20ms before accesing corresonding usb port. 8226 */ 8227 if ((hub_descr->wHubCharacteristics & 8228 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 8229 wait = hubd_device_delay / 10; 8230 } else { 8231 wait = max(HUB_DEFAULT_POPG, 8232 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 8233 } 8234 8235 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 8236 "hubd_toggle_port: popg=%d wait=%d", 8237 hub_descr->bPwrOn2PwrGood, wait); 8238 8239 retry = 0; 8240 8241 do { 8242 (void) hubd_enable_port_power(hubd, port); 8243 8244 mutex_exit(HUBD_MUTEX(hubd)); 8245 delay(drv_usectohz(wait)); 8246 mutex_enter(HUBD_MUTEX(hubd)); 8247 8248 /* Get port status */ 8249 (void) hubd_determine_port_status(hubd, port, 8250 &status, &change, 0); 8251 8252 /* For retry if any, use some extra delay */ 8253 wait = max(wait, hubd_device_delay / 10); 8254 8255 retry++; 8256 8257 } while ((!(status & PORT_STATUS_PPS)) && (retry < HUBD_PORT_RETRY)); 8258 8259 /* Print warning message if port has no power */ 8260 if (!(status & PORT_STATUS_PPS)) { 8261 8262 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 8263 "hubd_toggle_port: port %d power-on failed, " 8264 "port status 0x%x", port, status); 8265 8266 return (USB_FAILURE); 8267 } 8268 8269 return (USB_SUCCESS); 8270 } 8271 8272 8273 /* 8274 * hubd_init_power_budget: 8275 * Init power budget variables in hubd structure. According 8276 * to USB spec, the power budget rules are: 8277 * 1. local-powered hubs including root-hubs can supply 8278 * 500mA to each port at maximum 8279 * 2. two bus-powered hubs are not allowed to concatenate 8280 * 3. bus-powered hubs can supply 100mA to each port at 8281 * maximum, and the power consumed by all downstream 8282 * ports and the hub itself cannot exceed the max power 8283 * supplied by the upstream port, i.e., 500mA 8284 * The routine is only called during hub attach time 8285 */ 8286 static int 8287 hubd_init_power_budget(hubd_t *hubd) 8288 { 8289 uint16_t status = 0; 8290 usba_device_t *hubd_ud = NULL; 8291 size_t size; 8292 usb_cfg_descr_t cfg_descr; 8293 dev_info_t *pdip = NULL; 8294 hubd_t *phubd = NULL; 8295 8296 if (hubd->h_ignore_pwr_budget) { 8297 8298 return (USB_SUCCESS); 8299 } 8300 8301 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 8302 "hubd_init_power_budget:"); 8303 8304 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8305 ASSERT(hubd->h_default_pipe != 0); 8306 mutex_exit(HUBD_MUTEX(hubd)); 8307 8308 /* get device status */ 8309 if ((usb_get_status(hubd->h_dip, hubd->h_default_pipe, 8310 HUB_GET_DEVICE_STATUS_TYPE, 8311 0, &status, 0)) != USB_SUCCESS) { 8312 mutex_enter(HUBD_MUTEX(hubd)); 8313 8314 return (USB_FAILURE); 8315 } 8316 8317 hubd_ud = usba_get_usba_device(hubd->h_dip); 8318 8319 size = usb_parse_cfg_descr(hubd_ud->usb_cfg, hubd_ud->usb_cfg_length, 8320 &cfg_descr, USB_CFG_DESCR_SIZE); 8321 8322 if (size != USB_CFG_DESCR_SIZE) { 8323 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8324 "get hub configuration descriptor failed"); 8325 mutex_enter(HUBD_MUTEX(hubd)); 8326 8327 return (USB_FAILURE); 8328 } 8329 8330 mutex_enter(HUBD_MUTEX(hubd)); 8331 8332 hubd->h_local_pwr_capable = (cfg_descr.bmAttributes & 8333 USB_CFG_ATTR_SELFPWR); 8334 8335 if (hubd->h_local_pwr_capable) { 8336 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8337 "hub is capable of local power"); 8338 } 8339 8340 hubd->h_local_pwr_on = (status & 8341 USB_DEV_SLF_PWRD_STATUS) && hubd->h_local_pwr_capable; 8342 8343 if (hubd->h_local_pwr_on) { 8344 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8345 "hub is local-powered"); 8346 8347 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8348 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8349 } else { 8350 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8351 USB_LOW_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8352 8353 hubd->h_pwr_left = (USB_PWR_UNIT_LOAD * 8354 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8355 8356 ASSERT(!usba_is_root_hub(hubd->h_dip)); 8357 8358 if (!usba_is_root_hub(hubd->h_dip)) { 8359 /* 8360 * two bus-powered hubs are not 8361 * allowed to be concatenated 8362 */ 8363 mutex_exit(HUBD_MUTEX(hubd)); 8364 8365 pdip = ddi_get_parent(hubd->h_dip); 8366 phubd = hubd_get_soft_state(pdip); 8367 ASSERT(phubd != NULL); 8368 8369 if (!phubd->h_ignore_pwr_budget) { 8370 mutex_enter(HUBD_MUTEX(phubd)); 8371 if (phubd->h_local_pwr_on == B_FALSE) { 8372 USB_DPRINTF_L1(DPRINT_MASK_HUB, 8373 hubd->h_log_handle, 8374 "two bus-powered hubs cannot " 8375 "be concatenated"); 8376 8377 mutex_exit(HUBD_MUTEX(phubd)); 8378 mutex_enter(HUBD_MUTEX(hubd)); 8379 8380 return (USB_FAILURE); 8381 } 8382 mutex_exit(HUBD_MUTEX(phubd)); 8383 } 8384 8385 mutex_enter(HUBD_MUTEX(hubd)); 8386 8387 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8388 "hub is bus-powered"); 8389 } else { 8390 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8391 "root-hub must be local-powered"); 8392 } 8393 8394 /* 8395 * Subtract the power consumed by the hub itself 8396 * and get the power that can be supplied to 8397 * downstream ports 8398 */ 8399 hubd->h_pwr_left -= 8400 hubd->h_hub_descr.bHubContrCurrent / 8401 USB_CFG_DESCR_PWR_UNIT; 8402 if (hubd->h_pwr_left < 0) { 8403 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8404 "hubd->h_pwr_left is less than bHubContrCurrent, " 8405 "should fail"); 8406 8407 return (USB_FAILURE); 8408 } 8409 } 8410 8411 return (USB_SUCCESS); 8412 } 8413 8414 8415 /* 8416 * usba_hubdi_check_power_budget: 8417 * Check if the hub has enough power budget to allow a 8418 * child device to select a configuration of config_index. 8419 */ 8420 int 8421 usba_hubdi_check_power_budget(dev_info_t *dip, usba_device_t *child_ud, 8422 uint_t config_index) 8423 { 8424 int16_t pwr_left, pwr_limit, pwr_required; 8425 size_t size; 8426 usb_cfg_descr_t cfg_descr; 8427 hubd_t *hubd; 8428 8429 if ((hubd = hubd_get_soft_state(dip)) == NULL) { 8430 8431 return (USB_FAILURE); 8432 } 8433 8434 if (hubd->h_ignore_pwr_budget) { 8435 8436 return (USB_SUCCESS); 8437 } 8438 8439 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8440 "usba_hubdi_check_power_budget: " 8441 "dip=0x%p child_ud=0x%p conf_index=%d", (void *)dip, 8442 (void *)child_ud, config_index); 8443 8444 mutex_enter(HUBD_MUTEX(hubd)); 8445 pwr_limit = hubd->h_pwr_limit; 8446 if (hubd->h_local_pwr_on == B_FALSE) { 8447 pwr_left = hubd->h_pwr_left; 8448 pwr_limit = (pwr_limit <= pwr_left) ? pwr_limit : pwr_left; 8449 } 8450 mutex_exit(HUBD_MUTEX(hubd)); 8451 8452 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8453 "usba_hubdi_check_power_budget: " 8454 "available power is %dmA", pwr_limit * USB_CFG_DESCR_PWR_UNIT); 8455 8456 size = usb_parse_cfg_descr( 8457 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 8458 &cfg_descr, USB_CFG_DESCR_SIZE); 8459 8460 if (size != USB_CFG_DESCR_SIZE) { 8461 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8462 "get hub configuration descriptor failed"); 8463 8464 return (USB_FAILURE); 8465 } 8466 8467 pwr_required = cfg_descr.bMaxPower; 8468 8469 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8470 "usba_hubdi_check_power_budget: " 8471 "child bmAttributes=0x%x bMaxPower=%d " 8472 "with config_index=%d", cfg_descr.bmAttributes, 8473 pwr_required, config_index); 8474 8475 if (pwr_required > pwr_limit) { 8476 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8477 "configuration %d for device %s %s at port %d " 8478 "exceeds power available for this port, please " 8479 "re-insert your device into another hub port which " 8480 "has enough power", 8481 config_index, 8482 child_ud->usb_mfg_str, 8483 child_ud->usb_product_str, 8484 child_ud->usb_port); 8485 8486 return (USB_FAILURE); 8487 } 8488 8489 return (USB_SUCCESS); 8490 } 8491 8492 8493 /* 8494 * usba_hubdi_incr_power_budget: 8495 * Increase the hub power budget value when a child device 8496 * is removed from a bus-powered hub port. 8497 */ 8498 void 8499 usba_hubdi_incr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8500 { 8501 uint16_t pwr_value; 8502 hubd_t *hubd = hubd_get_soft_state(dip); 8503 8504 ASSERT(hubd != NULL); 8505 8506 if (hubd->h_ignore_pwr_budget) { 8507 8508 return; 8509 } 8510 8511 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8512 "usba_hubdi_incr_power_budget: " 8513 "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud); 8514 8515 mutex_enter(HUBD_MUTEX(hubd)); 8516 if (hubd->h_local_pwr_on == B_TRUE) { 8517 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8518 "usba_hubdi_incr_power_budget: " 8519 "hub is local powered"); 8520 mutex_exit(HUBD_MUTEX(hubd)); 8521 8522 return; 8523 } 8524 mutex_exit(HUBD_MUTEX(hubd)); 8525 8526 mutex_enter(&child_ud->usb_mutex); 8527 if (child_ud->usb_pwr_from_hub == 0) { 8528 mutex_exit(&child_ud->usb_mutex); 8529 8530 return; 8531 } 8532 pwr_value = child_ud->usb_pwr_from_hub; 8533 mutex_exit(&child_ud->usb_mutex); 8534 8535 mutex_enter(HUBD_MUTEX(hubd)); 8536 hubd->h_pwr_left += pwr_value; 8537 8538 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8539 "usba_hubdi_incr_power_budget: " 8540 "available power is %dmA, increased by %dmA", 8541 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8542 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8543 8544 mutex_exit(HUBD_MUTEX(hubd)); 8545 8546 mutex_enter(&child_ud->usb_mutex); 8547 child_ud->usb_pwr_from_hub = 0; 8548 mutex_exit(&child_ud->usb_mutex); 8549 } 8550 8551 8552 /* 8553 * usba_hubdi_decr_power_budget: 8554 * Decrease the hub power budget value when a child device 8555 * is inserted to a bus-powered hub port. 8556 */ 8557 void 8558 usba_hubdi_decr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8559 { 8560 uint16_t pwr_value; 8561 size_t size; 8562 usb_cfg_descr_t cfg_descr; 8563 hubd_t *hubd = hubd_get_soft_state(dip); 8564 8565 ASSERT(hubd != NULL); 8566 8567 if (hubd->h_ignore_pwr_budget) { 8568 8569 return; 8570 } 8571 8572 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8573 "usba_hubdi_decr_power_budget: " 8574 "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud); 8575 8576 mutex_enter(HUBD_MUTEX(hubd)); 8577 if (hubd->h_local_pwr_on == B_TRUE) { 8578 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8579 "usba_hubdi_decr_power_budget: " 8580 "hub is local powered"); 8581 mutex_exit(HUBD_MUTEX(hubd)); 8582 8583 return; 8584 } 8585 mutex_exit(HUBD_MUTEX(hubd)); 8586 8587 mutex_enter(&child_ud->usb_mutex); 8588 if (child_ud->usb_pwr_from_hub > 0) { 8589 mutex_exit(&child_ud->usb_mutex); 8590 8591 return; 8592 } 8593 mutex_exit(&child_ud->usb_mutex); 8594 8595 size = usb_parse_cfg_descr( 8596 child_ud->usb_cfg, child_ud->usb_cfg_length, 8597 &cfg_descr, USB_CFG_DESCR_SIZE); 8598 ASSERT(size == USB_CFG_DESCR_SIZE); 8599 8600 mutex_enter(HUBD_MUTEX(hubd)); 8601 pwr_value = cfg_descr.bMaxPower; 8602 hubd->h_pwr_left -= pwr_value; 8603 ASSERT(hubd->h_pwr_left >= 0); 8604 8605 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8606 "usba_hubdi_decr_power_budget: " 8607 "available power is %dmA, decreased by %dmA", 8608 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8609 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8610 8611 mutex_exit(HUBD_MUTEX(hubd)); 8612 8613 mutex_enter(&child_ud->usb_mutex); 8614 child_ud->usb_pwr_from_hub = pwr_value; 8615 mutex_exit(&child_ud->usb_mutex); 8616 } 8617 8618 /* 8619 * hubd_wait_for_hotplug_exit: 8620 * Waiting for the exit of the running hotplug thread or ioctl thread. 8621 */ 8622 static int 8623 hubd_wait_for_hotplug_exit(hubd_t *hubd) 8624 { 8625 clock_t until = drv_usectohz(1000000); 8626 int rval; 8627 8628 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8629 8630 if (hubd->h_hotplug_thread) { 8631 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8632 "waiting for hubd hotplug thread exit"); 8633 rval = cv_reltimedwait(&hubd->h_cv_hotplug_dev, 8634 &hubd->h_mutex, until, TR_CLOCK_TICK); 8635 8636 if ((rval <= 0) && (hubd->h_hotplug_thread)) { 8637 8638 return (USB_FAILURE); 8639 } 8640 } 8641 8642 return (USB_SUCCESS); 8643 } 8644 8645 /* 8646 * hubd_reset_thread: 8647 * handles the "USB_RESET_LVL_REATTACH" reset of usb device. 8648 * 8649 * - delete the child (force detaching the device and its children) 8650 * - reset the corresponding parent hub port 8651 * - create the child (force re-attaching the device and its children) 8652 */ 8653 static void 8654 hubd_reset_thread(void *arg) 8655 { 8656 hubd_reset_arg_t *hd_arg = (hubd_reset_arg_t *)arg; 8657 hubd_t *hubd = hd_arg->hubd; 8658 uint16_t reset_port = hd_arg->reset_port; 8659 uint16_t status, change; 8660 hub_power_t *hubpm; 8661 dev_info_t *hdip = hubd->h_dip; 8662 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 8663 dev_info_t *child_dip; 8664 boolean_t online_child = B_FALSE; 8665 int prh_circ, rh_circ, circ, devinst; 8666 char *devname; 8667 int i = 0; 8668 int rval = USB_FAILURE; 8669 8670 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8671 "hubd_reset_thread: started, hubd_reset_port = 0x%x", reset_port); 8672 8673 kmem_free(arg, sizeof (hubd_reset_arg_t)); 8674 8675 mutex_enter(HUBD_MUTEX(hubd)); 8676 8677 child_dip = hubd->h_children_dips[reset_port]; 8678 ASSERT(child_dip != NULL); 8679 8680 devname = (char *)ddi_driver_name(child_dip); 8681 devinst = ddi_get_instance(child_dip); 8682 8683 /* if our bus power entry point is active, quit the reset */ 8684 if (hubd->h_bus_pwr) { 8685 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8686 "%s%d is under bus power management, cannot be reset. " 8687 "Please disconnect and reconnect this device.", 8688 devname, devinst); 8689 8690 goto Fail; 8691 } 8692 8693 if (hubd_wait_for_hotplug_exit(hubd) == USB_FAILURE) { 8694 /* we got woken up because of a timeout */ 8695 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 8696 hubd->h_log_handle, "Time out when resetting the device" 8697 " %s%d. Please disconnect and reconnect this device.", 8698 devname, devinst); 8699 8700 goto Fail; 8701 } 8702 8703 hubd->h_hotplug_thread++; 8704 8705 /* is this the root hub? */ 8706 if ((hdip == rh_dip) && 8707 (hubd->h_dev_state == USB_DEV_PWRED_DOWN)) { 8708 hubpm = hubd->h_hubpm; 8709 8710 /* mark the root hub as full power */ 8711 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 8712 hubpm->hubp_time_at_full_power = ddi_get_time(); 8713 mutex_exit(HUBD_MUTEX(hubd)); 8714 8715 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8716 "hubd_reset_thread: call pm_power_has_changed"); 8717 8718 (void) pm_power_has_changed(hdip, 0, 8719 USB_DEV_OS_FULL_PWR); 8720 8721 mutex_enter(HUBD_MUTEX(hubd)); 8722 hubd->h_dev_state = USB_DEV_ONLINE; 8723 } 8724 8725 mutex_exit(HUBD_MUTEX(hubd)); 8726 8727 /* 8728 * this ensures one reset activity per system at a time. 8729 * we enter the parent PCI node to have this serialization. 8730 * this also excludes ioctls and deathrow thread 8731 */ 8732 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 8733 ndi_devi_enter(rh_dip, &rh_circ); 8734 8735 /* exclude other threads */ 8736 ndi_devi_enter(hdip, &circ); 8737 mutex_enter(HUBD_MUTEX(hubd)); 8738 8739 /* 8740 * We need to make sure that the child is still online for a hotplug 8741 * thread could have inserted which detached the child. 8742 */ 8743 if (hubd->h_children_dips[reset_port]) { 8744 mutex_exit(HUBD_MUTEX(hubd)); 8745 /* First disconnect the device */ 8746 hubd_post_event(hubd, reset_port, USBA_EVENT_TAG_HOT_REMOVAL); 8747 8748 /* delete cached dv_node's but drop locks first */ 8749 ndi_devi_exit(hdip, circ); 8750 ndi_devi_exit(rh_dip, rh_circ); 8751 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 8752 8753 (void) devfs_clean(rh_dip, NULL, DV_CLEAN_FORCE); 8754 8755 /* 8756 * workaround only for storage device. When it's able to force 8757 * detach a driver, this code can be removed safely. 8758 * 8759 * If we're to reset storage device and the device is used, we 8760 * will wait at most extra 20s for applications to exit and 8761 * close the device. This is especially useful for HAL-based 8762 * applications. 8763 */ 8764 if ((strcmp(devname, "scsa2usb") == 0) && 8765 DEVI(child_dip)->devi_ref != 0) { 8766 while (i++ < hubdi_reset_delay) { 8767 mutex_enter(HUBD_MUTEX(hubd)); 8768 rval = hubd_delete_child(hubd, reset_port, 8769 NDI_DEVI_REMOVE, B_FALSE); 8770 mutex_exit(HUBD_MUTEX(hubd)); 8771 if (rval == USB_SUCCESS) 8772 break; 8773 8774 delay(drv_usectohz(1000000)); /* 1s */ 8775 } 8776 } 8777 8778 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 8779 ndi_devi_enter(rh_dip, &rh_circ); 8780 ndi_devi_enter(hdip, &circ); 8781 8782 mutex_enter(HUBD_MUTEX(hubd)); 8783 8784 /* Then force detaching the device */ 8785 if ((rval != USB_SUCCESS) && (hubd_delete_child(hubd, 8786 reset_port, NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS)) { 8787 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8788 "%s%d cannot be reset due to other applications " 8789 "are using it, please first close these " 8790 "applications, then disconnect and reconnect" 8791 "the device.", devname, devinst); 8792 8793 mutex_exit(HUBD_MUTEX(hubd)); 8794 /* post a re-connect event */ 8795 hubd_post_event(hubd, reset_port, 8796 USBA_EVENT_TAG_HOT_INSERTION); 8797 mutex_enter(HUBD_MUTEX(hubd)); 8798 } else { 8799 (void) hubd_determine_port_status(hubd, reset_port, 8800 &status, &change, HUBD_ACK_ALL_CHANGES); 8801 8802 /* Reset the parent hubd port and create new child */ 8803 if (status & PORT_STATUS_CCS) { 8804 online_child |= (hubd_handle_port_connect(hubd, 8805 reset_port) == USB_SUCCESS); 8806 } 8807 } 8808 } 8809 8810 /* release locks so we can do a devfs_clean */ 8811 mutex_exit(HUBD_MUTEX(hubd)); 8812 8813 /* delete cached dv_node's but drop locks first */ 8814 ndi_devi_exit(hdip, circ); 8815 ndi_devi_exit(rh_dip, rh_circ); 8816 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 8817 8818 (void) devfs_clean(rh_dip, NULL, 0); 8819 8820 /* now check if any children need onlining */ 8821 if (online_child) { 8822 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8823 "hubd_reset_thread: onlining children"); 8824 8825 (void) ndi_devi_online(hubd->h_dip, 0); 8826 } 8827 8828 mutex_enter(HUBD_MUTEX(hubd)); 8829 8830 /* allow hotplug thread now */ 8831 hubd->h_hotplug_thread--; 8832 Fail: 8833 hubd_start_polling(hubd, 0); 8834 8835 /* mark this device as idle */ 8836 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 8837 8838 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8839 "hubd_reset_thread: exit, %d", hubd->h_hotplug_thread); 8840 8841 hubd->h_reset_port[reset_port] = B_FALSE; 8842 8843 mutex_exit(HUBD_MUTEX(hubd)); 8844 8845 ndi_rele_devi(hdip); 8846 } 8847 8848 /* 8849 * hubd_check_same_device: 8850 * - open the default pipe of the device. 8851 * - compare the old and new descriptors of the device. 8852 * - close the default pipe. 8853 */ 8854 static int 8855 hubd_check_same_device(hubd_t *hubd, usb_port_t port) 8856 { 8857 dev_info_t *dip = hubd->h_children_dips[port]; 8858 usb_pipe_handle_t ph; 8859 int rval = USB_FAILURE; 8860 8861 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8862 8863 mutex_exit(HUBD_MUTEX(hubd)); 8864 /* Open the default pipe to operate the device */ 8865 if (usb_pipe_open(dip, NULL, NULL, 8866 USB_FLAGS_SLEEP| USBA_FLAGS_PRIVILEGED, 8867 &ph) == USB_SUCCESS) { 8868 /* 8869 * Check that if the device's descriptors are different 8870 * from the values saved before the port reset. 8871 */ 8872 rval = usb_check_same_device(dip, 8873 hubd->h_log_handle, USB_LOG_L0, 8874 DPRINT_MASK_ALL, USB_CHK_ALL, NULL); 8875 8876 usb_pipe_close(dip, ph, USB_FLAGS_SLEEP | 8877 USBA_FLAGS_PRIVILEGED, NULL, NULL); 8878 } 8879 mutex_enter(HUBD_MUTEX(hubd)); 8880 8881 return (rval); 8882 } 8883 8884 /* 8885 * usba_hubdi_reset_device 8886 * Called by usb_reset_device to handle usb device reset. 8887 */ 8888 int 8889 usba_hubdi_reset_device(dev_info_t *dip, usb_dev_reset_lvl_t reset_level) 8890 { 8891 hubd_t *hubd; 8892 usb_port_t port = 0; 8893 dev_info_t *hdip; 8894 usb_pipe_state_t prev_pipe_state = 0; 8895 usba_device_t *usba_device; 8896 hubd_reset_arg_t *arg; 8897 int i, ph_open_cnt; 8898 int rval = USB_FAILURE; 8899 8900 if ((!dip) || usba_is_root_hub(dip)) { 8901 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8902 "usba_hubdi_reset_device: NULL dip or root hub"); 8903 8904 return (USB_INVALID_ARGS); 8905 } 8906 8907 if (!usb_owns_device(dip)) { 8908 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8909 "usba_hubdi_reset_device: Not owns the device"); 8910 8911 return (USB_INVALID_PERM); 8912 } 8913 8914 if ((reset_level != USB_RESET_LVL_REATTACH) && 8915 (reset_level != USB_RESET_LVL_DEFAULT)) { 8916 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8917 "usba_hubdi_reset_device: Unknown flags"); 8918 8919 return (USB_INVALID_ARGS); 8920 } 8921 8922 if ((hdip = ddi_get_parent(dip)) == NULL) { 8923 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8924 "usba_hubdi_reset_device: fail to get parent hub"); 8925 8926 return (USB_INVALID_ARGS); 8927 } 8928 8929 if ((hubd = hubd_get_soft_state(hdip)) == NULL) { 8930 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle, 8931 "usba_hubdi_reset_device: fail to get hub softstate"); 8932 8933 return (USB_INVALID_ARGS); 8934 } 8935 8936 mutex_enter(HUBD_MUTEX(hubd)); 8937 8938 /* make sure the hub is connected before trying any kinds of reset. */ 8939 if ((hubd->h_dev_state == USB_DEV_DISCONNECTED) || 8940 (hubd->h_dev_state == USB_DEV_SUSPENDED)) { 8941 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8942 "usb_reset_device: the state %d of the hub/roothub " 8943 "associated to the device 0x%p is incorrect", 8944 hubd->h_dev_state, (void *)dip); 8945 mutex_exit(HUBD_MUTEX(hubd)); 8946 8947 return (USB_INVALID_ARGS); 8948 } 8949 8950 mutex_exit(HUBD_MUTEX(hubd)); 8951 8952 port = hubd_child_dip2port(hubd, dip); 8953 8954 mutex_enter(HUBD_MUTEX(hubd)); 8955 8956 if (hubd->h_reset_port[port]) { 8957 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8958 "usb_reset_device: the corresponding port is resetting"); 8959 mutex_exit(HUBD_MUTEX(hubd)); 8960 8961 return (USB_SUCCESS); 8962 } 8963 8964 /* 8965 * For Default reset, client drivers should first close all the pipes 8966 * except default pipe before calling the function, also should not 8967 * call the function during interrupt context. 8968 */ 8969 if (reset_level == USB_RESET_LVL_DEFAULT) { 8970 usba_device = hubd->h_usba_devices[port]; 8971 mutex_exit(HUBD_MUTEX(hubd)); 8972 8973 if (servicing_interrupt()) { 8974 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8975 "usb_reset_device: during interrput context, quit"); 8976 8977 return (USB_INVALID_CONTEXT); 8978 } 8979 /* Check if all the pipes have been closed */ 8980 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) { 8981 if (usba_device->usb_ph_list[i].usba_ph_data) { 8982 ph_open_cnt++; 8983 break; 8984 } 8985 } 8986 if (ph_open_cnt) { 8987 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8988 "usb_reset_device: %d pipes are still open", 8989 ph_open_cnt); 8990 8991 return (USB_BUSY); 8992 } 8993 mutex_enter(HUBD_MUTEX(hubd)); 8994 } 8995 8996 /* Don't perform reset while the device is detaching */ 8997 if (hubd->h_port_state[port] & HUBD_CHILD_DETACHING) { 8998 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 8999 "usb_reset_device: the device is detaching, " 9000 "cannot be reset"); 9001 mutex_exit(HUBD_MUTEX(hubd)); 9002 9003 return (USB_FAILURE); 9004 } 9005 9006 hubd->h_reset_port[port] = B_TRUE; 9007 hdip = hubd->h_dip; 9008 mutex_exit(HUBD_MUTEX(hubd)); 9009 9010 /* Don't allow hub detached during the reset */ 9011 ndi_hold_devi(hdip); 9012 9013 mutex_enter(HUBD_MUTEX(hubd)); 9014 hubd_pm_busy_component(hubd, hdip, 0); 9015 mutex_exit(HUBD_MUTEX(hubd)); 9016 /* go full power */ 9017 (void) pm_raise_power(hdip, 0, USB_DEV_OS_FULL_PWR); 9018 mutex_enter(HUBD_MUTEX(hubd)); 9019 9020 hubd->h_hotplug_thread++; 9021 9022 /* stop polling if it was active */ 9023 if (hubd->h_ep1_ph) { 9024 mutex_exit(HUBD_MUTEX(hubd)); 9025 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 9026 USB_FLAGS_SLEEP); 9027 mutex_enter(HUBD_MUTEX(hubd)); 9028 9029 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 9030 hubd_stop_polling(hubd); 9031 } 9032 } 9033 9034 switch (reset_level) { 9035 case USB_RESET_LVL_REATTACH: 9036 mutex_exit(HUBD_MUTEX(hubd)); 9037 arg = (hubd_reset_arg_t *)kmem_zalloc( 9038 sizeof (hubd_reset_arg_t), KM_SLEEP); 9039 arg->hubd = hubd; 9040 arg->reset_port = port; 9041 mutex_enter(HUBD_MUTEX(hubd)); 9042 9043 if ((rval = usb_async_req(hdip, hubd_reset_thread, 9044 (void *)arg, 0)) == USB_SUCCESS) { 9045 hubd->h_hotplug_thread--; 9046 mutex_exit(HUBD_MUTEX(hubd)); 9047 9048 return (USB_SUCCESS); 9049 } else { 9050 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 9051 "Cannot create reset thread, the device %s%d failed" 9052 " to reset", ddi_driver_name(dip), 9053 ddi_get_instance(dip)); 9054 9055 kmem_free(arg, sizeof (hubd_reset_arg_t)); 9056 } 9057 9058 break; 9059 case USB_RESET_LVL_DEFAULT: 9060 /* 9061 * Reset hub port and then recover device's address, set back 9062 * device's configuration, hubd_handle_port_connect() will 9063 * handle errors happened during this process. 9064 */ 9065 if ((rval = hubd_handle_port_connect(hubd, port)) 9066 == USB_SUCCESS) { 9067 mutex_exit(HUBD_MUTEX(hubd)); 9068 /* re-open the default pipe */ 9069 rval = usba_persistent_pipe_open(usba_device); 9070 mutex_enter(HUBD_MUTEX(hubd)); 9071 if (rval != USB_SUCCESS) { 9072 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 9073 hubd->h_log_handle, "failed to reopen " 9074 "default pipe after reset, disable hub" 9075 "port for %s%d", ddi_driver_name(dip), 9076 ddi_get_instance(dip)); 9077 /* 9078 * Disable port to set out a hotplug thread 9079 * which will handle errors. 9080 */ 9081 (void) hubd_disable_port(hubd, port); 9082 } 9083 } 9084 9085 break; 9086 default: 9087 9088 break; 9089 } 9090 9091 /* allow hotplug thread now */ 9092 hubd->h_hotplug_thread--; 9093 9094 if ((hubd->h_dev_state == USB_DEV_ONLINE) && hubd->h_ep1_ph && 9095 (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 9096 hubd_start_polling(hubd, 0); 9097 } 9098 9099 hubd_pm_idle_component(hubd, hdip, 0); 9100 9101 /* Clear reset mark for the port. */ 9102 hubd->h_reset_port[port] = B_FALSE; 9103 9104 mutex_exit(HUBD_MUTEX(hubd)); 9105 9106 ndi_rele_devi(hdip); 9107 9108 return (rval); 9109 } 9110