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