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