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