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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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_L2(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 mutex_exit(HUBD_MUTEX(hubd)); 2429 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2430 DEVI_SET_DEVICE_REINSERTED(ch_dip); 2431 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2432 2433 /* 2434 * reopen pipes for children for 2435 * their DDI_RESUME 2436 */ 2437 rval = usba_persistent_pipe_open( 2438 usba_get_usba_device(ch_dip)); 2439 mutex_enter(HUBD_MUTEX(hubd)); 2440 ASSERT(rval == USB_SUCCESS); 2441 } 2442 } else { 2443 /* 2444 * Mark this dip for deletion as the device 2445 * is not physically present, and schedule 2446 * cleanup thread upon post resume 2447 */ 2448 mutex_exit(HUBD_MUTEX(hubd)); 2449 2450 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2451 hubd->h_log_handle, 2452 "hubd_restore_device_state: " 2453 "dip=%p on port=%d marked for cleanup", 2454 ch_dip, port); 2455 mutex_enter(&(DEVI(ch_dip)->devi_lock)); 2456 DEVI_SET_DEVICE_REMOVED(ch_dip); 2457 mutex_exit(&(DEVI(ch_dip)->devi_lock)); 2458 2459 mutex_enter(HUBD_MUTEX(hubd)); 2460 } 2461 } else if (ehci_root_hub) { 2462 /* get port status */ 2463 (void) hubd_determine_port_status(hubd, port, 2464 &status, &change, PORT_CHANGE_CSC); 2465 2466 /* check if it is truly connected */ 2467 if (status & PORT_STATUS_CCS) { 2468 /* 2469 * reset the port to find out if we have 2470 * 2.0 device connected or 1.X. A 2.0 2471 * device will still be seen as connected, 2472 * while a 1.X device will switch over to 2473 * the companion controller. 2474 */ 2475 (void) hubd_reset_port(hubd, port); 2476 2477 (void) hubd_determine_port_status(hubd, port, 2478 &status, &change, PORT_CHANGE_CSC); 2479 2480 if (status & 2481 (PORT_STATUS_CCS | PORT_STATUS_HSDA)) { 2482 /* 2483 * We have a USB 2.0 device 2484 * connected. Power cycle this port 2485 * so that hotplug thread can 2486 * enumerate this device. 2487 */ 2488 (void) hubd_toggle_port(hubd, port); 2489 } else { 2490 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2491 hubd->h_log_handle, 2492 "hubd_restore_device_state: " 2493 "device on port %d switched over", 2494 port); 2495 } 2496 } 2497 2498 } 2499 } 2500 2501 2502 /* if the device had remote wakeup earlier, enable it again */ 2503 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2504 mutex_exit(HUBD_MUTEX(hubd)); 2505 (void) usb_handle_remote_wakeup(hubd->h_dip, 2506 USB_REMOTE_WAKEUP_ENABLE); 2507 mutex_enter(HUBD_MUTEX(hubd)); 2508 } 2509 2510 hubd->h_dev_state = USB_DEV_ONLINE; 2511 hubd_start_polling(hubd, 0); 2512 (void) hubd_pm_idle_component(hubd, dip, 0); 2513 mutex_exit(HUBD_MUTEX(hubd)); 2514 } 2515 2516 2517 /* 2518 * hubd_cleanup: 2519 * cleanup hubd and deallocate. this function is called for 2520 * handling attach failures and detaching including dynamic 2521 * reconfiguration. If called from attaching, it must clean 2522 * up the whole thing and return success. 2523 */ 2524 /*ARGSUSED*/ 2525 static int 2526 hubd_cleanup(dev_info_t *dip, hubd_t *hubd) 2527 { 2528 int circ, rval, old_dev_state; 2529 hub_power_t *hubpm; 2530 #ifdef DEBUG 2531 usb_port_t port; 2532 #endif 2533 2534 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2535 "hubd_cleanup:"); 2536 2537 if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) { 2538 goto done; 2539 } 2540 2541 /* ensure we are the only one active */ 2542 ndi_devi_enter(dip, &circ); 2543 2544 mutex_enter(HUBD_MUTEX(hubd)); 2545 2546 /* Cleanup failure is only allowed if called from detach */ 2547 if (DEVI_IS_DETACHING(dip)) { 2548 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 2549 2550 /* 2551 * We are being called from detach. 2552 * Fail immediately if the hotplug thread is running 2553 * else set the dev_state to disconnected so that 2554 * hotplug thread just exits without doing anything. 2555 */ 2556 if (hubd->h_bus_ctls || hubd->h_bus_pwr || 2557 hubd->h_hotplug_thread) { 2558 mutex_exit(HUBD_MUTEX(hubd)); 2559 ndi_devi_exit(dip, circ); 2560 2561 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2562 "hubd_cleanup: hotplug thread/bus ctl active " 2563 "- failing detach"); 2564 2565 return (USB_FAILURE); 2566 } 2567 2568 /* 2569 * if the deathrow thread is still active or about 2570 * to become active, fail detach 2571 * the roothup can only be detached if nexus drivers 2572 * are unloaded or explicitly offlined 2573 */ 2574 if (rh_dip == dip) { 2575 if (hubd->h_cleanup_needed || 2576 hubd->h_cleanup_active) { 2577 mutex_exit(HUBD_MUTEX(hubd)); 2578 ndi_devi_exit(dip, circ); 2579 2580 USB_DPRINTF_L2(DPRINT_MASK_ATTA, 2581 hubd->h_log_handle, 2582 "hubd_cleanup: deathrow still active?" 2583 "- failing detach"); 2584 2585 return (USB_FAILURE); 2586 } 2587 } 2588 } 2589 2590 old_dev_state = hubd->h_dev_state; 2591 hubd->h_dev_state = USB_DEV_DISCONNECTED; 2592 2593 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2594 "hubd_cleanup: stop polling"); 2595 hubd_close_intr_pipe(hubd); 2596 2597 ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr || 2598 hubd->h_hotplug_thread) == 0); 2599 mutex_exit(HUBD_MUTEX(hubd)); 2600 2601 /* 2602 * deallocate events, if events are still registered 2603 * (ie. children still attached) then we have to fail the detach 2604 */ 2605 if (hubd->h_ndi_event_hdl) { 2606 2607 rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl); 2608 if (DEVI_IS_ATTACHING(dip)) { 2609 2610 /* It must return success if attaching. */ 2611 ASSERT(rval == NDI_SUCCESS); 2612 2613 } else if (rval != NDI_SUCCESS) { 2614 2615 USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle, 2616 "hubd_cleanup: ndi_event_free_hdl failed"); 2617 ndi_devi_exit(dip, circ); 2618 2619 return (USB_FAILURE); 2620 2621 } 2622 } 2623 2624 mutex_enter(HUBD_MUTEX(hubd)); 2625 2626 #ifdef DEBUG 2627 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 2628 ASSERT(hubd->h_usba_devices[port] == NULL); 2629 ASSERT(hubd->h_children_dips[port] == NULL); 2630 } 2631 #endif 2632 kmem_free(hubd->h_children_dips, hubd->h_cd_list_length); 2633 kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length); 2634 2635 /* 2636 * Disable the event callbacks first, after this point, event 2637 * callbacks will never get called. Note we shouldn't hold 2638 * mutex while unregistering events because there may be a 2639 * competing event callback thread. Event callbacks are done 2640 * with ndi mutex held and this can cause a potential deadlock. 2641 * Note that cleanup can't fail after deregistration of events. 2642 */ 2643 if (hubd->h_init_state & HUBD_EVENTS_REGISTERED) { 2644 mutex_exit(HUBD_MUTEX(hubd)); 2645 usb_unregister_event_cbs(dip, &hubd_events); 2646 hubd_unregister_cpr_callback(hubd); 2647 mutex_enter(HUBD_MUTEX(hubd)); 2648 } 2649 2650 /* restore the old dev state so that device can be put into low power */ 2651 hubd->h_dev_state = old_dev_state; 2652 hubpm = hubd->h_hubpm; 2653 2654 if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) { 2655 (void) hubd_pm_busy_component(hubd, dip, 0); 2656 mutex_exit(HUBD_MUTEX(hubd)); 2657 if (hubd->h_hubpm->hubp_wakeup_enabled) { 2658 /* 2659 * Bring the hub to full power before 2660 * issuing the disable remote wakeup command 2661 */ 2662 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2663 2664 if ((rval = usb_handle_remote_wakeup(hubd->h_dip, 2665 USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 2666 USB_DPRINTF_L2(DPRINT_MASK_PM, 2667 hubd->h_log_handle, 2668 "hubd_cleanup: disable remote wakeup " 2669 "fails=%d", rval); 2670 } 2671 } 2672 2673 (void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF); 2674 2675 mutex_enter(HUBD_MUTEX(hubd)); 2676 (void) hubd_pm_idle_component(hubd, dip, 0); 2677 } 2678 2679 if (hubpm) { 2680 if (hubpm->hubp_child_pwrstate) { 2681 kmem_free(hubpm->hubp_child_pwrstate, 2682 MAX_PORTS + 1); 2683 } 2684 kmem_free(hubpm, sizeof (hub_power_t)); 2685 } 2686 mutex_exit(HUBD_MUTEX(hubd)); 2687 2688 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2689 "hubd_cleanup: freeing space"); 2690 2691 if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) { 2692 rval = usba_hubdi_unregister(dip); 2693 ASSERT(rval == USB_SUCCESS); 2694 } 2695 2696 if (hubd->h_init_state & HUBD_LOCKS_DONE) { 2697 mutex_destroy(HUBD_MUTEX(hubd)); 2698 cv_destroy(&hubd->h_cv_reset_port); 2699 } 2700 2701 ndi_devi_exit(dip, circ); 2702 2703 if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) { 2704 ddi_remove_minor_node(dip, NULL); 2705 } 2706 2707 if (usba_is_root_hub(dip)) { 2708 usb_pipe_close(dip, hubd->h_default_pipe, 2709 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 2710 } 2711 2712 done: 2713 if (hubd->h_ancestry_str) { 2714 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN); 2715 } 2716 2717 usb_client_detach(dip, hubd->h_dev_data); 2718 2719 usb_free_log_hdl(hubd->h_log_handle); 2720 2721 if (!usba_is_root_hub(dip)) { 2722 ddi_soft_state_free(hubd_statep, ddi_get_instance(dip)); 2723 } 2724 2725 ddi_prop_remove_all(dip); 2726 2727 return (USB_SUCCESS); 2728 } 2729 2730 2731 /* 2732 * hubd_check_ports: 2733 * - get hub descriptor 2734 * - check initial port status 2735 * - enable power on all ports 2736 * - enable polling on ep1 2737 */ 2738 static int 2739 hubd_check_ports(hubd_t *hubd) 2740 { 2741 int rval; 2742 2743 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2744 2745 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 2746 "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip)); 2747 2748 if ((rval = hubd_get_hub_descriptor(hubd)) != USB_SUCCESS) { 2749 2750 return (rval); 2751 } 2752 2753 /* 2754 * First turn off all port power 2755 */ 2756 if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) { 2757 2758 /* disable whatever was enabled */ 2759 (void) hubd_disable_all_port_power(hubd); 2760 2761 return (rval); 2762 } 2763 2764 /* 2765 * do not switch on immediately (instantly on root hub) 2766 * and allow time to settle 2767 */ 2768 mutex_exit(HUBD_MUTEX(hubd)); 2769 delay(drv_usectohz(10000)); 2770 mutex_enter(HUBD_MUTEX(hubd)); 2771 2772 /* 2773 * enable power on all ports so we can see connects 2774 */ 2775 if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) { 2776 /* disable whatever was enabled */ 2777 (void) hubd_disable_all_port_power(hubd); 2778 2779 return (rval); 2780 } 2781 2782 /* wait at least 3 frames before accessing devices */ 2783 mutex_exit(HUBD_MUTEX(hubd)); 2784 delay(drv_usectohz(10000)); 2785 mutex_enter(HUBD_MUTEX(hubd)); 2786 2787 /* 2788 * allocate arrays for saving the dips of each child per port 2789 * 2790 * ports go from 1 - n, allocate 1 more entry 2791 */ 2792 hubd->h_cd_list_length = 2793 (sizeof (dev_info_t **)) * (hubd->h_hub_descr.bNbrPorts + 1); 2794 2795 hubd->h_children_dips = (dev_info_t **)kmem_zalloc( 2796 hubd->h_cd_list_length, KM_SLEEP); 2797 hubd->h_usba_devices = (usba_device_t **)kmem_zalloc( 2798 hubd->h_cd_list_length, KM_SLEEP); 2799 2800 if ((rval = hubd_open_intr_pipe(hubd)) == USB_SUCCESS) { 2801 hubd_start_polling(hubd, 0); 2802 } 2803 2804 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2805 "hubd_check_ports done"); 2806 2807 return (rval); 2808 } 2809 2810 2811 /* 2812 * hubd_get_hub_descriptor: 2813 */ 2814 static int 2815 hubd_get_hub_descriptor(hubd_t *hubd) 2816 { 2817 usb_hub_descr_t *hub_descr = &hubd->h_hub_descr; 2818 mblk_t *data = NULL; 2819 usb_cr_t completion_reason; 2820 usb_cb_flags_t cb_flags; 2821 uint16_t length; 2822 int rval; 2823 2824 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 2825 "hubd_get_hub_descriptor:"); 2826 2827 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 2828 ASSERT(hubd->h_default_pipe != 0); 2829 2830 /* get hub descriptor length first by requesting 8 bytes only */ 2831 mutex_exit(HUBD_MUTEX(hubd)); 2832 2833 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 2834 hubd->h_default_pipe, 2835 HUB_CLASS_REQ, 2836 USB_REQ_GET_DESCR, /* bRequest */ 2837 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 2838 0, /* wIndex */ 2839 8, /* wLength */ 2840 &data, 0, 2841 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2842 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2843 "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d", 2844 completion_reason, cb_flags, rval); 2845 freemsg(data); 2846 mutex_enter(HUBD_MUTEX(hubd)); 2847 2848 return (rval); 2849 } 2850 2851 length = *(data->b_rptr); 2852 2853 if (length > 8) { 2854 freemsg(data); 2855 data = NULL; 2856 2857 /* get complete hub descriptor */ 2858 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 2859 hubd->h_default_pipe, 2860 HUB_CLASS_REQ, 2861 USB_REQ_GET_DESCR, /* bRequest */ 2862 USB_DESCR_TYPE_SETUP_HUB, /* wValue */ 2863 0, /* wIndex */ 2864 length, /* wLength */ 2865 &data, 0, 2866 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 2867 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2868 "get hub descriptor failed: " 2869 "cr=%d cb_fl=0x%x rval=%d", 2870 completion_reason, cb_flags, rval); 2871 freemsg(data); 2872 mutex_enter(HUBD_MUTEX(hubd)); 2873 2874 return (rval); 2875 } 2876 } 2877 2878 mutex_enter(HUBD_MUTEX(hubd)); 2879 2880 /* parse the hub descriptor */ 2881 /* only 32 ports are supported at present */ 2882 ASSERT(*(data->b_rptr + 2) <= 32); 2883 if (usb_parse_CV_descr("cccscccccc", 2884 data->b_rptr, data->b_wptr - data->b_rptr, 2885 (void *)hub_descr, sizeof (usb_hub_descr_t)) == 0) { 2886 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 2887 "parsing hub descriptor failed"); 2888 2889 freemsg(data); 2890 2891 return (USB_FAILURE); 2892 } 2893 2894 freemsg(data); 2895 2896 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 2897 "rval = 0x%x bNbrPorts = 0x%x wHubChars = 0x%x " 2898 "PwrOn2PwrGood = 0x%x", rval, 2899 hub_descr->bNbrPorts, hub_descr->wHubCharacteristics, 2900 hub_descr->bPwrOn2PwrGood); 2901 2902 if (hub_descr->bNbrPorts > MAX_PORTS) { 2903 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle, 2904 "Hub driver supports max of %d ports on hub. " 2905 "Hence using the first %d port of %d ports available", 2906 MAX_PORTS, MAX_PORTS, hub_descr->bNbrPorts); 2907 2908 hub_descr->bNbrPorts = MAX_PORTS; 2909 } 2910 2911 return (USB_SUCCESS); 2912 } 2913 2914 2915 /* 2916 * hubd_open_intr_pipe: 2917 * we read all descriptors first for curiosity and then simply 2918 * open the pipe 2919 */ 2920 static int 2921 hubd_open_intr_pipe(hubd_t *hubd) 2922 { 2923 int rval; 2924 2925 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 2926 "hubd_open_intr_pipe:"); 2927 2928 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE); 2929 2930 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING; 2931 mutex_exit(HUBD_MUTEX(hubd)); 2932 2933 if ((rval = usb_pipe_open(hubd->h_dip, 2934 &hubd->h_ep1_descr, &hubd->h_pipe_policy, 2935 0, &hubd->h_ep1_ph)) != USB_SUCCESS) { 2936 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 2937 "open intr pipe failed (%d)", rval); 2938 2939 mutex_enter(HUBD_MUTEX(hubd)); 2940 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 2941 2942 return (rval); 2943 } 2944 2945 mutex_enter(HUBD_MUTEX(hubd)); 2946 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 2947 2948 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 2949 "open intr pipe succeeded, ph=0x%p", hubd->h_ep1_ph); 2950 2951 return (USB_SUCCESS); 2952 } 2953 2954 2955 /* 2956 * hubd_start_polling: 2957 * start or restart the polling 2958 */ 2959 static void 2960 hubd_start_polling(hubd_t *hubd, int always) 2961 { 2962 usb_intr_req_t *reqp; 2963 int rval; 2964 usb_pipe_state_t pipe_state; 2965 2966 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 2967 "start polling: always=%d dev_state=%d pipe_state=%d\n\t" 2968 "thread=%d ep1_ph=0x%p", 2969 always, hubd->h_dev_state, hubd->h_intr_pipe_state, 2970 hubd->h_hotplug_thread, hubd->h_ep1_ph); 2971 2972 /* 2973 * start or restart polling on the intr pipe 2974 * only if hotplug thread is not running 2975 */ 2976 if ((always == HUBD_ALWAYS_START_POLLING) || 2977 ((hubd->h_dev_state == USB_DEV_ONLINE) && 2978 (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 2979 (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) { 2980 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 2981 "start polling requested"); 2982 2983 reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP); 2984 2985 reqp->intr_client_private = (usb_opaque_t)hubd; 2986 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 2987 USB_ATTRS_AUTOCLEARING; 2988 reqp->intr_len = hubd->h_ep1_descr.wMaxPacketSize; 2989 reqp->intr_cb = hubd_read_cb; 2990 reqp->intr_exc_cb = hubd_exception_cb; 2991 mutex_exit(HUBD_MUTEX(hubd)); 2992 if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp, 2993 USB_FLAGS_SLEEP)) != USB_SUCCESS) { 2994 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 2995 "start polling failed, rval=%d", rval); 2996 usb_free_intr_req(reqp); 2997 } 2998 2999 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3000 USB_FLAGS_SLEEP); 3001 if (pipe_state != USB_PIPE_STATE_ACTIVE) { 3002 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3003 "intr pipe state=%d, rval=%d", pipe_state, rval); 3004 } 3005 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3006 "start polling request 0x%p", reqp); 3007 3008 mutex_enter(HUBD_MUTEX(hubd)); 3009 } 3010 } 3011 3012 3013 /* 3014 * hubd_stop_polling 3015 * stop polling but do not close the pipe 3016 */ 3017 static void 3018 hubd_stop_polling(hubd_t *hubd) 3019 { 3020 int rval; 3021 usb_pipe_state_t pipe_state; 3022 3023 if (hubd->h_ep1_ph) { 3024 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 3025 "hubd_stop_polling:"); 3026 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED; 3027 mutex_exit(HUBD_MUTEX(hubd)); 3028 3029 usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP); 3030 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state, 3031 USB_FLAGS_SLEEP); 3032 3033 if (pipe_state != USB_PIPE_STATE_IDLE) { 3034 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3035 "intr pipe state=%d, rval=%d", pipe_state, rval); 3036 } 3037 mutex_enter(HUBD_MUTEX(hubd)); 3038 if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) { 3039 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE; 3040 } 3041 } 3042 } 3043 3044 3045 /* 3046 * hubd_close_intr_pipe: 3047 * close the pipe (which also stops the polling 3048 * and wait for the hotplug thread to exit 3049 */ 3050 static void 3051 hubd_close_intr_pipe(hubd_t *hubd) 3052 { 3053 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3054 "hubd_close_intr_pipe:"); 3055 3056 /* 3057 * Now that no async operation is outstanding on pipe, 3058 * we can change the state to HUBD_INTR_PIPE_CLOSING 3059 */ 3060 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING; 3061 3062 ASSERT(hubd->h_hotplug_thread == 0); 3063 3064 if (hubd->h_ep1_ph) { 3065 mutex_exit(HUBD_MUTEX(hubd)); 3066 usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP, 3067 NULL, NULL); 3068 mutex_enter(HUBD_MUTEX(hubd)); 3069 hubd->h_ep1_ph = NULL; 3070 } 3071 3072 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE; 3073 } 3074 3075 3076 /* 3077 * hubd_exception_cb 3078 * interrupt ep1 exception callback function. 3079 * this callback executes in taskq thread context and assumes 3080 * autoclearing 3081 */ 3082 /*ARGSUSED*/ 3083 static void 3084 hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3085 { 3086 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3087 3088 USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3089 "hubd_exception_cb: " 3090 "req=0x%p cr=%d data=0x%p cb_flags=0x%x", reqp, 3091 reqp->intr_completion_reason, reqp->intr_data, 3092 reqp->intr_cb_flags); 3093 3094 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3095 3096 mutex_enter(HUBD_MUTEX(hubd)); 3097 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3098 3099 switch (reqp->intr_completion_reason) { 3100 case USB_CR_PIPE_RESET: 3101 /* only restart polling after autoclearing */ 3102 if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) && 3103 (hubd->h_port_reset_wait == 0)) { 3104 hubd_start_polling(hubd, 0); 3105 } 3106 3107 break; 3108 case USB_CR_DEV_NOT_RESP: 3109 case USB_CR_STOPPED_POLLING: 3110 case USB_CR_PIPE_CLOSING: 3111 case USB_CR_UNSPECIFIED_ERR: 3112 /* never restart polling on these conditions */ 3113 default: 3114 /* for all others, wait for the autoclearing PIPE_RESET cb */ 3115 3116 break; 3117 } 3118 3119 usb_free_intr_req(reqp); 3120 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3121 mutex_exit(HUBD_MUTEX(hubd)); 3122 } 3123 3124 3125 /* 3126 * helper function to convert LE bytes to a portmask 3127 */ 3128 static usb_port_mask_t 3129 hubd_mblk2portmask(mblk_t *data) 3130 { 3131 int len = min(data->b_wptr - data->b_rptr, sizeof (usb_port_mask_t)); 3132 usb_port_mask_t rval = 0; 3133 int i; 3134 3135 for (i = 0; i < len; i++) { 3136 rval |= data->b_rptr[i] << (i * 8); 3137 } 3138 3139 return (rval); 3140 } 3141 3142 3143 /* 3144 * hubd_read_cb: 3145 * interrupt ep1 callback function 3146 * 3147 * the status indicates just a change on the pipe with no indication 3148 * of what the change was 3149 * 3150 * known conditions: 3151 * - reset port completion 3152 * - connect 3153 * - disconnect 3154 * 3155 * for handling the hotplugging, create a new thread that can do 3156 * synchronous usba calls 3157 */ 3158 static void 3159 hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp) 3160 { 3161 hubd_t *hubd = (hubd_t *)(reqp->intr_client_private); 3162 size_t length; 3163 mblk_t *data = reqp->intr_data; 3164 3165 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 3166 "hubd_read_cb: ph=0x%p req=0x%p", pipe, reqp); 3167 3168 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 3169 3170 /* 3171 * At present, we are not handling notification for completion of 3172 * asynchronous pipe reset, for which this data ptr could be NULL 3173 */ 3174 3175 if (data == NULL) { 3176 usb_free_intr_req(reqp); 3177 3178 return; 3179 } 3180 3181 mutex_enter(HUBD_MUTEX(hubd)); 3182 3183 if ((hubd->h_dev_state == USB_DEV_SUSPENDED) || 3184 (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) { 3185 mutex_exit(HUBD_MUTEX(hubd)); 3186 usb_free_intr_req(reqp); 3187 3188 return; 3189 } 3190 3191 ASSERT(hubd->h_ep1_ph == pipe); 3192 3193 length = data->b_wptr - data->b_rptr; 3194 3195 /* 3196 * Only look at the data and startup the hotplug thread if 3197 * there actually is data. 3198 */ 3199 if (length != 0) { 3200 usb_port_mask_t port_change = hubd_mblk2portmask(data); 3201 3202 /* 3203 * if a port change was already reported and we are waiting for 3204 * reset port completion then wake up the hotplug thread which 3205 * should be waiting on reset port completion 3206 * 3207 * if there is disconnect event instead of reset completion, let 3208 * the hotplug thread figure this out 3209 */ 3210 3211 /* remove the reset wait bits from the status */ 3212 hubd->h_port_change |= port_change & 3213 ~hubd->h_port_reset_wait; 3214 3215 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3216 "port change=0x%x port_reset_wait=0x%x", 3217 hubd->h_port_change, hubd->h_port_reset_wait); 3218 3219 /* there should be only one reset bit active at the time */ 3220 if (hubd->h_port_reset_wait & port_change) { 3221 hubd->h_port_reset_wait = 0; 3222 cv_signal(&hubd->h_cv_reset_port); 3223 } 3224 3225 /* 3226 * kick off the thread only if device is ONLINE and it is not 3227 * during attaching or detaching 3228 */ 3229 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 3230 (!DEVI_IS_ATTACHING(hubd->h_dip)) && 3231 (!DEVI_IS_DETACHING(hubd->h_dip)) && 3232 (hubd->h_port_change) && 3233 (hubd->h_hotplug_thread == 0)) { 3234 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle, 3235 "creating hotplug thread: " 3236 "dev_state=%d", hubd->h_dev_state); 3237 3238 /* 3239 * Mark this device as busy. The will be marked idle 3240 * if the async req fails or at the exit of hotplug 3241 * thread 3242 */ 3243 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 3244 3245 if (usb_async_req(hubd->h_dip, 3246 hubd_hotplug_thread, 3247 (void *)hubd, 0) == USB_SUCCESS) { 3248 hubd->h_hotplug_thread++; 3249 } else { 3250 /* mark this device as idle */ 3251 (void) hubd_pm_idle_component(hubd, 3252 hubd->h_dip, 0); 3253 } 3254 } 3255 } 3256 mutex_exit(HUBD_MUTEX(hubd)); 3257 3258 usb_free_intr_req(reqp); 3259 } 3260 3261 3262 /* 3263 * hubd_hotplug_thread: 3264 * handles resetting of port, and creating children 3265 * 3266 * the ports to check are indicated in h_port_change bit mask 3267 * XXX note that one time poll doesn't work on the root hub 3268 */ 3269 static void 3270 hubd_hotplug_thread(void *arg) 3271 { 3272 hubd_t *hubd = (hubd_t *)arg; 3273 usb_port_t port; 3274 uint16_t nports; 3275 uint16_t status, change; 3276 hub_power_t *hubpm; 3277 dev_info_t *hdip = hubd->h_dip; 3278 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip; 3279 boolean_t online_child = B_FALSE; 3280 boolean_t offline_child = B_FALSE; 3281 boolean_t pwrup_child = B_FALSE; 3282 int prh_circ, rh_circ, circ, old_state; 3283 3284 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3285 "hubd_hotplug_thread: started"); 3286 3287 /* 3288 * if our bus power entry point is active, process the change 3289 * on the next notification of interrupt pipe 3290 */ 3291 mutex_enter(HUBD_MUTEX(hubd)); 3292 if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) { 3293 hubd->h_hotplug_thread--; 3294 3295 /* mark this device as idle */ 3296 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3297 mutex_exit(HUBD_MUTEX(hubd)); 3298 3299 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3300 "hubd_hotplug_thread: " 3301 "bus_power in progress/hotplugging undesirable - quit"); 3302 3303 return; 3304 } 3305 mutex_exit(HUBD_MUTEX(hubd)); 3306 3307 ndi_hold_devi(hdip); /* so we don't race with detach */ 3308 3309 mutex_enter(HUBD_MUTEX(hubd)); 3310 3311 /* is this the root hub? */ 3312 if (hdip == rh_dip) { 3313 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) { 3314 hubpm = hubd->h_hubpm; 3315 3316 /* mark the root hub as full power */ 3317 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 3318 hubpm->hubp_time_at_full_power = ddi_get_time(); 3319 mutex_exit(HUBD_MUTEX(hubd)); 3320 3321 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3322 "hubd_hotplug_thread: call pm_power_has_changed"); 3323 3324 (void) pm_power_has_changed(hdip, 0, 3325 USB_DEV_OS_FULL_PWR); 3326 3327 mutex_enter(HUBD_MUTEX(hubd)); 3328 hubd->h_dev_state = USB_DEV_ONLINE; 3329 } 3330 3331 } else { 3332 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3333 "hubd_hotplug_thread: not root hub"); 3334 } 3335 3336 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE); 3337 3338 nports = hubd->h_hub_descr.bNbrPorts; 3339 3340 hubd_stop_polling(hubd); 3341 mutex_exit(HUBD_MUTEX(hubd)); 3342 3343 /* 3344 * this ensures one hotplug activity per system at a time. 3345 * we enter the parent PCI node to have this serialization. 3346 * this also excludes ioctls and deathrow thread 3347 * (a bit crude but easier to debug) 3348 */ 3349 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 3350 ndi_devi_enter(rh_dip, &rh_circ); 3351 3352 /* exclude other threads */ 3353 ndi_devi_enter(hdip, &circ); 3354 mutex_enter(HUBD_MUTEX(hubd)); 3355 3356 while ((hubd->h_dev_state == USB_DEV_ONLINE) && 3357 (hubd->h_port_change)) { 3358 /* 3359 * The 0th bit is the hub status change bit. 3360 * handle loss of local power here 3361 */ 3362 if (hubd->h_port_change & HUB_CHANGE_STATUS) { 3363 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3364 "hubd_hotplug_thread: hub status change!"); 3365 3366 /* 3367 * This should be handled properly. For now, 3368 * mask off the bit. 3369 */ 3370 hubd->h_port_change &= ~HUB_CHANGE_STATUS; 3371 3372 /* 3373 * check and ack hub status 3374 * this causes stall conditions 3375 * when local power is removed 3376 */ 3377 (void) hubd_get_hub_status(hubd); 3378 } 3379 3380 for (port = 1; port <= nports; port++) { 3381 usb_port_mask_t port_mask; 3382 boolean_t was_connected; 3383 3384 port_mask = 1 << port; 3385 was_connected = 3386 (hubd->h_port_state[port] & PORT_STATUS_CCS) && 3387 (hubd->h_children_dips[port]); 3388 3389 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3390 "hubd_hotplug_thread: " 3391 "port %d mask=0x%x change=0x%x connected=0x%x", 3392 port, port_mask, hubd->h_port_change, 3393 was_connected); 3394 3395 /* 3396 * is this a port connection that changed? 3397 */ 3398 if ((hubd->h_port_change & port_mask) == 0) { 3399 3400 continue; 3401 } 3402 hubd->h_port_change &= ~port_mask; 3403 3404 /* ack all changes */ 3405 (void) hubd_determine_port_status(hubd, port, 3406 &status, &change, HUBD_ACK_ALL_CHANGES); 3407 3408 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3409 "handle port %d:\n\t" 3410 "new status=0x%x change=0x%x was_conn=0x%x ", 3411 port, status, change, was_connected); 3412 3413 /* Recover a disabled port */ 3414 if (change & PORT_CHANGE_PESC) { 3415 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 3416 hubd->h_log_handle, 3417 "port%d Disabled - " 3418 "status=0x%x, change=0x%x", 3419 port, status, change); 3420 3421 /* 3422 * if the port was connected and is still 3423 * connected, recover the port 3424 */ 3425 if (was_connected && (status & 3426 PORT_STATUS_CCS)) { 3427 online_child |= 3428 (hubd_recover_disabled_port(hubd, 3429 port) == USB_SUCCESS); 3430 } 3431 } 3432 3433 /* 3434 * Now check what changed on the port 3435 */ 3436 if (change & PORT_CHANGE_CSC) { 3437 if ((status & PORT_STATUS_CCS) && 3438 (!was_connected)) { 3439 /* new device plugged in */ 3440 online_child |= 3441 (hubd_handle_port_connect(hubd, 3442 port) == USB_SUCCESS); 3443 3444 } else if ((status & PORT_STATUS_CCS) && 3445 was_connected) { 3446 /* 3447 * In this case we can never be sure 3448 * if the device indeed got hotplugged 3449 * or the hub is falsely reporting the 3450 * change. 3451 * first post a disconnect event 3452 * to the child 3453 */ 3454 mutex_exit(HUBD_MUTEX(hubd)); 3455 hubd_post_event(hubd, port, 3456 USBA_EVENT_TAG_HOT_REMOVAL); 3457 mutex_enter(HUBD_MUTEX(hubd)); 3458 3459 /* 3460 * then reset the port and recover 3461 * the device 3462 */ 3463 online_child |= 3464 (hubd_handle_port_connect(hubd, 3465 port) == USB_SUCCESS); 3466 } else if (was_connected) { 3467 /* this is a disconnect */ 3468 mutex_exit(HUBD_MUTEX(hubd)); 3469 hubd_post_event(hubd, port, 3470 USBA_EVENT_TAG_HOT_REMOVAL); 3471 mutex_enter(HUBD_MUTEX(hubd)); 3472 3473 offline_child = B_TRUE; 3474 } 3475 } 3476 3477 /* 3478 * Check if any port is coming out of suspend 3479 */ 3480 if (change & PORT_CHANGE_PSSC) { 3481 /* a resuming device could have disconnected */ 3482 if (was_connected && 3483 hubd->h_children_dips[port]) { 3484 3485 /* device on this port resuming */ 3486 dev_info_t *dip; 3487 3488 dip = hubd->h_children_dips[port]; 3489 3490 /* 3491 * Don't raise power on detaching child 3492 */ 3493 if (!DEVI_IS_DETACHING(dip)) { 3494 /* 3495 * As this child is not 3496 * detaching, we set this 3497 * flag, causing bus_ctls 3498 * to stall detach till 3499 * pm_raise_power returns 3500 * and flag it for a deferred 3501 * raise_power. 3502 * 3503 * pm_raise_power is deferred 3504 * because we need to release 3505 * the locks first. 3506 */ 3507 hubd->h_port_state[port] |= 3508 HUBD_CHILD_RAISE_POWER; 3509 pwrup_child = B_TRUE; 3510 mutex_exit(HUBD_MUTEX(hubd)); 3511 3512 /* 3513 * make sure that child 3514 * doesn't disappear 3515 */ 3516 ndi_hold_devi(dip); 3517 3518 mutex_enter(HUBD_MUTEX(hubd)); 3519 } 3520 } 3521 } 3522 } 3523 } 3524 3525 /* release locks so we can do a devfs_clean */ 3526 mutex_exit(HUBD_MUTEX(hubd)); 3527 3528 /* delete cached dv_node's but drop locks first */ 3529 ndi_devi_exit(hdip, circ); 3530 ndi_devi_exit(rh_dip, rh_circ); 3531 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 3532 3533 (void) devfs_clean(rh_dip, NULL, 0); 3534 3535 /* now check if any children need onlining */ 3536 if (online_child) { 3537 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3538 "hubd_hotplug_thread: onlining children"); 3539 3540 (void) ndi_devi_online(hubd->h_dip, 0); 3541 } 3542 3543 /* now check if any disconnected devices need to be cleaned up */ 3544 if (offline_child) { 3545 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3546 "hubd_hotplug_thread: scheduling cleanup"); 3547 3548 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 3549 } 3550 3551 mutex_enter(HUBD_MUTEX(hubd)); 3552 3553 /* now raise power on the children that have woken up */ 3554 if (pwrup_child) { 3555 old_state = hubd->h_dev_state; 3556 hubd->h_dev_state = USB_DEV_HUB_CHILD_PWRLVL; 3557 for (port = 1; port <= nports; port++) { 3558 if (hubd->h_port_state[port] & HUBD_CHILD_RAISE_POWER) { 3559 dev_info_t *dip = hubd->h_children_dips[port]; 3560 3561 mutex_exit(HUBD_MUTEX(hubd)); 3562 3563 /* Get the device to full power */ 3564 (void) pm_busy_component(dip, 0); 3565 (void) pm_raise_power(dip, 0, 3566 USB_DEV_OS_FULL_PWR); 3567 (void) pm_idle_component(dip, 0); 3568 3569 /* release the hold on the child */ 3570 ndi_rele_devi(dip); 3571 mutex_enter(HUBD_MUTEX(hubd)); 3572 hubd->h_port_state[port] &= 3573 ~HUBD_CHILD_RAISE_POWER; 3574 } 3575 } 3576 /* 3577 * make sure that we don't accidentally 3578 * over write the disconnect state 3579 */ 3580 if (hubd->h_dev_state == USB_DEV_HUB_CHILD_PWRLVL) { 3581 hubd->h_dev_state = old_state; 3582 } 3583 } 3584 3585 /* 3586 * start polling can immediately kick off read callback 3587 * we need to set the h_hotplug_thread to 0 so that 3588 * the callback is not dropped 3589 */ 3590 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 3591 3592 /* 3593 * Earlier we would set the h_hotplug_thread = 0 before 3594 * polling was restarted so that 3595 * if there is any root hub status change interrupt, we can still kick 3596 * off the hotplug thread. This was valid when this interrupt was 3597 * delivered in hardware, and only ONE interrupt would be delivered. 3598 * Now that we poll on the root hub looking for status change in 3599 * software, this assignment is no longer required. 3600 */ 3601 hubd->h_hotplug_thread--; 3602 3603 /* mark this device as idle */ 3604 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3605 3606 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3607 "hubd_hotplug_thread: exit"); 3608 3609 mutex_exit(HUBD_MUTEX(hubd)); 3610 3611 ndi_rele_devi(hdip); 3612 } 3613 3614 3615 /* 3616 * hubd_handle_port_connect: 3617 * Transition a port from Disabled to Enabled. Ensure that the 3618 * port is in the correct state before attempting to 3619 * access the device. 3620 */ 3621 static int 3622 hubd_handle_port_connect(hubd_t *hubd, usb_port_t port) 3623 { 3624 int rval; 3625 int retry; 3626 long time_delay; 3627 long settling_time; 3628 uint16_t status; 3629 uint16_t change; 3630 usb_addr_t hubd_usb_addr; 3631 usba_device_t *usba_device; 3632 usb_port_status_t port_status = 0; 3633 usb_port_status_t hub_port_status = 0; 3634 3635 /* Get the hub address and port status */ 3636 usba_device = hubd->h_usba_device; 3637 mutex_enter(&usba_device->usb_mutex); 3638 hubd_usb_addr = usba_device->usb_addr; 3639 hub_port_status = usba_device->usb_port_status; 3640 mutex_exit(&usba_device->usb_mutex); 3641 3642 /* 3643 * If a device is connected, transition the 3644 * port from Disabled to the Enabled state. 3645 * The device will receive downstream packets 3646 * in the Enabled state. 3647 * 3648 * reset port and wait for the hub to report 3649 * completion 3650 */ 3651 change = status = 0; 3652 3653 /* 3654 * According to section 9.1.2 of USB 2.0 spec, the host should 3655 * wait for atleast 100ms to allow completion of an insertion 3656 * process and for power at the device to become stable. 3657 * We wait for 200 ms 3658 */ 3659 settling_time = drv_usectohz(hubd_device_delay / 5); 3660 mutex_exit(HUBD_MUTEX(hubd)); 3661 delay(settling_time); 3662 mutex_enter(HUBD_MUTEX(hubd)); 3663 3664 /* calculate 600 ms delay time */ 3665 time_delay = (6 * drv_usectohz(hubd_device_delay)) / 10; 3666 3667 for (retry = 0; (hubd->h_dev_state == USB_DEV_ONLINE) && 3668 (retry < hubd_retry_enumerate); retry++) { 3669 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3670 "resetting port%d, retry=%d", port, retry); 3671 3672 if ((rval = hubd_reset_port(hubd, port)) != USB_SUCCESS) { 3673 (void) hubd_determine_port_status(hubd, 3674 port, &status, &change, 0); 3675 3676 /* continue only if port is still connected */ 3677 if (status & PORT_STATUS_CCS) { 3678 continue; 3679 } 3680 3681 /* carry on regardless */ 3682 } 3683 3684 /* 3685 * according to USB 2.0 spec section 11.24.2.7.1.2 3686 * at the end of port reset, the hub enables the port. 3687 * But for some strange reasons, uhci port remains disabled. 3688 * And because the port remains disabled for the settling 3689 * time below, the device connected to the port gets wedged 3690 * - fails to enumerate (device not responding) 3691 * Hence, we enable it here immediately and later again after 3692 * the delay 3693 */ 3694 (void) hubd_enable_port(hubd, port); 3695 3696 /* we skip this delay in the first iteration */ 3697 if (retry) { 3698 /* 3699 * delay for device to signal disconnect/connect so 3700 * that hub properly recognizes the speed of the device 3701 */ 3702 mutex_exit(HUBD_MUTEX(hubd)); 3703 delay(settling_time); 3704 mutex_enter(HUBD_MUTEX(hubd)); 3705 3706 /* 3707 * When a low speed device is connected to any port of 3708 * PPX it has to be explicitly enabled 3709 * Also, if device intentionally signals 3710 * disconnect/connect, it will disable the port. 3711 * So enable it again. 3712 */ 3713 (void) hubd_enable_port(hubd, port); 3714 } 3715 3716 if ((rval = hubd_determine_port_status(hubd, port, &status, 3717 &change, 0)) != USB_SUCCESS) { 3718 3719 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3720 "getting status failed (%d)", rval); 3721 3722 (void) hubd_disable_port(hubd, port); 3723 3724 continue; 3725 } 3726 3727 if (status & PORT_STATUS_POCI) { 3728 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3729 "port %d overcurrent", port); 3730 3731 (void) hubd_disable_port(hubd, port); 3732 3733 /* ack changes */ 3734 (void) hubd_determine_port_status(hubd, 3735 port, &status, &change, PORT_CHANGE_OCIC); 3736 3737 continue; 3738 } 3739 3740 /* is status really OK? */ 3741 if ((status & PORT_STATUS_OK) != PORT_STATUS_OK) { 3742 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3743 "port %d status (0x%x) not OK on retry %d", 3744 port, status, retry); 3745 3746 /* check if we still have the connection */ 3747 if (!(status & PORT_STATUS_CCS)) { 3748 /* lost connection, set exit condition */ 3749 retry = hubd_retry_enumerate; 3750 3751 break; 3752 } 3753 } else { 3754 /* 3755 * Determine if the device is high or full 3756 * or low speed. 3757 */ 3758 if (status & PORT_STATUS_LSDA) { 3759 port_status = USBA_LOW_SPEED_DEV; 3760 } else if (status & PORT_STATUS_HSDA) { 3761 port_status = USBA_HIGH_SPEED_DEV; 3762 } else { 3763 port_status = USBA_FULL_SPEED_DEV; 3764 } 3765 3766 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3767 "creating child port%d, status=0x%x " 3768 "port status=0x%x", 3769 port, status, port_status); 3770 3771 /* 3772 * if the child already exists, set addrs and config 3773 * to the device post connect event to the child 3774 */ 3775 if (hubd->h_children_dips[port]) { 3776 /* set addrs to this device */ 3777 rval = hubd_setdevaddr(hubd, port); 3778 3779 /* 3780 * This delay is important for the CATC hub 3781 * to enumerate. But, avoid delay in the first 3782 * iteration 3783 */ 3784 if (retry) { 3785 mutex_exit(HUBD_MUTEX(hubd)); 3786 delay(drv_usectohz( 3787 hubd_device_delay/100)); 3788 mutex_enter(HUBD_MUTEX(hubd)); 3789 } 3790 3791 if (rval == USB_SUCCESS) { 3792 /* 3793 * set the default config for 3794 * this device 3795 */ 3796 hubd_setdevconfig(hubd, port); 3797 3798 /* 3799 * indicate to the child that 3800 * it is online again 3801 */ 3802 mutex_exit(HUBD_MUTEX(hubd)); 3803 hubd_post_event(hubd, port, 3804 USBA_EVENT_TAG_HOT_INSERTION); 3805 mutex_enter(HUBD_MUTEX(hubd)); 3806 3807 return (USB_SUCCESS); 3808 } 3809 } else { 3810 /* 3811 * We need to release access here 3812 * so that busctls on other ports can 3813 * continue and don't cause a deadlock 3814 * when busctl and removal of prom node 3815 * takes concurrently. This also ensures 3816 * busctls for attach of successfully 3817 * enumerated devices on other ports can 3818 * continue concurrently with the process 3819 * of enumerating the new devices. This 3820 * reduces the overall boot time of the system. 3821 */ 3822 rval = hubd_create_child(hubd->h_dip, 3823 hubd, 3824 hubd->h_usba_device, 3825 port_status, port, 3826 retry); 3827 if (rval == USB_SUCCESS) { 3828 usba_update_hotplug_stats(hubd->h_dip, 3829 USBA_TOTAL_HOTPLUG_SUCCESS| 3830 USBA_HOTPLUG_SUCCESS); 3831 hubd->h_total_hotplug_success++; 3832 3833 if (retry > 0) { 3834 USB_DPRINTF_L2( 3835 DPRINT_MASK_HOTPLUG, 3836 hubd->h_log_handle, 3837 "device on port %d " 3838 "enumerated after %d %s", 3839 port, retry, 3840 (retry > 1) ? "retries" : 3841 "retry"); 3842 3843 } 3844 3845 return (USB_SUCCESS); 3846 } 3847 } 3848 } 3849 3850 /* wait a while until it settles? */ 3851 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3852 "disabling port %d again", port); 3853 3854 (void) hubd_disable_port(hubd, port); 3855 if (retry) { 3856 mutex_exit(HUBD_MUTEX(hubd)); 3857 delay(time_delay); 3858 mutex_enter(HUBD_MUTEX(hubd)); 3859 } 3860 3861 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3862 "retrying on port %d", port); 3863 } 3864 3865 if (retry >= hubd_retry_enumerate) { 3866 /* 3867 * If it is a High Speed Root Hub and connected device 3868 * Is a Low/Full Speed, it will be handled by USB 1.1 3869 * Host Controller. In this case, USB 2.0 Host Controller 3870 * will transfer the ownership of this port to USB 1.1 3871 * Host Controller. So don't display any error message on 3872 * the console. 3873 */ 3874 if ((hubd_usb_addr == ROOT_HUB_ADDR) && 3875 (hub_port_status == USBA_HIGH_SPEED_DEV) && 3876 (port_status != USBA_HIGH_SPEED_DEV)) { 3877 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 3878 hubd->h_log_handle, 3879 "hubd_handle_port_connect: Low/Full speed " 3880 "device is connected to High Speed root hub"); 3881 } else { 3882 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 3883 hubd->h_log_handle, 3884 "Connecting device on port %d failed", port); 3885 } 3886 3887 (void) hubd_disable_port(hubd, port); 3888 usba_update_hotplug_stats(hubd->h_dip, 3889 USBA_TOTAL_HOTPLUG_FAILURE|USBA_HOTPLUG_FAILURE); 3890 hubd->h_total_hotplug_failure++; 3891 3892 /* 3893 * the port should be automagically 3894 * disabled but just in case, we do 3895 * it here 3896 */ 3897 (void) hubd_disable_port(hubd, port); 3898 3899 /* ack all changes because we disabled this port */ 3900 (void) hubd_determine_port_status(hubd, 3901 port, &status, &change, HUBD_ACK_ALL_CHANGES); 3902 3903 } 3904 3905 return (USB_FAILURE); 3906 } 3907 3908 3909 /* 3910 * hubd_get_hub_status: 3911 */ 3912 static int 3913 hubd_get_hub_status(hubd_t *hubd) 3914 { 3915 int rval; 3916 usb_cr_t completion_reason; 3917 usb_cb_flags_t cb_flags; 3918 mblk_t *data = NULL; 3919 uint16_t status; 3920 uint16_t change; 3921 usb_cfg_descr_t cfg_descr; 3922 size_t cfg_length; 3923 uchar_t *usb_cfg; 3924 uint8_t MaxPower; 3925 3926 mutex_exit(HUBD_MUTEX(hubd)); 3927 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe, 3928 HUB_CLASS_REQ, 3929 USB_REQ_GET_STATUS, 3930 0, 3931 0, 3932 GET_STATUS_LENGTH, 3933 &data, 0, 3934 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 3935 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3936 "get hub status failed: cr=%d cb=0x%x", 3937 completion_reason, cb_flags); 3938 3939 if (data) { 3940 freemsg(data); 3941 } 3942 3943 mutex_enter(HUBD_MUTEX(hubd)); 3944 3945 return (USB_FAILURE); 3946 } 3947 3948 mutex_enter(HUBD_MUTEX(hubd)); 3949 3950 status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 3951 change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 3952 3953 if (status || change) { 3954 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 3955 "hub status = 0x%x change = 0x%x", status, change); 3956 } 3957 3958 mutex_exit(HUBD_MUTEX(hubd)); 3959 freemsg(data); 3960 3961 /* Obtain the raw configuration descriptor */ 3962 usb_cfg = usb_get_raw_cfg_data(hubd->h_dip, &cfg_length); 3963 3964 /* get configuration descriptor */ 3965 rval = usb_parse_cfg_descr(usb_cfg, cfg_length, 3966 &cfg_descr, USB_CFG_DESCR_SIZE); 3967 3968 if (rval != USB_CFG_DESCR_SIZE) { 3969 3970 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 3971 "get hub configuration descriptor failed."); 3972 3973 mutex_enter(HUBD_MUTEX(hubd)); 3974 3975 return (USB_FAILURE); 3976 } else { 3977 MaxPower = cfg_descr.bMaxPower; 3978 } 3979 3980 /* check if local power status changed. */ 3981 if (change & C_HUB_LOCAL_POWER_STATUS) { 3982 3983 /* 3984 * local power has been lost, check the maximum 3985 * power consumption of current configuration. 3986 * see USB2.0 spec Table 11-12. 3987 */ 3988 if (status & HUB_LOCAL_POWER_STATUS) { 3989 3990 if (MaxPower == 0) { 3991 3992 /* 3993 * Self-powered only hub. Because it could 3994 * not draw any power from USB bus. 3995 * It can't work well on this condition. 3996 */ 3997 USB_DPRINTF_L1(DPRINT_MASK_PORT, 3998 hubd->h_log_handle, 3999 "local power has been lost, " 4000 "please disconnect hub"); 4001 } else { 4002 4003 /* 4004 * Bus-powered only or self/bus-powered hub. 4005 */ 4006 USB_DPRINTF_L1(DPRINT_MASK_PORT, 4007 hubd->h_log_handle, 4008 "local power has been lost," 4009 "the hub could draw %d" 4010 " mA power from the USB bus.", 4011 2*MaxPower); 4012 } 4013 4014 } 4015 4016 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4017 "clearing feature C_HUB_LOCAL_POWER "); 4018 4019 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4020 hubd->h_default_pipe, 4021 USB_DEV_REQ_TYPE_CLASS, 4022 USB_REQ_CLEAR_FEATURE, 4023 CFS_C_HUB_LOCAL_POWER, 4024 0, 4025 0, 4026 NULL, 0, 4027 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4028 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4029 hubd->h_log_handle, 4030 "clear feature C_HUB_LOCAL_POWER " 4031 "failed (%d 0x%x %d)", 4032 rval, completion_reason, cb_flags); 4033 } 4034 4035 } 4036 4037 if (change & C_HUB_OVER_CURRENT) { 4038 4039 if (status & HUB_OVER_CURRENT) { 4040 /* 4041 * the user must offline this hub in order to recover. 4042 * the port power is automatically disabled, so we 4043 * won't see disconnects. 4044 */ 4045 USB_DPRINTF_L0(DPRINT_MASK_PORT, hubd->h_log_handle, 4046 "global over current condition, " 4047 "please disconnect hub"); 4048 } 4049 4050 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4051 "clearing feature C_HUB_OVER_CURRENT"); 4052 4053 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4054 hubd->h_default_pipe, 4055 USB_DEV_REQ_TYPE_CLASS, 4056 USB_REQ_CLEAR_FEATURE, 4057 CFS_C_HUB_OVER_CURRENT, 4058 0, 4059 0, 4060 NULL, 0, 4061 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4062 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4063 hubd->h_log_handle, 4064 "clear feature C_HUB_OVER_CURRENT " 4065 "failed (%d 0x%x %d)", 4066 rval, completion_reason, cb_flags); 4067 } 4068 } 4069 4070 mutex_enter(HUBD_MUTEX(hubd)); 4071 4072 return (USB_SUCCESS); 4073 } 4074 4075 4076 /* 4077 * hubd_reset_port: 4078 */ 4079 static int 4080 hubd_reset_port(hubd_t *hubd, usb_port_t port) 4081 { 4082 int rval; 4083 usb_cr_t completion_reason; 4084 usb_cb_flags_t cb_flags; 4085 usb_port_mask_t port_mask = 1 << port; 4086 mblk_t *data; 4087 uint16_t status; 4088 uint16_t change; 4089 int i; 4090 clock_t current_time; 4091 4092 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4093 "hubd_reset_port: port=%d", port); 4094 4095 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4096 4097 hubd->h_port_reset_wait |= port_mask; 4098 4099 mutex_exit(HUBD_MUTEX(hubd)); 4100 4101 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4102 hubd->h_default_pipe, 4103 HANDLE_PORT_FEATURE, 4104 USB_REQ_SET_FEATURE, 4105 CFS_PORT_RESET, 4106 port, 4107 0, 4108 NULL, 0, 4109 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4110 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4111 "reset port%d failed (%d 0x%x %d)", 4112 port, completion_reason, cb_flags, rval); 4113 4114 mutex_enter(HUBD_MUTEX(hubd)); 4115 4116 return (USB_FAILURE); 4117 } 4118 4119 mutex_enter(HUBD_MUTEX(hubd)); 4120 4121 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4122 "waiting on cv for reset completion"); 4123 4124 /* 4125 * wait for port status change event 4126 */ 4127 for (i = 0; i < hubd_retry_enumerate; i++) { 4128 /* 4129 * start polling ep1 for receiving notification on 4130 * reset completion 4131 */ 4132 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 4133 4134 /* 4135 * sleep a max of 100ms for reset completion 4136 * notification to be received 4137 */ 4138 current_time = ddi_get_lbolt(); 4139 if (hubd->h_port_reset_wait & port_mask) { 4140 rval = cv_timedwait(&hubd->h_cv_reset_port, 4141 &hubd->h_mutex, 4142 current_time + 4143 drv_usectohz(hubd_device_delay / 10)); 4144 if ((rval <= 0) && 4145 (hubd->h_port_reset_wait & port_mask)) { 4146 /* we got woken up because of a timeout */ 4147 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4148 hubd->h_log_handle, 4149 "timeout: reset port=%d failed", port); 4150 4151 hubd->h_port_reset_wait &= ~port_mask; 4152 4153 hubd_stop_polling(hubd); 4154 4155 return (USB_FAILURE); 4156 } 4157 } 4158 4159 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4160 "reset completion received"); 4161 4162 hubd_stop_polling(hubd); 4163 4164 data = NULL; 4165 4166 /* check status to determine whether reset completed */ 4167 mutex_exit(HUBD_MUTEX(hubd)); 4168 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4169 hubd->h_default_pipe, 4170 GET_PORT_STATUS, 4171 USB_REQ_GET_STATUS, 4172 0, 4173 port, 4174 GET_STATUS_LENGTH, 4175 &data, 0, 4176 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4177 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4178 hubd->h_log_handle, 4179 "get status port%d failed (%d 0x%x %d)", 4180 port, completion_reason, cb_flags, rval); 4181 4182 if (data) { 4183 freemsg(data); 4184 data = NULL; 4185 } 4186 mutex_enter(HUBD_MUTEX(hubd)); 4187 4188 continue; 4189 } 4190 4191 status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4192 change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4193 4194 freemsg(data); 4195 4196 /* continue only if port is still connected */ 4197 if (!(status & PORT_STATUS_CCS)) { 4198 4199 /* lost connection, set exit condition */ 4200 i = hubd_retry_enumerate; 4201 4202 mutex_enter(HUBD_MUTEX(hubd)); 4203 4204 break; 4205 } 4206 4207 if (status & PORT_STATUS_PRS) { 4208 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4209 "port%d reset active", port); 4210 mutex_enter(HUBD_MUTEX(hubd)); 4211 4212 continue; 4213 } else { 4214 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4215 "port%d reset inactive", port); 4216 } 4217 4218 if (change & PORT_CHANGE_PRSC) { 4219 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4220 "clearing feature CFS_C_PORT_RESET"); 4221 4222 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4223 hubd->h_default_pipe, 4224 HANDLE_PORT_FEATURE, 4225 USB_REQ_CLEAR_FEATURE, 4226 CFS_C_PORT_RESET, 4227 port, 4228 0, 4229 NULL, 0, 4230 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 4231 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4232 hubd->h_log_handle, 4233 "clear feature CFS_C_PORT_RESET" 4234 " port%d failed (%d 0x%x %d)", 4235 port, completion_reason, cb_flags, rval); 4236 } 4237 } 4238 mutex_enter(HUBD_MUTEX(hubd)); 4239 4240 break; 4241 } 4242 4243 if (i >= hubd_retry_enumerate) { 4244 /* port reset has failed */ 4245 rval = USB_FAILURE; 4246 } 4247 4248 return (rval); 4249 } 4250 4251 4252 /* 4253 * hubd_enable_port: 4254 * this may fail if the hub as been disconnected 4255 */ 4256 static int 4257 hubd_enable_port(hubd_t *hubd, usb_port_t port) 4258 { 4259 int rval; 4260 usb_cr_t completion_reason; 4261 usb_cb_flags_t cb_flags; 4262 4263 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4264 "hubd_enable_port: port=%d", port); 4265 4266 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4267 4268 mutex_exit(HUBD_MUTEX(hubd)); 4269 4270 /* Do not issue a SetFeature(PORT_ENABLE) on external hubs */ 4271 if (!usba_is_root_hub(hubd->h_dip)) { 4272 mutex_enter(HUBD_MUTEX(hubd)); 4273 4274 return (USB_SUCCESS); 4275 } 4276 4277 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4278 hubd->h_default_pipe, 4279 HANDLE_PORT_FEATURE, 4280 USB_REQ_SET_FEATURE, 4281 CFS_PORT_ENABLE, 4282 port, 4283 0, 4284 NULL, 0, 4285 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4286 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4287 "enable port%d failed (%d 0x%x %d)", 4288 port, completion_reason, cb_flags, rval); 4289 } 4290 4291 mutex_enter(HUBD_MUTEX(hubd)); 4292 4293 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4294 "enabling port done"); 4295 4296 return (rval); 4297 } 4298 4299 4300 /* 4301 * hubd_disable_port 4302 */ 4303 static int 4304 hubd_disable_port(hubd_t *hubd, usb_port_t port) 4305 { 4306 int rval; 4307 usb_cr_t completion_reason; 4308 usb_cb_flags_t cb_flags; 4309 4310 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4311 "hubd_disable_port: port=%d", port); 4312 4313 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4314 4315 mutex_exit(HUBD_MUTEX(hubd)); 4316 4317 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4318 hubd->h_default_pipe, 4319 HANDLE_PORT_FEATURE, 4320 USB_REQ_CLEAR_FEATURE, 4321 CFS_PORT_ENABLE, 4322 port, 4323 0, 4324 NULL, 0, 4325 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4326 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4327 "disable port%d failed (%d 0x%x %d)", port, 4328 completion_reason, cb_flags, rval); 4329 mutex_enter(HUBD_MUTEX(hubd)); 4330 4331 return (USB_FAILURE); 4332 } 4333 4334 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4335 "clearing feature CFS_C_PORT_ENABLE"); 4336 4337 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4338 hubd->h_default_pipe, 4339 HANDLE_PORT_FEATURE, 4340 USB_REQ_CLEAR_FEATURE, 4341 CFS_C_PORT_ENABLE, 4342 port, 4343 0, 4344 NULL, 0, 4345 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4346 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4347 hubd->h_log_handle, 4348 "clear feature CFS_C_PORT_ENABLE port%d failed " 4349 "(%d 0x%x %d)", 4350 port, completion_reason, cb_flags, rval); 4351 4352 mutex_enter(HUBD_MUTEX(hubd)); 4353 4354 return (USB_FAILURE); 4355 } 4356 4357 mutex_enter(HUBD_MUTEX(hubd)); 4358 4359 return (USB_SUCCESS); 4360 } 4361 4362 4363 /* 4364 * hubd_determine_port_status: 4365 */ 4366 static int 4367 hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 4368 uint16_t *status, uint16_t *change, uint_t ack_flag) 4369 { 4370 int rval; 4371 mblk_t *data = NULL; 4372 usb_cr_t completion_reason; 4373 usb_cb_flags_t cb_flags; 4374 4375 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4376 "hubd_determine_port_status: port=%d, state=0x%x ack=0x%x", port, 4377 hubd->h_port_state[port], ack_flag); 4378 4379 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4380 4381 mutex_exit(HUBD_MUTEX(hubd)); 4382 4383 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4384 hubd->h_default_pipe, 4385 GET_PORT_STATUS, 4386 USB_REQ_GET_STATUS, 4387 0, 4388 port, 4389 GET_STATUS_LENGTH, 4390 &data, 0, 4391 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4392 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4393 "port=%d get status failed (%d 0x%x %d)", 4394 port, completion_reason, cb_flags, rval); 4395 4396 if (data) { 4397 freemsg(data); 4398 } 4399 4400 *status = *change = 0; 4401 mutex_enter(HUBD_MUTEX(hubd)); 4402 4403 return (rval); 4404 } 4405 4406 mutex_enter(HUBD_MUTEX(hubd)); 4407 if ((data->b_wptr - data->b_rptr) != GET_STATUS_LENGTH) { 4408 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4409 "port %d: length incorrect %d", 4410 port, data->b_wptr - data->b_rptr); 4411 freemsg(data); 4412 *status = *change = 0; 4413 4414 return (rval); 4415 } 4416 4417 4418 *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4419 *change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4420 4421 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4422 "port%d status=0x%x, change=0x%x", port, *status, *change); 4423 4424 freemsg(data); 4425 4426 if (*status & PORT_STATUS_CCS) { 4427 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4428 "port%d connected", port); 4429 4430 hubd->h_port_state[port] |= (PORT_STATUS_CCS & ack_flag); 4431 } else { 4432 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4433 "port%d disconnected", port); 4434 4435 hubd->h_port_state[port] &= ~(PORT_STATUS_CCS & ack_flag); 4436 } 4437 4438 if (*status & PORT_STATUS_PES) { 4439 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4440 "port%d enabled", port); 4441 4442 hubd->h_port_state[port] |= (PORT_STATUS_PES & ack_flag); 4443 } else { 4444 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4445 "port%d disabled", port); 4446 4447 hubd->h_port_state[port] &= ~(PORT_STATUS_PES & ack_flag); 4448 } 4449 4450 if (*status & PORT_STATUS_PSS) { 4451 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4452 "port%d suspended", port); 4453 4454 hubd->h_port_state[port] |= (PORT_STATUS_PSS & ack_flag); 4455 } else { 4456 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4457 "port%d not suspended", port); 4458 4459 hubd->h_port_state[port] &= ~(PORT_STATUS_PSS & ack_flag); 4460 } 4461 4462 if (*change & PORT_CHANGE_PRSC) { 4463 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4464 "port%d reset completed", port); 4465 4466 hubd->h_port_state[port] |= (PORT_CHANGE_PRSC & ack_flag); 4467 } else { 4468 4469 hubd->h_port_state[port] &= ~(PORT_CHANGE_PRSC & ack_flag); 4470 } 4471 4472 if (*status & PORT_STATUS_POCI) { 4473 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4474 "port%d overcurrent!", port); 4475 4476 hubd->h_port_state[port] |= (PORT_STATUS_POCI & ack_flag); 4477 } else { 4478 4479 hubd->h_port_state[port] &= ~(PORT_STATUS_POCI & ack_flag); 4480 } 4481 4482 if (*status & PORT_STATUS_PRS) { 4483 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4484 "port%d reset active", port); 4485 4486 hubd->h_port_state[port] |= (PORT_STATUS_PRS & ack_flag); 4487 } else { 4488 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4489 "port%d reset inactive", port); 4490 4491 hubd->h_port_state[port] &= ~(PORT_STATUS_PRS & ack_flag); 4492 } 4493 if (*status & PORT_STATUS_PPS) { 4494 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4495 "port%d power on", port); 4496 4497 hubd->h_port_state[port] |= (PORT_STATUS_PPS & ack_flag); 4498 } else { 4499 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4500 "port%d power off", port); 4501 4502 hubd->h_port_state[port] &= ~(PORT_STATUS_PPS & ack_flag); 4503 } 4504 if (*status & PORT_STATUS_LSDA) { 4505 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4506 "port%d low speed", port); 4507 4508 hubd->h_port_state[port] |= (PORT_STATUS_LSDA & ack_flag); 4509 } else { 4510 hubd->h_port_state[port] &= ~(PORT_STATUS_LSDA & ack_flag); 4511 if (*status & PORT_STATUS_HSDA) { 4512 USB_DPRINTF_L3(DPRINT_MASK_PORT, 4513 hubd->h_log_handle, "port%d " 4514 "high speed", port); 4515 4516 hubd->h_port_state[port] |= 4517 (PORT_STATUS_HSDA & ack_flag); 4518 } else { 4519 USB_DPRINTF_L3(DPRINT_MASK_PORT, 4520 hubd->h_log_handle, "port%d " 4521 "full speed", port); 4522 4523 hubd->h_port_state[port] &= 4524 ~(PORT_STATUS_HSDA & ack_flag); 4525 } 4526 } 4527 4528 /* 4529 * Acknowledge connection, enable, reset status 4530 */ 4531 if (ack_flag) { 4532 mutex_exit(HUBD_MUTEX(hubd)); 4533 if (*change & PORT_CHANGE_CSC & ack_flag) { 4534 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4535 "clearing feature CFS_C_PORT_CONNECTION"); 4536 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4537 hubd->h_default_pipe, 4538 HANDLE_PORT_FEATURE, 4539 USB_REQ_CLEAR_FEATURE, 4540 CFS_C_PORT_CONNECTION, 4541 port, 4542 0, NULL, 0, 4543 &completion_reason, &cb_flags, 0)) != 4544 USB_SUCCESS) { 4545 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4546 hubd->h_log_handle, 4547 "clear feature CFS_C_PORT_CONNECTION" 4548 " port%d failed (%d 0x%x %d)", 4549 port, completion_reason, cb_flags, rval); 4550 } 4551 } 4552 if (*change & PORT_CHANGE_PESC & ack_flag) { 4553 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4554 "clearing feature CFS_C_PORT_ENABLE"); 4555 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4556 hubd->h_default_pipe, 4557 HANDLE_PORT_FEATURE, 4558 USB_REQ_CLEAR_FEATURE, 4559 CFS_C_PORT_ENABLE, 4560 port, 4561 0, NULL, 0, 4562 &completion_reason, &cb_flags, 0)) != 4563 USB_SUCCESS) { 4564 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4565 hubd->h_log_handle, 4566 "clear feature CFS_C_PORT_ENABLE" 4567 " port%d failed (%d 0x%x %d)", 4568 port, completion_reason, cb_flags, rval); 4569 } 4570 } 4571 if (*change & PORT_CHANGE_PSSC & ack_flag) { 4572 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4573 "clearing feature CFS_C_PORT_SUSPEND"); 4574 4575 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4576 hubd->h_default_pipe, 4577 HANDLE_PORT_FEATURE, 4578 USB_REQ_CLEAR_FEATURE, 4579 CFS_C_PORT_SUSPEND, 4580 port, 4581 0, NULL, 0, 4582 &completion_reason, &cb_flags, 0)) != 4583 USB_SUCCESS) { 4584 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4585 hubd->h_log_handle, 4586 "clear feature CFS_C_PORT_SUSPEND" 4587 " port%d failed (%d 0x%x %d)", 4588 port, completion_reason, cb_flags, rval); 4589 } 4590 } 4591 if (*change & PORT_CHANGE_OCIC & ack_flag) { 4592 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4593 "clearing feature CFS_C_PORT_OVER_CURRENT"); 4594 4595 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4596 hubd->h_default_pipe, 4597 HANDLE_PORT_FEATURE, 4598 USB_REQ_CLEAR_FEATURE, 4599 CFS_C_PORT_OVER_CURRENT, 4600 port, 4601 0, NULL, 0, 4602 &completion_reason, &cb_flags, 0)) != 4603 USB_SUCCESS) { 4604 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4605 hubd->h_log_handle, 4606 "clear feature CFS_C_PORT_OVER_CURRENT" 4607 " port%d failed (%d 0x%x %d)", 4608 port, completion_reason, cb_flags, rval); 4609 } 4610 } 4611 if (*change & PORT_CHANGE_PRSC & ack_flag) { 4612 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4613 "clearing feature CFS_C_PORT_RESET"); 4614 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4615 hubd->h_default_pipe, 4616 HANDLE_PORT_FEATURE, 4617 USB_REQ_CLEAR_FEATURE, 4618 CFS_C_PORT_RESET, 4619 port, 4620 0, NULL, 0, 4621 &completion_reason, &cb_flags, 0)) != 4622 USB_SUCCESS) { 4623 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4624 hubd->h_log_handle, 4625 "clear feature CFS_C_PORT_RESET" 4626 " port%d failed (%d 0x%x %d)", 4627 port, completion_reason, cb_flags, rval); 4628 } 4629 } 4630 mutex_enter(HUBD_MUTEX(hubd)); 4631 } 4632 4633 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4634 "new port%d state 0x%x", port, hubd->h_port_state[port]); 4635 4636 4637 return (USB_SUCCESS); 4638 } 4639 4640 4641 /* 4642 * hubd_recover_disabled_port 4643 * if the port got disabled because of an error 4644 * enable it. If hub doesn't suport enable port, 4645 * reset the port to bring the device to life again 4646 */ 4647 static int 4648 hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port) 4649 { 4650 uint16_t status; 4651 uint16_t change; 4652 int rval = USB_FAILURE; 4653 4654 /* first try enabling the port */ 4655 (void) hubd_enable_port(hubd, port); 4656 4657 /* read the port status */ 4658 (void) hubd_determine_port_status(hubd, port, &status, &change, 4659 PORT_CHANGE_PESC); 4660 4661 if (status & PORT_STATUS_PES) { 4662 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4663 "Port%d now Enabled", port); 4664 } else if (status & PORT_STATUS_CCS) { 4665 /* first post a disconnect event to the child */ 4666 mutex_exit(HUBD_MUTEX(hubd)); 4667 hubd_post_event(hubd, port, USBA_EVENT_TAG_HOT_REMOVAL); 4668 mutex_enter(HUBD_MUTEX(hubd)); 4669 4670 /* then reset the port and recover the device */ 4671 rval = hubd_handle_port_connect(hubd, port); 4672 4673 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4674 "Port%d now Enabled by force", port); 4675 } 4676 4677 return (rval); 4678 } 4679 4680 4681 /* 4682 * hubd_enable_all_port_power: 4683 */ 4684 static int 4685 hubd_enable_all_port_power(hubd_t *hubd) 4686 { 4687 usb_hub_descr_t *hub_descr; 4688 int wait; 4689 usb_port_t port; 4690 uint_t retry; 4691 uint16_t status; 4692 uint16_t change; 4693 4694 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4695 "hubd_enable_all_port_power"); 4696 4697 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4698 4699 hub_descr = &hubd->h_hub_descr; 4700 4701 /* 4702 * According to section 11.11 of USB, for hubs with no power 4703 * switches, bPwrOn2PwrGood is zero. But we wait for some 4704 * arbitrary time to enable power to become stable. 4705 * 4706 * If an hub supports port power switching, we need to wait 4707 * at least 20ms before accessing corresponding usb port. 4708 */ 4709 if ((hub_descr->wHubCharacteristics & 4710 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 4711 wait = hubd_device_delay / 10; 4712 } else { 4713 wait = max(HUB_DEFAULT_POPG, 4714 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 4715 } 4716 4717 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4718 "hubd_enable_all_port_power: popg=%d wait=%d", 4719 hub_descr->bPwrOn2PwrGood, wait); 4720 4721 /* 4722 * Enable power per port. we ignore gang power and power mask 4723 * and always enable all ports one by one. 4724 */ 4725 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 4726 /* 4727 * Transition the port from the Powered Off to the 4728 * Disconnected state by supplying power to the port. 4729 */ 4730 USB_DPRINTF_L4(DPRINT_MASK_PORT, 4731 hubd->h_log_handle, 4732 "hubd_enable_all_port_power: power port=%d", port); 4733 4734 (void) hubd_enable_port_power(hubd, port); 4735 } 4736 4737 mutex_exit(HUBD_MUTEX(hubd)); 4738 delay(drv_usectohz(wait)); 4739 mutex_enter(HUBD_MUTEX(hubd)); 4740 4741 /* For retry if any, use some extra delay */ 4742 wait = max(wait, hubd_device_delay / 10); 4743 4744 /* Check each port power status for a given usb hub */ 4745 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 4746 4747 /* Get port status */ 4748 (void) hubd_determine_port_status(hubd, port, 4749 &status, &change, 0); 4750 4751 for (retry = 0; ((!(status & PORT_STATUS_PPS)) && 4752 (retry < HUBD_PORT_RETRY)); retry++) { 4753 4754 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4755 "Retry is in progress %d: port %d status %d", 4756 retry, port, status); 4757 4758 (void) hubd_enable_port_power(hubd, port); 4759 4760 mutex_exit(HUBD_MUTEX(hubd)); 4761 delay(drv_usectohz(wait)); 4762 mutex_enter(HUBD_MUTEX(hubd)); 4763 4764 /* Get port status */ 4765 (void) hubd_determine_port_status(hubd, port, 4766 &status, &change, 0); 4767 } 4768 4769 /* Print warning message if port has no power */ 4770 if (!(status & PORT_STATUS_PPS)) { 4771 4772 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4773 "hubd_enable_all_port_power: port %d power-on " 4774 "failed, port status 0x%x", port, status); 4775 } 4776 } 4777 4778 return (USB_SUCCESS); 4779 } 4780 4781 4782 /* 4783 * hubd_enable_port_power: 4784 * enable individual port power 4785 */ 4786 static int 4787 hubd_enable_port_power(hubd_t *hubd, usb_port_t port) 4788 { 4789 int rval; 4790 usb_cr_t completion_reason; 4791 usb_cb_flags_t cb_flags; 4792 4793 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4794 "hubd_enable_port_power: port=%d", port); 4795 4796 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4797 ASSERT(hubd->h_default_pipe != 0); 4798 4799 mutex_exit(HUBD_MUTEX(hubd)); 4800 4801 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4802 hubd->h_default_pipe, 4803 HANDLE_PORT_FEATURE, 4804 USB_REQ_SET_FEATURE, 4805 CFS_PORT_POWER, 4806 port, 4807 0, NULL, 0, 4808 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4809 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4810 "set port power failed (%d 0x%x %d)", 4811 completion_reason, cb_flags, rval); 4812 mutex_enter(HUBD_MUTEX(hubd)); 4813 4814 return (USB_FAILURE); 4815 } else { 4816 mutex_enter(HUBD_MUTEX(hubd)); 4817 hubd->h_port_state[port] |= PORT_STATUS_PPS; 4818 4819 return (USB_SUCCESS); 4820 } 4821 } 4822 4823 4824 /* 4825 * hubd_disable_all_port_power: 4826 */ 4827 static int 4828 hubd_disable_all_port_power(hubd_t *hubd) 4829 { 4830 usb_port_t port; 4831 4832 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4833 "hubd_disable_all_port_power"); 4834 4835 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4836 4837 /* 4838 * disable power per port, ignore gang power and power mask 4839 */ 4840 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 4841 (void) hubd_disable_port_power(hubd, port); 4842 } 4843 4844 return (USB_SUCCESS); 4845 } 4846 4847 4848 /* 4849 * hubd_disable_port_power: 4850 * disable individual port power 4851 */ 4852 static int 4853 hubd_disable_port_power(hubd_t *hubd, usb_port_t port) 4854 { 4855 int rval; 4856 usb_cr_t completion_reason; 4857 usb_cb_flags_t cb_flags; 4858 4859 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4860 "hubd_disable_port_power: port=%d", port); 4861 4862 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4863 4864 mutex_exit(HUBD_MUTEX(hubd)); 4865 4866 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4867 hubd->h_default_pipe, 4868 HANDLE_PORT_FEATURE, 4869 USB_REQ_CLEAR_FEATURE, 4870 CFS_PORT_POWER, 4871 port, 4872 0, NULL, 0, 4873 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4874 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4875 "clearing port%d power failed (%d 0x%x %d)", 4876 port, completion_reason, cb_flags, rval); 4877 4878 mutex_enter(HUBD_MUTEX(hubd)); 4879 4880 return (USB_FAILURE); 4881 } else { 4882 4883 mutex_enter(HUBD_MUTEX(hubd)); 4884 ASSERT(completion_reason == 0); 4885 hubd->h_port_state[port] &= ~PORT_STATUS_PPS; 4886 4887 return (USB_SUCCESS); 4888 } 4889 } 4890 4891 4892 /* 4893 * Search the database of user preferences and find out the preferred 4894 * configuration for this new device 4895 */ 4896 static int 4897 hubd_select_device_configuration(hubd_t *hubd, usb_port_t port, 4898 dev_info_t *child_dip, usba_device_t *child_ud) 4899 { 4900 char *pathname = NULL; 4901 char *tmp_path = NULL; 4902 int user_conf; 4903 int pathlen; 4904 usb_dev_descr_t *usbdev_ptr; 4905 usba_configrec_t *user_pref; 4906 4907 mutex_enter(&child_ud->usb_mutex); 4908 usbdev_ptr = child_ud->usb_dev_descr; 4909 mutex_exit(&child_ud->usb_mutex); 4910 4911 /* try to get pathname for this device */ 4912 tmp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4913 (void) ddi_pathname(child_dip, tmp_path); 4914 4915 pathlen = strlen(tmp_path) + 32; 4916 pathname = kmem_zalloc(pathlen, KM_SLEEP); 4917 4918 /* 4919 * We haven't initialized the node and it doesn't have an address 4920 * yet. Append port number to the physical pathname 4921 */ 4922 (void) sprintf(pathname, "%s@%d", tmp_path, port); 4923 4924 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4925 "hubd_select_device_configuration: Device=%s\n\t" 4926 "Child path=%s", 4927 usba_get_mfg_prod_sn_str(child_dip, tmp_path, MAXPATHLEN), 4928 pathname); 4929 kmem_free(tmp_path, MAXPATHLEN); 4930 4931 4932 /* database search for user preferences */ 4933 user_pref = usba_devdb_get_user_preferences(usbdev_ptr->idVendor, 4934 usbdev_ptr->idProduct, child_ud->usb_serialno_str, pathname); 4935 4936 if (user_pref) { 4937 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4938 "hubd_select_device_configuration: " 4939 "usba_devdb_get_user_preferences " 4940 "return user_conf=%d\npreferred driver=%s path=%s", 4941 user_pref->cfg_index, user_pref->driver, 4942 user_pref->pathname); 4943 4944 user_conf = user_pref->cfg_index; 4945 4946 if (user_pref->driver) { 4947 mutex_enter(&child_ud->usb_mutex); 4948 child_ud->usb_preferred_driver = user_pref->driver; 4949 mutex_exit(&child_ud->usb_mutex); 4950 } 4951 } else { 4952 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4953 "hubd_select_device_configuration: No match found"); 4954 4955 /* select default configuration for this device */ 4956 user_conf = USBA_DEV_CONFIG_INDEX_UNDEFINED; 4957 } 4958 kmem_free(pathname, pathlen); 4959 4960 /* if the device has just one configuration, set default value */ 4961 if (usbdev_ptr->bNumConfigurations == 1) { 4962 user_conf = USB_DEV_DEFAULT_CONFIG_INDEX; 4963 } 4964 4965 return (user_conf); 4966 } 4967 4968 4969 /* 4970 * Retrieves config cloud for this configuration 4971 */ 4972 int 4973 hubd_get_this_config_cloud(hubd_t *hubd, dev_info_t *dip, 4974 usba_device_t *child_ud, uint16_t conf_index) 4975 { 4976 usb_cfg_descr_t *confdescr; 4977 mblk_t *pdata = NULL; 4978 int rval; 4979 size_t size; 4980 char *tmpbuf; 4981 usb_cr_t completion_reason; 4982 usb_cb_flags_t cb_flags; 4983 usb_pipe_handle_t def_ph; 4984 4985 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4986 "hubd_get_this_config_cloud: conf_index=%d", conf_index); 4987 4988 4989 /* alloc temporary space for config descriptor */ 4990 confdescr = (usb_cfg_descr_t *)kmem_zalloc(USB_CFG_DESCR_SIZE, 4991 KM_SLEEP); 4992 4993 /* alloc temporary space for string descriptor */ 4994 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 4995 4996 def_ph = usba_get_dflt_pipe_handle(dip); 4997 4998 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 4999 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5000 USB_REQ_GET_DESCR, 5001 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5002 0, 5003 USB_CFG_DESCR_SIZE, 5004 &pdata, 5005 0, 5006 &completion_reason, 5007 &cb_flags, 5008 0)) == USB_SUCCESS) { 5009 5010 /* this must be true since we didn't allow data underruns */ 5011 ASSERT((pdata->b_wptr - pdata->b_rptr) == USB_CFG_DESCR_SIZE); 5012 5013 /* 5014 * Parse the configuration descriptor 5015 */ 5016 size = usb_parse_cfg_descr(pdata->b_rptr, 5017 pdata->b_wptr - pdata->b_rptr, confdescr, 5018 USB_CFG_DESCR_SIZE); 5019 5020 /* if parse cfg descr error, it should return failure */ 5021 if (size == USB_PARSE_ERROR) { 5022 5023 if (pdata->b_rptr[1] != USB_DESCR_TYPE_CFG) { 5024 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5025 hubd->h_log_handle, 5026 "device returned incorrect " 5027 "configuration descriptor type."); 5028 } 5029 rval = USB_FAILURE; 5030 goto done; 5031 } 5032 5033 if (confdescr->wTotalLength < USB_CFG_DESCR_SIZE) { 5034 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5035 hubd->h_log_handle, 5036 "device returned incorrect " 5037 "configuration descriptor size."); 5038 5039 rval = USB_FAILURE; 5040 goto done; 5041 } 5042 5043 freemsg(pdata); 5044 pdata = NULL; 5045 5046 /* Now fetch the complete config cloud */ 5047 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5048 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5049 USB_REQ_GET_DESCR, 5050 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5051 0, 5052 confdescr->wTotalLength, 5053 &pdata, 5054 0, 5055 &completion_reason, 5056 &cb_flags, 5057 0)) == USB_SUCCESS) { 5058 5059 if ((pdata->b_wptr - pdata->b_rptr) != 5060 confdescr->wTotalLength) { 5061 5062 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5063 hubd->h_log_handle, 5064 "device returned incorrect " 5065 "configuration descriptor."); 5066 5067 rval = USB_FAILURE; 5068 goto done; 5069 } 5070 5071 /* 5072 * copy config descriptor into usba_device 5073 */ 5074 mutex_enter(&child_ud->usb_mutex); 5075 child_ud->usb_cfg_array[conf_index] = 5076 kmem_alloc(confdescr->wTotalLength, KM_SLEEP); 5077 child_ud->usb_cfg_array_len[conf_index] = 5078 confdescr->wTotalLength; 5079 bcopy((caddr_t)pdata->b_rptr, 5080 (caddr_t)child_ud->usb_cfg_array[conf_index], 5081 confdescr->wTotalLength); 5082 mutex_exit(&child_ud->usb_mutex); 5083 5084 /* 5085 * retrieve string descriptor describing this 5086 * configuration 5087 */ 5088 if (confdescr->iConfiguration) { 5089 5090 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 5091 hubd->h_log_handle, 5092 "Get conf str descr for config_index=%d", 5093 conf_index); 5094 5095 /* 5096 * Now fetch the string descriptor describing 5097 * this configuration 5098 */ 5099 if ((rval = usb_get_string_descr(dip, 5100 USB_LANG_ID, confdescr->iConfiguration, 5101 tmpbuf, USB_MAXSTRINGLEN)) == 5102 USB_SUCCESS) { 5103 size = strlen(tmpbuf); 5104 if (size > 0) { 5105 child_ud->usb_cfg_str_descr 5106 [conf_index] = (char *) 5107 kmem_zalloc(size + 1, 5108 KM_SLEEP); 5109 (void) strcpy( 5110 child_ud->usb_cfg_str_descr 5111 [conf_index], tmpbuf); 5112 } 5113 } else { 5114 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5115 hubd->h_log_handle, 5116 "hubd_get_this_config_cloud: " 5117 "getting config string (%d) " 5118 "failed", 5119 confdescr->iConfiguration); 5120 5121 /* ignore this error */ 5122 rval = USB_SUCCESS; 5123 } 5124 } 5125 } 5126 } 5127 5128 done: 5129 if (rval != USB_SUCCESS) { 5130 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5131 "hubd_get_this_config_cloud: " 5132 "error in retrieving config descriptor for " 5133 "config index=%d rval=%d cr=%d", 5134 conf_index, rval, completion_reason); 5135 } 5136 5137 if (pdata) { 5138 freemsg(pdata); 5139 pdata = NULL; 5140 } 5141 5142 kmem_free(confdescr, USB_CFG_DESCR_SIZE); 5143 kmem_free(tmpbuf, USB_MAXSTRINGLEN); 5144 5145 return (rval); 5146 } 5147 5148 5149 /* 5150 * Retrieves the entire config cloud for all configurations of the device 5151 */ 5152 int 5153 hubd_get_all_device_config_cloud(hubd_t *hubd, dev_info_t *dip, 5154 usba_device_t *child_ud) 5155 { 5156 int rval = USB_SUCCESS; 5157 int ncfgs; 5158 uint16_t size; 5159 uint16_t conf_index; 5160 uchar_t **cfg_array; 5161 uint16_t *cfg_array_len; 5162 char **str_descr; 5163 5164 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5165 "hubd_get_all_device_config_cloud: Start"); 5166 5167 /* alloc pointer array for conf. descriptors */ 5168 mutex_enter(&child_ud->usb_mutex); 5169 ncfgs = child_ud->usb_n_cfgs; 5170 mutex_exit(&child_ud->usb_mutex); 5171 5172 size = sizeof (uchar_t *) * ncfgs; 5173 cfg_array = kmem_zalloc(size, KM_SLEEP); 5174 cfg_array_len = kmem_zalloc(ncfgs * sizeof (uint16_t), KM_SLEEP); 5175 str_descr = kmem_zalloc(size, KM_SLEEP); 5176 5177 mutex_enter(&child_ud->usb_mutex); 5178 child_ud->usb_cfg_array = cfg_array; 5179 child_ud->usb_cfg_array_len = cfg_array_len; 5180 child_ud->usb_cfg_array_length = size; 5181 child_ud->usb_cfg_array_len_length = ncfgs * sizeof (uint16_t); 5182 child_ud->usb_cfg_str_descr = str_descr; 5183 mutex_exit(&child_ud->usb_mutex); 5184 5185 /* Get configuration descriptor for each configuration */ 5186 for (conf_index = 0; (conf_index < ncfgs) && 5187 (rval == USB_SUCCESS); conf_index++) { 5188 5189 rval = hubd_get_this_config_cloud(hubd, dip, child_ud, 5190 conf_index); 5191 } 5192 5193 return (rval); 5194 } 5195 5196 5197 /* 5198 * hubd_ready_device: 5199 * Update the usba_device structure 5200 * Set the given configuration 5201 * Prepares the device node for driver to online. If an existing 5202 * OBP node is found, it will switch to the OBP node. 5203 */ 5204 static dev_info_t * 5205 hubd_ready_device(hubd_t *hubd, dev_info_t *child_dip, usba_device_t *child_ud, 5206 int config_index) 5207 { 5208 usb_cr_t completion_reason; 5209 usb_cb_flags_t cb_flags; 5210 size_t size; 5211 usb_cfg_descr_t config_descriptor; 5212 usb_pipe_handle_t def_ph; 5213 usba_pipe_handle_data_t *ph; 5214 5215 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5216 "hubd_ready_device: dip=0x%p, user_conf_index=%d", child_dip, 5217 config_index); 5218 5219 ASSERT(config_index >= 0); 5220 5221 size = usb_parse_cfg_descr( 5222 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 5223 &config_descriptor, USB_CFG_DESCR_SIZE); 5224 ASSERT(size == USB_CFG_DESCR_SIZE); 5225 5226 def_ph = usba_get_dflt_pipe_handle(child_dip); 5227 5228 /* Set the configuration */ 5229 (void) usb_pipe_sync_ctrl_xfer(child_dip, def_ph, 5230 USB_DEV_REQ_HOST_TO_DEV, 5231 USB_REQ_SET_CFG, /* bRequest */ 5232 config_descriptor.bConfigurationValue, /* wValue */ 5233 0, /* wIndex */ 5234 0, /* wLength */ 5235 NULL, 5236 0, 5237 &completion_reason, 5238 &cb_flags, 5239 0); 5240 5241 mutex_enter(&child_ud->usb_mutex); 5242 child_ud->usb_active_cfg_ndx = config_index; 5243 child_ud->usb_cfg = child_ud->usb_cfg_array[config_index]; 5244 child_ud->usb_cfg_length = config_descriptor.wTotalLength; 5245 child_ud->usb_cfg_value = config_descriptor.bConfigurationValue; 5246 child_ud->usb_n_ifs = config_descriptor.bNumInterfaces; 5247 child_ud->usb_dip = child_dip; 5248 5249 child_ud->usb_client_flags = kmem_zalloc( 5250 child_ud->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 5251 5252 child_ud->usb_client_attach_list = kmem_zalloc( 5253 child_ud->usb_n_ifs * 5254 sizeof (*child_ud->usb_client_attach_list), KM_SLEEP); 5255 5256 child_ud->usb_client_ev_cb_list = kmem_zalloc( 5257 child_ud->usb_n_ifs * 5258 sizeof (*child_ud->usb_client_ev_cb_list), KM_SLEEP); 5259 5260 mutex_exit(&child_ud->usb_mutex); 5261 5262 /* ready the device node */ 5263 child_dip = usba_ready_device_node(child_dip); 5264 5265 /* set owner of default pipe to child dip */ 5266 ph = usba_get_ph_data(def_ph); 5267 mutex_enter(&ph->p_mutex); 5268 mutex_enter(&ph->p_ph_impl->usba_ph_mutex); 5269 ph->p_ph_impl->usba_ph_dip = ph->p_dip = child_dip; 5270 mutex_exit(&ph->p_ph_impl->usba_ph_mutex); 5271 mutex_exit(&ph->p_mutex); 5272 5273 return (child_dip); 5274 } 5275 5276 5277 /* 5278 * hubd_create_child 5279 * - create child dip 5280 * - open default pipe 5281 * - get device descriptor 5282 * - set the address 5283 * - get device string descriptors 5284 * - get the entire config cloud (all configurations) of the device 5285 * - set user preferred configuration 5286 * - close default pipe 5287 * - load appropriate driver(s) 5288 */ 5289 static int 5290 hubd_create_child(dev_info_t *dip, 5291 hubd_t *hubd, 5292 usba_device_t *hubd_ud, 5293 usb_port_status_t port_status, 5294 usb_port_t port, 5295 int iteration) 5296 { 5297 dev_info_t *child_dip = NULL; 5298 usb_dev_descr_t usb_dev_descr; 5299 int rval; 5300 usba_device_t *child_ud = NULL; 5301 usba_device_t *parent_ud = NULL; 5302 usb_pipe_handle_t ph = NULL; /* default pipe handle */ 5303 mblk_t *pdata = NULL; 5304 usb_cr_t completion_reason; 5305 int user_conf_index, config_index; 5306 usb_cb_flags_t cb_flags; 5307 uchar_t address = 0; 5308 uint16_t length; 5309 size_t size; 5310 usb_addr_t parent_usb_addr; 5311 usb_port_t parent_usb_port; 5312 usba_device_t *parent_usba_dev; 5313 usb_port_status_t parent_port_status; 5314 5315 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5316 "hubd_create_child: port=%d", port); 5317 5318 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5319 ASSERT(hubd->h_usba_devices[port] == NULL); 5320 5321 mutex_exit(HUBD_MUTEX(hubd)); 5322 5323 /* 5324 * create a dip which can be used to open the pipe. we set 5325 * the name after getting the descriptors from the device 5326 */ 5327 rval = usba_create_child_devi(dip, 5328 "device", /* driver name */ 5329 hubd_ud->usb_hcdi_ops, /* usba_hcdi ops */ 5330 hubd_ud->usb_root_hub_dip, 5331 port_status, /* low speed device */ 5332 child_ud, 5333 &child_dip); 5334 5335 if (rval != USB_SUCCESS) { 5336 5337 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5338 "usb_create_child_devi failed (%d)", rval); 5339 5340 goto fail_cleanup; 5341 } 5342 5343 child_ud = usba_get_usba_device(child_dip); 5344 ASSERT(child_ud != NULL); 5345 5346 parent_ud = hubd->h_usba_device; 5347 mutex_enter(&parent_ud->usb_mutex); 5348 parent_port_status = parent_ud->usb_port_status; 5349 5350 /* 5351 * To support split transactions, update address and port 5352 * of high speed hub to which given device is connected. 5353 */ 5354 if (parent_port_status == USBA_HIGH_SPEED_DEV) { 5355 parent_usba_dev = parent_ud; 5356 parent_usb_addr = parent_ud->usb_addr; 5357 parent_usb_port = port; 5358 } else { 5359 parent_usba_dev = parent_ud->usb_hs_hub_usba_dev; 5360 parent_usb_addr = parent_ud->usb_hs_hub_addr; 5361 parent_usb_port = parent_ud->usb_hs_hub_port; 5362 } 5363 mutex_exit(&parent_ud->usb_mutex); 5364 5365 mutex_enter(&child_ud->usb_mutex); 5366 address = child_ud->usb_addr; 5367 child_ud->usb_addr = 0; 5368 child_ud->usb_dev_descr = kmem_alloc(sizeof (usb_dev_descr_t), 5369 KM_SLEEP); 5370 bzero(&usb_dev_descr, sizeof (usb_dev_descr_t)); 5371 usb_dev_descr.bMaxPacketSize0 = 5372 (port_status == USBA_LOW_SPEED_DEV) ? 8 : 64; 5373 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5374 sizeof (usb_dev_descr_t)); 5375 child_ud->usb_port = port; 5376 child_ud->usb_hs_hub_usba_dev = parent_usba_dev; 5377 child_ud->usb_hs_hub_addr = parent_usb_addr; 5378 child_ud->usb_hs_hub_port = parent_usb_port; 5379 mutex_exit(&child_ud->usb_mutex); 5380 5381 /* Open the default pipe */ 5382 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5383 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 5384 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5385 "usb_pipe_open failed (%d)", rval); 5386 5387 goto fail_cleanup; 5388 } 5389 5390 /* 5391 * get device descriptor 5392 */ 5393 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5394 "hubd_create_child: get device descriptor: 64 bytes"); 5395 5396 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5397 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5398 USB_REQ_GET_DESCR, /* bRequest */ 5399 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5400 0, /* wIndex */ 5401 64, /* wLength */ 5402 &pdata, USB_ATTRS_SHORT_XFER_OK, 5403 &completion_reason, &cb_flags, 0); 5404 5405 if ((rval != USB_SUCCESS) && 5406 (!((completion_reason == USB_CR_DATA_OVERRUN) && pdata))) { 5407 5408 /* 5409 * rval != USB_SUCCESS AND 5410 * completion_reason != USB_CR_DATA_OVERRUN 5411 * pdata could be != NULL. 5412 * Free pdata now to prevent memory leak. 5413 */ 5414 freemsg(pdata); 5415 pdata = NULL; 5416 5417 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5418 "hubd_create_child: get device descriptor: 8 bytes"); 5419 5420 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5421 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5422 USB_REQ_GET_DESCR, /* bRequest */ 5423 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5424 0, /* wIndex */ 5425 8, /* wLength */ 5426 &pdata, USB_ATTRS_NONE, 5427 &completion_reason, &cb_flags, 0); 5428 5429 if (rval != USB_SUCCESS) { 5430 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5431 "getting device descriptor failed (%s 0x%x %d)", 5432 usb_str_cr(completion_reason), cb_flags, rval); 5433 goto fail_cleanup; 5434 } 5435 } else { 5436 ASSERT(completion_reason == USB_CR_OK); 5437 } 5438 5439 ASSERT(pdata != NULL); 5440 5441 size = usb_parse_dev_descr( 5442 pdata->b_rptr, 5443 pdata->b_wptr - pdata->b_rptr, 5444 &usb_dev_descr, 5445 sizeof (usb_dev_descr_t)); 5446 5447 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5448 "parsing device descriptor returned %lu", size); 5449 5450 length = *(pdata->b_rptr); 5451 freemsg(pdata); 5452 pdata = NULL; 5453 if (size < 8) { 5454 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5455 "get device descriptor returned %lu bytes", size); 5456 5457 goto fail_cleanup; 5458 } 5459 5460 if (length < 8) { 5461 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5462 "fail enumeration: bLength=%d", length); 5463 5464 goto fail_cleanup; 5465 } 5466 5467 /* Set the address of the device */ 5468 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5469 USB_DEV_REQ_HOST_TO_DEV, 5470 USB_REQ_SET_ADDRESS, /* bRequest */ 5471 address, /* wValue */ 5472 0, /* wIndex */ 5473 0, /* wLength */ 5474 NULL, 0, 5475 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5476 char buffer[64]; 5477 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5478 "setting address failed (cr=%s cb_flags=%s rval=%d)", 5479 usb_str_cr(completion_reason), 5480 usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)), 5481 rval); 5482 5483 goto fail_cleanup; 5484 } 5485 5486 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5487 "set address 0x%x done", address); 5488 5489 /* now close the pipe for addr 0 */ 5490 usb_pipe_close(child_dip, ph, 5491 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 5492 5493 /* 5494 * This delay is important for the CATC hub to enumerate 5495 * But, avoid delay in the first iteration 5496 */ 5497 if (iteration) { 5498 delay(drv_usectohz(hubd_device_delay/100)); 5499 } 5500 5501 /* assign the address in the usba_device structure */ 5502 mutex_enter(&child_ud->usb_mutex); 5503 child_ud->usb_addr = address; 5504 child_ud->usb_no_cpr = 0; 5505 child_ud->usb_port_status = port_status; 5506 /* save this device descriptor */ 5507 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5508 sizeof (usb_dev_descr_t)); 5509 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 5510 mutex_exit(&child_ud->usb_mutex); 5511 5512 /* re-open the pipe for the device with the new address */ 5513 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5514 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 5515 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5516 "usb_pipe_open failed (%d)", rval); 5517 5518 goto fail_cleanup; 5519 } 5520 5521 /* 5522 * Get full device descriptor only if we have not received full 5523 * device descriptor earlier. 5524 */ 5525 if (size < length) { 5526 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5527 "hubd_create_child: get full device descriptor: " 5528 "%d bytes", length); 5529 5530 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5531 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5532 USB_REQ_GET_DESCR, /* bRequest */ 5533 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5534 0, /* wIndex */ 5535 length, /* wLength */ 5536 &pdata, 0, 5537 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5538 freemsg(pdata); 5539 pdata = NULL; 5540 5541 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 5542 hubd->h_log_handle, 5543 "hubd_create_child: get full device descriptor: " 5544 "64 bytes"); 5545 5546 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5547 USB_DEV_REQ_DEV_TO_HOST | 5548 USB_DEV_REQ_TYPE_STANDARD, 5549 USB_REQ_GET_DESCR, /* bRequest */ 5550 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5551 0, /* wIndex */ 5552 64, /* wLength */ 5553 &pdata, USB_ATTRS_SHORT_XFER_OK, 5554 &completion_reason, &cb_flags, 0); 5555 5556 /* we have to trust the data now */ 5557 if (pdata) { 5558 int len = *(pdata->b_rptr); 5559 5560 length = pdata->b_wptr - pdata->b_rptr; 5561 if (length < len) { 5562 5563 goto fail_cleanup; 5564 } 5565 } else if (rval != USB_SUCCESS) { 5566 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5567 hubd->h_log_handle, 5568 "getting device descriptor failed " 5569 "(%d 0x%x %d)", 5570 completion_reason, cb_flags, rval); 5571 5572 goto fail_cleanup; 5573 } 5574 } 5575 5576 size = usb_parse_dev_descr( 5577 pdata->b_rptr, 5578 pdata->b_wptr - pdata->b_rptr, 5579 &usb_dev_descr, 5580 sizeof (usb_dev_descr_t)); 5581 5582 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5583 "parsing device descriptor returned %lu", size); 5584 5585 /* 5586 * For now, free the data 5587 * eventually, each configuration may need to be looked at 5588 */ 5589 freemsg(pdata); 5590 pdata = NULL; 5591 5592 if (size != USB_DEV_DESCR_SIZE) { 5593 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5594 "fail enumeration: descriptor size=%lu " 5595 "expected size=%u", size, USB_DEV_DESCR_SIZE); 5596 5597 goto fail_cleanup; 5598 } 5599 5600 /* 5601 * save the device descriptor in usba_device since it is needed 5602 * later on again 5603 */ 5604 mutex_enter(&child_ud->usb_mutex); 5605 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5606 sizeof (usb_dev_descr_t)); 5607 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 5608 mutex_exit(&child_ud->usb_mutex); 5609 } 5610 5611 if (usb_dev_descr.bNumConfigurations == 0) { 5612 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5613 "device descriptor:\n\t" 5614 "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t" 5615 "protocol=0x%x maxpktsize=0x%x " 5616 "Vid=0x%x Pid=0x%x rel=0x%x\n\t" 5617 "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x", 5618 usb_dev_descr.bLength, usb_dev_descr.bDescriptorType, 5619 usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass, 5620 usb_dev_descr.bDeviceSubClass, 5621 usb_dev_descr.bDeviceProtocol, 5622 usb_dev_descr.bMaxPacketSize0, 5623 usb_dev_descr.idVendor, 5624 usb_dev_descr.idProduct, usb_dev_descr.bcdDevice, 5625 usb_dev_descr.iManufacturer, usb_dev_descr.iProduct, 5626 usb_dev_descr.iSerialNumber, 5627 usb_dev_descr.bNumConfigurations); 5628 goto fail_cleanup; 5629 } 5630 5631 5632 /* get the device string descriptor(s) */ 5633 usba_get_dev_string_descrs(child_dip, child_ud); 5634 5635 /* retrieve config cloud for all configurations */ 5636 rval = hubd_get_all_device_config_cloud(hubd, child_dip, child_ud); 5637 if (rval != USB_SUCCESS) { 5638 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5639 "failed to get configuration descriptor(s)"); 5640 5641 goto fail_cleanup; 5642 } 5643 5644 /* get the preferred configuration for this device */ 5645 user_conf_index = hubd_select_device_configuration(hubd, port, 5646 child_dip, child_ud); 5647 5648 /* Check if the user selected configuration index is in range */ 5649 if (user_conf_index >= usb_dev_descr.bNumConfigurations) { 5650 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5651 "Configuration index for device idVendor=%d " 5652 "idProduct=%d is=%d, and is out of range[0..%d]", 5653 usb_dev_descr.idVendor, usb_dev_descr.idProduct, 5654 user_conf_index, usb_dev_descr.bNumConfigurations - 1); 5655 5656 /* treat this as user didn't specify configuration */ 5657 user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED; 5658 } 5659 5660 5661 /* 5662 * Warn users of a performance hit if connecting a 5663 * High Speed behind a 1.1 hub, which is behind a 5664 * 2.0 port. 5665 */ 5666 if ((parent_port_status != USBA_HIGH_SPEED_DEV) && 5667 !(usba_is_root_hub(parent_ud->usb_dip)) && 5668 (parent_usb_addr)) { 5669 5670 /* 5671 * Now that we know the root port is a high speed port 5672 * and that the parent port is not a high speed port, 5673 * let's find out if the device itself is a high speed 5674 * device. If it is a high speed device, 5675 * USB_DESCR_TYPE_SETUP_DEV_QLF should return a value, 5676 * otherwise the command will fail. 5677 */ 5678 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5679 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5680 USB_REQ_GET_DESCR, /* bRequest */ 5681 USB_DESCR_TYPE_SETUP_DEV_QLF, /* wValue */ 5682 0, /* wIndex */ 5683 10, /* wLength */ 5684 &pdata, USB_ATTRS_SHORT_XFER_OK, 5685 &completion_reason, &cb_flags, 0); 5686 5687 if (pdata) { 5688 freemsg(pdata); 5689 pdata = NULL; 5690 } 5691 5692 /* 5693 * USB_DESCR_TYPE_SETUP_DEV_QLF query was successful 5694 * that means this is a high speed device behind a 5695 * high speed root hub, but running at full speed 5696 * because there is a full speed hub in the middle. 5697 */ 5698 if (rval == USB_SUCCESS) { 5699 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 5700 hubd->h_log_handle, 5701 "Connecting a high speed device to a " 5702 "non high speed hub (port %d) will result " 5703 "in a loss of performance. Please connect " 5704 "the device to a high speed hub to get " 5705 "the maximum performance.", 5706 port); 5707 } 5708 } 5709 5710 /* 5711 * Now we try to online the device by attaching a driver 5712 * The following truth table illustrates the logic:- 5713 * Cfgndx Driver Action 5714 * 0 0 loop all configs for driver with full 5715 * compatible properties. 5716 * 0 1 set first configuration, 5717 * compatible prop = drivername. 5718 * 1 0 Set config, full compatible prop 5719 * 1 1 Set config, compatible prop = drivername. 5720 * 5721 * Note: 5722 * cfgndx = user_conf_index 5723 * Driver = usb_preferred_driver 5724 */ 5725 if (user_conf_index == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 5726 if (child_ud->usb_preferred_driver) { 5727 /* 5728 * It is the job of the "preferred driver" to put the 5729 * device in the desired configuration. Till then 5730 * put the device in config index 0. 5731 */ 5732 child_dip = hubd_ready_device(hubd, child_dip, 5733 child_ud, USB_DEV_DEFAULT_CONFIG_INDEX); 5734 5735 /* 5736 * Assign the dip before onlining to avoid race 5737 * with busctl 5738 */ 5739 mutex_enter(HUBD_MUTEX(hubd)); 5740 hubd->h_children_dips[port] = child_dip; 5741 mutex_exit(HUBD_MUTEX(hubd)); 5742 5743 (void) usba_bind_driver(child_dip); 5744 } else { 5745 /* 5746 * loop through all the configurations to see if we 5747 * can find a driver for any one config. If not, set 5748 * the device in config_index 0 5749 */ 5750 rval = USB_FAILURE; 5751 for (config_index = 0; 5752 (config_index < usb_dev_descr.bNumConfigurations) && 5753 (rval != USB_SUCCESS); config_index++) { 5754 5755 child_dip = hubd_ready_device(hubd, child_dip, 5756 child_ud, config_index); 5757 5758 /* 5759 * Assign the dip before onlining to avoid race 5760 * with busctl 5761 */ 5762 mutex_enter(HUBD_MUTEX(hubd)); 5763 hubd->h_children_dips[port] = child_dip; 5764 mutex_exit(HUBD_MUTEX(hubd)); 5765 5766 rval = usba_bind_driver(child_dip); 5767 } 5768 if (rval != USB_SUCCESS) { 5769 child_dip = hubd_ready_device(hubd, child_dip, 5770 child_ud, 0); 5771 mutex_enter(HUBD_MUTEX(hubd)); 5772 hubd->h_children_dips[port] = child_dip; 5773 mutex_exit(HUBD_MUTEX(hubd)); 5774 } 5775 } /* end else loop all configs */ 5776 } else { 5777 child_dip = hubd_ready_device(hubd, child_dip, 5778 child_ud, user_conf_index); 5779 5780 /* 5781 * Assign the dip before onlining to avoid race 5782 * with busctl 5783 */ 5784 mutex_enter(HUBD_MUTEX(hubd)); 5785 hubd->h_children_dips[port] = child_dip; 5786 mutex_exit(HUBD_MUTEX(hubd)); 5787 5788 (void) usba_bind_driver(child_dip); 5789 } 5790 5791 mutex_enter(HUBD_MUTEX(hubd)); 5792 if (hubd->h_usba_devices[port] == NULL) { 5793 hubd->h_usba_devices[port] = usba_get_usba_device(child_dip); 5794 } else { 5795 ASSERT(hubd->h_usba_devices[port] == 5796 usba_get_usba_device(child_dip)); 5797 } 5798 5799 return (USB_SUCCESS); 5800 5801 5802 fail_cleanup: 5803 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5804 "hubd_create_child: fail_cleanup"); 5805 5806 mutex_enter(HUBD_MUTEX(hubd)); 5807 hubd->h_children_dips[port] = NULL; 5808 mutex_exit(HUBD_MUTEX(hubd)); 5809 5810 if (pdata) { 5811 freemsg(pdata); 5812 } 5813 5814 if (ph) { 5815 usb_pipe_close(child_dip, ph, 5816 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 5817 } 5818 5819 if (child_dip) { 5820 int rval = usba_destroy_child_devi(child_dip, 5821 NDI_DEVI_REMOVE); 5822 if (rval != USB_SUCCESS) { 5823 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5824 "failure to remove child node"); 5825 } 5826 } 5827 5828 if (child_ud) { 5829 /* to make sure we free the address */ 5830 mutex_enter(&child_ud->usb_mutex); 5831 child_ud->usb_addr = address; 5832 ASSERT(child_ud->usb_ref_count == 0); 5833 mutex_exit(&child_ud->usb_mutex); 5834 5835 mutex_enter(HUBD_MUTEX(hubd)); 5836 if (hubd->h_usba_devices[port] == NULL) { 5837 mutex_exit(HUBD_MUTEX(hubd)); 5838 usba_free_usba_device(child_ud); 5839 } else { 5840 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 5841 mutex_exit(HUBD_MUTEX(hubd)); 5842 } 5843 } 5844 5845 mutex_enter(HUBD_MUTEX(hubd)); 5846 5847 return (USB_FAILURE); 5848 } 5849 5850 5851 /* 5852 * hubd_delete_child: 5853 * - free usb address 5854 * - lookup child dips, there may be multiple on this port 5855 * - offline each child devi 5856 */ 5857 static int 5858 hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, boolean_t retry) 5859 { 5860 dev_info_t *child_dip; 5861 usba_device_t *usba_device; 5862 int rval = USB_SUCCESS; 5863 5864 child_dip = hubd->h_children_dips[port]; 5865 5866 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5867 "hubd_delete_child: port=%d, dip=0x%p usba_device=0x%p", 5868 port, child_dip); 5869 5870 mutex_exit(HUBD_MUTEX(hubd)); 5871 if (child_dip) { 5872 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5873 "hubd_delete_child:\n\t" 5874 "dip = 0x%p (%s) at port %d", 5875 child_dip, ddi_node_name(child_dip), port); 5876 5877 rval = usba_destroy_child_devi(child_dip, flag); 5878 5879 if ((rval == USB_SUCCESS) && (flag & NDI_DEVI_REMOVE)) { 5880 /* 5881 * if the child was still < DS_INITIALIZED 5882 * then our bus_unconfig was not called and 5883 * we have to zap the child here 5884 */ 5885 mutex_enter(HUBD_MUTEX(hubd)); 5886 if (hubd->h_children_dips[port] == child_dip) { 5887 usba_device_t *ud = 5888 hubd->h_usba_devices[port]; 5889 hubd->h_children_dips[port] = NULL; 5890 if (ud) { 5891 mutex_exit(HUBD_MUTEX(hubd)); 5892 5893 mutex_enter(&ud->usb_mutex); 5894 ud->usb_ref_count = 0; 5895 mutex_exit(&ud->usb_mutex); 5896 5897 usba_free_usba_device(ud); 5898 mutex_enter(HUBD_MUTEX(hubd)); 5899 hubd->h_usba_devices[port] = NULL; 5900 } 5901 } 5902 mutex_exit(HUBD_MUTEX(hubd)); 5903 } 5904 } 5905 5906 if ((rval != USB_SUCCESS) && retry) { 5907 mutex_enter(HUBD_MUTEX(hubd)); 5908 usba_device = hubd->h_usba_devices[port]; 5909 mutex_exit(HUBD_MUTEX(hubd)); 5910 5911 hubd_schedule_cleanup(usba_device->usb_root_hub_dip); 5912 } 5913 mutex_enter(HUBD_MUTEX(hubd)); 5914 5915 return (rval); 5916 } 5917 5918 5919 /* 5920 * hubd_free_usba_device: 5921 * free usb device structure unless it is associated with 5922 * the root hub which is handled differently 5923 */ 5924 static void 5925 hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device) 5926 { 5927 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5928 "hubd_free_usba_device: hubd=0x%p, usba_device=0x%p", 5929 hubd, usba_device); 5930 5931 if (usba_device && (usba_device->usb_addr != ROOT_HUB_ADDR)) { 5932 usb_port_t port = usba_device->usb_port; 5933 dev_info_t *dip = hubd->h_children_dips[port]; 5934 5935 #ifdef DEBUG 5936 if (dip) { 5937 ASSERT(i_ddi_node_state(dip) < DS_INITIALIZED); 5938 } 5939 #endif 5940 5941 port = usba_device->usb_port; 5942 hubd->h_usba_devices[port] = NULL; 5943 5944 mutex_exit(HUBD_MUTEX(hubd)); 5945 usba_free_usba_device(usba_device); 5946 mutex_enter(HUBD_MUTEX(hubd)); 5947 } 5948 } 5949 5950 5951 /* 5952 * event support 5953 * 5954 * busctl event support 5955 */ 5956 static int 5957 hubd_busop_get_eventcookie(dev_info_t *dip, 5958 dev_info_t *rdip, 5959 char *eventname, 5960 ddi_eventcookie_t *cookie) 5961 { 5962 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 5963 5964 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5965 "hubd_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 5966 "event=%s", (void *)dip, (void *)rdip, eventname); 5967 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5968 "(dip=%s%d, rdip=%s%d)", 5969 ddi_driver_name(dip), ddi_get_instance(dip), 5970 ddi_driver_name(rdip), ddi_get_instance(rdip)); 5971 5972 /* return event cookie, iblock cookie, and level */ 5973 return (ndi_event_retrieve_cookie(hubd->h_ndi_event_hdl, 5974 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 5975 } 5976 5977 5978 static int 5979 hubd_busop_add_eventcall(dev_info_t *dip, 5980 dev_info_t *rdip, 5981 ddi_eventcookie_t cookie, 5982 void (*callback)(dev_info_t *dip, 5983 ddi_eventcookie_t cookie, void *arg, 5984 void *bus_impldata), 5985 void *arg, ddi_callback_id_t *cb_id) 5986 { 5987 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 5988 usb_port_t port = hubd_child_dip2port(hubd, rdip); 5989 5990 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5991 "hubd_busop_add_eventcall: dip=0x%p, rdip=0x%p " 5992 "cookie=0x%p, cb=0x%p, arg=0x%p", 5993 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 5994 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5995 "(dip=%s%d, rdip=%s%d, event=%s)", 5996 ddi_driver_name(dip), ddi_get_instance(dip), 5997 ddi_driver_name(rdip), ddi_get_instance(rdip), 5998 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, cookie)); 5999 6000 /* Set flag on children registering events */ 6001 switch (ndi_event_cookie_to_tag(hubd->h_ndi_event_hdl, cookie)) { 6002 case USBA_EVENT_TAG_HOT_REMOVAL: 6003 mutex_enter(HUBD_MUTEX(hubd)); 6004 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6005 mutex_exit(HUBD_MUTEX(hubd)); 6006 6007 break; 6008 case USBA_EVENT_TAG_PRE_SUSPEND: 6009 mutex_enter(HUBD_MUTEX(hubd)); 6010 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6011 mutex_exit(HUBD_MUTEX(hubd)); 6012 6013 break; 6014 default: 6015 6016 break; 6017 } 6018 6019 /* add callback to our event set */ 6020 return (ndi_event_add_callback(hubd->h_ndi_event_hdl, 6021 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 6022 } 6023 6024 6025 static int 6026 hubd_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 6027 { 6028 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6029 ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id; 6030 6031 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6032 "hubd_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 6033 "cookie=0x%p", (void *)dip, id->ndi_evtcb_dip, 6034 id->ndi_evtcb_cookie); 6035 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6036 "(dip=%s%d, rdip=%s%d, event=%s)", 6037 ddi_driver_name(dip), ddi_get_instance(dip), 6038 ddi_driver_name(id->ndi_evtcb_dip), 6039 ddi_get_instance(id->ndi_evtcb_dip), 6040 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, 6041 id->ndi_evtcb_cookie)); 6042 6043 /* remove event registration from our event set */ 6044 return (ndi_event_remove_callback(hubd->h_ndi_event_hdl, cb_id)); 6045 } 6046 6047 6048 /* 6049 * event distribution 6050 * 6051 * hubd_do_callback: 6052 * Post this event to the specified child 6053 */ 6054 static void 6055 hubd_do_callback(hubd_t *hubd, dev_info_t *cdip, ddi_eventcookie_t cookie) 6056 { 6057 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6058 "hubd_do_callback"); 6059 6060 (void) ndi_event_do_callback(hubd->h_ndi_event_hdl, cdip, cookie, NULL); 6061 } 6062 6063 6064 /* 6065 * hubd_run_callbacks: 6066 * Send this event to all children 6067 */ 6068 static void 6069 hubd_run_callbacks(hubd_t *hubd, usba_event_t type) 6070 { 6071 usb_port_t port; 6072 6073 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6074 "hubd_run_callbacks"); 6075 6076 mutex_enter(HUBD_MUTEX(hubd)); 6077 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 6078 /* 6079 * the childen_dips list may have dips that have been 6080 * already deallocated. we only get a post_detach notification 6081 * but not a destroy notification 6082 */ 6083 if (hubd->h_children_dips[port]) { 6084 mutex_exit(HUBD_MUTEX(hubd)); 6085 hubd_post_event(hubd, port, type); 6086 mutex_enter(HUBD_MUTEX(hubd)); 6087 } 6088 } 6089 mutex_exit(HUBD_MUTEX(hubd)); 6090 } 6091 6092 6093 /* 6094 * hubd_post_event 6095 * post event to a child on the port depending on the type 6096 */ 6097 static void 6098 hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type) 6099 { 6100 int rval; 6101 dev_info_t *dip; 6102 usba_device_t *usba_device; 6103 ddi_eventcookie_t cookie, rm_cookie, suspend_cookie; 6104 6105 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6106 "hubd_post_event: port=%d event=%s", port, 6107 ndi_event_tag_to_name(hubd->h_ndi_event_hdl, type)); 6108 6109 cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, type); 6110 rm_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6111 USBA_EVENT_TAG_HOT_REMOVAL); 6112 suspend_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6113 USBA_EVENT_TAG_PRE_SUSPEND); 6114 6115 /* 6116 * Hotplug daemon may be attaching a driver that may be registering 6117 * event callbacks. So it already has got the device tree lock and 6118 * event handle mutex. So to prevent a deadlock while posting events, 6119 * we grab and release the locks in the same order. 6120 */ 6121 mutex_enter(HUBD_MUTEX(hubd)); 6122 dip = hubd->h_children_dips[port]; 6123 usba_device = hubd->h_usba_devices[port]; 6124 mutex_exit(HUBD_MUTEX(hubd)); 6125 6126 switch (type) { 6127 case USBA_EVENT_TAG_HOT_REMOVAL: 6128 /* Clear the registered event flag */ 6129 mutex_enter(HUBD_MUTEX(hubd)); 6130 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_DISCONNECT; 6131 mutex_exit(HUBD_MUTEX(hubd)); 6132 6133 hubd_do_callback(hubd, dip, cookie); 6134 usba_persistent_pipe_close(usba_device); 6135 6136 /* 6137 * Mark the dip for deletion only after the driver has 6138 * seen the disconnect event to prevent cleanup thread 6139 * from stepping in between. 6140 */ 6141 mutex_enter(&(DEVI(dip)->devi_lock)); 6142 DEVI_SET_DEVICE_REMOVED(dip); 6143 mutex_exit(&(DEVI(dip)->devi_lock)); 6144 6145 break; 6146 case USBA_EVENT_TAG_PRE_SUSPEND: 6147 mutex_enter(HUBD_MUTEX(hubd)); 6148 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_PRESUSPEND; 6149 mutex_exit(HUBD_MUTEX(hubd)); 6150 6151 hubd_do_callback(hubd, dip, cookie); 6152 /* 6153 * persistent pipe close for this event is taken care by the 6154 * caller after verfying that all children can suspend 6155 */ 6156 6157 break; 6158 case USBA_EVENT_TAG_HOT_INSERTION: 6159 /* 6160 * Check if this child has missed the disconnect event before 6161 * it registered for event callbacks 6162 */ 6163 mutex_enter(HUBD_MUTEX(hubd)); 6164 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_DISCONNECT) { 6165 /* clear the flag and post disconnect event */ 6166 hubd->h_child_events[port] &= 6167 ~HUBD_CHILD_EVENT_DISCONNECT; 6168 mutex_exit(HUBD_MUTEX(hubd)); 6169 hubd_do_callback(hubd, dip, rm_cookie); 6170 usba_persistent_pipe_close(usba_device); 6171 mutex_enter(HUBD_MUTEX(hubd)); 6172 } 6173 mutex_exit(HUBD_MUTEX(hubd)); 6174 6175 /* 6176 * Mark the dip as reinserted to prevent cleanup thread 6177 * from stepping in. 6178 */ 6179 mutex_enter(&(DEVI(dip)->devi_lock)); 6180 DEVI_SET_DEVICE_REINSERTED(dip); 6181 mutex_exit(&(DEVI(dip)->devi_lock)); 6182 6183 rval = usba_persistent_pipe_open(usba_device); 6184 if (rval != USB_SUCCESS) { 6185 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6186 hubd->h_log_handle, 6187 "failed to reopen all pipes on reconnect"); 6188 } 6189 6190 hubd_do_callback(hubd, dip, cookie); 6191 6192 /* 6193 * We might see a connect event only if hotplug thread for 6194 * disconnect event don't run in time. 6195 * Set the flag again, so we don't miss posting a 6196 * disconnect event. 6197 */ 6198 mutex_enter(HUBD_MUTEX(hubd)); 6199 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6200 mutex_exit(HUBD_MUTEX(hubd)); 6201 6202 break; 6203 case USBA_EVENT_TAG_POST_RESUME: 6204 /* 6205 * Check if this child has missed the pre-suspend event before 6206 * it registered for event callbacks 6207 */ 6208 mutex_enter(HUBD_MUTEX(hubd)); 6209 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_PRESUSPEND) { 6210 /* clear the flag and post pre_suspend event */ 6211 hubd->h_port_state[port] &= 6212 ~HUBD_CHILD_EVENT_PRESUSPEND; 6213 mutex_exit(HUBD_MUTEX(hubd)); 6214 hubd_do_callback(hubd, dip, suspend_cookie); 6215 mutex_enter(HUBD_MUTEX(hubd)); 6216 } 6217 mutex_exit(HUBD_MUTEX(hubd)); 6218 6219 mutex_enter(&usba_device->usb_mutex); 6220 usba_device->usb_no_cpr = 0; 6221 mutex_exit(&usba_device->usb_mutex); 6222 6223 /* 6224 * Since the pipe has already been opened by hub 6225 * at DDI_RESUME time, there is no need for a 6226 * persistent pipe open 6227 */ 6228 hubd_do_callback(hubd, dip, cookie); 6229 6230 /* 6231 * Set the flag again, so we don't miss posting a 6232 * pre-suspend event. This enforces a tighter 6233 * dev_state model. 6234 */ 6235 mutex_enter(HUBD_MUTEX(hubd)); 6236 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6237 mutex_exit(HUBD_MUTEX(hubd)); 6238 break; 6239 } 6240 } 6241 6242 6243 /* 6244 * handling of events coming from above 6245 */ 6246 static int 6247 hubd_disconnect_event_cb(dev_info_t *dip) 6248 { 6249 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6250 usb_port_t port, nports; 6251 usba_device_t *usba_dev; 6252 usba_event_t tag = USBA_EVENT_TAG_HOT_REMOVAL; 6253 int circ; 6254 6255 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6256 "hubd_disconnect_event_cb: tag=%d", tag); 6257 6258 ndi_devi_enter(dip, &circ); 6259 6260 mutex_enter(HUBD_MUTEX(hubd)); 6261 switch (hubd->h_dev_state) { 6262 case USB_DEV_ONLINE: 6263 case USB_DEV_PWRED_DOWN: 6264 hubd->h_dev_state = USB_DEV_DISCONNECTED; 6265 /* stop polling on the interrupt pipe */ 6266 hubd_stop_polling(hubd); 6267 6268 /* FALLTHROUGH */ 6269 case USB_DEV_SUSPENDED: 6270 /* we remain in this state */ 6271 mutex_exit(HUBD_MUTEX(hubd)); 6272 hubd_run_callbacks(hubd, tag); 6273 mutex_enter(HUBD_MUTEX(hubd)); 6274 6275 /* close all the open pipes of our children */ 6276 nports = hubd->h_hub_descr.bNbrPorts; 6277 for (port = 1; port <= nports; port++) { 6278 usba_dev = hubd->h_usba_devices[port]; 6279 if (usba_dev != NULL) { 6280 mutex_exit(HUBD_MUTEX(hubd)); 6281 usba_persistent_pipe_close(usba_dev); 6282 mutex_enter(HUBD_MUTEX(hubd)); 6283 } 6284 } 6285 6286 break; 6287 case USB_DEV_DISCONNECTED: 6288 /* avoid passing multiple disconnects to children */ 6289 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6290 "hubd_disconnect_event_cb: Already disconnected"); 6291 6292 break; 6293 default: 6294 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6295 "hubd_disconnect_event_cb: Illegal devstate=%d", 6296 hubd->h_dev_state); 6297 6298 break; 6299 } 6300 mutex_exit(HUBD_MUTEX(hubd)); 6301 6302 ndi_devi_exit(dip, circ); 6303 6304 return (USB_SUCCESS); 6305 } 6306 6307 6308 static int 6309 hubd_reconnect_event_cb(dev_info_t *dip) 6310 { 6311 int rval, circ; 6312 6313 ndi_devi_enter(dip, &circ); 6314 rval = hubd_restore_state_cb(dip); 6315 ndi_devi_exit(dip, circ); 6316 6317 return (rval); 6318 } 6319 6320 6321 /* 6322 * hubd_pre_suspend_event_cb 6323 * propogate event for binary compatibility of old drivers 6324 */ 6325 static int 6326 hubd_pre_suspend_event_cb(dev_info_t *dip) 6327 { 6328 int circ; 6329 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6330 6331 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6332 "hubd_pre_suspend_event_cb"); 6333 6334 /* disable hotplug thread */ 6335 mutex_enter(HUBD_MUTEX(hubd)); 6336 hubd->h_hotplug_thread++; 6337 hubd_stop_polling(hubd); 6338 6339 /* keep PM out till we see a cpr resume */ 6340 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6341 mutex_exit(HUBD_MUTEX(hubd)); 6342 6343 ndi_devi_enter(dip, &circ); 6344 hubd_run_callbacks(hubd, USBA_EVENT_TAG_PRE_SUSPEND); 6345 ndi_devi_exit(dip, circ); 6346 6347 return (USB_SUCCESS); 6348 } 6349 6350 6351 /* 6352 * hubd_post_resume_event_cb 6353 * propogate event for binary compatibility of old drivers 6354 */ 6355 static int 6356 hubd_post_resume_event_cb(dev_info_t *dip) 6357 { 6358 int circ; 6359 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6360 6361 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6362 "hubd_post_resume_event_cb"); 6363 6364 ndi_devi_enter(dip, &circ); 6365 hubd_run_callbacks(hubd, USBA_EVENT_TAG_POST_RESUME); 6366 ndi_devi_exit(dip, circ); 6367 6368 mutex_enter(HUBD_MUTEX(hubd)); 6369 6370 /* enable PM */ 6371 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6372 6373 /* allow hotplug thread */ 6374 hubd->h_hotplug_thread--; 6375 6376 /* start polling */ 6377 hubd_start_polling(hubd, 0); 6378 mutex_exit(HUBD_MUTEX(hubd)); 6379 6380 return (USB_SUCCESS); 6381 } 6382 6383 6384 /* 6385 * hubd_cpr_suspend 6386 * save the current state of the driver/device 6387 */ 6388 static int 6389 hubd_cpr_suspend(hubd_t *hubd) 6390 { 6391 usb_port_t port, nports; 6392 usba_device_t *usba_dev; 6393 uchar_t no_cpr = 0; 6394 int rval = USB_FAILURE; 6395 6396 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6397 "hubd_cpr_suspend: Begin"); 6398 6399 /* Make sure device is powered up to save state. */ 6400 mutex_enter(HUBD_MUTEX(hubd)); 6401 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6402 mutex_exit(HUBD_MUTEX(hubd)); 6403 6404 /* bring the device to full power */ 6405 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 6406 mutex_enter(HUBD_MUTEX(hubd)); 6407 6408 switch (hubd->h_dev_state) { 6409 case USB_DEV_ONLINE: 6410 case USB_DEV_PWRED_DOWN: 6411 case USB_DEV_DISCONNECTED: 6412 /* find out if all our children have been quiesced */ 6413 nports = hubd->h_hub_descr.bNbrPorts; 6414 for (port = 1; (no_cpr == 0) && (port <= nports); port++) { 6415 usba_dev = hubd->h_usba_devices[port]; 6416 if (usba_dev != NULL) { 6417 mutex_enter(&usba_dev->usb_mutex); 6418 no_cpr += usba_dev->usb_no_cpr; 6419 mutex_exit(&usba_dev->usb_mutex); 6420 } 6421 } 6422 if (no_cpr > 0) { 6423 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6424 "Children busy - can't checkpoint"); 6425 /* remain in same state to fail checkpoint */ 6426 6427 break; 6428 } else { 6429 /* 6430 * do not suspend if our hotplug thread 6431 * or the deathrow thread is active 6432 */ 6433 if ((hubd->h_hotplug_thread > 1) || 6434 (hubd->h_cleanup_active == B_TRUE)) { 6435 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6436 hubd->h_log_handle, 6437 "hotplug thread active - can't cpr"); 6438 /* remain in same state to fail checkpoint */ 6439 6440 break; 6441 } 6442 6443 /* quiesce ourselves now */ 6444 hubd->h_dev_state = USB_DEV_SUSPENDED; 6445 hubd_stop_polling(hubd); 6446 6447 /* close all the open pipes of our children */ 6448 for (port = 1; port <= nports; port++) { 6449 usba_dev = hubd->h_usba_devices[port]; 6450 if (usba_dev != NULL) { 6451 mutex_exit(HUBD_MUTEX(hubd)); 6452 usba_persistent_pipe_close(usba_dev); 6453 mutex_enter(HUBD_MUTEX(hubd)); 6454 } 6455 } 6456 /* 6457 * turn off power to all the ports so that we 6458 * don't see any spurious activity 6459 */ 6460 (void) hubd_disable_all_port_power(hubd); 6461 6462 /* 6463 * if we are the root hub, we close our pipes 6464 * ourselves. 6465 */ 6466 if (usba_is_root_hub(hubd->h_dip)) { 6467 mutex_exit(HUBD_MUTEX(hubd)); 6468 usba_persistent_pipe_close( 6469 usba_get_usba_device(hubd->h_dip)); 6470 mutex_enter(HUBD_MUTEX(hubd)); 6471 } 6472 rval = USB_SUCCESS; 6473 6474 break; 6475 } 6476 case USB_DEV_SUSPENDED: 6477 default: 6478 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6479 "hubd_cpr_suspend: Illegal dev state=%d", 6480 hubd->h_dev_state); 6481 6482 break; 6483 } 6484 6485 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6486 mutex_exit(HUBD_MUTEX(hubd)); 6487 6488 return (rval); 6489 } 6490 6491 static void 6492 hubd_cpr_resume(dev_info_t *dip) 6493 { 6494 int rval, circ; 6495 6496 ndi_devi_enter(dip, &circ); 6497 /* 6498 * if we are the root hub, we open our pipes 6499 * ourselves. 6500 */ 6501 if (usba_is_root_hub(dip)) { 6502 rval = usba_persistent_pipe_open( 6503 usba_get_usba_device(dip)); 6504 ASSERT(rval == USB_SUCCESS); 6505 } 6506 (void) hubd_restore_state_cb(dip); 6507 ndi_devi_exit(dip, circ); 6508 } 6509 6510 6511 /* 6512 * hubd_restore_state_cb 6513 * Event callback to restore device state 6514 */ 6515 static int 6516 hubd_restore_state_cb(dev_info_t *dip) 6517 { 6518 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6519 6520 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6521 "hubd_restore_state_cb: Begin"); 6522 6523 /* restore the state of this device */ 6524 hubd_restore_device_state(dip, hubd); 6525 6526 return (USB_SUCCESS); 6527 } 6528 6529 6530 /* 6531 * registering for events 6532 */ 6533 static int 6534 hubd_register_events(hubd_t *hubd) 6535 { 6536 int rval = USB_SUCCESS; 6537 6538 if (usba_is_root_hub(hubd->h_dip)) { 6539 hubd_register_cpr_callback(hubd); 6540 } else { 6541 rval = usb_register_event_cbs(hubd->h_dip, &hubd_events, 0); 6542 } 6543 6544 return (rval); 6545 } 6546 6547 6548 /* 6549 * hubd cpr callback related functions 6550 * 6551 * hubd_cpr_post_user_callb: 6552 * This function is called during checkpoint & resume - 6553 * 1. after user threads are stopped during checkpoint 6554 * 2. after kernel threads are resumed during resume 6555 */ 6556 /* ARGSUSED */ 6557 static boolean_t 6558 hubd_cpr_post_user_callb(void *arg, int code) 6559 { 6560 hubd_cpr_t *cpr_cb = (hubd_cpr_t *)arg; 6561 hubd_t *hubd = cpr_cb->statep; 6562 int retry = 0; 6563 6564 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6565 "hubd_cpr_post_user_callb"); 6566 6567 switch (code) { 6568 case CB_CODE_CPR_CHKPT: 6569 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6570 "hubd_cpr_post_user_callb: CB_CODE_CPR_CHKPT"); 6571 6572 mutex_enter(HUBD_MUTEX(hubd)); 6573 6574 /* turn off deathrow thread */ 6575 hubd->h_cleanup_enabled = B_FALSE; 6576 6577 /* give up if deathrow thread doesn't exit */ 6578 while ((hubd->h_cleanup_active == B_TRUE) && (retry++ < 3)) { 6579 mutex_exit(HUBD_MUTEX(hubd)); 6580 delay(drv_usectohz(hubd_dip_cleanup_delay)); 6581 6582 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6583 "hubd_cpr_post_user_callb, waiting for " 6584 "deathrow thread to exit"); 6585 mutex_enter(HUBD_MUTEX(hubd)); 6586 } 6587 6588 mutex_exit(HUBD_MUTEX(hubd)); 6589 6590 /* save the state of the device */ 6591 (void) hubd_pre_suspend_event_cb(hubd->h_dip); 6592 6593 return (B_TRUE); 6594 case CB_CODE_CPR_RESUME: 6595 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6596 "hubd_cpr_post_user_callb: CB_CODE_CPR_RESUME"); 6597 6598 /* restore the state of the device */ 6599 (void) hubd_post_resume_event_cb(hubd->h_dip); 6600 6601 /* turn on deathrow thread */ 6602 mutex_enter(HUBD_MUTEX(hubd)); 6603 hubd->h_cleanup_enabled = B_TRUE; 6604 mutex_exit(HUBD_MUTEX(hubd)); 6605 6606 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 6607 6608 return (B_TRUE); 6609 default: 6610 6611 return (B_FALSE); 6612 } 6613 6614 } 6615 6616 6617 /* register callback with cpr framework */ 6618 void 6619 hubd_register_cpr_callback(hubd_t *hubd) 6620 { 6621 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6622 "hubd_register_cpr_callback"); 6623 6624 mutex_enter(HUBD_MUTEX(hubd)); 6625 hubd->h_cpr_cb = 6626 (hubd_cpr_t *)kmem_zalloc(sizeof (hubd_cpr_t), KM_SLEEP); 6627 mutex_exit(HUBD_MUTEX(hubd)); 6628 mutex_init(&hubd->h_cpr_cb->lockp, NULL, MUTEX_DRIVER, 6629 hubd->h_dev_data->dev_iblock_cookie); 6630 hubd->h_cpr_cb->statep = hubd; 6631 hubd->h_cpr_cb->cpr.cc_lockp = &hubd->h_cpr_cb->lockp; 6632 hubd->h_cpr_cb->cpr.cc_id = callb_add(hubd_cpr_post_user_callb, 6633 (void *)hubd->h_cpr_cb, CB_CL_CPR_POST_USER, "hubd"); 6634 } 6635 6636 6637 /* unregister callback with cpr framework */ 6638 void 6639 hubd_unregister_cpr_callback(hubd_t *hubd) 6640 { 6641 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6642 "hubd_unregister_cpr_callback"); 6643 6644 if (hubd->h_cpr_cb) { 6645 (void) callb_delete(hubd->h_cpr_cb->cpr.cc_id); 6646 mutex_destroy(&hubd->h_cpr_cb->lockp); 6647 mutex_enter(HUBD_MUTEX(hubd)); 6648 kmem_free(hubd->h_cpr_cb, sizeof (hubd_cpr_t)); 6649 mutex_exit(HUBD_MUTEX(hubd)); 6650 } 6651 } 6652 6653 6654 /* 6655 * Power management 6656 * 6657 * create the pm components required for power management 6658 */ 6659 static void 6660 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd) 6661 { 6662 hub_power_t *hubpm; 6663 6664 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 6665 "hubd_create_pm_components: Begin"); 6666 6667 /* Allocate the state structure */ 6668 hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP); 6669 6670 hubd->h_hubpm = hubpm; 6671 hubpm->hubp_hubd = hubd; 6672 hubpm->hubp_pm_capabilities = 0; 6673 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 6674 hubpm->hubp_time_at_full_power = ddi_get_time(); 6675 hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold; 6676 6677 /* alloc memory to save power states of children */ 6678 hubpm->hubp_child_pwrstate = (uint8_t *) 6679 kmem_zalloc(MAX_PORTS + 1, KM_SLEEP); 6680 6681 /* 6682 * if the enable remote wakeup fails 6683 * we still want to enable 6684 * parent notification so we can PM the children 6685 */ 6686 usb_enable_parent_notification(dip); 6687 6688 if (usb_handle_remote_wakeup(dip, 6689 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 6690 uint_t pwr_states; 6691 6692 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 6693 "hubd_create_pm_components: " 6694 "Remote Wakeup Enabled"); 6695 6696 if (usb_create_pm_components(dip, &pwr_states) == 6697 USB_SUCCESS) { 6698 mutex_enter(HUBD_MUTEX(hubd)); 6699 hubpm->hubp_wakeup_enabled = 1; 6700 hubpm->hubp_pwr_states = (uint8_t)pwr_states; 6701 6702 /* we are busy now till end of the attach */ 6703 hubd_pm_busy_component(hubd, dip, 0); 6704 mutex_exit(HUBD_MUTEX(hubd)); 6705 6706 /* bring the device to full power */ 6707 (void) pm_raise_power(dip, 0, 6708 USB_DEV_OS_FULL_PWR); 6709 } 6710 } 6711 6712 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 6713 "hubd_create_pm_components: END"); 6714 } 6715 6716 6717 /* 6718 * Attachment point management 6719 */ 6720 /* ARGSUSED */ 6721 int 6722 usba_hubdi_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, 6723 cred_t *credp) 6724 { 6725 hubd_t *hubd; 6726 6727 if (otyp != OTYP_CHR) 6728 return (EINVAL); 6729 6730 hubd = hubd_get_soft_state(dip); 6731 if (hubd == NULL) { 6732 return (ENXIO); 6733 } 6734 6735 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 6736 "hubd_open:"); 6737 6738 mutex_enter(HUBD_MUTEX(hubd)); 6739 if ((flags & FEXCL) && (hubd->h_softstate & HUBD_SS_ISOPEN)) { 6740 mutex_exit(HUBD_MUTEX(hubd)); 6741 6742 return (EBUSY); 6743 } 6744 6745 hubd->h_softstate |= HUBD_SS_ISOPEN; 6746 mutex_exit(HUBD_MUTEX(hubd)); 6747 6748 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "opened"); 6749 6750 return (0); 6751 } 6752 6753 6754 /* ARGSUSED */ 6755 int 6756 usba_hubdi_close(dev_info_t *dip, dev_t dev, int flag, int otyp, 6757 cred_t *credp) 6758 { 6759 hubd_t *hubd; 6760 6761 if (otyp != OTYP_CHR) { 6762 return (EINVAL); 6763 } 6764 6765 hubd = hubd_get_soft_state(dip); 6766 6767 if (hubd == NULL) { 6768 return (ENXIO); 6769 } 6770 6771 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "hubd_close:"); 6772 6773 mutex_enter(HUBD_MUTEX(hubd)); 6774 hubd->h_softstate &= ~HUBD_SS_ISOPEN; 6775 mutex_exit(HUBD_MUTEX(hubd)); 6776 6777 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "closed"); 6778 6779 return (0); 6780 } 6781 6782 6783 /* 6784 * hubd_ioctl: cfgadm controls 6785 */ 6786 /* ARGSUSED */ 6787 int 6788 usba_hubdi_ioctl(dev_info_t *self, dev_t dev, int cmd, intptr_t arg, 6789 int mode, cred_t *credp, int *rvalp) 6790 { 6791 int rv = 0; 6792 char *msg; /* for messages */ 6793 hubd_t *hubd; 6794 usb_port_t port = 0; 6795 dev_info_t *child_dip = NULL; 6796 dev_info_t *rh_dip; 6797 devctl_ap_state_t ap_state; 6798 struct devctl_iocdata *dcp = NULL; 6799 usb_pipe_state_t prev_pipe_state = 0; 6800 int circ, rh_circ, prh_circ; 6801 6802 if ((hubd = hubd_get_soft_state(self)) == NULL) { 6803 6804 return (ENXIO); 6805 } 6806 6807 rh_dip = hubd->h_usba_device->usb_root_hub_dip; 6808 6809 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 6810 "usba_hubdi_ioctl: " 6811 "cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx", 6812 cmd, arg, mode, credp, rvalp, dev); 6813 6814 /* read devctl ioctl data */ 6815 if ((cmd != DEVCTL_AP_CONTROL) && 6816 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 6817 6818 return (EFAULT); 6819 } 6820 6821 /* 6822 * make sure the hub is connected before trying any 6823 * of the following operations: 6824 * configure, connect, disconnect 6825 */ 6826 mutex_enter(HUBD_MUTEX(hubd)); 6827 6828 switch (cmd) { 6829 case DEVCTL_AP_DISCONNECT: 6830 case DEVCTL_AP_UNCONFIGURE: 6831 case DEVCTL_AP_CONFIGURE: 6832 if (hubd->h_dev_state == USB_DEV_DISCONNECTED) { 6833 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 6834 "hubd: already gone"); 6835 mutex_exit(HUBD_MUTEX(hubd)); 6836 if (dcp) { 6837 ndi_dc_freehdl(dcp); 6838 } 6839 6840 return (EIO); 6841 } 6842 6843 /* FALLTHROUGH */ 6844 case DEVCTL_AP_GETSTATE: 6845 if ((port = hubd_get_port_num(hubd, dcp)) == 0) { 6846 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 6847 "hubd: bad port"); 6848 mutex_exit(HUBD_MUTEX(hubd)); 6849 if (dcp) { 6850 ndi_dc_freehdl(dcp); 6851 } 6852 6853 return (EINVAL); 6854 } 6855 break; 6856 6857 case DEVCTL_AP_CONTROL: 6858 6859 break; 6860 default: 6861 mutex_exit(HUBD_MUTEX(hubd)); 6862 if (dcp) { 6863 ndi_dc_freehdl(dcp); 6864 } 6865 6866 return (ENOTTY); 6867 } 6868 6869 /* should not happen, just in case */ 6870 if (hubd->h_dev_state == USB_DEV_SUSPENDED) { 6871 mutex_exit(HUBD_MUTEX(hubd)); 6872 if (dcp) { 6873 ndi_dc_freehdl(dcp); 6874 } 6875 6876 return (EIO); 6877 } 6878 6879 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6880 mutex_exit(HUBD_MUTEX(hubd)); 6881 6882 /* go full power */ 6883 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 6884 6885 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 6886 ndi_devi_enter(rh_dip, &rh_circ); 6887 ndi_devi_enter(hubd->h_dip, &circ); 6888 6889 mutex_enter(HUBD_MUTEX(hubd)); 6890 6891 /* stop polling iff it was active */ 6892 if (hubd->h_ep1_ph) { 6893 mutex_exit(HUBD_MUTEX(hubd)); 6894 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 6895 USB_FLAGS_SLEEP); 6896 mutex_enter(HUBD_MUTEX(hubd)); 6897 6898 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 6899 hubd_stop_polling(hubd); 6900 } 6901 } 6902 6903 hubd->h_hotplug_thread++; 6904 6905 switch (cmd) { 6906 case DEVCTL_AP_DISCONNECT: 6907 if (hubd_delete_child(hubd, port, 6908 NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS) { 6909 rv = EIO; 6910 } 6911 6912 break; 6913 case DEVCTL_AP_UNCONFIGURE: 6914 if (hubd_delete_child(hubd, port, 6915 NDI_UNCONFIG, B_FALSE) != USB_SUCCESS) { 6916 rv = EIO; 6917 } 6918 6919 break; 6920 case DEVCTL_AP_CONFIGURE: 6921 /* toggle port */ 6922 if (hubd_toggle_port(hubd, port) != USB_SUCCESS) { 6923 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6924 rv = EIO; 6925 6926 break; 6927 } 6928 6929 (void) hubd_handle_port_connect(hubd, port); 6930 child_dip = hubd_get_child_dip(hubd, port); 6931 mutex_exit(HUBD_MUTEX(hubd)); 6932 6933 ndi_devi_exit(hubd->h_dip, circ); 6934 ndi_devi_exit(rh_dip, rh_circ); 6935 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 6936 if ((child_dip == NULL) || 6937 (ndi_devi_online(child_dip, 0) != NDI_SUCCESS)) { 6938 rv = EIO; 6939 } 6940 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 6941 ndi_devi_enter(rh_dip, &rh_circ); 6942 ndi_devi_enter(hubd->h_dip, &circ); 6943 6944 mutex_enter(HUBD_MUTEX(hubd)); 6945 6946 break; 6947 case DEVCTL_AP_GETSTATE: 6948 switch (hubd_cfgadm_state(hubd, port)) { 6949 case HUBD_CFGADM_DISCONNECTED: 6950 /* port previously 'disconnected' by cfgadm */ 6951 ap_state.ap_rstate = AP_RSTATE_DISCONNECTED; 6952 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 6953 ap_state.ap_condition = AP_COND_OK; 6954 6955 break; 6956 case HUBD_CFGADM_UNCONFIGURED: 6957 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 6958 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 6959 ap_state.ap_condition = AP_COND_OK; 6960 6961 break; 6962 case HUBD_CFGADM_CONFIGURED: 6963 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 6964 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 6965 ap_state.ap_condition = AP_COND_OK; 6966 6967 break; 6968 case HUBD_CFGADM_STILL_REFERENCED: 6969 ap_state.ap_rstate = AP_RSTATE_EMPTY; 6970 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 6971 ap_state.ap_condition = AP_COND_UNUSABLE; 6972 6973 break; 6974 case HUBD_CFGADM_EMPTY: 6975 default: 6976 ap_state.ap_rstate = AP_RSTATE_EMPTY; 6977 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 6978 ap_state.ap_condition = AP_COND_OK; 6979 6980 break; 6981 } 6982 6983 ap_state.ap_last_change = (time_t)-1; 6984 ap_state.ap_error_code = 0; 6985 ap_state.ap_in_transition = 0; 6986 6987 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 6988 "DEVCTL_AP_GETSTATE: " 6989 "ostate=0x%x, rstate=0x%x, condition=0x%x", 6990 ap_state.ap_ostate, 6991 ap_state.ap_rstate, ap_state.ap_condition); 6992 6993 /* copy the return-AP-state information to the user space */ 6994 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 6995 rv = EFAULT; 6996 } 6997 6998 break; 6999 case DEVCTL_AP_CONTROL: 7000 { 7001 /* 7002 * Generic devctl for hardware-specific functionality. 7003 * For list of sub-commands see hubd_impl.h 7004 */ 7005 hubd_ioctl_data_t ioc; /* for 64 byte copies */ 7006 7007 /* copy user ioctl data in first */ 7008 #ifdef _MULTI_DATAMODEL 7009 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 7010 hubd_ioctl_data_32_t ioc32; 7011 7012 if (ddi_copyin((void *)arg, (void *)&ioc32, 7013 sizeof (ioc32), mode) != 0) { 7014 rv = EFAULT; 7015 7016 break; 7017 } 7018 ioc.cmd = (uint_t)ioc32.cmd; 7019 ioc.port = (uint_t)ioc32.port; 7020 ioc.get_size = (uint_t)ioc32.get_size; 7021 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 7022 ioc.bufsiz = (uint_t)ioc32.bufsiz; 7023 ioc.misc_arg = (uint_t)ioc32.misc_arg; 7024 } else 7025 #endif /* _MULTI_DATAMODEL */ 7026 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc), 7027 mode) != 0) { 7028 rv = EFAULT; 7029 7030 break; 7031 } 7032 7033 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7034 "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d" 7035 "\n\tbuf=0x%p, bufsiz=%d, misc_arg=%d", ioc.cmd, 7036 ioc.port, ioc.get_size, ioc.buf, ioc.bufsiz, ioc.misc_arg); 7037 7038 /* 7039 * To avoid BE/LE and 32/64 issues, a get_size always 7040 * returns a 32-bit number. 7041 */ 7042 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) { 7043 rv = EINVAL; 7044 7045 break; 7046 } 7047 7048 switch (ioc.cmd) { 7049 case USB_DESCR_TYPE_DEV: 7050 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC"; 7051 if (ioc.get_size) { 7052 /* uint32 so this works 32/64 */ 7053 uint32_t size = sizeof (usb_dev_descr_t); 7054 7055 if (ddi_copyout((void *)&size, ioc.buf, 7056 ioc.bufsiz, mode) != 0) { 7057 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7058 hubd->h_log_handle, 7059 "%s: get_size copyout failed", msg); 7060 rv = EIO; 7061 7062 break; 7063 } 7064 } else { /* send out the actual descr */ 7065 usb_dev_descr_t *dev_descrp; 7066 7067 /* check child_dip */ 7068 if ((child_dip = hubd_get_child_dip(hubd, 7069 ioc.port)) == NULL) { 7070 rv = EINVAL; 7071 7072 break; 7073 } 7074 7075 dev_descrp = usb_get_dev_descr(child_dip); 7076 if (ioc.bufsiz != sizeof (*dev_descrp)) { 7077 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7078 hubd->h_log_handle, 7079 "%s: bufsize passed (%d) != sizeof " 7080 "usba_device_descr_t (%d)", msg, 7081 ioc.bufsiz, dev_descrp->bLength); 7082 rv = EINVAL; 7083 7084 break; 7085 } 7086 7087 if (ddi_copyout((void *)dev_descrp, 7088 ioc.buf, ioc.bufsiz, mode) != 0) { 7089 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7090 hubd->h_log_handle, 7091 "%s: copyout failed.", msg); 7092 rv = EIO; 7093 7094 break; 7095 } 7096 } 7097 break; 7098 case USB_DESCR_TYPE_STRING: 7099 { 7100 char *str; 7101 uint32_t size; 7102 usba_device_t *usba_device; 7103 7104 msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR"; 7105 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7106 "%s: string request: %d", msg, ioc.misc_arg); 7107 7108 /* recheck */ 7109 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7110 NULL) { 7111 rv = EINVAL; 7112 7113 break; 7114 } 7115 usba_device = usba_get_usba_device(child_dip); 7116 7117 switch (ioc.misc_arg) { 7118 case HUBD_MFG_STR: 7119 str = usba_device->usb_mfg_str; 7120 7121 break; 7122 case HUBD_PRODUCT_STR: 7123 str = usba_device->usb_product_str; 7124 7125 break; 7126 case HUBD_SERIALNO_STR: 7127 str = usba_device->usb_serialno_str; 7128 7129 break; 7130 case HUBD_CFG_DESCR_STR: 7131 mutex_enter(&usba_device->usb_mutex); 7132 str = usba_device->usb_cfg_str_descr[ 7133 usba_device->usb_active_cfg_ndx]; 7134 mutex_exit(&usba_device->usb_mutex); 7135 7136 break; 7137 default: 7138 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7139 hubd->h_log_handle, 7140 "%s: Invalid string request", msg); 7141 rv = EINVAL; 7142 7143 break; 7144 } /* end of switch */ 7145 7146 if (rv != 0) { 7147 7148 break; 7149 } 7150 7151 size = (str != NULL) ? strlen(str) + 1 : 0; 7152 if (ioc.get_size) { 7153 if (ddi_copyout((void *)&size, ioc.buf, 7154 ioc.bufsiz, mode) != 0) { 7155 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7156 hubd->h_log_handle, 7157 "%s: copyout of size failed.", msg); 7158 rv = EIO; 7159 7160 break; 7161 } 7162 } else { 7163 if (size == 0) { 7164 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, 7165 hubd->h_log_handle, 7166 "%s: String is NULL", msg); 7167 rv = EINVAL; 7168 7169 break; 7170 } 7171 7172 if (ioc.bufsiz != size) { 7173 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7174 hubd->h_log_handle, 7175 "%s: string buf size wrong", msg); 7176 rv = EINVAL; 7177 7178 break; 7179 } 7180 7181 if (ddi_copyout((void *)str, ioc.buf, 7182 ioc.bufsiz, mode) != 0) { 7183 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7184 hubd->h_log_handle, 7185 "%s: copyout failed.", msg); 7186 rv = EIO; 7187 7188 break; 7189 } 7190 } 7191 break; 7192 } 7193 case HUBD_GET_CFGADM_NAME: 7194 { 7195 uint32_t name_len; 7196 const char *name; 7197 7198 /* recheck */ 7199 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7200 NULL) { 7201 rv = EINVAL; 7202 7203 break; 7204 } 7205 name = ddi_node_name(child_dip); 7206 if (name == NULL) { 7207 name = "unsupported"; 7208 } 7209 name_len = strlen(name) + 1; 7210 7211 msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME"; 7212 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7213 "%s: name=%s name_len=%d", msg, name, name_len); 7214 7215 if (ioc.get_size) { 7216 if (ddi_copyout((void *)&name_len, 7217 ioc.buf, ioc.bufsiz, mode) != 0) { 7218 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7219 hubd->h_log_handle, 7220 "%s: copyout of size failed", msg); 7221 rv = EIO; 7222 7223 break; 7224 } 7225 } else { 7226 if (ioc.bufsiz != name_len) { 7227 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7228 hubd->h_log_handle, 7229 "%s: string buf length wrong", msg); 7230 rv = EINVAL; 7231 7232 break; 7233 } 7234 7235 if (ddi_copyout((void *)name, ioc.buf, 7236 ioc.bufsiz, mode) != 0) { 7237 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7238 hubd->h_log_handle, 7239 "%s: copyout failed.", msg); 7240 rv = EIO; 7241 7242 break; 7243 } 7244 } 7245 7246 break; 7247 } 7248 7249 /* 7250 * Return the config index for the currently-configured 7251 * configuration. 7252 */ 7253 case HUBD_GET_CURRENT_CONFIG: 7254 { 7255 uint_t config_index; 7256 uint32_t size = sizeof (config_index); 7257 usba_device_t *usba_device; 7258 7259 msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG"; 7260 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7261 "%s", msg); 7262 7263 /* 7264 * Return the config index for the configuration 7265 * currently in use. 7266 * Recheck if child_dip exists 7267 */ 7268 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7269 NULL) { 7270 rv = EINVAL; 7271 7272 break; 7273 } 7274 7275 usba_device = usba_get_usba_device(child_dip); 7276 mutex_enter(&usba_device->usb_mutex); 7277 config_index = usba_device->usb_active_cfg_ndx; 7278 mutex_exit(&usba_device->usb_mutex); 7279 7280 if (ioc.get_size) { 7281 if (ddi_copyout((void *)&size, 7282 ioc.buf, ioc.bufsiz, mode) != 0) { 7283 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7284 hubd->h_log_handle, 7285 "%s: copyout of size failed.", msg); 7286 rv = EIO; 7287 7288 break; 7289 } 7290 } else { 7291 if (ioc.bufsiz != size) { 7292 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7293 hubd->h_log_handle, 7294 "%s: buffer size wrong", msg); 7295 rv = EINVAL; 7296 7297 break; 7298 } 7299 if (ddi_copyout((void *)&config_index, 7300 ioc.buf, ioc.bufsiz, mode) != 0) { 7301 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7302 hubd->h_log_handle, 7303 "%s: copyout failed", msg); 7304 rv = EIO; 7305 } 7306 } 7307 7308 break; 7309 } 7310 case HUBD_GET_DEVICE_PATH: 7311 { 7312 char *path; 7313 uint32_t size; 7314 7315 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH"; 7316 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7317 "%s", msg); 7318 7319 /* Recheck if child_dip exists */ 7320 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7321 NULL) { 7322 rv = EINVAL; 7323 7324 break; 7325 } 7326 7327 /* ddi_pathname doesn't supply /devices, so we do. */ 7328 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7329 (void) strcpy(path, "/devices"); 7330 (void) ddi_pathname(child_dip, path + strlen(path)); 7331 size = strlen(path) + 1; 7332 7333 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7334 "%s: device path=%s size=%d", msg, path, size); 7335 7336 if (ioc.get_size) { 7337 if (ddi_copyout((void *)&size, 7338 ioc.buf, ioc.bufsiz, mode) != 0) { 7339 7340 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7341 hubd->h_log_handle, 7342 "%s: copyout of size failed.", msg); 7343 rv = EIO; 7344 } 7345 } else { 7346 if (ioc.bufsiz != size) { 7347 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7348 hubd->h_log_handle, 7349 "%s: buffer wrong size.", msg); 7350 rv = EINVAL; 7351 } else if (ddi_copyout((void *)path, 7352 ioc.buf, ioc.bufsiz, mode) != 0) { 7353 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7354 hubd->h_log_handle, 7355 "%s: copyout failed.", msg); 7356 rv = EIO; 7357 } 7358 } 7359 kmem_free(path, MAXPATHLEN); 7360 7361 break; 7362 } 7363 case HUBD_REFRESH_DEVDB: 7364 msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB"; 7365 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7366 "%s", msg); 7367 7368 if ((rv = usba_devdb_refresh()) != USB_SUCCESS) { 7369 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7370 hubd->h_log_handle, 7371 "%s: Failed: %d", msg, rv); 7372 rv = EIO; 7373 } 7374 7375 break; 7376 default: 7377 rv = ENOTSUP; 7378 } /* end switch */ 7379 7380 break; 7381 } 7382 7383 default: 7384 rv = ENOTTY; 7385 } 7386 7387 if (dcp) { 7388 ndi_dc_freehdl(dcp); 7389 } 7390 7391 /* allow hotplug thread now */ 7392 hubd->h_hotplug_thread--; 7393 7394 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 7395 hubd->h_ep1_ph && (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 7396 hubd_start_polling(hubd, 0); 7397 } 7398 mutex_exit(HUBD_MUTEX(hubd)); 7399 7400 ndi_devi_exit(hubd->h_dip, circ); 7401 ndi_devi_exit(rh_dip, rh_circ); 7402 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 7403 7404 mutex_enter(HUBD_MUTEX(hubd)); 7405 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7406 mutex_exit(HUBD_MUTEX(hubd)); 7407 7408 return (rv); 7409 } 7410 7411 7412 /* 7413 * Helper func used only to help construct the names for the attachment point 7414 * minor nodes. Used only in usba_hubdi_attach. 7415 * Returns whether it found ancestry or not (USB_SUCCESS if yes). 7416 * ports between the root hub and the device represented by dip. 7417 * E.g., "2.4.3.1" means this device is 7418 * plugged into port 1 of a hub that is 7419 * plugged into port 3 of a hub that is 7420 * plugged into port 4 of a hub that is 7421 * plugged into port 2 of the root hub. 7422 * NOTE: Max ap_id path len is HUBD_APID_NAMELEN (32 chars), which is 7423 * more than sufficient (as hubs are a max 6 levels deep, port needs 3 7424 * chars plus NULL each) 7425 */ 7426 static void 7427 hubd_get_ancestry_str(hubd_t *hubd) 7428 { 7429 char dev_path[MAXPATHLEN]; 7430 char *port_num_pos; 7431 char port_list[HUBD_APID_NAMELEN]; 7432 char *port_list_end = port_list; 7433 7434 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 7435 "hubd_get_ancestry_str: hubd=0x%p", hubd); 7436 7437 dev_path[0] = '\0'; 7438 (void) ddi_pathname(hubd->h_dip, dev_path); 7439 port_num_pos = dev_path; 7440 7441 port_list[0] = NULL; 7442 while ((port_num_pos = (char *)strstr(port_num_pos, "hub@")) != NULL) { 7443 /* 7444 * Found a non-root hub between the root hub port and device. 7445 * Get the number of the port this hub is plugged into, 7446 * and append it to the ancestry string. 7447 */ 7448 if (port_list_end != port_list) { /* have list already */ 7449 (void) strcat(port_list_end, "."); 7450 port_list_end++; 7451 } 7452 7453 while (!isdigit(*port_num_pos)) { 7454 if (*port_num_pos++ == '\0') { 7455 7456 break; 7457 } 7458 } 7459 7460 while (isdigit(*port_num_pos)) { 7461 *port_list_end++ = *port_num_pos++; 7462 ASSERT(port_list_end < 7463 (port_list + sizeof (port_list))); 7464 ASSERT(port_num_pos < (dev_path + sizeof (dev_path))); 7465 } 7466 *port_list_end = '\0'; 7467 } 7468 7469 if (port_list_end != port_list) { 7470 (void) strcpy(hubd->h_ancestry_str, port_list); 7471 (void) strcat(hubd->h_ancestry_str, "."); 7472 } 7473 } 7474 7475 7476 /* Get which port to operate on. */ 7477 static usb_port_t 7478 hubd_get_port_num(hubd_t *hubd, struct devctl_iocdata *dcp) 7479 { 7480 int32_t port; 7481 7482 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 7483 7484 /* Get which port to operate on. */ 7485 if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) { 7486 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7487 "hubd_get_port_num: port lookup failed"); 7488 port = 0; 7489 } 7490 7491 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7492 "hubd_get_port_num: hubd=0x%p, port=%d", hubd, port); 7493 7494 return ((usb_port_t)port); 7495 } 7496 7497 7498 /* check if child still exists */ 7499 static dev_info_t * 7500 hubd_get_child_dip(hubd_t *hubd, usb_port_t port) 7501 { 7502 dev_info_t *child_dip = hubd->h_children_dips[port]; 7503 7504 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7505 "hubd_get_child_dip: hubd=0x%p, port=%d", hubd, port); 7506 7507 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 7508 7509 return (child_dip); 7510 } 7511 7512 7513 /* 7514 * hubd_cfgadm_state: 7515 * 7516 * child_dip list port_state cfgadm_state 7517 * -------------- ---------- ------------ 7518 * != NULL connected configured or 7519 * unconfigured 7520 * != NULL not connected disconnect but 7521 * busy/still referenced 7522 * NULL connected logically disconnected 7523 * NULL not connected empty 7524 */ 7525 static uint_t 7526 hubd_cfgadm_state(hubd_t *hubd, usb_port_t port) 7527 { 7528 uint_t state; 7529 dev_info_t *child_dip = hubd_get_child_dip(hubd, port); 7530 7531 if (child_dip) { 7532 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 7533 /* 7534 * connected, now check if driver exists 7535 */ 7536 if (DEVI_IS_DEVICE_OFFLINE(child_dip) || 7537 (i_ddi_node_state(child_dip) < DS_ATTACHED)) { 7538 state = HUBD_CFGADM_UNCONFIGURED; 7539 } else { 7540 state = HUBD_CFGADM_CONFIGURED; 7541 } 7542 } else { 7543 /* 7544 * this means that the dip is around for 7545 * a device that is still referenced but 7546 * has been yanked out. So the cfgadm info 7547 * for this state should be EMPTY (port empty) 7548 * and CONFIGURED (dip still valid). 7549 */ 7550 state = HUBD_CFGADM_STILL_REFERENCED; 7551 } 7552 } else { 7553 /* connected but no child dip */ 7554 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 7555 /* logically disconnected */ 7556 state = HUBD_CFGADM_DISCONNECTED; 7557 } else { 7558 /* physically disconnected */ 7559 state = HUBD_CFGADM_EMPTY; 7560 } 7561 } 7562 7563 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7564 "hubd_cfgadm_state: hubd=0x%p, port=%d state=0x%x", 7565 hubd, port, state); 7566 7567 return (state); 7568 } 7569 7570 7571 /* 7572 * hubd_toggle_port: 7573 */ 7574 static int 7575 hubd_toggle_port(hubd_t *hubd, usb_port_t port) 7576 { 7577 usb_hub_descr_t *hub_descr; 7578 int wait; 7579 uint_t retry; 7580 uint16_t status; 7581 uint16_t change; 7582 7583 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7584 "hubd_toggle_port: hubd=0x%p, port=%d", hubd, port); 7585 7586 if ((hubd_disable_port_power(hubd, port)) != USB_SUCCESS) { 7587 7588 return (USB_FAILURE); 7589 } 7590 7591 /* 7592 * see hubd_enable_all_port_power() which 7593 * requires longer delay for hubs. 7594 */ 7595 mutex_exit(HUBD_MUTEX(hubd)); 7596 delay(drv_usectohz(hubd_device_delay / 10)); 7597 mutex_enter(HUBD_MUTEX(hubd)); 7598 7599 hub_descr = &hubd->h_hub_descr; 7600 7601 /* 7602 * According to section 11.11 of USB, for hubs with no power 7603 * switches, bPwrOn2PwrGood is zero. But we wait for some 7604 * arbitrary time to enable power to become stable. 7605 * 7606 * If an hub supports port power swicthing, we need to wait 7607 * at least 20ms before accesing corresonding usb port. 7608 */ 7609 if ((hub_descr->wHubCharacteristics & 7610 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 7611 wait = hubd_device_delay / 10; 7612 } else { 7613 wait = max(HUB_DEFAULT_POPG, 7614 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 7615 } 7616 7617 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 7618 "hubd_toggle_port: popg=%d wait=%d", 7619 hub_descr->bPwrOn2PwrGood, wait); 7620 7621 retry = 0; 7622 7623 do { 7624 (void) hubd_enable_port_power(hubd, port); 7625 7626 mutex_exit(HUBD_MUTEX(hubd)); 7627 delay(drv_usectohz(wait)); 7628 mutex_enter(HUBD_MUTEX(hubd)); 7629 7630 /* Get port status */ 7631 (void) hubd_determine_port_status(hubd, port, 7632 &status, &change, 0); 7633 7634 /* For retry if any, use some extra delay */ 7635 wait = max(wait, hubd_device_delay / 10); 7636 7637 retry++; 7638 7639 } while ((!(status & PORT_STATUS_PPS)) && (retry < HUBD_PORT_RETRY)); 7640 7641 /* Print warning message if port has no power */ 7642 if (!(status & PORT_STATUS_PPS)) { 7643 7644 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 7645 "hubd_toggle_port: port %d power-on failed, " 7646 "port status 0x%x", port, status); 7647 7648 return (USB_FAILURE); 7649 } 7650 7651 return (USB_SUCCESS); 7652 } 7653