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