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