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 boolean_t online_child = B_FALSE; 3468 boolean_t offline_child = B_FALSE; 3469 boolean_t pwrup_child = B_FALSE; 3470 int prh_circ, rh_circ, circ, old_state; 3471 3472 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3473 "hubd_hotplug_thread: started"); 3474 3475 kmem_free(arg, sizeof (hubd_hotplug_arg_t)); 3476 3477 /* 3478 * if our bus power entry point is active, process the change 3479 * on the next notification of interrupt pipe 3480 */ 3481 mutex_enter(HUBD_MUTEX(hubd)); 3482 if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) { 3483 hubd->h_hotplug_thread--; 3484 3485 /* mark this device as idle */ 3486 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3487 mutex_exit(HUBD_MUTEX(hubd)); 3488 3489 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3490 "hubd_hotplug_thread: " 3491 "bus_power in progress/hotplugging undesirable - quit"); 3492 3493 return; 3494 } 3495 mutex_exit(HUBD_MUTEX(hubd)); 3496 3497 ndi_hold_devi(hdip); /* so we don't race with detach */ 3498 3499 mutex_enter(HUBD_MUTEX(hubd)); 3500 3501 /* is this the root hub? */ 3502 if (hdip == rh_dip) { 3503 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) { 3504 hubpm = hubd->h_hubpm; 3505 3506 /* mark the root hub as full power */ 3507 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 3508 hubpm->hubp_time_at_full_power = ddi_get_time(); 3509 mutex_exit(HUBD_MUTEX(hubd)); 3510 3511 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3512 "hubd_hotplug_thread: call pm_power_has_changed"); 3513 3514 (void) pm_power_has_changed(hdip, 0, 3515 USB_DEV_OS_FULL_PWR); 3516 3517 mutex_enter(HUBD_MUTEX(hubd)); 3518 hubd->h_dev_state = USB_DEV_ONLINE; 3519 } 3520 3521 } else { 3522 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3523 "hubd_hotplug_thread: not root hub"); 3524 } 3525 3526 ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE); 3527 3528 nports = hubd->h_hub_descr.bNbrPorts; 3529 3530 hubd_stop_polling(hubd); 3531 mutex_exit(HUBD_MUTEX(hubd)); 3532 3533 /* 3534 * this ensures one hotplug activity per system at a time. 3535 * we enter the parent PCI node to have this serialization. 3536 * this also excludes ioctls and deathrow thread 3537 * (a bit crude but easier to debug) 3538 */ 3539 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 3540 ndi_devi_enter(rh_dip, &rh_circ); 3541 3542 /* exclude other threads */ 3543 ndi_devi_enter(hdip, &circ); 3544 mutex_enter(HUBD_MUTEX(hubd)); 3545 3546 while ((hubd->h_dev_state == USB_DEV_ONLINE) && 3547 (hubd->h_port_change)) { 3548 /* 3549 * The 0th bit is the hub status change bit. 3550 * handle loss of local power here 3551 */ 3552 if (hubd->h_port_change & HUB_CHANGE_STATUS) { 3553 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3554 "hubd_hotplug_thread: hub status change!"); 3555 3556 /* 3557 * This should be handled properly. For now, 3558 * mask off the bit. 3559 */ 3560 hubd->h_port_change &= ~HUB_CHANGE_STATUS; 3561 3562 /* 3563 * check and ack hub status 3564 * this causes stall conditions 3565 * when local power is removed 3566 */ 3567 (void) hubd_get_hub_status(hubd); 3568 } 3569 3570 for (port = 1; port <= nports; port++) { 3571 usb_port_mask_t port_mask; 3572 boolean_t was_connected; 3573 3574 port_mask = 1 << port; 3575 was_connected = 3576 (hubd->h_port_state[port] & PORT_STATUS_CCS) && 3577 (hubd->h_children_dips[port]); 3578 3579 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3580 "hubd_hotplug_thread: " 3581 "port %d mask=0x%x change=0x%x connected=0x%x", 3582 port, port_mask, hubd->h_port_change, 3583 was_connected); 3584 3585 /* 3586 * is this a port connection that changed? 3587 */ 3588 if ((hubd->h_port_change & port_mask) == 0) { 3589 3590 continue; 3591 } 3592 hubd->h_port_change &= ~port_mask; 3593 3594 /* ack all changes */ 3595 (void) hubd_determine_port_status(hubd, port, 3596 &status, &change, HUBD_ACK_ALL_CHANGES); 3597 3598 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3599 "handle port %d:\n\t" 3600 "new status=0x%x change=0x%x was_conn=0x%x ", 3601 port, status, change, was_connected); 3602 3603 /* Recover a disabled port */ 3604 if (change & PORT_CHANGE_PESC) { 3605 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 3606 hubd->h_log_handle, 3607 "port%d Disabled - " 3608 "status=0x%x, change=0x%x", 3609 port, status, change); 3610 3611 /* 3612 * if the port was connected and is still 3613 * connected, recover the port 3614 */ 3615 if (was_connected && (status & 3616 PORT_STATUS_CCS)) { 3617 online_child |= 3618 (hubd_recover_disabled_port(hubd, 3619 port) == USB_SUCCESS); 3620 } 3621 } 3622 3623 /* 3624 * Now check what changed on the port 3625 */ 3626 if ((change & PORT_CHANGE_CSC) || attach_flg) { 3627 if ((status & PORT_STATUS_CCS) && 3628 (!was_connected)) { 3629 /* new device plugged in */ 3630 online_child |= 3631 (hubd_handle_port_connect(hubd, 3632 port) == USB_SUCCESS); 3633 3634 } else if ((status & PORT_STATUS_CCS) && 3635 was_connected) { 3636 /* 3637 * In this case we can never be sure 3638 * if the device indeed got hotplugged 3639 * or the hub is falsely reporting the 3640 * change. 3641 * first post a disconnect event 3642 * to the child 3643 */ 3644 mutex_exit(HUBD_MUTEX(hubd)); 3645 hubd_post_event(hubd, port, 3646 USBA_EVENT_TAG_HOT_REMOVAL); 3647 mutex_enter(HUBD_MUTEX(hubd)); 3648 3649 /* 3650 * then reset the port and recover 3651 * the device 3652 */ 3653 online_child |= 3654 (hubd_handle_port_connect(hubd, 3655 port) == USB_SUCCESS); 3656 } else if (was_connected) { 3657 /* this is a disconnect */ 3658 mutex_exit(HUBD_MUTEX(hubd)); 3659 hubd_post_event(hubd, port, 3660 USBA_EVENT_TAG_HOT_REMOVAL); 3661 mutex_enter(HUBD_MUTEX(hubd)); 3662 3663 offline_child = B_TRUE; 3664 } 3665 } 3666 3667 /* 3668 * Check if any port is coming out of suspend 3669 */ 3670 if (change & PORT_CHANGE_PSSC) { 3671 /* a resuming device could have disconnected */ 3672 if (was_connected && 3673 hubd->h_children_dips[port]) { 3674 3675 /* device on this port resuming */ 3676 dev_info_t *dip; 3677 3678 dip = hubd->h_children_dips[port]; 3679 3680 /* 3681 * Don't raise power on detaching child 3682 */ 3683 if (!DEVI_IS_DETACHING(dip)) { 3684 /* 3685 * As this child is not 3686 * detaching, we set this 3687 * flag, causing bus_ctls 3688 * to stall detach till 3689 * pm_raise_power returns 3690 * and flag it for a deferred 3691 * raise_power. 3692 * 3693 * pm_raise_power is deferred 3694 * because we need to release 3695 * the locks first. 3696 */ 3697 hubd->h_port_state[port] |= 3698 HUBD_CHILD_RAISE_POWER; 3699 pwrup_child = B_TRUE; 3700 mutex_exit(HUBD_MUTEX(hubd)); 3701 3702 /* 3703 * make sure that child 3704 * doesn't disappear 3705 */ 3706 ndi_hold_devi(dip); 3707 3708 mutex_enter(HUBD_MUTEX(hubd)); 3709 } 3710 } 3711 } 3712 3713 /* 3714 * Check if the port is over-current 3715 */ 3716 if (change & PORT_CHANGE_OCIC) { 3717 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 3718 hubd->h_log_handle, 3719 "Port%d in over current condition, " 3720 "please check the attached device to " 3721 "clear the condition. The system will " 3722 "try to recover the port, but if not " 3723 "successful, you need to re-connect " 3724 "the hub or reboot the system to bring " 3725 "the port back to work", port); 3726 3727 if (!(status & PORT_STATUS_PPS)) { 3728 /* 3729 * Try to enable port power, but 3730 * possibly fail. Ignore failure 3731 */ 3732 (void) hubd_enable_port_power(hubd, 3733 port); 3734 3735 /* 3736 * Delay some time to avoid 3737 * over-current event to happen 3738 * too frequently in some cases 3739 */ 3740 mutex_exit(HUBD_MUTEX(hubd)); 3741 delay(drv_usectohz(500000)); 3742 mutex_enter(HUBD_MUTEX(hubd)); 3743 } 3744 } 3745 } 3746 } 3747 3748 /* release locks so we can do a devfs_clean */ 3749 mutex_exit(HUBD_MUTEX(hubd)); 3750 3751 /* delete cached dv_node's but drop locks first */ 3752 ndi_devi_exit(hdip, circ); 3753 ndi_devi_exit(rh_dip, rh_circ); 3754 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 3755 3756 (void) devfs_clean(rh_dip, NULL, 0); 3757 3758 /* now check if any children need onlining */ 3759 if (online_child) { 3760 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3761 "hubd_hotplug_thread: onlining children"); 3762 3763 (void) ndi_devi_online(hubd->h_dip, 0); 3764 } 3765 3766 /* now check if any disconnected devices need to be cleaned up */ 3767 if (offline_child) { 3768 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3769 "hubd_hotplug_thread: scheduling cleanup"); 3770 3771 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 3772 } 3773 3774 mutex_enter(HUBD_MUTEX(hubd)); 3775 3776 /* now raise power on the children that have woken up */ 3777 if (pwrup_child) { 3778 old_state = hubd->h_dev_state; 3779 hubd->h_dev_state = USB_DEV_HUB_CHILD_PWRLVL; 3780 for (port = 1; port <= nports; port++) { 3781 if (hubd->h_port_state[port] & HUBD_CHILD_RAISE_POWER) { 3782 dev_info_t *dip = hubd->h_children_dips[port]; 3783 3784 mutex_exit(HUBD_MUTEX(hubd)); 3785 3786 /* Get the device to full power */ 3787 (void) pm_busy_component(dip, 0); 3788 (void) pm_raise_power(dip, 0, 3789 USB_DEV_OS_FULL_PWR); 3790 (void) pm_idle_component(dip, 0); 3791 3792 /* release the hold on the child */ 3793 ndi_rele_devi(dip); 3794 mutex_enter(HUBD_MUTEX(hubd)); 3795 hubd->h_port_state[port] &= 3796 ~HUBD_CHILD_RAISE_POWER; 3797 } 3798 } 3799 /* 3800 * make sure that we don't accidentally 3801 * over write the disconnect state 3802 */ 3803 if (hubd->h_dev_state == USB_DEV_HUB_CHILD_PWRLVL) { 3804 hubd->h_dev_state = old_state; 3805 } 3806 } 3807 3808 /* 3809 * start polling can immediately kick off read callback 3810 * we need to set the h_hotplug_thread to 0 so that 3811 * the callback is not dropped 3812 */ 3813 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 3814 3815 /* 3816 * Earlier we would set the h_hotplug_thread = 0 before 3817 * polling was restarted so that 3818 * if there is any root hub status change interrupt, we can still kick 3819 * off the hotplug thread. This was valid when this interrupt was 3820 * delivered in hardware, and only ONE interrupt would be delivered. 3821 * Now that we poll on the root hub looking for status change in 3822 * software, this assignment is no longer required. 3823 */ 3824 hubd->h_hotplug_thread--; 3825 3826 /* mark this device as idle */ 3827 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 3828 3829 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3830 "hubd_hotplug_thread: exit"); 3831 3832 mutex_exit(HUBD_MUTEX(hubd)); 3833 3834 ndi_rele_devi(hdip); 3835 } 3836 3837 3838 /* 3839 * hubd_handle_port_connect: 3840 * Transition a port from Disabled to Enabled. Ensure that the 3841 * port is in the correct state before attempting to 3842 * access the device. 3843 */ 3844 static int 3845 hubd_handle_port_connect(hubd_t *hubd, usb_port_t port) 3846 { 3847 int rval; 3848 int retry; 3849 long time_delay; 3850 long settling_time; 3851 uint16_t status; 3852 uint16_t change; 3853 usb_addr_t hubd_usb_addr; 3854 usba_device_t *usba_device; 3855 usb_port_status_t port_status = 0; 3856 usb_port_status_t hub_port_status = 0; 3857 3858 /* Get the hub address and port status */ 3859 usba_device = hubd->h_usba_device; 3860 mutex_enter(&usba_device->usb_mutex); 3861 hubd_usb_addr = usba_device->usb_addr; 3862 hub_port_status = usba_device->usb_port_status; 3863 mutex_exit(&usba_device->usb_mutex); 3864 3865 /* 3866 * If a device is connected, transition the 3867 * port from Disabled to the Enabled state. 3868 * The device will receive downstream packets 3869 * in the Enabled state. 3870 * 3871 * reset port and wait for the hub to report 3872 * completion 3873 */ 3874 change = status = 0; 3875 3876 /* 3877 * According to section 9.1.2 of USB 2.0 spec, the host should 3878 * wait for atleast 100ms to allow completion of an insertion 3879 * process and for power at the device to become stable. 3880 * We wait for 200 ms 3881 */ 3882 settling_time = drv_usectohz(hubd_device_delay / 5); 3883 mutex_exit(HUBD_MUTEX(hubd)); 3884 delay(settling_time); 3885 mutex_enter(HUBD_MUTEX(hubd)); 3886 3887 /* calculate 600 ms delay time */ 3888 time_delay = (6 * drv_usectohz(hubd_device_delay)) / 10; 3889 3890 for (retry = 0; (hubd->h_dev_state == USB_DEV_ONLINE) && 3891 (retry < hubd_retry_enumerate); retry++) { 3892 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3893 "resetting port%d, retry=%d", port, retry); 3894 3895 if ((rval = hubd_reset_port(hubd, port)) != USB_SUCCESS) { 3896 (void) hubd_determine_port_status(hubd, 3897 port, &status, &change, 0); 3898 3899 /* continue only if port is still connected */ 3900 if (status & PORT_STATUS_CCS) { 3901 continue; 3902 } 3903 3904 /* carry on regardless */ 3905 } 3906 3907 /* 3908 * according to USB 2.0 spec section 11.24.2.7.1.2 3909 * at the end of port reset, the hub enables the port. 3910 * But for some strange reasons, uhci port remains disabled. 3911 * And because the port remains disabled for the settling 3912 * time below, the device connected to the port gets wedged 3913 * - fails to enumerate (device not responding) 3914 * Hence, we enable it here immediately and later again after 3915 * the delay 3916 */ 3917 (void) hubd_enable_port(hubd, port); 3918 3919 /* we skip this delay in the first iteration */ 3920 if (retry) { 3921 /* 3922 * delay for device to signal disconnect/connect so 3923 * that hub properly recognizes the speed of the device 3924 */ 3925 mutex_exit(HUBD_MUTEX(hubd)); 3926 delay(settling_time); 3927 mutex_enter(HUBD_MUTEX(hubd)); 3928 3929 /* 3930 * When a low speed device is connected to any port of 3931 * PPX it has to be explicitly enabled 3932 * Also, if device intentionally signals 3933 * disconnect/connect, it will disable the port. 3934 * So enable it again. 3935 */ 3936 (void) hubd_enable_port(hubd, port); 3937 } 3938 3939 if ((rval = hubd_determine_port_status(hubd, port, &status, 3940 &change, 0)) != USB_SUCCESS) { 3941 3942 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3943 "getting status failed (%d)", rval); 3944 3945 (void) hubd_disable_port(hubd, port); 3946 3947 continue; 3948 } 3949 3950 if (status & PORT_STATUS_POCI) { 3951 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3952 "port %d overcurrent", port); 3953 3954 (void) hubd_disable_port(hubd, port); 3955 3956 /* ack changes */ 3957 (void) hubd_determine_port_status(hubd, 3958 port, &status, &change, PORT_CHANGE_OCIC); 3959 3960 continue; 3961 } 3962 3963 /* is status really OK? */ 3964 if ((status & PORT_STATUS_OK) != PORT_STATUS_OK) { 3965 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3966 "port %d status (0x%x) not OK on retry %d", 3967 port, status, retry); 3968 3969 /* check if we still have the connection */ 3970 if (!(status & PORT_STATUS_CCS)) { 3971 /* lost connection, set exit condition */ 3972 retry = hubd_retry_enumerate; 3973 3974 break; 3975 } 3976 } else { 3977 /* 3978 * Determine if the device is high or full 3979 * or low speed. 3980 */ 3981 if (status & PORT_STATUS_LSDA) { 3982 port_status = USBA_LOW_SPEED_DEV; 3983 } else if (status & PORT_STATUS_HSDA) { 3984 port_status = USBA_HIGH_SPEED_DEV; 3985 } else { 3986 port_status = USBA_FULL_SPEED_DEV; 3987 } 3988 3989 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 3990 "creating child port%d, status=0x%x " 3991 "port status=0x%x", 3992 port, status, port_status); 3993 3994 /* 3995 * if the child already exists, set addrs and config 3996 * to the device post connect event to the child 3997 */ 3998 if (hubd->h_children_dips[port]) { 3999 /* set addrs to this device */ 4000 rval = hubd_setdevaddr(hubd, port); 4001 4002 /* 4003 * This delay is important for the CATC hub 4004 * to enumerate. But, avoid delay in the first 4005 * iteration 4006 */ 4007 if (retry) { 4008 mutex_exit(HUBD_MUTEX(hubd)); 4009 delay(drv_usectohz( 4010 hubd_device_delay/100)); 4011 mutex_enter(HUBD_MUTEX(hubd)); 4012 } 4013 4014 if (rval == USB_SUCCESS) { 4015 /* 4016 * set the default config for 4017 * this device 4018 */ 4019 hubd_setdevconfig(hubd, port); 4020 4021 /* 4022 * indicate to the child that 4023 * it is online again 4024 */ 4025 mutex_exit(HUBD_MUTEX(hubd)); 4026 hubd_post_event(hubd, port, 4027 USBA_EVENT_TAG_HOT_INSERTION); 4028 mutex_enter(HUBD_MUTEX(hubd)); 4029 4030 return (USB_SUCCESS); 4031 } 4032 } else { 4033 /* 4034 * We need to release access here 4035 * so that busctls on other ports can 4036 * continue and don't cause a deadlock 4037 * when busctl and removal of prom node 4038 * takes concurrently. This also ensures 4039 * busctls for attach of successfully 4040 * enumerated devices on other ports can 4041 * continue concurrently with the process 4042 * of enumerating the new devices. This 4043 * reduces the overall boot time of the system. 4044 */ 4045 rval = hubd_create_child(hubd->h_dip, 4046 hubd, 4047 hubd->h_usba_device, 4048 port_status, port, 4049 retry); 4050 if (rval == USB_SUCCESS) { 4051 usba_update_hotplug_stats(hubd->h_dip, 4052 USBA_TOTAL_HOTPLUG_SUCCESS| 4053 USBA_HOTPLUG_SUCCESS); 4054 hubd->h_total_hotplug_success++; 4055 4056 if (retry > 0) { 4057 USB_DPRINTF_L2( 4058 DPRINT_MASK_HOTPLUG, 4059 hubd->h_log_handle, 4060 "device on port %d " 4061 "enumerated after %d %s", 4062 port, retry, 4063 (retry > 1) ? "retries" : 4064 "retry"); 4065 4066 } 4067 4068 return (USB_SUCCESS); 4069 } 4070 } 4071 } 4072 4073 /* wait a while until it settles? */ 4074 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4075 "disabling port %d again", port); 4076 4077 (void) hubd_disable_port(hubd, port); 4078 if (retry) { 4079 mutex_exit(HUBD_MUTEX(hubd)); 4080 delay(time_delay); 4081 mutex_enter(HUBD_MUTEX(hubd)); 4082 } 4083 4084 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4085 "retrying on port %d", port); 4086 } 4087 4088 if (retry >= hubd_retry_enumerate) { 4089 /* 4090 * If it is a High Speed Root Hub and connected device 4091 * Is a Low/Full Speed, it will be handled by USB 1.1 4092 * Host Controller. In this case, USB 2.0 Host Controller 4093 * will transfer the ownership of this port to USB 1.1 4094 * Host Controller. So don't display any error message on 4095 * the console. 4096 */ 4097 if ((hubd_usb_addr == ROOT_HUB_ADDR) && 4098 (hub_port_status == USBA_HIGH_SPEED_DEV) && 4099 (port_status != USBA_HIGH_SPEED_DEV)) { 4100 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4101 hubd->h_log_handle, 4102 "hubd_handle_port_connect: Low/Full speed " 4103 "device is connected to High Speed root hub"); 4104 } else { 4105 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4106 hubd->h_log_handle, 4107 "Connecting device on port %d failed", port); 4108 } 4109 4110 (void) hubd_disable_port(hubd, port); 4111 usba_update_hotplug_stats(hubd->h_dip, 4112 USBA_TOTAL_HOTPLUG_FAILURE|USBA_HOTPLUG_FAILURE); 4113 hubd->h_total_hotplug_failure++; 4114 4115 /* 4116 * the port should be automagically 4117 * disabled but just in case, we do 4118 * it here 4119 */ 4120 (void) hubd_disable_port(hubd, port); 4121 4122 /* ack all changes because we disabled this port */ 4123 (void) hubd_determine_port_status(hubd, 4124 port, &status, &change, HUBD_ACK_ALL_CHANGES); 4125 4126 } 4127 4128 return (USB_FAILURE); 4129 } 4130 4131 4132 /* 4133 * hubd_get_hub_status: 4134 */ 4135 static int 4136 hubd_get_hub_status(hubd_t *hubd) 4137 { 4138 int rval; 4139 usb_cr_t completion_reason; 4140 usb_cb_flags_t cb_flags; 4141 uint16_t stword[2]; 4142 uint16_t status; 4143 uint16_t change; 4144 usb_cfg_descr_t cfg_descr; 4145 size_t cfg_length; 4146 uchar_t *usb_cfg; 4147 uint8_t MaxPower; 4148 usb_hub_descr_t *hub_descr; 4149 usb_port_t port; 4150 4151 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4152 "hubd_get_hub_status:"); 4153 4154 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4155 4156 if ((hubd_get_hub_status_words(hubd, stword)) != USB_SUCCESS) { 4157 4158 return (USB_FAILURE); 4159 } 4160 status = stword[0]; 4161 change = stword[1]; 4162 4163 mutex_exit(HUBD_MUTEX(hubd)); 4164 4165 /* Obtain the raw configuration descriptor */ 4166 usb_cfg = usb_get_raw_cfg_data(hubd->h_dip, &cfg_length); 4167 4168 /* get configuration descriptor */ 4169 rval = usb_parse_cfg_descr(usb_cfg, cfg_length, 4170 &cfg_descr, USB_CFG_DESCR_SIZE); 4171 4172 if (rval != USB_CFG_DESCR_SIZE) { 4173 4174 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4175 "get hub configuration descriptor failed."); 4176 4177 mutex_enter(HUBD_MUTEX(hubd)); 4178 4179 return (USB_FAILURE); 4180 } else { 4181 MaxPower = cfg_descr.bMaxPower; 4182 } 4183 4184 /* check if local power status changed. */ 4185 if (change & C_HUB_LOCAL_POWER_STATUS) { 4186 4187 /* 4188 * local power has been lost, check the maximum 4189 * power consumption of current configuration. 4190 * see USB2.0 spec Table 11-12. 4191 */ 4192 if (status & HUB_LOCAL_POWER_STATUS) { 4193 4194 if (MaxPower == 0) { 4195 4196 /* 4197 * Self-powered only hub. Because it could 4198 * not draw any power from USB bus. 4199 * It can't work well on this condition. 4200 */ 4201 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 4202 hubd->h_log_handle, 4203 "local power has been lost, " 4204 "please disconnect hub"); 4205 } else { 4206 4207 /* 4208 * Bus-powered only or self/bus-powered hub. 4209 */ 4210 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, 4211 hubd->h_log_handle, 4212 "local power has been lost," 4213 "the hub could draw %d" 4214 " mA power from the USB bus.", 4215 2*MaxPower); 4216 } 4217 4218 } 4219 4220 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4221 "clearing feature C_HUB_LOCAL_POWER "); 4222 4223 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4224 hubd->h_default_pipe, 4225 HUB_HANDLE_HUB_FEATURE_TYPE, 4226 USB_REQ_CLEAR_FEATURE, 4227 CFS_C_HUB_LOCAL_POWER, 4228 0, 4229 0, 4230 NULL, 0, 4231 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4232 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4233 hubd->h_log_handle, 4234 "clear feature C_HUB_LOCAL_POWER " 4235 "failed (%d 0x%x %d)", 4236 rval, completion_reason, cb_flags); 4237 } 4238 4239 } 4240 4241 if (change & C_HUB_OVER_CURRENT) { 4242 4243 if (status & HUB_OVER_CURRENT) { 4244 4245 if (usba_is_root_hub(hubd->h_dip)) { 4246 /* 4247 * The root hub should be automatically 4248 * recovered when over-current condition is 4249 * cleared. But there might be exception and 4250 * need user interaction to recover. 4251 */ 4252 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4253 hubd->h_log_handle, 4254 "Root hub over current condition, " 4255 "please check your system to clear the " 4256 "condition as soon as possible. And you " 4257 "may need to reboot the system to bring " 4258 "the root hub back to work if it cannot " 4259 "recover automatically"); 4260 } else { 4261 /* 4262 * The driver would try to recover port power 4263 * on over current condition. When the recovery 4264 * fails, the user may still need to offline 4265 * this hub in order to recover. 4266 * The port power is automatically disabled, 4267 * so we won't see disconnects. 4268 */ 4269 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 4270 hubd->h_log_handle, 4271 "Hub global over current condition, " 4272 "please disconnect the devices connected " 4273 "to the hub to clear the condition. And " 4274 "you may need to re-connect the hub if " 4275 "the ports do not work"); 4276 } 4277 } 4278 4279 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4280 "clearing feature C_HUB_OVER_CURRENT"); 4281 4282 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4283 hubd->h_default_pipe, 4284 HUB_HANDLE_HUB_FEATURE_TYPE, 4285 USB_REQ_CLEAR_FEATURE, 4286 CFS_C_HUB_OVER_CURRENT, 4287 0, 4288 0, 4289 NULL, 0, 4290 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4291 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 4292 hubd->h_log_handle, 4293 "clear feature C_HUB_OVER_CURRENT " 4294 "failed (%d 0x%x %d)", 4295 rval, completion_reason, cb_flags); 4296 } 4297 4298 /* 4299 * Try to recover all port power if they are turned off. 4300 * Don't do this for root hub, but rely on the root hub 4301 * to recover itself. 4302 */ 4303 if (!usba_is_root_hub(hubd->h_dip)) { 4304 4305 mutex_enter(HUBD_MUTEX(hubd)); 4306 4307 /* 4308 * Only check the power status of the 1st port 4309 * since all port power status should be the same. 4310 */ 4311 (void) hubd_determine_port_status(hubd, 1, &status, 4312 &change, 0); 4313 4314 if (status & PORT_STATUS_PPS) { 4315 4316 return (USB_SUCCESS); 4317 } 4318 4319 hub_descr = &hubd->h_hub_descr; 4320 4321 for (port = 1; port <= hub_descr->bNbrPorts; 4322 port++) { 4323 4324 (void) hubd_enable_port_power(hubd, port); 4325 } 4326 4327 mutex_exit(HUBD_MUTEX(hubd)); 4328 4329 /* 4330 * Delay some time to avoid over-current event 4331 * to happen too frequently in some cases 4332 */ 4333 delay(drv_usectohz(500000)); 4334 } 4335 } 4336 4337 mutex_enter(HUBD_MUTEX(hubd)); 4338 4339 return (USB_SUCCESS); 4340 } 4341 4342 4343 /* 4344 * hubd_reset_port: 4345 */ 4346 static int 4347 hubd_reset_port(hubd_t *hubd, usb_port_t port) 4348 { 4349 int rval; 4350 usb_cr_t completion_reason; 4351 usb_cb_flags_t cb_flags; 4352 usb_port_mask_t port_mask = 1 << port; 4353 mblk_t *data; 4354 uint16_t status; 4355 uint16_t change; 4356 int i; 4357 clock_t current_time; 4358 4359 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4360 "hubd_reset_port: port=%d", port); 4361 4362 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4363 4364 hubd->h_port_reset_wait |= port_mask; 4365 4366 mutex_exit(HUBD_MUTEX(hubd)); 4367 4368 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4369 hubd->h_default_pipe, 4370 HUB_HANDLE_PORT_FEATURE_TYPE, 4371 USB_REQ_SET_FEATURE, 4372 CFS_PORT_RESET, 4373 port, 4374 0, 4375 NULL, 0, 4376 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4377 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4378 "reset port%d failed (%d 0x%x %d)", 4379 port, completion_reason, cb_flags, rval); 4380 4381 mutex_enter(HUBD_MUTEX(hubd)); 4382 4383 return (USB_FAILURE); 4384 } 4385 4386 mutex_enter(HUBD_MUTEX(hubd)); 4387 4388 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4389 "waiting on cv for reset completion"); 4390 4391 /* 4392 * wait for port status change event 4393 */ 4394 for (i = 0; i < hubd_retry_enumerate; i++) { 4395 /* 4396 * start polling ep1 for receiving notification on 4397 * reset completion 4398 */ 4399 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING); 4400 4401 /* 4402 * sleep a max of 100ms for reset completion 4403 * notification to be received 4404 */ 4405 current_time = ddi_get_lbolt(); 4406 if (hubd->h_port_reset_wait & port_mask) { 4407 rval = cv_timedwait(&hubd->h_cv_reset_port, 4408 &hubd->h_mutex, 4409 current_time + 4410 drv_usectohz(hubd_device_delay / 10)); 4411 if ((rval <= 0) && 4412 (hubd->h_port_reset_wait & port_mask)) { 4413 /* we got woken up because of a timeout */ 4414 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4415 hubd->h_log_handle, 4416 "timeout: reset port=%d failed", port); 4417 4418 hubd->h_port_reset_wait &= ~port_mask; 4419 4420 hubd_stop_polling(hubd); 4421 4422 return (USB_FAILURE); 4423 } 4424 } 4425 4426 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4427 "reset completion received"); 4428 4429 hubd_stop_polling(hubd); 4430 4431 data = NULL; 4432 4433 /* check status to determine whether reset completed */ 4434 mutex_exit(HUBD_MUTEX(hubd)); 4435 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4436 hubd->h_default_pipe, 4437 HUB_GET_PORT_STATUS_TYPE, 4438 USB_REQ_GET_STATUS, 4439 0, 4440 port, 4441 GET_STATUS_LENGTH, 4442 &data, 0, 4443 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4444 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4445 hubd->h_log_handle, 4446 "get status port%d failed (%d 0x%x %d)", 4447 port, completion_reason, cb_flags, rval); 4448 4449 if (data) { 4450 freemsg(data); 4451 data = NULL; 4452 } 4453 mutex_enter(HUBD_MUTEX(hubd)); 4454 4455 continue; 4456 } 4457 4458 status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4459 change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4460 4461 freemsg(data); 4462 4463 /* continue only if port is still connected */ 4464 if (!(status & PORT_STATUS_CCS)) { 4465 4466 /* lost connection, set exit condition */ 4467 i = hubd_retry_enumerate; 4468 4469 mutex_enter(HUBD_MUTEX(hubd)); 4470 4471 break; 4472 } 4473 4474 if (status & PORT_STATUS_PRS) { 4475 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4476 "port%d reset active", port); 4477 mutex_enter(HUBD_MUTEX(hubd)); 4478 4479 continue; 4480 } else { 4481 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4482 "port%d reset inactive", port); 4483 } 4484 4485 if (change & PORT_CHANGE_PRSC) { 4486 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4487 "clearing feature CFS_C_PORT_RESET"); 4488 4489 if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4490 hubd->h_default_pipe, 4491 HUB_HANDLE_PORT_FEATURE_TYPE, 4492 USB_REQ_CLEAR_FEATURE, 4493 CFS_C_PORT_RESET, 4494 port, 4495 0, 4496 NULL, 0, 4497 &completion_reason, &cb_flags, 0) != USB_SUCCESS) { 4498 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4499 hubd->h_log_handle, 4500 "clear feature CFS_C_PORT_RESET" 4501 " port%d failed (%d 0x%x %d)", 4502 port, completion_reason, cb_flags, rval); 4503 } 4504 } 4505 mutex_enter(HUBD_MUTEX(hubd)); 4506 4507 break; 4508 } 4509 4510 if (i >= hubd_retry_enumerate) { 4511 /* port reset has failed */ 4512 rval = USB_FAILURE; 4513 } 4514 4515 return (rval); 4516 } 4517 4518 4519 /* 4520 * hubd_enable_port: 4521 * this may fail if the hub as been disconnected 4522 */ 4523 static int 4524 hubd_enable_port(hubd_t *hubd, usb_port_t port) 4525 { 4526 int rval; 4527 usb_cr_t completion_reason; 4528 usb_cb_flags_t cb_flags; 4529 4530 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4531 "hubd_enable_port: port=%d", port); 4532 4533 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4534 4535 mutex_exit(HUBD_MUTEX(hubd)); 4536 4537 /* Do not issue a SetFeature(PORT_ENABLE) on external hubs */ 4538 if (!usba_is_root_hub(hubd->h_dip)) { 4539 mutex_enter(HUBD_MUTEX(hubd)); 4540 4541 return (USB_SUCCESS); 4542 } 4543 4544 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4545 hubd->h_default_pipe, 4546 HUB_HANDLE_PORT_FEATURE_TYPE, 4547 USB_REQ_SET_FEATURE, 4548 CFS_PORT_ENABLE, 4549 port, 4550 0, 4551 NULL, 0, 4552 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4553 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4554 "enable port%d failed (%d 0x%x %d)", 4555 port, completion_reason, cb_flags, rval); 4556 } 4557 4558 mutex_enter(HUBD_MUTEX(hubd)); 4559 4560 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4561 "enabling port done"); 4562 4563 return (rval); 4564 } 4565 4566 4567 /* 4568 * hubd_disable_port 4569 */ 4570 static int 4571 hubd_disable_port(hubd_t *hubd, usb_port_t port) 4572 { 4573 int rval; 4574 usb_cr_t completion_reason; 4575 usb_cb_flags_t cb_flags; 4576 4577 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4578 "hubd_disable_port: port=%d", port); 4579 4580 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4581 4582 mutex_exit(HUBD_MUTEX(hubd)); 4583 4584 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4585 hubd->h_default_pipe, 4586 HUB_HANDLE_PORT_FEATURE_TYPE, 4587 USB_REQ_CLEAR_FEATURE, 4588 CFS_PORT_ENABLE, 4589 port, 4590 0, 4591 NULL, 0, 4592 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4593 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4594 "disable port%d failed (%d 0x%x %d)", port, 4595 completion_reason, cb_flags, rval); 4596 mutex_enter(HUBD_MUTEX(hubd)); 4597 4598 return (USB_FAILURE); 4599 } 4600 4601 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4602 "clearing feature CFS_C_PORT_ENABLE"); 4603 4604 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4605 hubd->h_default_pipe, 4606 HUB_HANDLE_PORT_FEATURE_TYPE, 4607 USB_REQ_CLEAR_FEATURE, 4608 CFS_C_PORT_ENABLE, 4609 port, 4610 0, 4611 NULL, 0, 4612 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4613 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4614 hubd->h_log_handle, 4615 "clear feature CFS_C_PORT_ENABLE port%d failed " 4616 "(%d 0x%x %d)", 4617 port, completion_reason, cb_flags, rval); 4618 4619 mutex_enter(HUBD_MUTEX(hubd)); 4620 4621 return (USB_FAILURE); 4622 } 4623 4624 mutex_enter(HUBD_MUTEX(hubd)); 4625 4626 return (USB_SUCCESS); 4627 } 4628 4629 4630 /* 4631 * hubd_determine_port_status: 4632 */ 4633 static int 4634 hubd_determine_port_status(hubd_t *hubd, usb_port_t port, 4635 uint16_t *status, uint16_t *change, uint_t ack_flag) 4636 { 4637 int rval; 4638 mblk_t *data = NULL; 4639 usb_cr_t completion_reason; 4640 usb_cb_flags_t cb_flags; 4641 4642 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4643 "hubd_determine_port_status: port=%d, state=0x%x ack=0x%x", port, 4644 hubd->h_port_state[port], ack_flag); 4645 4646 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4647 4648 mutex_exit(HUBD_MUTEX(hubd)); 4649 4650 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4651 hubd->h_default_pipe, 4652 HUB_GET_PORT_STATUS_TYPE, 4653 USB_REQ_GET_STATUS, 4654 0, 4655 port, 4656 GET_STATUS_LENGTH, 4657 &data, 0, 4658 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 4659 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4660 "port=%d get status failed (%d 0x%x %d)", 4661 port, completion_reason, cb_flags, rval); 4662 4663 if (data) { 4664 freemsg(data); 4665 } 4666 4667 *status = *change = 0; 4668 mutex_enter(HUBD_MUTEX(hubd)); 4669 4670 return (rval); 4671 } 4672 4673 mutex_enter(HUBD_MUTEX(hubd)); 4674 if ((data->b_wptr - data->b_rptr) != GET_STATUS_LENGTH) { 4675 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4676 "port %d: length incorrect %d", 4677 port, data->b_wptr - data->b_rptr); 4678 freemsg(data); 4679 *status = *change = 0; 4680 4681 return (rval); 4682 } 4683 4684 4685 *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 4686 *change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2); 4687 4688 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4689 "port%d status=0x%x, change=0x%x", port, *status, *change); 4690 4691 freemsg(data); 4692 4693 if (*status & PORT_STATUS_CCS) { 4694 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4695 "port%d connected", port); 4696 4697 hubd->h_port_state[port] |= (PORT_STATUS_CCS & ack_flag); 4698 } else { 4699 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4700 "port%d disconnected", port); 4701 4702 hubd->h_port_state[port] &= ~(PORT_STATUS_CCS & ack_flag); 4703 } 4704 4705 if (*status & PORT_STATUS_PES) { 4706 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4707 "port%d enabled", port); 4708 4709 hubd->h_port_state[port] |= (PORT_STATUS_PES & ack_flag); 4710 } else { 4711 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4712 "port%d disabled", port); 4713 4714 hubd->h_port_state[port] &= ~(PORT_STATUS_PES & ack_flag); 4715 } 4716 4717 if (*status & PORT_STATUS_PSS) { 4718 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4719 "port%d suspended", port); 4720 4721 hubd->h_port_state[port] |= (PORT_STATUS_PSS & ack_flag); 4722 } else { 4723 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4724 "port%d not suspended", port); 4725 4726 hubd->h_port_state[port] &= ~(PORT_STATUS_PSS & ack_flag); 4727 } 4728 4729 if (*change & PORT_CHANGE_PRSC) { 4730 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4731 "port%d reset completed", port); 4732 4733 hubd->h_port_state[port] |= (PORT_CHANGE_PRSC & ack_flag); 4734 } else { 4735 4736 hubd->h_port_state[port] &= ~(PORT_CHANGE_PRSC & ack_flag); 4737 } 4738 4739 if (*status & PORT_STATUS_POCI) { 4740 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 4741 "port%d overcurrent!", port); 4742 4743 hubd->h_port_state[port] |= (PORT_STATUS_POCI & ack_flag); 4744 } else { 4745 4746 hubd->h_port_state[port] &= ~(PORT_STATUS_POCI & ack_flag); 4747 } 4748 4749 if (*status & PORT_STATUS_PRS) { 4750 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4751 "port%d reset active", port); 4752 4753 hubd->h_port_state[port] |= (PORT_STATUS_PRS & ack_flag); 4754 } else { 4755 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4756 "port%d reset inactive", port); 4757 4758 hubd->h_port_state[port] &= ~(PORT_STATUS_PRS & ack_flag); 4759 } 4760 if (*status & PORT_STATUS_PPS) { 4761 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4762 "port%d power on", port); 4763 4764 hubd->h_port_state[port] |= (PORT_STATUS_PPS & ack_flag); 4765 } else { 4766 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4767 "port%d power off", port); 4768 4769 hubd->h_port_state[port] &= ~(PORT_STATUS_PPS & ack_flag); 4770 } 4771 if (*status & PORT_STATUS_LSDA) { 4772 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4773 "port%d low speed", port); 4774 4775 hubd->h_port_state[port] |= (PORT_STATUS_LSDA & ack_flag); 4776 } else { 4777 hubd->h_port_state[port] &= ~(PORT_STATUS_LSDA & ack_flag); 4778 if (*status & PORT_STATUS_HSDA) { 4779 USB_DPRINTF_L3(DPRINT_MASK_PORT, 4780 hubd->h_log_handle, "port%d " 4781 "high speed", port); 4782 4783 hubd->h_port_state[port] |= 4784 (PORT_STATUS_HSDA & ack_flag); 4785 } else { 4786 USB_DPRINTF_L3(DPRINT_MASK_PORT, 4787 hubd->h_log_handle, "port%d " 4788 "full speed", port); 4789 4790 hubd->h_port_state[port] &= 4791 ~(PORT_STATUS_HSDA & ack_flag); 4792 } 4793 } 4794 4795 /* 4796 * Acknowledge connection, enable, reset status 4797 */ 4798 if (ack_flag) { 4799 mutex_exit(HUBD_MUTEX(hubd)); 4800 if (*change & PORT_CHANGE_CSC & ack_flag) { 4801 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4802 "clearing feature CFS_C_PORT_CONNECTION"); 4803 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4804 hubd->h_default_pipe, 4805 HUB_HANDLE_PORT_FEATURE_TYPE, 4806 USB_REQ_CLEAR_FEATURE, 4807 CFS_C_PORT_CONNECTION, 4808 port, 4809 0, NULL, 0, 4810 &completion_reason, &cb_flags, 0)) != 4811 USB_SUCCESS) { 4812 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4813 hubd->h_log_handle, 4814 "clear feature CFS_C_PORT_CONNECTION" 4815 " port%d failed (%d 0x%x %d)", 4816 port, completion_reason, cb_flags, rval); 4817 } 4818 } 4819 if (*change & PORT_CHANGE_PESC & ack_flag) { 4820 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4821 "clearing feature CFS_C_PORT_ENABLE"); 4822 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4823 hubd->h_default_pipe, 4824 HUB_HANDLE_PORT_FEATURE_TYPE, 4825 USB_REQ_CLEAR_FEATURE, 4826 CFS_C_PORT_ENABLE, 4827 port, 4828 0, NULL, 0, 4829 &completion_reason, &cb_flags, 0)) != 4830 USB_SUCCESS) { 4831 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4832 hubd->h_log_handle, 4833 "clear feature CFS_C_PORT_ENABLE" 4834 " port%d failed (%d 0x%x %d)", 4835 port, completion_reason, cb_flags, rval); 4836 } 4837 } 4838 if (*change & PORT_CHANGE_PSSC & ack_flag) { 4839 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4840 "clearing feature CFS_C_PORT_SUSPEND"); 4841 4842 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4843 hubd->h_default_pipe, 4844 HUB_HANDLE_PORT_FEATURE_TYPE, 4845 USB_REQ_CLEAR_FEATURE, 4846 CFS_C_PORT_SUSPEND, 4847 port, 4848 0, NULL, 0, 4849 &completion_reason, &cb_flags, 0)) != 4850 USB_SUCCESS) { 4851 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4852 hubd->h_log_handle, 4853 "clear feature CFS_C_PORT_SUSPEND" 4854 " port%d failed (%d 0x%x %d)", 4855 port, completion_reason, cb_flags, rval); 4856 } 4857 } 4858 if (*change & PORT_CHANGE_OCIC & ack_flag) { 4859 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4860 "clearing feature CFS_C_PORT_OVER_CURRENT"); 4861 4862 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4863 hubd->h_default_pipe, 4864 HUB_HANDLE_PORT_FEATURE_TYPE, 4865 USB_REQ_CLEAR_FEATURE, 4866 CFS_C_PORT_OVER_CURRENT, 4867 port, 4868 0, NULL, 0, 4869 &completion_reason, &cb_flags, 0)) != 4870 USB_SUCCESS) { 4871 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4872 hubd->h_log_handle, 4873 "clear feature CFS_C_PORT_OVER_CURRENT" 4874 " port%d failed (%d 0x%x %d)", 4875 port, completion_reason, cb_flags, rval); 4876 } 4877 } 4878 if (*change & PORT_CHANGE_PRSC & ack_flag) { 4879 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 4880 "clearing feature CFS_C_PORT_RESET"); 4881 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 4882 hubd->h_default_pipe, 4883 HUB_HANDLE_PORT_FEATURE_TYPE, 4884 USB_REQ_CLEAR_FEATURE, 4885 CFS_C_PORT_RESET, 4886 port, 4887 0, NULL, 0, 4888 &completion_reason, &cb_flags, 0)) != 4889 USB_SUCCESS) { 4890 USB_DPRINTF_L2(DPRINT_MASK_PORT, 4891 hubd->h_log_handle, 4892 "clear feature CFS_C_PORT_RESET" 4893 " port%d failed (%d 0x%x %d)", 4894 port, completion_reason, cb_flags, rval); 4895 } 4896 } 4897 mutex_enter(HUBD_MUTEX(hubd)); 4898 } 4899 4900 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4901 "new port%d state 0x%x", port, hubd->h_port_state[port]); 4902 4903 4904 return (USB_SUCCESS); 4905 } 4906 4907 4908 /* 4909 * hubd_recover_disabled_port 4910 * if the port got disabled because of an error 4911 * enable it. If hub doesn't suport enable port, 4912 * reset the port to bring the device to life again 4913 */ 4914 static int 4915 hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port) 4916 { 4917 uint16_t status; 4918 uint16_t change; 4919 int rval = USB_FAILURE; 4920 4921 /* first try enabling the port */ 4922 (void) hubd_enable_port(hubd, port); 4923 4924 /* read the port status */ 4925 (void) hubd_determine_port_status(hubd, port, &status, &change, 4926 PORT_CHANGE_PESC); 4927 4928 if (status & PORT_STATUS_PES) { 4929 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4930 "Port%d now Enabled", port); 4931 } else if (status & PORT_STATUS_CCS) { 4932 /* first post a disconnect event to the child */ 4933 mutex_exit(HUBD_MUTEX(hubd)); 4934 hubd_post_event(hubd, port, USBA_EVENT_TAG_HOT_REMOVAL); 4935 mutex_enter(HUBD_MUTEX(hubd)); 4936 4937 /* then reset the port and recover the device */ 4938 rval = hubd_handle_port_connect(hubd, port); 4939 4940 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 4941 "Port%d now Enabled by force", port); 4942 } 4943 4944 return (rval); 4945 } 4946 4947 4948 /* 4949 * hubd_enable_all_port_power: 4950 */ 4951 static int 4952 hubd_enable_all_port_power(hubd_t *hubd) 4953 { 4954 usb_hub_descr_t *hub_descr; 4955 int wait; 4956 usb_port_t port; 4957 uint_t retry; 4958 uint16_t status; 4959 uint16_t change; 4960 4961 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4962 "hubd_enable_all_port_power"); 4963 4964 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 4965 4966 hub_descr = &hubd->h_hub_descr; 4967 4968 /* 4969 * According to section 11.11 of USB, for hubs with no power 4970 * switches, bPwrOn2PwrGood is zero. But we wait for some 4971 * arbitrary time to enable power to become stable. 4972 * 4973 * If an hub supports port power switching, we need to wait 4974 * at least 20ms before accessing corresponding usb port. 4975 */ 4976 if ((hub_descr->wHubCharacteristics & 4977 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 4978 wait = hubd_device_delay / 10; 4979 } else { 4980 wait = max(HUB_DEFAULT_POPG, 4981 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 4982 } 4983 4984 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 4985 "hubd_enable_all_port_power: popg=%d wait=%d", 4986 hub_descr->bPwrOn2PwrGood, wait); 4987 4988 /* 4989 * Enable power per port. we ignore gang power and power mask 4990 * and always enable all ports one by one. 4991 */ 4992 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 4993 /* 4994 * Transition the port from the Powered Off to the 4995 * Disconnected state by supplying power to the port. 4996 */ 4997 USB_DPRINTF_L4(DPRINT_MASK_PORT, 4998 hubd->h_log_handle, 4999 "hubd_enable_all_port_power: power port=%d", port); 5000 5001 (void) hubd_enable_port_power(hubd, port); 5002 } 5003 5004 mutex_exit(HUBD_MUTEX(hubd)); 5005 delay(drv_usectohz(wait)); 5006 mutex_enter(HUBD_MUTEX(hubd)); 5007 5008 /* For retry if any, use some extra delay */ 5009 wait = max(wait, hubd_device_delay / 10); 5010 5011 /* Check each port power status for a given usb hub */ 5012 for (port = 1; port <= hub_descr->bNbrPorts; port++) { 5013 5014 /* Get port status */ 5015 (void) hubd_determine_port_status(hubd, port, 5016 &status, &change, 0); 5017 5018 for (retry = 0; ((!(status & PORT_STATUS_PPS)) && 5019 (retry < HUBD_PORT_RETRY)); retry++) { 5020 5021 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5022 "Retry is in progress %d: port %d status %d", 5023 retry, port, status); 5024 5025 (void) hubd_enable_port_power(hubd, port); 5026 5027 mutex_exit(HUBD_MUTEX(hubd)); 5028 delay(drv_usectohz(wait)); 5029 mutex_enter(HUBD_MUTEX(hubd)); 5030 5031 /* Get port status */ 5032 (void) hubd_determine_port_status(hubd, port, 5033 &status, &change, 0); 5034 } 5035 5036 /* Print warning message if port has no power */ 5037 if (!(status & PORT_STATUS_PPS)) { 5038 5039 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5040 "hubd_enable_all_port_power: port %d power-on " 5041 "failed, port status 0x%x", port, status); 5042 } 5043 } 5044 5045 return (USB_SUCCESS); 5046 } 5047 5048 5049 /* 5050 * hubd_enable_port_power: 5051 * enable individual port power 5052 */ 5053 static int 5054 hubd_enable_port_power(hubd_t *hubd, usb_port_t port) 5055 { 5056 int rval; 5057 usb_cr_t completion_reason; 5058 usb_cb_flags_t cb_flags; 5059 5060 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5061 "hubd_enable_port_power: port=%d", port); 5062 5063 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5064 ASSERT(hubd->h_default_pipe != 0); 5065 5066 mutex_exit(HUBD_MUTEX(hubd)); 5067 5068 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5069 hubd->h_default_pipe, 5070 HUB_HANDLE_PORT_FEATURE_TYPE, 5071 USB_REQ_SET_FEATURE, 5072 CFS_PORT_POWER, 5073 port, 5074 0, NULL, 0, 5075 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5076 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5077 "set port power failed (%d 0x%x %d)", 5078 completion_reason, cb_flags, rval); 5079 mutex_enter(HUBD_MUTEX(hubd)); 5080 5081 return (USB_FAILURE); 5082 } else { 5083 mutex_enter(HUBD_MUTEX(hubd)); 5084 hubd->h_port_state[port] |= PORT_STATUS_PPS; 5085 5086 return (USB_SUCCESS); 5087 } 5088 } 5089 5090 5091 /* 5092 * hubd_disable_all_port_power: 5093 */ 5094 static int 5095 hubd_disable_all_port_power(hubd_t *hubd) 5096 { 5097 usb_port_t port; 5098 5099 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5100 "hubd_disable_all_port_power"); 5101 5102 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5103 5104 /* 5105 * disable power per port, ignore gang power and power mask 5106 */ 5107 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 5108 (void) hubd_disable_port_power(hubd, port); 5109 } 5110 5111 return (USB_SUCCESS); 5112 } 5113 5114 5115 /* 5116 * hubd_disable_port_power: 5117 * disable individual port power 5118 */ 5119 static int 5120 hubd_disable_port_power(hubd_t *hubd, usb_port_t port) 5121 { 5122 int rval; 5123 usb_cr_t completion_reason; 5124 usb_cb_flags_t cb_flags; 5125 5126 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle, 5127 "hubd_disable_port_power: port=%d", port); 5128 5129 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5130 5131 mutex_exit(HUBD_MUTEX(hubd)); 5132 5133 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip, 5134 hubd->h_default_pipe, 5135 HUB_HANDLE_PORT_FEATURE_TYPE, 5136 USB_REQ_CLEAR_FEATURE, 5137 CFS_PORT_POWER, 5138 port, 5139 0, NULL, 0, 5140 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5141 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 5142 "clearing port%d power failed (%d 0x%x %d)", 5143 port, completion_reason, cb_flags, rval); 5144 5145 mutex_enter(HUBD_MUTEX(hubd)); 5146 5147 return (USB_FAILURE); 5148 } else { 5149 5150 mutex_enter(HUBD_MUTEX(hubd)); 5151 ASSERT(completion_reason == 0); 5152 hubd->h_port_state[port] &= ~PORT_STATUS_PPS; 5153 5154 return (USB_SUCCESS); 5155 } 5156 } 5157 5158 5159 /* 5160 * Search the database of user preferences and find out the preferred 5161 * configuration for this new device 5162 */ 5163 static int 5164 hubd_select_device_configuration(hubd_t *hubd, usb_port_t port, 5165 dev_info_t *child_dip, usba_device_t *child_ud) 5166 { 5167 char *pathname = NULL; 5168 char *tmp_path = NULL; 5169 int user_conf; 5170 int pathlen; 5171 usb_dev_descr_t *usbdev_ptr; 5172 usba_configrec_t *user_pref; 5173 5174 mutex_enter(&child_ud->usb_mutex); 5175 usbdev_ptr = child_ud->usb_dev_descr; 5176 mutex_exit(&child_ud->usb_mutex); 5177 5178 /* try to get pathname for this device */ 5179 tmp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5180 (void) ddi_pathname(child_dip, tmp_path); 5181 5182 pathlen = strlen(tmp_path) + 32; 5183 pathname = kmem_zalloc(pathlen, KM_SLEEP); 5184 5185 /* 5186 * We haven't initialized the node and it doesn't have an address 5187 * yet. Append port number to the physical pathname 5188 */ 5189 (void) sprintf(pathname, "%s@%d", tmp_path, port); 5190 5191 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5192 "hubd_select_device_configuration: Device=%s\n\t" 5193 "Child path=%s", 5194 usba_get_mfg_prod_sn_str(child_dip, tmp_path, MAXPATHLEN), 5195 pathname); 5196 kmem_free(tmp_path, MAXPATHLEN); 5197 5198 5199 /* database search for user preferences */ 5200 user_pref = usba_devdb_get_user_preferences(usbdev_ptr->idVendor, 5201 usbdev_ptr->idProduct, child_ud->usb_serialno_str, pathname); 5202 5203 if (user_pref) { 5204 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5205 "hubd_select_device_configuration: " 5206 "usba_devdb_get_user_preferences " 5207 "return user_conf=%d\npreferred driver=%s path=%s", 5208 user_pref->cfg_index, user_pref->driver, 5209 user_pref->pathname); 5210 5211 user_conf = user_pref->cfg_index; 5212 5213 if (user_pref->driver) { 5214 mutex_enter(&child_ud->usb_mutex); 5215 child_ud->usb_preferred_driver = user_pref->driver; 5216 mutex_exit(&child_ud->usb_mutex); 5217 } 5218 } else { 5219 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5220 "hubd_select_device_configuration: No match found"); 5221 5222 /* select default configuration for this device */ 5223 user_conf = USBA_DEV_CONFIG_INDEX_UNDEFINED; 5224 } 5225 kmem_free(pathname, pathlen); 5226 5227 /* if the device has just one configuration, set default value */ 5228 if (usbdev_ptr->bNumConfigurations == 1) { 5229 user_conf = USB_DEV_DEFAULT_CONFIG_INDEX; 5230 } 5231 5232 return (user_conf); 5233 } 5234 5235 5236 /* 5237 * Retrieves config cloud for this configuration 5238 */ 5239 int 5240 hubd_get_this_config_cloud(hubd_t *hubd, dev_info_t *dip, 5241 usba_device_t *child_ud, uint16_t conf_index) 5242 { 5243 usb_cfg_descr_t *confdescr; 5244 mblk_t *pdata = NULL; 5245 int rval; 5246 size_t size; 5247 char *tmpbuf; 5248 usb_cr_t completion_reason; 5249 usb_cb_flags_t cb_flags; 5250 usb_pipe_handle_t def_ph; 5251 5252 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5253 "hubd_get_this_config_cloud: conf_index=%d", conf_index); 5254 5255 5256 /* alloc temporary space for config descriptor */ 5257 confdescr = (usb_cfg_descr_t *)kmem_zalloc(USB_CFG_DESCR_SIZE, 5258 KM_SLEEP); 5259 5260 /* alloc temporary space for string descriptor */ 5261 tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 5262 5263 def_ph = usba_get_dflt_pipe_handle(dip); 5264 5265 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5266 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5267 USB_REQ_GET_DESCR, 5268 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5269 0, 5270 USB_CFG_DESCR_SIZE, 5271 &pdata, 5272 0, 5273 &completion_reason, 5274 &cb_flags, 5275 0)) == USB_SUCCESS) { 5276 5277 /* this must be true since we didn't allow data underruns */ 5278 if ((pdata->b_wptr - pdata->b_rptr) != USB_CFG_DESCR_SIZE) { 5279 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5280 "device returned incorrect configuration " 5281 "descriptor size."); 5282 5283 rval = USB_FAILURE; 5284 goto done; 5285 } 5286 5287 /* 5288 * Parse the configuration descriptor 5289 */ 5290 size = usb_parse_cfg_descr(pdata->b_rptr, 5291 pdata->b_wptr - pdata->b_rptr, confdescr, 5292 USB_CFG_DESCR_SIZE); 5293 5294 /* if parse cfg descr error, it should return failure */ 5295 if (size == USB_PARSE_ERROR) { 5296 5297 if (pdata->b_rptr[1] != USB_DESCR_TYPE_CFG) { 5298 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5299 hubd->h_log_handle, 5300 "device returned incorrect " 5301 "configuration descriptor type."); 5302 } 5303 rval = USB_FAILURE; 5304 goto done; 5305 } 5306 5307 if (confdescr->wTotalLength < USB_CFG_DESCR_SIZE) { 5308 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5309 hubd->h_log_handle, 5310 "device returned incorrect " 5311 "configuration descriptor size."); 5312 5313 rval = USB_FAILURE; 5314 goto done; 5315 } 5316 5317 freemsg(pdata); 5318 pdata = NULL; 5319 5320 /* Now fetch the complete config cloud */ 5321 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph, 5322 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5323 USB_REQ_GET_DESCR, 5324 USB_DESCR_TYPE_SETUP_CFG | conf_index, 5325 0, 5326 confdescr->wTotalLength, 5327 &pdata, 5328 0, 5329 &completion_reason, 5330 &cb_flags, 5331 0)) == USB_SUCCESS) { 5332 5333 if ((pdata->b_wptr - pdata->b_rptr) != 5334 confdescr->wTotalLength) { 5335 5336 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5337 hubd->h_log_handle, 5338 "device returned incorrect " 5339 "configuration descriptor."); 5340 5341 rval = USB_FAILURE; 5342 goto done; 5343 } 5344 5345 /* 5346 * copy config descriptor into usba_device 5347 */ 5348 mutex_enter(&child_ud->usb_mutex); 5349 child_ud->usb_cfg_array[conf_index] = 5350 kmem_alloc(confdescr->wTotalLength, KM_SLEEP); 5351 child_ud->usb_cfg_array_len[conf_index] = 5352 confdescr->wTotalLength; 5353 bcopy((caddr_t)pdata->b_rptr, 5354 (caddr_t)child_ud->usb_cfg_array[conf_index], 5355 confdescr->wTotalLength); 5356 mutex_exit(&child_ud->usb_mutex); 5357 5358 /* 5359 * retrieve string descriptor describing this 5360 * configuration 5361 */ 5362 if (confdescr->iConfiguration) { 5363 5364 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 5365 hubd->h_log_handle, 5366 "Get conf str descr for config_index=%d", 5367 conf_index); 5368 5369 /* 5370 * Now fetch the string descriptor describing 5371 * this configuration 5372 */ 5373 if ((rval = usb_get_string_descr(dip, 5374 USB_LANG_ID, confdescr->iConfiguration, 5375 tmpbuf, USB_MAXSTRINGLEN)) == 5376 USB_SUCCESS) { 5377 size = strlen(tmpbuf); 5378 if (size > 0) { 5379 child_ud->usb_cfg_str_descr 5380 [conf_index] = (char *) 5381 kmem_zalloc(size + 1, 5382 KM_SLEEP); 5383 (void) strcpy( 5384 child_ud->usb_cfg_str_descr 5385 [conf_index], tmpbuf); 5386 } 5387 } else { 5388 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5389 hubd->h_log_handle, 5390 "hubd_get_this_config_cloud: " 5391 "getting config string (%d) " 5392 "failed", 5393 confdescr->iConfiguration); 5394 5395 /* ignore this error */ 5396 rval = USB_SUCCESS; 5397 } 5398 } 5399 } 5400 } 5401 5402 done: 5403 if (rval != USB_SUCCESS) { 5404 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5405 "hubd_get_this_config_cloud: " 5406 "error in retrieving config descriptor for " 5407 "config index=%d rval=%d cr=%d", 5408 conf_index, rval, completion_reason); 5409 } 5410 5411 if (pdata) { 5412 freemsg(pdata); 5413 pdata = NULL; 5414 } 5415 5416 kmem_free(confdescr, USB_CFG_DESCR_SIZE); 5417 kmem_free(tmpbuf, USB_MAXSTRINGLEN); 5418 5419 return (rval); 5420 } 5421 5422 5423 /* 5424 * Retrieves the entire config cloud for all configurations of the device 5425 */ 5426 int 5427 hubd_get_all_device_config_cloud(hubd_t *hubd, dev_info_t *dip, 5428 usba_device_t *child_ud) 5429 { 5430 int rval = USB_SUCCESS; 5431 int ncfgs; 5432 uint16_t size; 5433 uint16_t conf_index; 5434 uchar_t **cfg_array; 5435 uint16_t *cfg_array_len; 5436 char **str_descr; 5437 5438 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5439 "hubd_get_all_device_config_cloud: Start"); 5440 5441 /* alloc pointer array for conf. descriptors */ 5442 mutex_enter(&child_ud->usb_mutex); 5443 ncfgs = child_ud->usb_n_cfgs; 5444 mutex_exit(&child_ud->usb_mutex); 5445 5446 size = sizeof (uchar_t *) * ncfgs; 5447 cfg_array = kmem_zalloc(size, KM_SLEEP); 5448 cfg_array_len = kmem_zalloc(ncfgs * sizeof (uint16_t), KM_SLEEP); 5449 str_descr = kmem_zalloc(size, KM_SLEEP); 5450 5451 mutex_enter(&child_ud->usb_mutex); 5452 child_ud->usb_cfg_array = cfg_array; 5453 child_ud->usb_cfg_array_len = cfg_array_len; 5454 child_ud->usb_cfg_array_length = size; 5455 child_ud->usb_cfg_array_len_length = ncfgs * sizeof (uint16_t); 5456 child_ud->usb_cfg_str_descr = str_descr; 5457 mutex_exit(&child_ud->usb_mutex); 5458 5459 /* Get configuration descriptor for each configuration */ 5460 for (conf_index = 0; (conf_index < ncfgs) && 5461 (rval == USB_SUCCESS); conf_index++) { 5462 5463 rval = hubd_get_this_config_cloud(hubd, dip, child_ud, 5464 conf_index); 5465 } 5466 5467 return (rval); 5468 } 5469 5470 5471 /* 5472 * hubd_ready_device: 5473 * Update the usba_device structure 5474 * Set the given configuration 5475 * Prepares the device node for driver to online. If an existing 5476 * OBP node is found, it will switch to the OBP node. 5477 */ 5478 static dev_info_t * 5479 hubd_ready_device(hubd_t *hubd, dev_info_t *child_dip, usba_device_t *child_ud, 5480 uint_t config_index) 5481 { 5482 usb_cr_t completion_reason; 5483 usb_cb_flags_t cb_flags; 5484 size_t size; 5485 usb_cfg_descr_t config_descriptor; 5486 usb_pipe_handle_t def_ph; 5487 usba_pipe_handle_data_t *ph; 5488 5489 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5490 "hubd_ready_device: dip=0x%p, user_conf_index=%d", child_dip, 5491 config_index); 5492 5493 size = usb_parse_cfg_descr( 5494 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 5495 &config_descriptor, USB_CFG_DESCR_SIZE); 5496 ASSERT(size == USB_CFG_DESCR_SIZE); 5497 5498 def_ph = usba_get_dflt_pipe_handle(child_dip); 5499 5500 /* Set the configuration */ 5501 (void) usb_pipe_sync_ctrl_xfer(child_dip, def_ph, 5502 USB_DEV_REQ_HOST_TO_DEV, 5503 USB_REQ_SET_CFG, /* bRequest */ 5504 config_descriptor.bConfigurationValue, /* wValue */ 5505 0, /* wIndex */ 5506 0, /* wLength */ 5507 NULL, 5508 0, 5509 &completion_reason, 5510 &cb_flags, 5511 0); 5512 5513 mutex_enter(&child_ud->usb_mutex); 5514 child_ud->usb_active_cfg_ndx = config_index; 5515 child_ud->usb_cfg = child_ud->usb_cfg_array[config_index]; 5516 child_ud->usb_cfg_length = config_descriptor.wTotalLength; 5517 child_ud->usb_cfg_value = config_descriptor.bConfigurationValue; 5518 child_ud->usb_n_ifs = config_descriptor.bNumInterfaces; 5519 child_ud->usb_dip = child_dip; 5520 5521 child_ud->usb_client_flags = kmem_zalloc( 5522 child_ud->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP); 5523 5524 child_ud->usb_client_attach_list = kmem_zalloc( 5525 child_ud->usb_n_ifs * 5526 sizeof (*child_ud->usb_client_attach_list), KM_SLEEP); 5527 5528 child_ud->usb_client_ev_cb_list = kmem_zalloc( 5529 child_ud->usb_n_ifs * 5530 sizeof (*child_ud->usb_client_ev_cb_list), KM_SLEEP); 5531 5532 mutex_exit(&child_ud->usb_mutex); 5533 5534 /* ready the device node */ 5535 child_dip = usba_ready_device_node(child_dip); 5536 5537 /* set owner of default pipe to child dip */ 5538 ph = usba_get_ph_data(def_ph); 5539 mutex_enter(&ph->p_mutex); 5540 mutex_enter(&ph->p_ph_impl->usba_ph_mutex); 5541 ph->p_ph_impl->usba_ph_dip = ph->p_dip = child_dip; 5542 mutex_exit(&ph->p_ph_impl->usba_ph_mutex); 5543 mutex_exit(&ph->p_mutex); 5544 5545 return (child_dip); 5546 } 5547 5548 5549 /* 5550 * hubd_create_child 5551 * - create child dip 5552 * - open default pipe 5553 * - get device descriptor 5554 * - set the address 5555 * - get device string descriptors 5556 * - get the entire config cloud (all configurations) of the device 5557 * - set user preferred configuration 5558 * - close default pipe 5559 * - load appropriate driver(s) 5560 */ 5561 static int 5562 hubd_create_child(dev_info_t *dip, 5563 hubd_t *hubd, 5564 usba_device_t *hubd_ud, 5565 usb_port_status_t port_status, 5566 usb_port_t port, 5567 int iteration) 5568 { 5569 dev_info_t *child_dip = NULL; 5570 usb_dev_descr_t usb_dev_descr; 5571 int rval; 5572 usba_device_t *child_ud = NULL; 5573 usba_device_t *parent_ud = NULL; 5574 usb_pipe_handle_t ph = NULL; /* default pipe handle */ 5575 mblk_t *pdata = NULL; 5576 usb_cr_t completion_reason; 5577 int user_conf_index; 5578 uint_t config_index; 5579 usb_cb_flags_t cb_flags; 5580 uchar_t address = 0; 5581 uint16_t length; 5582 size_t size; 5583 usb_addr_t parent_usb_addr; 5584 usb_port_t parent_usb_port; 5585 usba_device_t *parent_usba_dev; 5586 usb_port_status_t parent_port_status; 5587 5588 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5589 "hubd_create_child: port=%d", port); 5590 5591 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 5592 ASSERT(hubd->h_usba_devices[port] == NULL); 5593 5594 mutex_exit(HUBD_MUTEX(hubd)); 5595 5596 /* 5597 * create a dip which can be used to open the pipe. we set 5598 * the name after getting the descriptors from the device 5599 */ 5600 rval = usba_create_child_devi(dip, 5601 "device", /* driver name */ 5602 hubd_ud->usb_hcdi_ops, /* usba_hcdi ops */ 5603 hubd_ud->usb_root_hub_dip, 5604 port_status, /* low speed device */ 5605 child_ud, 5606 &child_dip); 5607 5608 if (rval != USB_SUCCESS) { 5609 5610 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5611 "usb_create_child_devi failed (%d)", rval); 5612 5613 goto fail_cleanup; 5614 } 5615 5616 child_ud = usba_get_usba_device(child_dip); 5617 ASSERT(child_ud != NULL); 5618 5619 parent_ud = hubd->h_usba_device; 5620 mutex_enter(&parent_ud->usb_mutex); 5621 parent_port_status = parent_ud->usb_port_status; 5622 5623 /* 5624 * To support split transactions, update address and port 5625 * of high speed hub to which given device is connected. 5626 */ 5627 if (parent_port_status == USBA_HIGH_SPEED_DEV) { 5628 parent_usba_dev = parent_ud; 5629 parent_usb_addr = parent_ud->usb_addr; 5630 parent_usb_port = port; 5631 } else { 5632 parent_usba_dev = parent_ud->usb_hs_hub_usba_dev; 5633 parent_usb_addr = parent_ud->usb_hs_hub_addr; 5634 parent_usb_port = parent_ud->usb_hs_hub_port; 5635 } 5636 mutex_exit(&parent_ud->usb_mutex); 5637 5638 mutex_enter(&child_ud->usb_mutex); 5639 address = child_ud->usb_addr; 5640 child_ud->usb_addr = 0; 5641 child_ud->usb_dev_descr = kmem_alloc(sizeof (usb_dev_descr_t), 5642 KM_SLEEP); 5643 bzero(&usb_dev_descr, sizeof (usb_dev_descr_t)); 5644 usb_dev_descr.bMaxPacketSize0 = 5645 (port_status == USBA_LOW_SPEED_DEV) ? 8 : 64; 5646 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5647 sizeof (usb_dev_descr_t)); 5648 child_ud->usb_port = port; 5649 child_ud->usb_hs_hub_usba_dev = parent_usba_dev; 5650 child_ud->usb_hs_hub_addr = parent_usb_addr; 5651 child_ud->usb_hs_hub_port = parent_usb_port; 5652 mutex_exit(&child_ud->usb_mutex); 5653 5654 /* Open the default pipe */ 5655 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5656 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 5657 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5658 "usb_pipe_open failed (%d)", rval); 5659 5660 goto fail_cleanup; 5661 } 5662 5663 /* 5664 * get device descriptor 5665 */ 5666 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5667 "hubd_create_child: get device descriptor: 64 bytes"); 5668 5669 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5670 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5671 USB_REQ_GET_DESCR, /* bRequest */ 5672 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5673 0, /* wIndex */ 5674 64, /* wLength */ 5675 &pdata, USB_ATTRS_SHORT_XFER_OK, 5676 &completion_reason, &cb_flags, 0); 5677 5678 if ((rval != USB_SUCCESS) && 5679 (!((completion_reason == USB_CR_DATA_OVERRUN) && pdata))) { 5680 5681 /* 5682 * rval != USB_SUCCESS AND 5683 * completion_reason != USB_CR_DATA_OVERRUN 5684 * pdata could be != NULL. 5685 * Free pdata now to prevent memory leak. 5686 */ 5687 freemsg(pdata); 5688 pdata = NULL; 5689 5690 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5691 "hubd_create_child: get device descriptor: 8 bytes"); 5692 5693 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5694 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5695 USB_REQ_GET_DESCR, /* bRequest */ 5696 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5697 0, /* wIndex */ 5698 8, /* wLength */ 5699 &pdata, USB_ATTRS_NONE, 5700 &completion_reason, &cb_flags, 0); 5701 5702 if (rval != USB_SUCCESS) { 5703 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5704 "getting device descriptor failed (%s 0x%x %d)", 5705 usb_str_cr(completion_reason), cb_flags, rval); 5706 goto fail_cleanup; 5707 } 5708 } else { 5709 ASSERT(completion_reason == USB_CR_OK); 5710 } 5711 5712 ASSERT(pdata != NULL); 5713 5714 size = usb_parse_dev_descr( 5715 pdata->b_rptr, 5716 pdata->b_wptr - pdata->b_rptr, 5717 &usb_dev_descr, 5718 sizeof (usb_dev_descr_t)); 5719 5720 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5721 "parsing device descriptor returned %lu", size); 5722 5723 length = *(pdata->b_rptr); 5724 freemsg(pdata); 5725 pdata = NULL; 5726 if (size < 8) { 5727 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5728 "get device descriptor returned %lu bytes", size); 5729 5730 goto fail_cleanup; 5731 } 5732 5733 if (length < 8) { 5734 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5735 "fail enumeration: bLength=%d", length); 5736 5737 goto fail_cleanup; 5738 } 5739 5740 /* Set the address of the device */ 5741 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5742 USB_DEV_REQ_HOST_TO_DEV, 5743 USB_REQ_SET_ADDRESS, /* bRequest */ 5744 address, /* wValue */ 5745 0, /* wIndex */ 5746 0, /* wLength */ 5747 NULL, 0, 5748 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5749 char buffer[64]; 5750 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5751 "setting address failed (cr=%s cb_flags=%s rval=%d)", 5752 usb_str_cr(completion_reason), 5753 usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)), 5754 rval); 5755 5756 goto fail_cleanup; 5757 } 5758 5759 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5760 "set address 0x%x done", address); 5761 5762 /* now close the pipe for addr 0 */ 5763 usb_pipe_close(child_dip, ph, 5764 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 5765 5766 /* 5767 * This delay is important for the CATC hub to enumerate 5768 * But, avoid delay in the first iteration 5769 */ 5770 if (iteration) { 5771 delay(drv_usectohz(hubd_device_delay/100)); 5772 } 5773 5774 /* assign the address in the usba_device structure */ 5775 mutex_enter(&child_ud->usb_mutex); 5776 child_ud->usb_addr = address; 5777 child_ud->usb_no_cpr = 0; 5778 child_ud->usb_port_status = port_status; 5779 /* save this device descriptor */ 5780 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5781 sizeof (usb_dev_descr_t)); 5782 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 5783 mutex_exit(&child_ud->usb_mutex); 5784 5785 /* re-open the pipe for the device with the new address */ 5786 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5787 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) { 5788 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5789 "usb_pipe_open failed (%d)", rval); 5790 5791 goto fail_cleanup; 5792 } 5793 5794 /* 5795 * Get full device descriptor only if we have not received full 5796 * device descriptor earlier. 5797 */ 5798 if (size < length) { 5799 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5800 "hubd_create_child: get full device descriptor: " 5801 "%d bytes", length); 5802 5803 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5804 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5805 USB_REQ_GET_DESCR, /* bRequest */ 5806 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5807 0, /* wIndex */ 5808 length, /* wLength */ 5809 &pdata, 0, 5810 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5811 freemsg(pdata); 5812 pdata = NULL; 5813 5814 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, 5815 hubd->h_log_handle, 5816 "hubd_create_child: get full device descriptor: " 5817 "64 bytes"); 5818 5819 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5820 USB_DEV_REQ_DEV_TO_HOST | 5821 USB_DEV_REQ_TYPE_STANDARD, 5822 USB_REQ_GET_DESCR, /* bRequest */ 5823 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5824 0, /* wIndex */ 5825 64, /* wLength */ 5826 &pdata, USB_ATTRS_SHORT_XFER_OK, 5827 &completion_reason, &cb_flags, 0); 5828 5829 /* we have to trust the data now */ 5830 if (pdata) { 5831 int len = *(pdata->b_rptr); 5832 5833 length = pdata->b_wptr - pdata->b_rptr; 5834 if (length < len) { 5835 5836 goto fail_cleanup; 5837 } 5838 } else if (rval != USB_SUCCESS) { 5839 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 5840 hubd->h_log_handle, 5841 "getting device descriptor failed " 5842 "(%d 0x%x %d)", 5843 completion_reason, cb_flags, rval); 5844 5845 goto fail_cleanup; 5846 } 5847 } 5848 5849 size = usb_parse_dev_descr( 5850 pdata->b_rptr, 5851 pdata->b_wptr - pdata->b_rptr, 5852 &usb_dev_descr, 5853 sizeof (usb_dev_descr_t)); 5854 5855 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5856 "parsing device descriptor returned %lu", size); 5857 5858 /* 5859 * For now, free the data 5860 * eventually, each configuration may need to be looked at 5861 */ 5862 freemsg(pdata); 5863 pdata = NULL; 5864 5865 if (size != USB_DEV_DESCR_SIZE) { 5866 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5867 "fail enumeration: descriptor size=%lu " 5868 "expected size=%u", size, USB_DEV_DESCR_SIZE); 5869 5870 goto fail_cleanup; 5871 } 5872 5873 /* 5874 * save the device descriptor in usba_device since it is needed 5875 * later on again 5876 */ 5877 mutex_enter(&child_ud->usb_mutex); 5878 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5879 sizeof (usb_dev_descr_t)); 5880 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 5881 mutex_exit(&child_ud->usb_mutex); 5882 } 5883 5884 if (usb_dev_descr.bNumConfigurations == 0) { 5885 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5886 "device descriptor:\n\t" 5887 "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t" 5888 "protocol=0x%x maxpktsize=0x%x " 5889 "Vid=0x%x Pid=0x%x rel=0x%x\n\t" 5890 "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x", 5891 usb_dev_descr.bLength, usb_dev_descr.bDescriptorType, 5892 usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass, 5893 usb_dev_descr.bDeviceSubClass, 5894 usb_dev_descr.bDeviceProtocol, 5895 usb_dev_descr.bMaxPacketSize0, 5896 usb_dev_descr.idVendor, 5897 usb_dev_descr.idProduct, usb_dev_descr.bcdDevice, 5898 usb_dev_descr.iManufacturer, usb_dev_descr.iProduct, 5899 usb_dev_descr.iSerialNumber, 5900 usb_dev_descr.bNumConfigurations); 5901 goto fail_cleanup; 5902 } 5903 5904 5905 /* get the device string descriptor(s) */ 5906 usba_get_dev_string_descrs(child_dip, child_ud); 5907 5908 /* retrieve config cloud for all configurations */ 5909 rval = hubd_get_all_device_config_cloud(hubd, child_dip, child_ud); 5910 if (rval != USB_SUCCESS) { 5911 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5912 "failed to get configuration descriptor(s)"); 5913 5914 goto fail_cleanup; 5915 } 5916 5917 /* get the preferred configuration for this device */ 5918 user_conf_index = hubd_select_device_configuration(hubd, port, 5919 child_dip, child_ud); 5920 5921 /* Check if the user selected configuration index is in range */ 5922 if ((user_conf_index >= usb_dev_descr.bNumConfigurations) || 5923 (user_conf_index < 0)) { 5924 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 5925 "Configuration index for device idVendor=%d " 5926 "idProduct=%d is=%d, and is out of range[0..%d]", 5927 usb_dev_descr.idVendor, usb_dev_descr.idProduct, 5928 user_conf_index, usb_dev_descr.bNumConfigurations - 1); 5929 5930 /* treat this as user didn't specify configuration */ 5931 user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED; 5932 } 5933 5934 5935 /* 5936 * Warn users of a performance hit if connecting a 5937 * High Speed behind a 1.1 hub, which is behind a 5938 * 2.0 port. 5939 */ 5940 if ((parent_port_status != USBA_HIGH_SPEED_DEV) && 5941 !(usba_is_root_hub(parent_ud->usb_dip)) && 5942 (parent_usb_addr)) { 5943 5944 /* 5945 * Now that we know the root port is a high speed port 5946 * and that the parent port is not a high speed port, 5947 * let's find out if the device itself is a high speed 5948 * device. If it is a high speed device, 5949 * USB_DESCR_TYPE_SETUP_DEV_QLF should return a value, 5950 * otherwise the command will fail. 5951 */ 5952 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5953 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5954 USB_REQ_GET_DESCR, /* bRequest */ 5955 USB_DESCR_TYPE_SETUP_DEV_QLF, /* wValue */ 5956 0, /* wIndex */ 5957 10, /* wLength */ 5958 &pdata, USB_ATTRS_SHORT_XFER_OK, 5959 &completion_reason, &cb_flags, 0); 5960 5961 if (pdata) { 5962 freemsg(pdata); 5963 pdata = NULL; 5964 } 5965 5966 /* 5967 * USB_DESCR_TYPE_SETUP_DEV_QLF query was successful 5968 * that means this is a high speed device behind a 5969 * high speed root hub, but running at full speed 5970 * because there is a full speed hub in the middle. 5971 */ 5972 if (rval == USB_SUCCESS) { 5973 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, 5974 hubd->h_log_handle, 5975 "Connecting a high speed device to a " 5976 "non high speed hub (port %d) will result " 5977 "in a loss of performance. Please connect " 5978 "the device to a high speed hub to get " 5979 "the maximum performance.", 5980 port); 5981 } 5982 } 5983 5984 /* 5985 * Now we try to online the device by attaching a driver 5986 * The following truth table illustrates the logic:- 5987 * Cfgndx Driver Action 5988 * 0 0 loop all configs for driver with full 5989 * compatible properties. 5990 * 0 1 set first configuration, 5991 * compatible prop = drivername. 5992 * 1 0 Set config, full compatible prop 5993 * 1 1 Set config, compatible prop = drivername. 5994 * 5995 * Note: 5996 * cfgndx = user_conf_index 5997 * Driver = usb_preferred_driver 5998 */ 5999 if (user_conf_index == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 6000 if (child_ud->usb_preferred_driver) { 6001 /* 6002 * It is the job of the "preferred driver" to put the 6003 * device in the desired configuration. Till then 6004 * put the device in config index 0. 6005 */ 6006 if ((rval = usba_hubdi_check_power_budget(dip, child_ud, 6007 USB_DEV_DEFAULT_CONFIG_INDEX)) != USB_SUCCESS) { 6008 6009 goto fail_cleanup; 6010 } 6011 6012 child_dip = hubd_ready_device(hubd, child_dip, 6013 child_ud, USB_DEV_DEFAULT_CONFIG_INDEX); 6014 6015 /* 6016 * Assign the dip before onlining to avoid race 6017 * with busctl 6018 */ 6019 mutex_enter(HUBD_MUTEX(hubd)); 6020 hubd->h_children_dips[port] = child_dip; 6021 mutex_exit(HUBD_MUTEX(hubd)); 6022 6023 (void) usba_bind_driver(child_dip); 6024 } else { 6025 /* 6026 * loop through all the configurations to see if we 6027 * can find a driver for any one config. If not, set 6028 * the device in config_index 0 6029 */ 6030 rval = USB_FAILURE; 6031 for (config_index = 0; 6032 (config_index < usb_dev_descr.bNumConfigurations) && 6033 (rval != USB_SUCCESS); config_index++) { 6034 6035 child_dip = hubd_ready_device(hubd, child_dip, 6036 child_ud, config_index); 6037 6038 /* 6039 * Assign the dip before onlining to avoid race 6040 * with busctl 6041 */ 6042 mutex_enter(HUBD_MUTEX(hubd)); 6043 hubd->h_children_dips[port] = child_dip; 6044 mutex_exit(HUBD_MUTEX(hubd)); 6045 6046 rval = usba_bind_driver(child_dip); 6047 6048 /* 6049 * Normally power budget should be checked 6050 * before device is configured. A failure in 6051 * power budget checking will stop the device 6052 * from being configured with current 6053 * config_index and may enable the device to 6054 * be configured in another configuration. 6055 * This may break the user experience that a 6056 * device which previously worked in config 6057 * A now works in config B after power budget 6058 * control is enabled. To avoid such situation, 6059 * power budget checking is moved here and will 6060 * fail the child creation directly if config 6061 * A exceeds the power available. 6062 */ 6063 if (rval == USB_SUCCESS) { 6064 if ((usba_hubdi_check_power_budget(dip, 6065 child_ud, config_index)) != 6066 USB_SUCCESS) { 6067 6068 goto fail_cleanup; 6069 } 6070 } 6071 } 6072 if (rval != USB_SUCCESS) { 6073 6074 if ((usba_hubdi_check_power_budget(dip, 6075 child_ud, 0)) != USB_SUCCESS) { 6076 6077 goto fail_cleanup; 6078 } 6079 6080 child_dip = hubd_ready_device(hubd, child_dip, 6081 child_ud, 0); 6082 mutex_enter(HUBD_MUTEX(hubd)); 6083 hubd->h_children_dips[port] = child_dip; 6084 mutex_exit(HUBD_MUTEX(hubd)); 6085 } 6086 } /* end else loop all configs */ 6087 } else { 6088 6089 if ((usba_hubdi_check_power_budget(dip, child_ud, 6090 (uint_t)user_conf_index)) != USB_SUCCESS) { 6091 6092 goto fail_cleanup; 6093 } 6094 6095 child_dip = hubd_ready_device(hubd, child_dip, 6096 child_ud, (uint_t)user_conf_index); 6097 6098 /* 6099 * Assign the dip before onlining to avoid race 6100 * with busctl 6101 */ 6102 mutex_enter(HUBD_MUTEX(hubd)); 6103 hubd->h_children_dips[port] = child_dip; 6104 mutex_exit(HUBD_MUTEX(hubd)); 6105 6106 (void) usba_bind_driver(child_dip); 6107 } 6108 6109 usba_hubdi_decr_power_budget(dip, child_ud); 6110 6111 mutex_enter(HUBD_MUTEX(hubd)); 6112 if (hubd->h_usba_devices[port] == NULL) { 6113 hubd->h_usba_devices[port] = usba_get_usba_device(child_dip); 6114 } else { 6115 ASSERT(hubd->h_usba_devices[port] == 6116 usba_get_usba_device(child_dip)); 6117 } 6118 6119 return (USB_SUCCESS); 6120 6121 6122 fail_cleanup: 6123 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6124 "hubd_create_child: fail_cleanup"); 6125 6126 mutex_enter(HUBD_MUTEX(hubd)); 6127 hubd->h_children_dips[port] = NULL; 6128 mutex_exit(HUBD_MUTEX(hubd)); 6129 6130 if (pdata) { 6131 freemsg(pdata); 6132 } 6133 6134 if (ph) { 6135 usb_pipe_close(child_dip, ph, 6136 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 6137 } 6138 6139 if (child_dip) { 6140 int rval = usba_destroy_child_devi(child_dip, 6141 NDI_DEVI_REMOVE); 6142 if (rval != USB_SUCCESS) { 6143 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6144 "failure to remove child node"); 6145 } 6146 } 6147 6148 if (child_ud) { 6149 /* to make sure we free the address */ 6150 mutex_enter(&child_ud->usb_mutex); 6151 child_ud->usb_addr = address; 6152 ASSERT(child_ud->usb_ref_count == 0); 6153 mutex_exit(&child_ud->usb_mutex); 6154 6155 mutex_enter(HUBD_MUTEX(hubd)); 6156 if (hubd->h_usba_devices[port] == NULL) { 6157 mutex_exit(HUBD_MUTEX(hubd)); 6158 usba_free_usba_device(child_ud); 6159 } else { 6160 hubd_free_usba_device(hubd, hubd->h_usba_devices[port]); 6161 mutex_exit(HUBD_MUTEX(hubd)); 6162 } 6163 } 6164 6165 mutex_enter(HUBD_MUTEX(hubd)); 6166 6167 return (USB_FAILURE); 6168 } 6169 6170 6171 /* 6172 * hubd_delete_child: 6173 * - free usb address 6174 * - lookup child dips, there may be multiple on this port 6175 * - offline each child devi 6176 */ 6177 static int 6178 hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, boolean_t retry) 6179 { 6180 dev_info_t *child_dip; 6181 usba_device_t *usba_device; 6182 int rval = USB_SUCCESS; 6183 6184 child_dip = hubd->h_children_dips[port]; 6185 usba_device = hubd->h_usba_devices[port]; 6186 6187 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6188 "hubd_delete_child: port=%d, dip=0x%p usba_device=0x%p", 6189 port, child_dip, usba_device); 6190 6191 mutex_exit(HUBD_MUTEX(hubd)); 6192 if (child_dip) { 6193 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6194 "hubd_delete_child:\n\t" 6195 "dip = 0x%p (%s) at port %d", 6196 child_dip, ddi_node_name(child_dip), port); 6197 6198 if (usba_device) { 6199 usba_hubdi_incr_power_budget(hubd->h_dip, usba_device); 6200 } 6201 6202 rval = usba_destroy_child_devi(child_dip, flag); 6203 6204 if ((rval == USB_SUCCESS) && (flag & NDI_DEVI_REMOVE)) { 6205 /* 6206 * if the child was still < DS_INITIALIZED 6207 * then our bus_unconfig was not called and 6208 * we have to zap the child here 6209 */ 6210 mutex_enter(HUBD_MUTEX(hubd)); 6211 if (hubd->h_children_dips[port] == child_dip) { 6212 usba_device_t *ud = 6213 hubd->h_usba_devices[port]; 6214 hubd->h_children_dips[port] = NULL; 6215 if (ud) { 6216 mutex_exit(HUBD_MUTEX(hubd)); 6217 6218 mutex_enter(&ud->usb_mutex); 6219 ud->usb_ref_count = 0; 6220 mutex_exit(&ud->usb_mutex); 6221 6222 usba_free_usba_device(ud); 6223 mutex_enter(HUBD_MUTEX(hubd)); 6224 hubd->h_usba_devices[port] = NULL; 6225 } 6226 } 6227 mutex_exit(HUBD_MUTEX(hubd)); 6228 } 6229 } 6230 6231 if ((rval != USB_SUCCESS) && retry) { 6232 6233 hubd_schedule_cleanup(usba_device->usb_root_hub_dip); 6234 } 6235 mutex_enter(HUBD_MUTEX(hubd)); 6236 6237 return (rval); 6238 } 6239 6240 6241 /* 6242 * hubd_free_usba_device: 6243 * free usb device structure unless it is associated with 6244 * the root hub which is handled differently 6245 */ 6246 static void 6247 hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device) 6248 { 6249 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6250 "hubd_free_usba_device: hubd=0x%p, usba_device=0x%p", 6251 hubd, usba_device); 6252 6253 if (usba_device && (usba_device->usb_addr != ROOT_HUB_ADDR)) { 6254 usb_port_t port = usba_device->usb_port; 6255 dev_info_t *dip = hubd->h_children_dips[port]; 6256 6257 #ifdef DEBUG 6258 if (dip) { 6259 ASSERT(i_ddi_node_state(dip) < DS_INITIALIZED); 6260 } 6261 #endif 6262 6263 port = usba_device->usb_port; 6264 hubd->h_usba_devices[port] = NULL; 6265 6266 mutex_exit(HUBD_MUTEX(hubd)); 6267 usba_free_usba_device(usba_device); 6268 mutex_enter(HUBD_MUTEX(hubd)); 6269 } 6270 } 6271 6272 6273 /* 6274 * event support 6275 * 6276 * busctl event support 6277 */ 6278 static int 6279 hubd_busop_get_eventcookie(dev_info_t *dip, 6280 dev_info_t *rdip, 6281 char *eventname, 6282 ddi_eventcookie_t *cookie) 6283 { 6284 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6285 6286 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6287 "hubd_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 6288 "event=%s", (void *)dip, (void *)rdip, eventname); 6289 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6290 "(dip=%s%d, rdip=%s%d)", 6291 ddi_driver_name(dip), ddi_get_instance(dip), 6292 ddi_driver_name(rdip), ddi_get_instance(rdip)); 6293 6294 /* return event cookie, iblock cookie, and level */ 6295 return (ndi_event_retrieve_cookie(hubd->h_ndi_event_hdl, 6296 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 6297 } 6298 6299 6300 static int 6301 hubd_busop_add_eventcall(dev_info_t *dip, 6302 dev_info_t *rdip, 6303 ddi_eventcookie_t cookie, 6304 void (*callback)(dev_info_t *dip, 6305 ddi_eventcookie_t cookie, void *arg, 6306 void *bus_impldata), 6307 void *arg, ddi_callback_id_t *cb_id) 6308 { 6309 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6310 usb_port_t port = hubd_child_dip2port(hubd, rdip); 6311 6312 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6313 "hubd_busop_add_eventcall: dip=0x%p, rdip=0x%p " 6314 "cookie=0x%p, cb=0x%p, arg=0x%p", 6315 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 6316 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6317 "(dip=%s%d, rdip=%s%d, event=%s)", 6318 ddi_driver_name(dip), ddi_get_instance(dip), 6319 ddi_driver_name(rdip), ddi_get_instance(rdip), 6320 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, cookie)); 6321 6322 /* Set flag on children registering events */ 6323 switch (ndi_event_cookie_to_tag(hubd->h_ndi_event_hdl, cookie)) { 6324 case USBA_EVENT_TAG_HOT_REMOVAL: 6325 mutex_enter(HUBD_MUTEX(hubd)); 6326 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6327 mutex_exit(HUBD_MUTEX(hubd)); 6328 6329 break; 6330 case USBA_EVENT_TAG_PRE_SUSPEND: 6331 mutex_enter(HUBD_MUTEX(hubd)); 6332 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6333 mutex_exit(HUBD_MUTEX(hubd)); 6334 6335 break; 6336 default: 6337 6338 break; 6339 } 6340 6341 /* add callback to our event set */ 6342 return (ndi_event_add_callback(hubd->h_ndi_event_hdl, 6343 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 6344 } 6345 6346 6347 static int 6348 hubd_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 6349 { 6350 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6351 ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id; 6352 6353 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6354 "hubd_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 6355 "cookie=0x%p", (void *)dip, id->ndi_evtcb_dip, 6356 id->ndi_evtcb_cookie); 6357 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6358 "(dip=%s%d, rdip=%s%d, event=%s)", 6359 ddi_driver_name(dip), ddi_get_instance(dip), 6360 ddi_driver_name(id->ndi_evtcb_dip), 6361 ddi_get_instance(id->ndi_evtcb_dip), 6362 ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, 6363 id->ndi_evtcb_cookie)); 6364 6365 /* remove event registration from our event set */ 6366 return (ndi_event_remove_callback(hubd->h_ndi_event_hdl, cb_id)); 6367 } 6368 6369 6370 /* 6371 * event distribution 6372 * 6373 * hubd_do_callback: 6374 * Post this event to the specified child 6375 */ 6376 static void 6377 hubd_do_callback(hubd_t *hubd, dev_info_t *cdip, ddi_eventcookie_t cookie) 6378 { 6379 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6380 "hubd_do_callback"); 6381 6382 (void) ndi_event_do_callback(hubd->h_ndi_event_hdl, cdip, cookie, NULL); 6383 } 6384 6385 6386 /* 6387 * hubd_run_callbacks: 6388 * Send this event to all children 6389 */ 6390 static void 6391 hubd_run_callbacks(hubd_t *hubd, usba_event_t type) 6392 { 6393 usb_port_t port; 6394 6395 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6396 "hubd_run_callbacks"); 6397 6398 mutex_enter(HUBD_MUTEX(hubd)); 6399 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) { 6400 /* 6401 * the childen_dips list may have dips that have been 6402 * already deallocated. we only get a post_detach notification 6403 * but not a destroy notification 6404 */ 6405 if (hubd->h_children_dips[port]) { 6406 mutex_exit(HUBD_MUTEX(hubd)); 6407 hubd_post_event(hubd, port, type); 6408 mutex_enter(HUBD_MUTEX(hubd)); 6409 } 6410 } 6411 mutex_exit(HUBD_MUTEX(hubd)); 6412 } 6413 6414 6415 /* 6416 * hubd_post_event 6417 * post event to a child on the port depending on the type 6418 */ 6419 static void 6420 hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type) 6421 { 6422 int rval; 6423 dev_info_t *dip; 6424 usba_device_t *usba_device; 6425 ddi_eventcookie_t cookie, rm_cookie, suspend_cookie; 6426 6427 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6428 "hubd_post_event: port=%d event=%s", port, 6429 ndi_event_tag_to_name(hubd->h_ndi_event_hdl, type)); 6430 6431 cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, type); 6432 rm_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6433 USBA_EVENT_TAG_HOT_REMOVAL); 6434 suspend_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, 6435 USBA_EVENT_TAG_PRE_SUSPEND); 6436 6437 /* 6438 * Hotplug daemon may be attaching a driver that may be registering 6439 * event callbacks. So it already has got the device tree lock and 6440 * event handle mutex. So to prevent a deadlock while posting events, 6441 * we grab and release the locks in the same order. 6442 */ 6443 mutex_enter(HUBD_MUTEX(hubd)); 6444 dip = hubd->h_children_dips[port]; 6445 usba_device = hubd->h_usba_devices[port]; 6446 mutex_exit(HUBD_MUTEX(hubd)); 6447 6448 switch (type) { 6449 case USBA_EVENT_TAG_HOT_REMOVAL: 6450 /* Clear the registered event flag */ 6451 mutex_enter(HUBD_MUTEX(hubd)); 6452 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_DISCONNECT; 6453 mutex_exit(HUBD_MUTEX(hubd)); 6454 6455 hubd_do_callback(hubd, dip, cookie); 6456 usba_persistent_pipe_close(usba_device); 6457 6458 /* 6459 * Mark the dip for deletion only after the driver has 6460 * seen the disconnect event to prevent cleanup thread 6461 * from stepping in between. 6462 */ 6463 mutex_enter(&(DEVI(dip)->devi_lock)); 6464 DEVI_SET_DEVICE_REMOVED(dip); 6465 mutex_exit(&(DEVI(dip)->devi_lock)); 6466 6467 break; 6468 case USBA_EVENT_TAG_PRE_SUSPEND: 6469 mutex_enter(HUBD_MUTEX(hubd)); 6470 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_PRESUSPEND; 6471 mutex_exit(HUBD_MUTEX(hubd)); 6472 6473 hubd_do_callback(hubd, dip, cookie); 6474 /* 6475 * persistent pipe close for this event is taken care by the 6476 * caller after verfying that all children can suspend 6477 */ 6478 6479 break; 6480 case USBA_EVENT_TAG_HOT_INSERTION: 6481 /* 6482 * Check if this child has missed the disconnect event before 6483 * it registered for event callbacks 6484 */ 6485 mutex_enter(HUBD_MUTEX(hubd)); 6486 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_DISCONNECT) { 6487 /* clear the flag and post disconnect event */ 6488 hubd->h_child_events[port] &= 6489 ~HUBD_CHILD_EVENT_DISCONNECT; 6490 mutex_exit(HUBD_MUTEX(hubd)); 6491 hubd_do_callback(hubd, dip, rm_cookie); 6492 usba_persistent_pipe_close(usba_device); 6493 mutex_enter(HUBD_MUTEX(hubd)); 6494 } 6495 mutex_exit(HUBD_MUTEX(hubd)); 6496 6497 /* 6498 * Mark the dip as reinserted to prevent cleanup thread 6499 * from stepping in. 6500 */ 6501 mutex_enter(&(DEVI(dip)->devi_lock)); 6502 DEVI_SET_DEVICE_REINSERTED(dip); 6503 mutex_exit(&(DEVI(dip)->devi_lock)); 6504 6505 rval = usba_persistent_pipe_open(usba_device); 6506 if (rval != USB_SUCCESS) { 6507 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6508 hubd->h_log_handle, 6509 "failed to reopen all pipes on reconnect"); 6510 } 6511 6512 hubd_do_callback(hubd, dip, cookie); 6513 6514 /* 6515 * We might see a connect event only if hotplug thread for 6516 * disconnect event don't run in time. 6517 * Set the flag again, so we don't miss posting a 6518 * disconnect event. 6519 */ 6520 mutex_enter(HUBD_MUTEX(hubd)); 6521 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT; 6522 mutex_exit(HUBD_MUTEX(hubd)); 6523 6524 break; 6525 case USBA_EVENT_TAG_POST_RESUME: 6526 /* 6527 * Check if this child has missed the pre-suspend event before 6528 * it registered for event callbacks 6529 */ 6530 mutex_enter(HUBD_MUTEX(hubd)); 6531 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_PRESUSPEND) { 6532 /* clear the flag and post pre_suspend event */ 6533 hubd->h_port_state[port] &= 6534 ~HUBD_CHILD_EVENT_PRESUSPEND; 6535 mutex_exit(HUBD_MUTEX(hubd)); 6536 hubd_do_callback(hubd, dip, suspend_cookie); 6537 mutex_enter(HUBD_MUTEX(hubd)); 6538 } 6539 mutex_exit(HUBD_MUTEX(hubd)); 6540 6541 mutex_enter(&usba_device->usb_mutex); 6542 usba_device->usb_no_cpr = 0; 6543 mutex_exit(&usba_device->usb_mutex); 6544 6545 /* 6546 * Since the pipe has already been opened by hub 6547 * at DDI_RESUME time, there is no need for a 6548 * persistent pipe open 6549 */ 6550 hubd_do_callback(hubd, dip, cookie); 6551 6552 /* 6553 * Set the flag again, so we don't miss posting a 6554 * pre-suspend event. This enforces a tighter 6555 * dev_state model. 6556 */ 6557 mutex_enter(HUBD_MUTEX(hubd)); 6558 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND; 6559 mutex_exit(HUBD_MUTEX(hubd)); 6560 break; 6561 } 6562 } 6563 6564 6565 /* 6566 * handling of events coming from above 6567 */ 6568 static int 6569 hubd_disconnect_event_cb(dev_info_t *dip) 6570 { 6571 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6572 usb_port_t port, nports; 6573 usba_device_t *usba_dev; 6574 usba_event_t tag = USBA_EVENT_TAG_HOT_REMOVAL; 6575 int circ; 6576 6577 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6578 "hubd_disconnect_event_cb: tag=%d", tag); 6579 6580 ndi_devi_enter(dip, &circ); 6581 6582 mutex_enter(HUBD_MUTEX(hubd)); 6583 switch (hubd->h_dev_state) { 6584 case USB_DEV_ONLINE: 6585 case USB_DEV_PWRED_DOWN: 6586 hubd->h_dev_state = USB_DEV_DISCONNECTED; 6587 /* stop polling on the interrupt pipe */ 6588 hubd_stop_polling(hubd); 6589 6590 /* FALLTHROUGH */ 6591 case USB_DEV_SUSPENDED: 6592 /* we remain in this state */ 6593 mutex_exit(HUBD_MUTEX(hubd)); 6594 hubd_run_callbacks(hubd, tag); 6595 mutex_enter(HUBD_MUTEX(hubd)); 6596 6597 /* close all the open pipes of our children */ 6598 nports = hubd->h_hub_descr.bNbrPorts; 6599 for (port = 1; port <= nports; port++) { 6600 usba_dev = hubd->h_usba_devices[port]; 6601 if (usba_dev != NULL) { 6602 mutex_exit(HUBD_MUTEX(hubd)); 6603 usba_persistent_pipe_close(usba_dev); 6604 mutex_enter(HUBD_MUTEX(hubd)); 6605 } 6606 } 6607 6608 break; 6609 case USB_DEV_DISCONNECTED: 6610 /* avoid passing multiple disconnects to children */ 6611 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6612 "hubd_disconnect_event_cb: Already disconnected"); 6613 6614 break; 6615 default: 6616 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6617 "hubd_disconnect_event_cb: Illegal devstate=%d", 6618 hubd->h_dev_state); 6619 6620 break; 6621 } 6622 mutex_exit(HUBD_MUTEX(hubd)); 6623 6624 ndi_devi_exit(dip, circ); 6625 6626 return (USB_SUCCESS); 6627 } 6628 6629 6630 static int 6631 hubd_reconnect_event_cb(dev_info_t *dip) 6632 { 6633 int rval, circ; 6634 6635 ndi_devi_enter(dip, &circ); 6636 rval = hubd_restore_state_cb(dip); 6637 ndi_devi_exit(dip, circ); 6638 6639 return (rval); 6640 } 6641 6642 6643 /* 6644 * hubd_pre_suspend_event_cb 6645 * propogate event for binary compatibility of old drivers 6646 */ 6647 static int 6648 hubd_pre_suspend_event_cb(dev_info_t *dip) 6649 { 6650 int circ; 6651 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6652 6653 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6654 "hubd_pre_suspend_event_cb"); 6655 6656 /* disable hotplug thread */ 6657 mutex_enter(HUBD_MUTEX(hubd)); 6658 hubd->h_hotplug_thread++; 6659 hubd_stop_polling(hubd); 6660 6661 /* keep PM out till we see a cpr resume */ 6662 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6663 mutex_exit(HUBD_MUTEX(hubd)); 6664 6665 ndi_devi_enter(dip, &circ); 6666 hubd_run_callbacks(hubd, USBA_EVENT_TAG_PRE_SUSPEND); 6667 ndi_devi_exit(dip, circ); 6668 6669 return (USB_SUCCESS); 6670 } 6671 6672 6673 /* 6674 * hubd_post_resume_event_cb 6675 * propogate event for binary compatibility of old drivers 6676 */ 6677 static int 6678 hubd_post_resume_event_cb(dev_info_t *dip) 6679 { 6680 int circ; 6681 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6682 6683 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6684 "hubd_post_resume_event_cb"); 6685 6686 ndi_devi_enter(dip, &circ); 6687 hubd_run_callbacks(hubd, USBA_EVENT_TAG_POST_RESUME); 6688 ndi_devi_exit(dip, circ); 6689 6690 mutex_enter(HUBD_MUTEX(hubd)); 6691 6692 /* enable PM */ 6693 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6694 6695 /* allow hotplug thread */ 6696 hubd->h_hotplug_thread--; 6697 6698 /* start polling */ 6699 hubd_start_polling(hubd, 0); 6700 mutex_exit(HUBD_MUTEX(hubd)); 6701 6702 return (USB_SUCCESS); 6703 } 6704 6705 6706 /* 6707 * hubd_cpr_suspend 6708 * save the current state of the driver/device 6709 */ 6710 static int 6711 hubd_cpr_suspend(hubd_t *hubd) 6712 { 6713 usb_port_t port, nports; 6714 usba_device_t *usba_dev; 6715 uchar_t no_cpr = 0; 6716 int rval = USB_FAILURE; 6717 6718 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6719 "hubd_cpr_suspend: Begin"); 6720 6721 /* Make sure device is powered up to save state. */ 6722 mutex_enter(HUBD_MUTEX(hubd)); 6723 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 6724 mutex_exit(HUBD_MUTEX(hubd)); 6725 6726 /* bring the device to full power */ 6727 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 6728 mutex_enter(HUBD_MUTEX(hubd)); 6729 6730 switch (hubd->h_dev_state) { 6731 case USB_DEV_ONLINE: 6732 case USB_DEV_PWRED_DOWN: 6733 case USB_DEV_DISCONNECTED: 6734 /* find out if all our children have been quiesced */ 6735 nports = hubd->h_hub_descr.bNbrPorts; 6736 for (port = 1; (no_cpr == 0) && (port <= nports); port++) { 6737 usba_dev = hubd->h_usba_devices[port]; 6738 if (usba_dev != NULL) { 6739 mutex_enter(&usba_dev->usb_mutex); 6740 no_cpr += usba_dev->usb_no_cpr; 6741 mutex_exit(&usba_dev->usb_mutex); 6742 } 6743 } 6744 if (no_cpr > 0) { 6745 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6746 "Children busy - can't checkpoint"); 6747 /* remain in same state to fail checkpoint */ 6748 6749 break; 6750 } else { 6751 /* 6752 * do not suspend if our hotplug thread 6753 * or the deathrow thread is active 6754 */ 6755 if ((hubd->h_hotplug_thread > 1) || 6756 (hubd->h_cleanup_active == B_TRUE)) { 6757 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, 6758 hubd->h_log_handle, 6759 "hotplug thread active - can't cpr"); 6760 /* remain in same state to fail checkpoint */ 6761 6762 break; 6763 } 6764 6765 /* quiesce ourselves now */ 6766 hubd->h_dev_state = USB_DEV_SUSPENDED; 6767 hubd_stop_polling(hubd); 6768 6769 /* close all the open pipes of our children */ 6770 for (port = 1; port <= nports; port++) { 6771 usba_dev = hubd->h_usba_devices[port]; 6772 if (usba_dev != NULL) { 6773 mutex_exit(HUBD_MUTEX(hubd)); 6774 usba_persistent_pipe_close(usba_dev); 6775 mutex_enter(HUBD_MUTEX(hubd)); 6776 } 6777 } 6778 /* 6779 * turn off power to all the ports so that we 6780 * don't see any spurious activity 6781 */ 6782 (void) hubd_disable_all_port_power(hubd); 6783 6784 /* 6785 * if we are the root hub, we close our pipes 6786 * ourselves. 6787 */ 6788 if (usba_is_root_hub(hubd->h_dip)) { 6789 mutex_exit(HUBD_MUTEX(hubd)); 6790 usba_persistent_pipe_close( 6791 usba_get_usba_device(hubd->h_dip)); 6792 mutex_enter(HUBD_MUTEX(hubd)); 6793 } 6794 rval = USB_SUCCESS; 6795 6796 break; 6797 } 6798 case USB_DEV_SUSPENDED: 6799 default: 6800 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6801 "hubd_cpr_suspend: Illegal dev state=%d", 6802 hubd->h_dev_state); 6803 6804 break; 6805 } 6806 6807 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 6808 mutex_exit(HUBD_MUTEX(hubd)); 6809 6810 return (rval); 6811 } 6812 6813 static void 6814 hubd_cpr_resume(dev_info_t *dip) 6815 { 6816 int rval, circ; 6817 6818 ndi_devi_enter(dip, &circ); 6819 /* 6820 * if we are the root hub, we open our pipes 6821 * ourselves. 6822 */ 6823 if (usba_is_root_hub(dip)) { 6824 rval = usba_persistent_pipe_open( 6825 usba_get_usba_device(dip)); 6826 ASSERT(rval == USB_SUCCESS); 6827 } 6828 (void) hubd_restore_state_cb(dip); 6829 ndi_devi_exit(dip, circ); 6830 } 6831 6832 6833 /* 6834 * hubd_restore_state_cb 6835 * Event callback to restore device state 6836 */ 6837 static int 6838 hubd_restore_state_cb(dev_info_t *dip) 6839 { 6840 hubd_t *hubd = (hubd_t *)hubd_get_soft_state(dip); 6841 6842 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 6843 "hubd_restore_state_cb: Begin"); 6844 6845 /* restore the state of this device */ 6846 hubd_restore_device_state(dip, hubd); 6847 6848 return (USB_SUCCESS); 6849 } 6850 6851 6852 /* 6853 * registering for events 6854 */ 6855 static int 6856 hubd_register_events(hubd_t *hubd) 6857 { 6858 int rval = USB_SUCCESS; 6859 6860 if (usba_is_root_hub(hubd->h_dip)) { 6861 hubd_register_cpr_callback(hubd); 6862 } else { 6863 rval = usb_register_event_cbs(hubd->h_dip, &hubd_events, 0); 6864 } 6865 6866 return (rval); 6867 } 6868 6869 6870 /* 6871 * hubd cpr callback related functions 6872 * 6873 * hubd_cpr_post_user_callb: 6874 * This function is called during checkpoint & resume - 6875 * 1. after user threads are stopped during checkpoint 6876 * 2. after kernel threads are resumed during resume 6877 */ 6878 /* ARGSUSED */ 6879 static boolean_t 6880 hubd_cpr_post_user_callb(void *arg, int code) 6881 { 6882 hubd_cpr_t *cpr_cb = (hubd_cpr_t *)arg; 6883 hubd_t *hubd = cpr_cb->statep; 6884 int retry = 0; 6885 6886 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6887 "hubd_cpr_post_user_callb"); 6888 6889 switch (code) { 6890 case CB_CODE_CPR_CHKPT: 6891 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6892 "hubd_cpr_post_user_callb: CB_CODE_CPR_CHKPT"); 6893 6894 mutex_enter(HUBD_MUTEX(hubd)); 6895 6896 /* turn off deathrow thread */ 6897 hubd->h_cleanup_enabled = B_FALSE; 6898 6899 /* give up if deathrow thread doesn't exit */ 6900 while ((hubd->h_cleanup_active == B_TRUE) && (retry++ < 3)) { 6901 mutex_exit(HUBD_MUTEX(hubd)); 6902 delay(drv_usectohz(hubd_dip_cleanup_delay)); 6903 6904 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6905 "hubd_cpr_post_user_callb, waiting for " 6906 "deathrow thread to exit"); 6907 mutex_enter(HUBD_MUTEX(hubd)); 6908 } 6909 6910 mutex_exit(HUBD_MUTEX(hubd)); 6911 6912 /* save the state of the device */ 6913 (void) hubd_pre_suspend_event_cb(hubd->h_dip); 6914 6915 return (B_TRUE); 6916 case CB_CODE_CPR_RESUME: 6917 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6918 "hubd_cpr_post_user_callb: CB_CODE_CPR_RESUME"); 6919 6920 /* restore the state of the device */ 6921 (void) hubd_post_resume_event_cb(hubd->h_dip); 6922 6923 /* turn on deathrow thread */ 6924 mutex_enter(HUBD_MUTEX(hubd)); 6925 hubd->h_cleanup_enabled = B_TRUE; 6926 mutex_exit(HUBD_MUTEX(hubd)); 6927 6928 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip); 6929 6930 return (B_TRUE); 6931 default: 6932 6933 return (B_FALSE); 6934 } 6935 6936 } 6937 6938 6939 /* register callback with cpr framework */ 6940 void 6941 hubd_register_cpr_callback(hubd_t *hubd) 6942 { 6943 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6944 "hubd_register_cpr_callback"); 6945 6946 mutex_enter(HUBD_MUTEX(hubd)); 6947 hubd->h_cpr_cb = 6948 (hubd_cpr_t *)kmem_zalloc(sizeof (hubd_cpr_t), KM_SLEEP); 6949 mutex_exit(HUBD_MUTEX(hubd)); 6950 mutex_init(&hubd->h_cpr_cb->lockp, NULL, MUTEX_DRIVER, 6951 hubd->h_dev_data->dev_iblock_cookie); 6952 hubd->h_cpr_cb->statep = hubd; 6953 hubd->h_cpr_cb->cpr.cc_lockp = &hubd->h_cpr_cb->lockp; 6954 hubd->h_cpr_cb->cpr.cc_id = callb_add(hubd_cpr_post_user_callb, 6955 (void *)hubd->h_cpr_cb, CB_CL_CPR_POST_USER, "hubd"); 6956 } 6957 6958 6959 /* unregister callback with cpr framework */ 6960 void 6961 hubd_unregister_cpr_callback(hubd_t *hubd) 6962 { 6963 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle, 6964 "hubd_unregister_cpr_callback"); 6965 6966 if (hubd->h_cpr_cb) { 6967 (void) callb_delete(hubd->h_cpr_cb->cpr.cc_id); 6968 mutex_destroy(&hubd->h_cpr_cb->lockp); 6969 mutex_enter(HUBD_MUTEX(hubd)); 6970 kmem_free(hubd->h_cpr_cb, sizeof (hubd_cpr_t)); 6971 mutex_exit(HUBD_MUTEX(hubd)); 6972 } 6973 } 6974 6975 6976 /* 6977 * Power management 6978 * 6979 * create the pm components required for power management 6980 */ 6981 static void 6982 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd) 6983 { 6984 hub_power_t *hubpm; 6985 6986 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 6987 "hubd_create_pm_components: Begin"); 6988 6989 /* Allocate the state structure */ 6990 hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP); 6991 6992 hubd->h_hubpm = hubpm; 6993 hubpm->hubp_hubd = hubd; 6994 hubpm->hubp_pm_capabilities = 0; 6995 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR; 6996 hubpm->hubp_time_at_full_power = ddi_get_time(); 6997 hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold; 6998 6999 /* alloc memory to save power states of children */ 7000 hubpm->hubp_child_pwrstate = (uint8_t *) 7001 kmem_zalloc(MAX_PORTS + 1, KM_SLEEP); 7002 7003 /* 7004 * if the enable remote wakeup fails 7005 * we still want to enable 7006 * parent notification so we can PM the children 7007 */ 7008 usb_enable_parent_notification(dip); 7009 7010 if (usb_handle_remote_wakeup(dip, 7011 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 7012 uint_t pwr_states; 7013 7014 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, 7015 "hubd_create_pm_components: " 7016 "Remote Wakeup Enabled"); 7017 7018 if (usb_create_pm_components(dip, &pwr_states) == 7019 USB_SUCCESS) { 7020 mutex_enter(HUBD_MUTEX(hubd)); 7021 hubpm->hubp_wakeup_enabled = 1; 7022 hubpm->hubp_pwr_states = (uint8_t)pwr_states; 7023 7024 /* we are busy now till end of the attach */ 7025 hubd_pm_busy_component(hubd, dip, 0); 7026 mutex_exit(HUBD_MUTEX(hubd)); 7027 7028 /* bring the device to full power */ 7029 (void) pm_raise_power(dip, 0, 7030 USB_DEV_OS_FULL_PWR); 7031 } 7032 } 7033 7034 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle, 7035 "hubd_create_pm_components: END"); 7036 } 7037 7038 7039 /* 7040 * Attachment point management 7041 */ 7042 /* ARGSUSED */ 7043 int 7044 usba_hubdi_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, 7045 cred_t *credp) 7046 { 7047 hubd_t *hubd; 7048 7049 if (otyp != OTYP_CHR) 7050 return (EINVAL); 7051 7052 hubd = hubd_get_soft_state(dip); 7053 if (hubd == NULL) { 7054 return (ENXIO); 7055 } 7056 7057 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7058 "hubd_open:"); 7059 7060 mutex_enter(HUBD_MUTEX(hubd)); 7061 if ((flags & FEXCL) && (hubd->h_softstate & HUBD_SS_ISOPEN)) { 7062 mutex_exit(HUBD_MUTEX(hubd)); 7063 7064 return (EBUSY); 7065 } 7066 7067 hubd->h_softstate |= HUBD_SS_ISOPEN; 7068 mutex_exit(HUBD_MUTEX(hubd)); 7069 7070 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "opened"); 7071 7072 return (0); 7073 } 7074 7075 7076 /* ARGSUSED */ 7077 int 7078 usba_hubdi_close(dev_info_t *dip, dev_t dev, int flag, int otyp, 7079 cred_t *credp) 7080 { 7081 hubd_t *hubd; 7082 7083 if (otyp != OTYP_CHR) { 7084 return (EINVAL); 7085 } 7086 7087 hubd = hubd_get_soft_state(dip); 7088 7089 if (hubd == NULL) { 7090 return (ENXIO); 7091 } 7092 7093 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "hubd_close:"); 7094 7095 mutex_enter(HUBD_MUTEX(hubd)); 7096 hubd->h_softstate &= ~HUBD_SS_ISOPEN; 7097 mutex_exit(HUBD_MUTEX(hubd)); 7098 7099 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "closed"); 7100 7101 return (0); 7102 } 7103 7104 7105 /* 7106 * hubd_ioctl: cfgadm controls 7107 */ 7108 /* ARGSUSED */ 7109 int 7110 usba_hubdi_ioctl(dev_info_t *self, dev_t dev, int cmd, intptr_t arg, 7111 int mode, cred_t *credp, int *rvalp) 7112 { 7113 int rv = 0; 7114 char *msg; /* for messages */ 7115 hubd_t *hubd; 7116 usb_port_t port = 0; 7117 dev_info_t *child_dip = NULL; 7118 dev_info_t *rh_dip; 7119 devctl_ap_state_t ap_state; 7120 struct devctl_iocdata *dcp = NULL; 7121 usb_pipe_state_t prev_pipe_state = 0; 7122 int circ, rh_circ, prh_circ; 7123 7124 if ((hubd = hubd_get_soft_state(self)) == NULL) { 7125 7126 return (ENXIO); 7127 } 7128 7129 rh_dip = hubd->h_usba_device->usb_root_hub_dip; 7130 7131 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7132 "usba_hubdi_ioctl: " 7133 "cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx", 7134 cmd, arg, mode, credp, rvalp, dev); 7135 7136 /* read devctl ioctl data */ 7137 if ((cmd != DEVCTL_AP_CONTROL) && 7138 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 7139 7140 return (EFAULT); 7141 } 7142 7143 /* 7144 * make sure the hub is connected before trying any 7145 * of the following operations: 7146 * configure, connect, disconnect 7147 */ 7148 mutex_enter(HUBD_MUTEX(hubd)); 7149 7150 switch (cmd) { 7151 case DEVCTL_AP_DISCONNECT: 7152 case DEVCTL_AP_UNCONFIGURE: 7153 case DEVCTL_AP_CONFIGURE: 7154 if (hubd->h_dev_state == USB_DEV_DISCONNECTED) { 7155 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7156 "hubd: already gone"); 7157 mutex_exit(HUBD_MUTEX(hubd)); 7158 if (dcp) { 7159 ndi_dc_freehdl(dcp); 7160 } 7161 7162 return (EIO); 7163 } 7164 7165 /* FALLTHROUGH */ 7166 case DEVCTL_AP_GETSTATE: 7167 if ((port = hubd_get_port_num(hubd, dcp)) == 0) { 7168 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 7169 "hubd: bad port"); 7170 mutex_exit(HUBD_MUTEX(hubd)); 7171 if (dcp) { 7172 ndi_dc_freehdl(dcp); 7173 } 7174 7175 return (EINVAL); 7176 } 7177 break; 7178 7179 case DEVCTL_AP_CONTROL: 7180 7181 break; 7182 default: 7183 mutex_exit(HUBD_MUTEX(hubd)); 7184 if (dcp) { 7185 ndi_dc_freehdl(dcp); 7186 } 7187 7188 return (ENOTTY); 7189 } 7190 7191 /* should not happen, just in case */ 7192 if (hubd->h_dev_state == USB_DEV_SUSPENDED) { 7193 mutex_exit(HUBD_MUTEX(hubd)); 7194 if (dcp) { 7195 ndi_dc_freehdl(dcp); 7196 } 7197 7198 return (EIO); 7199 } 7200 7201 hubd_pm_busy_component(hubd, hubd->h_dip, 0); 7202 mutex_exit(HUBD_MUTEX(hubd)); 7203 7204 /* go full power */ 7205 (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR); 7206 7207 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 7208 ndi_devi_enter(rh_dip, &rh_circ); 7209 ndi_devi_enter(hubd->h_dip, &circ); 7210 7211 mutex_enter(HUBD_MUTEX(hubd)); 7212 7213 /* stop polling iff it was active */ 7214 if (hubd->h_ep1_ph) { 7215 mutex_exit(HUBD_MUTEX(hubd)); 7216 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state, 7217 USB_FLAGS_SLEEP); 7218 mutex_enter(HUBD_MUTEX(hubd)); 7219 7220 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) { 7221 hubd_stop_polling(hubd); 7222 } 7223 } 7224 7225 hubd->h_hotplug_thread++; 7226 7227 switch (cmd) { 7228 case DEVCTL_AP_DISCONNECT: 7229 if (hubd_delete_child(hubd, port, 7230 NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS) { 7231 rv = EIO; 7232 } 7233 7234 break; 7235 case DEVCTL_AP_UNCONFIGURE: 7236 if (hubd_delete_child(hubd, port, 7237 NDI_UNCONFIG, B_FALSE) != USB_SUCCESS) { 7238 rv = EIO; 7239 } 7240 7241 break; 7242 case DEVCTL_AP_CONFIGURE: 7243 /* toggle port */ 7244 if (hubd_toggle_port(hubd, port) != USB_SUCCESS) { 7245 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7246 rv = EIO; 7247 7248 break; 7249 } 7250 7251 (void) hubd_handle_port_connect(hubd, port); 7252 child_dip = hubd_get_child_dip(hubd, port); 7253 mutex_exit(HUBD_MUTEX(hubd)); 7254 7255 ndi_devi_exit(hubd->h_dip, circ); 7256 ndi_devi_exit(rh_dip, rh_circ); 7257 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 7258 if ((child_dip == NULL) || 7259 (ndi_devi_online(child_dip, 0) != NDI_SUCCESS)) { 7260 rv = EIO; 7261 } 7262 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 7263 ndi_devi_enter(rh_dip, &rh_circ); 7264 ndi_devi_enter(hubd->h_dip, &circ); 7265 7266 mutex_enter(HUBD_MUTEX(hubd)); 7267 7268 break; 7269 case DEVCTL_AP_GETSTATE: 7270 switch (hubd_cfgadm_state(hubd, port)) { 7271 case HUBD_CFGADM_DISCONNECTED: 7272 /* port previously 'disconnected' by cfgadm */ 7273 ap_state.ap_rstate = AP_RSTATE_DISCONNECTED; 7274 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7275 ap_state.ap_condition = AP_COND_OK; 7276 7277 break; 7278 case HUBD_CFGADM_UNCONFIGURED: 7279 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7280 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7281 ap_state.ap_condition = AP_COND_OK; 7282 7283 break; 7284 case HUBD_CFGADM_CONFIGURED: 7285 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 7286 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7287 ap_state.ap_condition = AP_COND_OK; 7288 7289 break; 7290 case HUBD_CFGADM_STILL_REFERENCED: 7291 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7292 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 7293 ap_state.ap_condition = AP_COND_UNUSABLE; 7294 7295 break; 7296 case HUBD_CFGADM_EMPTY: 7297 default: 7298 ap_state.ap_rstate = AP_RSTATE_EMPTY; 7299 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 7300 ap_state.ap_condition = AP_COND_OK; 7301 7302 break; 7303 } 7304 7305 ap_state.ap_last_change = (time_t)-1; 7306 ap_state.ap_error_code = 0; 7307 ap_state.ap_in_transition = 0; 7308 7309 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7310 "DEVCTL_AP_GETSTATE: " 7311 "ostate=0x%x, rstate=0x%x, condition=0x%x", 7312 ap_state.ap_ostate, 7313 ap_state.ap_rstate, ap_state.ap_condition); 7314 7315 /* copy the return-AP-state information to the user space */ 7316 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 7317 rv = EFAULT; 7318 } 7319 7320 break; 7321 case DEVCTL_AP_CONTROL: 7322 { 7323 /* 7324 * Generic devctl for hardware-specific functionality. 7325 * For list of sub-commands see hubd_impl.h 7326 */ 7327 hubd_ioctl_data_t ioc; /* for 64 byte copies */ 7328 7329 /* copy user ioctl data in first */ 7330 #ifdef _MULTI_DATAMODEL 7331 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 7332 hubd_ioctl_data_32_t ioc32; 7333 7334 if (ddi_copyin((void *)arg, (void *)&ioc32, 7335 sizeof (ioc32), mode) != 0) { 7336 rv = EFAULT; 7337 7338 break; 7339 } 7340 ioc.cmd = (uint_t)ioc32.cmd; 7341 ioc.port = (uint_t)ioc32.port; 7342 ioc.get_size = (uint_t)ioc32.get_size; 7343 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 7344 ioc.bufsiz = (uint_t)ioc32.bufsiz; 7345 ioc.misc_arg = (uint_t)ioc32.misc_arg; 7346 } else 7347 #endif /* _MULTI_DATAMODEL */ 7348 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc), 7349 mode) != 0) { 7350 rv = EFAULT; 7351 7352 break; 7353 } 7354 7355 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7356 "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d" 7357 "\n\tbuf=0x%p, bufsiz=%d, misc_arg=%d", ioc.cmd, 7358 ioc.port, ioc.get_size, ioc.buf, ioc.bufsiz, ioc.misc_arg); 7359 7360 /* 7361 * To avoid BE/LE and 32/64 issues, a get_size always 7362 * returns a 32-bit number. 7363 */ 7364 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) { 7365 rv = EINVAL; 7366 7367 break; 7368 } 7369 7370 switch (ioc.cmd) { 7371 case USB_DESCR_TYPE_DEV: 7372 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC"; 7373 if (ioc.get_size) { 7374 /* uint32 so this works 32/64 */ 7375 uint32_t size = sizeof (usb_dev_descr_t); 7376 7377 if (ddi_copyout((void *)&size, ioc.buf, 7378 ioc.bufsiz, mode) != 0) { 7379 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7380 hubd->h_log_handle, 7381 "%s: get_size copyout failed", msg); 7382 rv = EIO; 7383 7384 break; 7385 } 7386 } else { /* send out the actual descr */ 7387 usb_dev_descr_t *dev_descrp; 7388 7389 /* check child_dip */ 7390 if ((child_dip = hubd_get_child_dip(hubd, 7391 ioc.port)) == NULL) { 7392 rv = EINVAL; 7393 7394 break; 7395 } 7396 7397 dev_descrp = usb_get_dev_descr(child_dip); 7398 if (ioc.bufsiz != sizeof (*dev_descrp)) { 7399 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7400 hubd->h_log_handle, 7401 "%s: bufsize passed (%d) != sizeof " 7402 "usba_device_descr_t (%d)", msg, 7403 ioc.bufsiz, dev_descrp->bLength); 7404 rv = EINVAL; 7405 7406 break; 7407 } 7408 7409 if (ddi_copyout((void *)dev_descrp, 7410 ioc.buf, ioc.bufsiz, mode) != 0) { 7411 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7412 hubd->h_log_handle, 7413 "%s: copyout failed.", msg); 7414 rv = EIO; 7415 7416 break; 7417 } 7418 } 7419 break; 7420 case USB_DESCR_TYPE_STRING: 7421 { 7422 char *str; 7423 uint32_t size; 7424 usba_device_t *usba_device; 7425 7426 msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR"; 7427 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7428 "%s: string request: %d", msg, ioc.misc_arg); 7429 7430 /* recheck */ 7431 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7432 NULL) { 7433 rv = EINVAL; 7434 7435 break; 7436 } 7437 usba_device = usba_get_usba_device(child_dip); 7438 7439 switch (ioc.misc_arg) { 7440 case HUBD_MFG_STR: 7441 str = usba_device->usb_mfg_str; 7442 7443 break; 7444 case HUBD_PRODUCT_STR: 7445 str = usba_device->usb_product_str; 7446 7447 break; 7448 case HUBD_SERIALNO_STR: 7449 str = usba_device->usb_serialno_str; 7450 7451 break; 7452 case HUBD_CFG_DESCR_STR: 7453 mutex_enter(&usba_device->usb_mutex); 7454 str = usba_device->usb_cfg_str_descr[ 7455 usba_device->usb_active_cfg_ndx]; 7456 mutex_exit(&usba_device->usb_mutex); 7457 7458 break; 7459 default: 7460 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7461 hubd->h_log_handle, 7462 "%s: Invalid string request", msg); 7463 rv = EINVAL; 7464 7465 break; 7466 } /* end of switch */ 7467 7468 if (rv != 0) { 7469 7470 break; 7471 } 7472 7473 size = (str != NULL) ? strlen(str) + 1 : 0; 7474 if (ioc.get_size) { 7475 if (ddi_copyout((void *)&size, ioc.buf, 7476 ioc.bufsiz, mode) != 0) { 7477 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7478 hubd->h_log_handle, 7479 "%s: copyout of size failed.", msg); 7480 rv = EIO; 7481 7482 break; 7483 } 7484 } else { 7485 if (size == 0) { 7486 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, 7487 hubd->h_log_handle, 7488 "%s: String is NULL", msg); 7489 rv = EINVAL; 7490 7491 break; 7492 } 7493 7494 if (ioc.bufsiz != size) { 7495 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7496 hubd->h_log_handle, 7497 "%s: string buf size wrong", msg); 7498 rv = EINVAL; 7499 7500 break; 7501 } 7502 7503 if (ddi_copyout((void *)str, ioc.buf, 7504 ioc.bufsiz, mode) != 0) { 7505 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7506 hubd->h_log_handle, 7507 "%s: copyout failed.", msg); 7508 rv = EIO; 7509 7510 break; 7511 } 7512 } 7513 break; 7514 } 7515 case HUBD_GET_CFGADM_NAME: 7516 { 7517 uint32_t name_len; 7518 const char *name; 7519 7520 /* recheck */ 7521 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7522 NULL) { 7523 rv = EINVAL; 7524 7525 break; 7526 } 7527 name = ddi_node_name(child_dip); 7528 if (name == NULL) { 7529 name = "unsupported"; 7530 } 7531 name_len = strlen(name) + 1; 7532 7533 msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME"; 7534 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7535 "%s: name=%s name_len=%d", msg, name, name_len); 7536 7537 if (ioc.get_size) { 7538 if (ddi_copyout((void *)&name_len, 7539 ioc.buf, ioc.bufsiz, mode) != 0) { 7540 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7541 hubd->h_log_handle, 7542 "%s: copyout of size failed", msg); 7543 rv = EIO; 7544 7545 break; 7546 } 7547 } else { 7548 if (ioc.bufsiz != name_len) { 7549 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7550 hubd->h_log_handle, 7551 "%s: string buf length wrong", msg); 7552 rv = EINVAL; 7553 7554 break; 7555 } 7556 7557 if (ddi_copyout((void *)name, ioc.buf, 7558 ioc.bufsiz, mode) != 0) { 7559 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7560 hubd->h_log_handle, 7561 "%s: copyout failed.", msg); 7562 rv = EIO; 7563 7564 break; 7565 } 7566 } 7567 7568 break; 7569 } 7570 7571 /* 7572 * Return the config index for the currently-configured 7573 * configuration. 7574 */ 7575 case HUBD_GET_CURRENT_CONFIG: 7576 { 7577 uint_t config_index; 7578 uint32_t size = sizeof (config_index); 7579 usba_device_t *usba_device; 7580 7581 msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG"; 7582 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7583 "%s", msg); 7584 7585 /* 7586 * Return the config index for the configuration 7587 * currently in use. 7588 * Recheck if child_dip exists 7589 */ 7590 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7591 NULL) { 7592 rv = EINVAL; 7593 7594 break; 7595 } 7596 7597 usba_device = usba_get_usba_device(child_dip); 7598 mutex_enter(&usba_device->usb_mutex); 7599 config_index = usba_device->usb_active_cfg_ndx; 7600 mutex_exit(&usba_device->usb_mutex); 7601 7602 if (ioc.get_size) { 7603 if (ddi_copyout((void *)&size, 7604 ioc.buf, ioc.bufsiz, mode) != 0) { 7605 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7606 hubd->h_log_handle, 7607 "%s: copyout of size failed.", msg); 7608 rv = EIO; 7609 7610 break; 7611 } 7612 } else { 7613 if (ioc.bufsiz != size) { 7614 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7615 hubd->h_log_handle, 7616 "%s: buffer size wrong", msg); 7617 rv = EINVAL; 7618 7619 break; 7620 } 7621 if (ddi_copyout((void *)&config_index, 7622 ioc.buf, ioc.bufsiz, mode) != 0) { 7623 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7624 hubd->h_log_handle, 7625 "%s: copyout failed", msg); 7626 rv = EIO; 7627 } 7628 } 7629 7630 break; 7631 } 7632 case HUBD_GET_DEVICE_PATH: 7633 { 7634 char *path; 7635 uint32_t size; 7636 7637 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH"; 7638 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7639 "%s", msg); 7640 7641 /* Recheck if child_dip exists */ 7642 if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) == 7643 NULL) { 7644 rv = EINVAL; 7645 7646 break; 7647 } 7648 7649 /* ddi_pathname doesn't supply /devices, so we do. */ 7650 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7651 (void) strcpy(path, "/devices"); 7652 (void) ddi_pathname(child_dip, path + strlen(path)); 7653 size = strlen(path) + 1; 7654 7655 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7656 "%s: device path=%s size=%d", msg, path, size); 7657 7658 if (ioc.get_size) { 7659 if (ddi_copyout((void *)&size, 7660 ioc.buf, ioc.bufsiz, mode) != 0) { 7661 7662 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7663 hubd->h_log_handle, 7664 "%s: copyout of size failed.", msg); 7665 rv = EIO; 7666 } 7667 } else { 7668 if (ioc.bufsiz != size) { 7669 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7670 hubd->h_log_handle, 7671 "%s: buffer wrong size.", msg); 7672 rv = EINVAL; 7673 } else if (ddi_copyout((void *)path, 7674 ioc.buf, ioc.bufsiz, mode) != 0) { 7675 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7676 hubd->h_log_handle, 7677 "%s: copyout failed.", msg); 7678 rv = EIO; 7679 } 7680 } 7681 kmem_free(path, MAXPATHLEN); 7682 7683 break; 7684 } 7685 case HUBD_REFRESH_DEVDB: 7686 msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB"; 7687 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7688 "%s", msg); 7689 7690 if ((rv = usba_devdb_refresh()) != USB_SUCCESS) { 7691 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, 7692 hubd->h_log_handle, 7693 "%s: Failed: %d", msg, rv); 7694 rv = EIO; 7695 } 7696 7697 break; 7698 default: 7699 rv = ENOTSUP; 7700 } /* end switch */ 7701 7702 break; 7703 } 7704 7705 default: 7706 rv = ENOTTY; 7707 } 7708 7709 if (dcp) { 7710 ndi_dc_freehdl(dcp); 7711 } 7712 7713 /* allow hotplug thread now */ 7714 hubd->h_hotplug_thread--; 7715 7716 if ((hubd->h_dev_state == USB_DEV_ONLINE) && 7717 hubd->h_ep1_ph && (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) { 7718 hubd_start_polling(hubd, 0); 7719 } 7720 mutex_exit(HUBD_MUTEX(hubd)); 7721 7722 ndi_devi_exit(hubd->h_dip, circ); 7723 ndi_devi_exit(rh_dip, rh_circ); 7724 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 7725 7726 mutex_enter(HUBD_MUTEX(hubd)); 7727 hubd_pm_idle_component(hubd, hubd->h_dip, 0); 7728 mutex_exit(HUBD_MUTEX(hubd)); 7729 7730 return (rv); 7731 } 7732 7733 7734 /* 7735 * Helper func used only to help construct the names for the attachment point 7736 * minor nodes. Used only in usba_hubdi_attach. 7737 * Returns whether it found ancestry or not (USB_SUCCESS if yes). 7738 * ports between the root hub and the device represented by dip. 7739 * E.g., "2.4.3.1" means this device is 7740 * plugged into port 1 of a hub that is 7741 * plugged into port 3 of a hub that is 7742 * plugged into port 4 of a hub that is 7743 * plugged into port 2 of the root hub. 7744 * NOTE: Max ap_id path len is HUBD_APID_NAMELEN (32 chars), which is 7745 * more than sufficient (as hubs are a max 6 levels deep, port needs 3 7746 * chars plus NULL each) 7747 */ 7748 static void 7749 hubd_get_ancestry_str(hubd_t *hubd) 7750 { 7751 char dev_path[MAXPATHLEN]; 7752 char *port_num_pos; 7753 char port_list[HUBD_APID_NAMELEN]; 7754 char *port_list_end = port_list; 7755 7756 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 7757 "hubd_get_ancestry_str: hubd=0x%p", hubd); 7758 7759 dev_path[0] = '\0'; 7760 (void) ddi_pathname(hubd->h_dip, dev_path); 7761 port_num_pos = dev_path; 7762 7763 port_list[0] = NULL; 7764 while ((port_num_pos = (char *)strstr(port_num_pos, "hub@")) != NULL) { 7765 /* 7766 * Found a non-root hub between the root hub port and device. 7767 * Get the number of the port this hub is plugged into, 7768 * and append it to the ancestry string. 7769 */ 7770 if (port_list_end != port_list) { /* have list already */ 7771 (void) strcat(port_list_end, "."); 7772 port_list_end++; 7773 } 7774 7775 while (!isdigit(*port_num_pos)) { 7776 if (*port_num_pos++ == '\0') { 7777 7778 break; 7779 } 7780 } 7781 7782 while (isdigit(*port_num_pos)) { 7783 *port_list_end++ = *port_num_pos++; 7784 ASSERT(port_list_end < 7785 (port_list + sizeof (port_list))); 7786 ASSERT(port_num_pos < (dev_path + sizeof (dev_path))); 7787 } 7788 *port_list_end = '\0'; 7789 } 7790 7791 if (port_list_end != port_list) { 7792 (void) strcpy(hubd->h_ancestry_str, port_list); 7793 (void) strcat(hubd->h_ancestry_str, "."); 7794 } 7795 } 7796 7797 7798 /* Get which port to operate on. */ 7799 static usb_port_t 7800 hubd_get_port_num(hubd_t *hubd, struct devctl_iocdata *dcp) 7801 { 7802 int32_t port; 7803 7804 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 7805 7806 /* Get which port to operate on. */ 7807 if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) { 7808 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7809 "hubd_get_port_num: port lookup failed"); 7810 port = 0; 7811 } 7812 7813 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7814 "hubd_get_port_num: hubd=0x%p, port=%d", hubd, port); 7815 7816 return ((usb_port_t)port); 7817 } 7818 7819 7820 /* check if child still exists */ 7821 static dev_info_t * 7822 hubd_get_child_dip(hubd_t *hubd, usb_port_t port) 7823 { 7824 dev_info_t *child_dip = hubd->h_children_dips[port]; 7825 7826 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7827 "hubd_get_child_dip: hubd=0x%p, port=%d", hubd, port); 7828 7829 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 7830 7831 return (child_dip); 7832 } 7833 7834 7835 /* 7836 * hubd_cfgadm_state: 7837 * 7838 * child_dip list port_state cfgadm_state 7839 * -------------- ---------- ------------ 7840 * != NULL connected configured or 7841 * unconfigured 7842 * != NULL not connected disconnect but 7843 * busy/still referenced 7844 * NULL connected logically disconnected 7845 * NULL not connected empty 7846 */ 7847 static uint_t 7848 hubd_cfgadm_state(hubd_t *hubd, usb_port_t port) 7849 { 7850 uint_t state; 7851 dev_info_t *child_dip = hubd_get_child_dip(hubd, port); 7852 7853 if (child_dip) { 7854 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 7855 /* 7856 * connected, now check if driver exists 7857 */ 7858 if (DEVI_IS_DEVICE_OFFLINE(child_dip) || 7859 !i_ddi_devi_attached(child_dip)) { 7860 state = HUBD_CFGADM_UNCONFIGURED; 7861 } else { 7862 state = HUBD_CFGADM_CONFIGURED; 7863 } 7864 } else { 7865 /* 7866 * this means that the dip is around for 7867 * a device that is still referenced but 7868 * has been yanked out. So the cfgadm info 7869 * for this state should be EMPTY (port empty) 7870 * and CONFIGURED (dip still valid). 7871 */ 7872 state = HUBD_CFGADM_STILL_REFERENCED; 7873 } 7874 } else { 7875 /* connected but no child dip */ 7876 if (hubd->h_port_state[port] & PORT_STATUS_CCS) { 7877 /* logically disconnected */ 7878 state = HUBD_CFGADM_DISCONNECTED; 7879 } else { 7880 /* physically disconnected */ 7881 state = HUBD_CFGADM_EMPTY; 7882 } 7883 } 7884 7885 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7886 "hubd_cfgadm_state: hubd=0x%p, port=%d state=0x%x", 7887 hubd, port, state); 7888 7889 return (state); 7890 } 7891 7892 7893 /* 7894 * hubd_toggle_port: 7895 */ 7896 static int 7897 hubd_toggle_port(hubd_t *hubd, usb_port_t port) 7898 { 7899 usb_hub_descr_t *hub_descr; 7900 int wait; 7901 uint_t retry; 7902 uint16_t status; 7903 uint16_t change; 7904 7905 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, 7906 "hubd_toggle_port: hubd=0x%p, port=%d", hubd, port); 7907 7908 if ((hubd_disable_port_power(hubd, port)) != USB_SUCCESS) { 7909 7910 return (USB_FAILURE); 7911 } 7912 7913 /* 7914 * see hubd_enable_all_port_power() which 7915 * requires longer delay for hubs. 7916 */ 7917 mutex_exit(HUBD_MUTEX(hubd)); 7918 delay(drv_usectohz(hubd_device_delay / 10)); 7919 mutex_enter(HUBD_MUTEX(hubd)); 7920 7921 hub_descr = &hubd->h_hub_descr; 7922 7923 /* 7924 * According to section 11.11 of USB, for hubs with no power 7925 * switches, bPwrOn2PwrGood is zero. But we wait for some 7926 * arbitrary time to enable power to become stable. 7927 * 7928 * If an hub supports port power swicthing, we need to wait 7929 * at least 20ms before accesing corresonding usb port. 7930 */ 7931 if ((hub_descr->wHubCharacteristics & 7932 HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) { 7933 wait = hubd_device_delay / 10; 7934 } else { 7935 wait = max(HUB_DEFAULT_POPG, 7936 hub_descr->bPwrOn2PwrGood) * 2 * 1000; 7937 } 7938 7939 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle, 7940 "hubd_toggle_port: popg=%d wait=%d", 7941 hub_descr->bPwrOn2PwrGood, wait); 7942 7943 retry = 0; 7944 7945 do { 7946 (void) hubd_enable_port_power(hubd, port); 7947 7948 mutex_exit(HUBD_MUTEX(hubd)); 7949 delay(drv_usectohz(wait)); 7950 mutex_enter(HUBD_MUTEX(hubd)); 7951 7952 /* Get port status */ 7953 (void) hubd_determine_port_status(hubd, port, 7954 &status, &change, 0); 7955 7956 /* For retry if any, use some extra delay */ 7957 wait = max(wait, hubd_device_delay / 10); 7958 7959 retry++; 7960 7961 } while ((!(status & PORT_STATUS_PPS)) && (retry < HUBD_PORT_RETRY)); 7962 7963 /* Print warning message if port has no power */ 7964 if (!(status & PORT_STATUS_PPS)) { 7965 7966 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle, 7967 "hubd_toggle_port: port %d power-on failed, " 7968 "port status 0x%x", port, status); 7969 7970 return (USB_FAILURE); 7971 } 7972 7973 return (USB_SUCCESS); 7974 } 7975 7976 7977 /* 7978 * hubd_init_power_budget: 7979 * Init power budget variables in hubd structure. According 7980 * to USB spec, the power budget rules are: 7981 * 1. local-powered hubs including root-hubs can supply 7982 * 500mA to each port at maximum 7983 * 2. two bus-powered hubs are not allowed to concatenate 7984 * 3. bus-powered hubs can supply 100mA to each port at 7985 * maximum, and the power consumed by all downstream 7986 * ports and the hub itself cannot exceed the max power 7987 * supplied by the upstream port, i.e., 500mA 7988 * The routine is only called during hub attach time 7989 */ 7990 static int 7991 hubd_init_power_budget(hubd_t *hubd) 7992 { 7993 uint16_t status = 0; 7994 usba_device_t *hubd_ud = NULL; 7995 size_t size; 7996 usb_cfg_descr_t cfg_descr; 7997 dev_info_t *pdip = NULL; 7998 hubd_t *phubd = NULL; 7999 8000 if (hubd->h_ignore_pwr_budget) { 8001 8002 return (USB_SUCCESS); 8003 } 8004 8005 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle, 8006 "hubd_init_power_budget:"); 8007 8008 ASSERT(mutex_owned(HUBD_MUTEX(hubd))); 8009 ASSERT(hubd->h_default_pipe != 0); 8010 mutex_exit(HUBD_MUTEX(hubd)); 8011 8012 /* get device status */ 8013 if ((usb_get_status(hubd->h_dip, hubd->h_default_pipe, 8014 HUB_GET_DEVICE_STATUS_TYPE, 8015 0, &status, 0)) != USB_SUCCESS) { 8016 mutex_enter(HUBD_MUTEX(hubd)); 8017 8018 return (USB_FAILURE); 8019 } 8020 8021 hubd_ud = usba_get_usba_device(hubd->h_dip); 8022 8023 size = usb_parse_cfg_descr(hubd_ud->usb_cfg, hubd_ud->usb_cfg_length, 8024 &cfg_descr, USB_CFG_DESCR_SIZE); 8025 8026 if (size != USB_CFG_DESCR_SIZE) { 8027 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8028 "get hub configuration descriptor failed"); 8029 mutex_enter(HUBD_MUTEX(hubd)); 8030 8031 return (USB_FAILURE); 8032 } 8033 8034 mutex_enter(HUBD_MUTEX(hubd)); 8035 8036 hubd->h_local_pwr_capable = (cfg_descr.bmAttributes & 8037 USB_CFG_ATTR_SELFPWR); 8038 8039 if (hubd->h_local_pwr_capable) { 8040 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8041 "hub is capable of local power"); 8042 } 8043 8044 hubd->h_local_pwr_on = (status & 8045 USB_DEV_SLF_PWRD_STATUS) && hubd->h_local_pwr_capable; 8046 8047 if (hubd->h_local_pwr_on) { 8048 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8049 "hub is local-powered"); 8050 8051 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8052 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8053 } else { 8054 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD * 8055 USB_LOW_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8056 8057 hubd->h_pwr_left = (USB_PWR_UNIT_LOAD * 8058 USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT; 8059 8060 ASSERT(!usba_is_root_hub(hubd->h_dip)); 8061 8062 if (!usba_is_root_hub(hubd->h_dip)) { 8063 /* 8064 * two bus-powered hubs are not 8065 * allowed to be concatenated 8066 */ 8067 mutex_exit(HUBD_MUTEX(hubd)); 8068 8069 pdip = ddi_get_parent(hubd->h_dip); 8070 phubd = hubd_get_soft_state(pdip); 8071 ASSERT(phubd != NULL); 8072 8073 if (!phubd->h_ignore_pwr_budget) { 8074 mutex_enter(HUBD_MUTEX(phubd)); 8075 if (phubd->h_local_pwr_on == B_FALSE) { 8076 USB_DPRINTF_L1(DPRINT_MASK_HUB, 8077 hubd->h_log_handle, 8078 "two bus-powered hubs cannot " 8079 "be concatenated"); 8080 8081 mutex_exit(HUBD_MUTEX(phubd)); 8082 mutex_enter(HUBD_MUTEX(hubd)); 8083 8084 return (USB_FAILURE); 8085 } 8086 mutex_exit(HUBD_MUTEX(phubd)); 8087 } 8088 8089 mutex_enter(HUBD_MUTEX(hubd)); 8090 8091 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8092 "hub is bus-powered"); 8093 } else { 8094 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle, 8095 "root-hub must be local-powered"); 8096 } 8097 8098 /* 8099 * Subtract the power consumed by the hub itself 8100 * and get the power that can be supplied to 8101 * downstream ports 8102 */ 8103 hubd->h_pwr_left -= 8104 hubd->h_hub_descr.bHubContrCurrent / 8105 USB_CFG_DESCR_PWR_UNIT; 8106 if (hubd->h_pwr_left < 0) { 8107 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle, 8108 "hubd->h_pwr_left is less than bHubContrCurrent, " 8109 "should fail"); 8110 8111 return (USB_FAILURE); 8112 } 8113 } 8114 8115 return (USB_SUCCESS); 8116 } 8117 8118 8119 /* 8120 * usba_hubdi_check_power_budget: 8121 * Check if the hub has enough power budget to allow a 8122 * child device to select a configuration of config_index. 8123 */ 8124 int 8125 usba_hubdi_check_power_budget(dev_info_t *dip, usba_device_t *child_ud, 8126 uint_t config_index) 8127 { 8128 int16_t pwr_left, pwr_limit, pwr_required; 8129 size_t size; 8130 usb_cfg_descr_t cfg_descr; 8131 hubd_t *hubd; 8132 8133 if ((hubd = hubd_get_soft_state(dip)) == NULL) { 8134 8135 return (USB_FAILURE); 8136 } 8137 8138 if (hubd->h_ignore_pwr_budget) { 8139 8140 return (USB_SUCCESS); 8141 } 8142 8143 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8144 "usba_hubdi_check_power_budget: " 8145 "dip=0x%p child_ud=0x%p conf_index=%d", dip, 8146 child_ud, config_index); 8147 8148 mutex_enter(HUBD_MUTEX(hubd)); 8149 pwr_limit = hubd->h_pwr_limit; 8150 if (hubd->h_local_pwr_on == B_FALSE) { 8151 pwr_left = hubd->h_pwr_left; 8152 pwr_limit = (pwr_limit <= pwr_left) ? pwr_limit : pwr_left; 8153 } 8154 mutex_exit(HUBD_MUTEX(hubd)); 8155 8156 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8157 "usba_hubdi_check_power_budget: " 8158 "available power is %dmA", pwr_limit * USB_CFG_DESCR_PWR_UNIT); 8159 8160 size = usb_parse_cfg_descr( 8161 child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE, 8162 &cfg_descr, USB_CFG_DESCR_SIZE); 8163 8164 if (size != USB_CFG_DESCR_SIZE) { 8165 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8166 "get hub configuration descriptor failed"); 8167 8168 return (USB_FAILURE); 8169 } 8170 8171 pwr_required = cfg_descr.bMaxPower; 8172 8173 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8174 "usba_hubdi_check_power_budget: " 8175 "child bmAttributes=0x%x bMaxPower=%d " 8176 "with config_index=%d", cfg_descr.bmAttributes, 8177 pwr_required, config_index); 8178 8179 if (pwr_required > pwr_limit) { 8180 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, hubd->h_log_handle, 8181 "configuration %d for device %s %s at port %d " 8182 "exceeds power available for this port, please " 8183 "re-insert your device into another hub port which " 8184 "has enough power", 8185 config_index, 8186 child_ud->usb_mfg_str, 8187 child_ud->usb_product_str, 8188 child_ud->usb_port); 8189 8190 return (USB_FAILURE); 8191 } 8192 8193 return (USB_SUCCESS); 8194 } 8195 8196 8197 /* 8198 * usba_hubdi_incr_power_budget: 8199 * Increase the hub power budget value when a child device 8200 * is removed from a bus-powered hub port. 8201 */ 8202 void 8203 usba_hubdi_incr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8204 { 8205 uint16_t pwr_value; 8206 hubd_t *hubd = hubd_get_soft_state(dip); 8207 8208 ASSERT(hubd != NULL); 8209 8210 if (hubd->h_ignore_pwr_budget) { 8211 8212 return; 8213 } 8214 8215 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8216 "usba_hubdi_incr_power_budget: " 8217 "dip=0x%p child_ud=0x%p", dip, child_ud); 8218 8219 mutex_enter(HUBD_MUTEX(hubd)); 8220 if (hubd->h_local_pwr_on == B_TRUE) { 8221 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8222 "usba_hubdi_incr_power_budget: " 8223 "hub is local powered"); 8224 mutex_exit(HUBD_MUTEX(hubd)); 8225 8226 return; 8227 } 8228 mutex_exit(HUBD_MUTEX(hubd)); 8229 8230 mutex_enter(&child_ud->usb_mutex); 8231 if (child_ud->usb_pwr_from_hub == 0) { 8232 mutex_exit(&child_ud->usb_mutex); 8233 8234 return; 8235 } 8236 pwr_value = child_ud->usb_pwr_from_hub; 8237 mutex_exit(&child_ud->usb_mutex); 8238 8239 mutex_enter(HUBD_MUTEX(hubd)); 8240 hubd->h_pwr_left += pwr_value; 8241 8242 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8243 "usba_hubdi_incr_power_budget: " 8244 "available power is %dmA, increased by %dmA", 8245 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8246 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8247 8248 mutex_exit(HUBD_MUTEX(hubd)); 8249 8250 mutex_enter(&child_ud->usb_mutex); 8251 child_ud->usb_pwr_from_hub = 0; 8252 mutex_exit(&child_ud->usb_mutex); 8253 } 8254 8255 8256 /* 8257 * usba_hubdi_decr_power_budget: 8258 * Decrease the hub power budget value when a child device 8259 * is inserted to a bus-powered hub port. 8260 */ 8261 void 8262 usba_hubdi_decr_power_budget(dev_info_t *dip, usba_device_t *child_ud) 8263 { 8264 uint16_t pwr_value; 8265 size_t size; 8266 usb_cfg_descr_t cfg_descr; 8267 hubd_t *hubd = hubd_get_soft_state(dip); 8268 8269 ASSERT(hubd != NULL); 8270 8271 if (hubd->h_ignore_pwr_budget) { 8272 8273 return; 8274 } 8275 8276 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle, 8277 "usba_hubdi_decr_power_budget: " 8278 "dip=0x%p child_ud=0x%p", dip, child_ud); 8279 8280 mutex_enter(HUBD_MUTEX(hubd)); 8281 if (hubd->h_local_pwr_on == B_TRUE) { 8282 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8283 "usba_hubdi_decr_power_budget: " 8284 "hub is local powered"); 8285 mutex_exit(HUBD_MUTEX(hubd)); 8286 8287 return; 8288 } 8289 mutex_exit(HUBD_MUTEX(hubd)); 8290 8291 mutex_enter(&child_ud->usb_mutex); 8292 if (child_ud->usb_pwr_from_hub > 0) { 8293 mutex_exit(&child_ud->usb_mutex); 8294 8295 return; 8296 } 8297 mutex_exit(&child_ud->usb_mutex); 8298 8299 size = usb_parse_cfg_descr( 8300 child_ud->usb_cfg, child_ud->usb_cfg_length, 8301 &cfg_descr, USB_CFG_DESCR_SIZE); 8302 ASSERT(size == USB_CFG_DESCR_SIZE); 8303 8304 mutex_enter(HUBD_MUTEX(hubd)); 8305 pwr_value = cfg_descr.bMaxPower; 8306 hubd->h_pwr_left -= pwr_value; 8307 ASSERT(hubd->h_pwr_left >= 0); 8308 8309 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle, 8310 "usba_hubdi_decr_power_budget: " 8311 "available power is %dmA, decreased by %dmA", 8312 hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT, 8313 pwr_value * USB_CFG_DESCR_PWR_UNIT); 8314 8315 mutex_exit(HUBD_MUTEX(hubd)); 8316 8317 mutex_enter(&child_ud->usb_mutex); 8318 child_ud->usb_pwr_from_hub = pwr_value; 8319 mutex_exit(&child_ud->usb_mutex); 8320 } 8321