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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27 */ 28 29 /* 30 * The Data Transfer Interface driver for Host Wire Adapter device 31 * 32 * HWA device has two interfaces, one is the data transfer interface, 33 * another is the radio control interface. This driver (hwahc) is only 34 * for data transfer interface support, but it depends on the radio 35 * control interface driver (hwarc) to work. That means the hwarc 36 * driver must be loaded while the hwahc is working. This is now 37 * ensured by holding hwarc open until hwahc detaches or powers down. 38 * 39 * The data transfer interface has three endpoints besides the default 40 * control endpoint which is shared between the two interfaces. The 41 * three endpoints are: 42 * 43 * - notification endpoint (intr in type, for asynchronous event 44 * notifications and transfer status notifications) 45 * 46 * - data transfer OUT endpoint (bulk out type, for sending transfer 47 * requests and transfer data from the host to the HWA device) 48 * 49 * - data transfer IN endpoint (bulk in type, for returning transfer 50 * status and transfer data from the HWA device to the host) 51 * 52 * The HWA device is a USB 2.0 device, so it supports the standard USB 53 * requests defined in chapter 9 of USB 2.0 specification as other USB 54 * client devices. But its most important functionality is to work as 55 * a wireless USB host. This means the hwahc driver needs to supply 56 * host controller functionalities, which include children hotplug 57 * support and data transfer support to children device endpoints. 58 * 59 * So hwahc driver is implemented as a nexus driver and it follows the 60 * event mechanism in existing USBA framework to support children 61 * hotplug events. 62 * 63 * The hwahc driver works as the root-hub on wireless USB bus. And it 64 * relays data transfers to/from wireless bus to the USB bus where ehci/ 65 * ohci/uhci works as the root-hub. This makes a bus cascading topology. 66 * 67 * The data transfer to/from wireless device endpoints is implemented by 68 * remote pipe (rpipe) mechanism. The rpipe descriptor on the HWA defines 69 * the attributes of a wireless USB transfer, such as the transfer type, 70 * the target device address, the target endpoint address and the max 71 * packet size. And the transfer requests through data transfer OUT 72 * endpoint will take a certain rpipe as the transfer target, thus 73 * fulfills the data transfer across buses. Refer to chapter 8 of WUSB 74 * 1.0 specification for details of this. 75 */ 76 77 #define USBDRV_MAJOR_VER 2 78 #define USBDRV_MINOR_VER 0 79 80 #include <sys/usb/hwa/hwahc/hwahc.h> 81 #include <sys/usb/hwa/hwahc/hwahc_util.h> 82 #include <sys/usb/usba/wa.h> 83 #include <sys/usb/usba/wusba.h> 84 #include <sys/usb/usba/whcdi.h> 85 #include <sys/usb/usba.h> 86 #include <sys/usb/usba/usba_impl.h> 87 #include <sys/usb/usba/usba_devdb.h> /* for usba_devdb_refresh */ 88 #include <sys/usb/hubd/hubdvar.h> 89 #include <sys/usb/hubd/hubd_impl.h> /* for hubd_ioctl_data_t */ 90 #include <sys/strsubr.h> /* for allocb_wait */ 91 #include <sys/strsun.h> /* for MBLKL macro */ 92 #include <sys/fs/dv_node.h> /* for devfs_clean */ 93 #include <sys/uwb/uwbai.h> /* for uwb ioctls */ 94 #include <sys/random.h> 95 96 void *hwahc_statep; 97 98 /* number of instances */ 99 #define HWAHC_INSTS 1 100 101 /* default value for set number DNTS slots request */ 102 #define HWAHC_DEFAULT_DNTS_INTERVAL 2 /* ms */ 103 #define HWAHC_DEFAULT_DNTS_SLOT_NUM 4 104 105 106 /* debug support */ 107 uint_t hwahc_errmask = (uint_t)PRINT_MASK_ALL; 108 uint_t hwahc_errlevel = USB_LOG_L4; 109 uint_t hwahc_instance_debug = (uint_t)-1; 110 111 /* bus config debug flag */ 112 uint_t hwahc_bus_config_debug = 0; 113 uint8_t hwahc_enable_trust_timeout = 1; 114 115 116 /* 117 * Use the default GTK for the whole life of HWA driver. 118 * Not so compatible with WUSB spec. 119 */ 120 static uint8_t dft_gtk[16]; 121 static uint8_t dft_gtkid[3]; 122 123 extern usb_log_handle_t whcdi_log_handle; 124 125 /* 126 * Function Prototypes 127 */ 128 /* driver operations (dev_ops) entry points */ 129 static int hwahc_open(dev_t *, int, int, cred_t *); 130 static int hwahc_close(dev_t, int, int, cred_t *); 131 static int hwahc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 132 133 static int hwahc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 134 static int hwahc_attach(dev_info_t *, ddi_attach_cmd_t); 135 static int hwahc_detach(dev_info_t *, ddi_detach_cmd_t); 136 static int hwahc_power(dev_info_t *, int, int); 137 138 /* bus_ops entry points */ 139 static int hwahc_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 140 void *, void *); 141 static int hwahc_busop_get_eventcookie(dev_info_t *, dev_info_t *, 142 char *, ddi_eventcookie_t *); 143 static int hwahc_busop_add_eventcall( 144 dev_info_t *, dev_info_t *, ddi_eventcookie_t, 145 void (*)(dev_info_t *, ddi_eventcookie_t, void *, void *), 146 void *, ddi_callback_id_t *); 147 static int hwahc_busop_remove_eventcall(dev_info_t *, ddi_callback_id_t); 148 static int hwahc_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, 149 void *, dev_info_t **); 150 static int hwahc_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t, 151 void *); 152 153 /* hotplug and power management supporting functions */ 154 static int hwahc_disconnect_event_cb(dev_info_t *dip); 155 static int hwahc_reconnect_event_cb(dev_info_t *dip); 156 static int hwahc_pre_suspend_event_cb(dev_info_t *dip); 157 static int hwahc_post_resume_event_cb(dev_info_t *dip); 158 static int hwahc_cpr_suspend(dev_info_t *); 159 static int hwahc_cpr_resume(dev_info_t *); 160 static void hwahc_restore_device_state(dev_info_t *, hwahc_state_t *); 161 static void hwahc_run_callbacks(hwahc_state_t *, usba_event_t); 162 static void hwahc_post_event(hwahc_state_t *, usb_port_t, usba_event_t); 163 164 static int hwahc_cleanup(dev_info_t *, hwahc_state_t *); 165 static void hwahc_create_pm_components(dev_info_t *, hwahc_state_t *); 166 static void hwahc_destroy_pm_components(hwahc_state_t *); 167 static void hwahc_pm_busy_component(hwahc_state_t *); 168 static void hwahc_pm_idle_component(hwahc_state_t *); 169 static int hwahc_pwrlvl0(hwahc_state_t *); 170 static int hwahc_pwrlvl1(hwahc_state_t *); 171 static int hwahc_pwrlvl2(hwahc_state_t *); 172 static int hwahc_pwrlvl3(hwahc_state_t *); 173 static int hwahc_hc_channel_suspend(hwahc_state_t *); 174 175 /* hardware initialization and deinitialization functions */ 176 static int hwahc_parse_security_data(wusb_secrt_data_t *, 177 usb_cfg_data_t *); 178 static void hwahc_print_secrt_data(hwahc_state_t *); 179 180 static int hwahc_hub_attach(hwahc_state_t *); 181 static int hwahc_hub_detach(hwahc_state_t *); 182 183 static int hwahc_hc_initial_start(hwahc_state_t *); 184 static int hwahc_hc_final_stop(hwahc_state_t *); 185 static int hwahc_wa_start(hwahc_state_t *); 186 static void hwahc_wa_stop(hwahc_state_t *); 187 static int hwahc_hc_channel_start(hwahc_state_t *); 188 static int hwahc_hc_channel_stop(hwahc_state_t *); 189 static void hwahc_hc_data_init(hwahc_state_t *); 190 static void hwahc_hc_data_fini(hwahc_state_t *); 191 192 /* ioctl support */ 193 static int hwahc_cfgadm_ioctl(hwahc_state_t *, int, intptr_t, int, 194 cred_t *, int *); 195 static int hwahc_wusb_ioctl(hwahc_state_t *, int, intptr_t, int, 196 cred_t *, int *); 197 198 /* callbacks registered to USBA */ 199 static void hwahc_disconnect_dev(dev_info_t *, usb_port_t); 200 static void hwahc_reconnect_dev(dev_info_t *, usb_port_t); 201 static int hwahc_create_child(dev_info_t *, usb_port_t); 202 static int hwahc_destroy_child(dev_info_t *, usb_port_t); 203 static int hwahc_cleanup_child(dev_info_t *); 204 static int hwahc_delete_child(dev_info_t *, usb_port_t, uint_t, boolean_t); 205 206 /* data transfer and notification handling */ 207 static void hwahc_intr_cb(usb_pipe_handle_t, struct usb_intr_req *); 208 static void hwahc_intr_exc_cb(usb_pipe_handle_t, struct usb_intr_req *); 209 static void hwahc_handle_notif(hwahc_state_t *, mblk_t *); 210 static void hwahc_handle_xfer_result(hwahc_state_t *, uint8_t); 211 static void hwahc_stop_result_thread(hwahc_state_t *); 212 static void hwahc_result_thread(void *); 213 static void hwahc_handle_dn_notif(hwahc_state_t *, hwa_notif_dn_recvd_t *); 214 static void hwahc_notif_thread(void *); 215 static void hwahc_handle_dn(hwahc_state_t *, hwa_notif_dn_recvd_t *); 216 static void hwahc_drain_notif_queue(hwahc_state_t *); 217 static void hwahc_rpipe_xfer_cb(dev_info_t *, usba_pipe_handle_data_t *, 218 wusb_wa_trans_wrapper_t *, usb_cr_t); 219 220 static void hwahc_trust_timeout_handler(void *arg); 221 static void hwahc_stop_trust_timer(wusb_dev_info_t *dev); 222 223 static int hwahc_pipe_submit_periodic_req(wusb_wa_data_t *wa_data, 224 usba_pipe_handle_data_t *ph); 225 226 /* hwa specific requests */ 227 static int hwahc_set_chid(hwahc_state_t *, uint8_t *); 228 229 /* helper functions */ 230 static usb_port_t hwahc_get_port_num(hwahc_state_t *, struct devctl_iocdata *); 231 static dev_info_t *hwahc_get_child_dip(hwahc_state_t *, usb_port_t); 232 233 static struct cb_ops hwahc_cb_ops = { 234 hwahc_open, /* Open */ 235 hwahc_close, /* Close */ 236 nodev, /* Strategy */ 237 nodev, /* Print */ 238 nodev, /* Dump */ 239 nodev, /* Read */ 240 nodev, /* Write */ 241 hwahc_ioctl, /* Ioctl */ 242 nodev, /* Devmap */ 243 nodev, /* Mmap */ 244 nodev, /* Segmap */ 245 nochpoll, /* Poll */ 246 ddi_prop_op, /* cb_prop_op */ 247 NULL, /* Streamtab */ 248 D_MP /* Driver compatibility flag */ 249 }; 250 251 static struct bus_ops hwahc_busops = { 252 BUSO_REV, 253 nullbusmap, /* bus_map */ 254 NULL, /* bus_get_intrspec */ 255 NULL, /* bus_add_intrspec */ 256 NULL, /* bus_remove_intrspec */ 257 NULL, /* bus_map_fault */ 258 NULL, /* bus_dma_map */ 259 ddi_dma_allochdl, 260 ddi_dma_freehdl, 261 ddi_dma_bindhdl, 262 ddi_dma_unbindhdl, 263 ddi_dma_flush, 264 ddi_dma_win, 265 ddi_dma_mctl, /* bus_dma_ctl */ 266 hwahc_bus_ctl, /* bus_ctl */ 267 ddi_bus_prop_op, /* bus_prop_op */ 268 hwahc_busop_get_eventcookie, /* bus_get_eventcookie */ 269 hwahc_busop_add_eventcall, /* bus_add_eventcall */ 270 hwahc_busop_remove_eventcall, /* bus_remove_eventcall */ 271 NULL, /* bus_post_event */ 272 NULL, /* bus_intr_ctl */ 273 hwahc_bus_config, /* bus_config */ 274 hwahc_bus_unconfig, /* bus_unconfig */ 275 NULL, /* bus_fm_init */ 276 NULL, /* bus_fm_fini */ 277 NULL, /* bus_fm_access_enter */ 278 NULL, /* bus_fm_access_exit */ 279 NULL, /* bus_power */ 280 }; 281 282 static struct dev_ops hwahc_ops = { 283 DEVO_REV, /* Devo_rev */ 284 0, /* Refcnt */ 285 hwahc_info, /* Info */ 286 nulldev, /* Identify */ 287 nulldev, /* Probe */ 288 hwahc_attach, /* Attach */ 289 hwahc_detach, /* Detach */ 290 nodev, /* Reset */ 291 &hwahc_cb_ops, /* Driver operations */ 292 &hwahc_busops, /* Bus operations */ 293 hwahc_power, /* Power */ 294 ddi_quiesce_not_needed, /* devo_quiesce */ 295 }; 296 297 static struct modldrv hwahc_modldrv = { 298 &mod_driverops, 299 "WUSB hwa-hc driver", 300 &hwahc_ops 301 }; 302 303 static struct modlinkage modlinkage = { 304 MODREV_1, 305 &hwahc_modldrv, 306 NULL 307 }; 308 309 /* events from parent */ 310 static usb_event_t hwahc_events = { 311 hwahc_disconnect_event_cb, 312 hwahc_reconnect_event_cb, 313 hwahc_pre_suspend_event_cb, 314 hwahc_post_resume_event_cb 315 }; 316 317 /* 318 * events support for children 319 * A map tween USBA_EVENTs and DDI_EVENTs. 320 */ 321 static ndi_event_definition_t hwahc_ndi_event_defs[] = { 322 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 323 NDI_EVENT_POST_TO_ALL}, 324 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 325 NDI_EVENT_POST_TO_ALL}, 326 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 327 NDI_EVENT_POST_TO_ALL}, 328 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 329 NDI_EVENT_POST_TO_ALL} 330 }; 331 332 #define HWAHC_N_NDI_EVENTS \ 333 (sizeof (hwahc_ndi_event_defs) / sizeof (ndi_event_definition_t)) 334 335 static ndi_event_set_t hwahc_ndi_events = { 336 NDI_EVENTS_REV1, HWAHC_N_NDI_EVENTS, hwahc_ndi_event_defs}; 337 338 /* transfer callbacks */ 339 static wusb_wa_cb_t hwahc_cbs = { 340 hwahc_pipe_submit_periodic_req, 341 hwahc_intr_cb, 342 hwahc_intr_exc_cb, 343 hwahc_rpipe_xfer_cb 344 }; 345 346 347 /* 348 * Module-wide initialization routine. 349 */ 350 int 351 _init(void) 352 { 353 int rval; 354 355 if ((rval = ddi_soft_state_init(&hwahc_statep, sizeof (hwahc_state_t), 356 HWAHC_INSTS)) != 0) { 357 358 return (rval); 359 } 360 361 if ((rval = mod_install(&modlinkage)) != 0) { 362 ddi_soft_state_fini(&hwahc_statep); 363 } 364 365 return (rval); 366 } 367 368 369 /* 370 * Module-wide tear-down routine. 371 */ 372 int 373 _fini(void) 374 { 375 int rval; 376 377 if ((rval = mod_remove(&modlinkage)) == 0) { 378 /* Release per module resources */ 379 ddi_soft_state_fini(&hwahc_statep); 380 } 381 382 return (rval); 383 } 384 385 386 int 387 _info(struct modinfo *modinfop) 388 { 389 return (mod_info(&modlinkage, modinfop)); 390 } 391 392 393 /* 394 * hwahc_info: 395 * Get minor number, instance number, etc. 396 */ 397 /*ARGSUSED*/ 398 static int 399 hwahc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 400 void *arg, void **result) 401 { 402 hwahc_state_t *hwahcp; 403 int error = DDI_FAILURE; 404 int instance = HWAHC_MINOR_TO_INSTANCE(getminor((dev_t)arg)); 405 406 switch (infocmd) { 407 case DDI_INFO_DEVT2DEVINFO: 408 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 409 instance)) != NULL) { 410 *result = hwahcp->hwahc_dip; 411 if (*result != NULL) { 412 error = DDI_SUCCESS; 413 } 414 } else { 415 *result = NULL; 416 } 417 break; 418 case DDI_INFO_DEVT2INSTANCE: 419 *result = (void *)(uintptr_t)instance; 420 error = DDI_SUCCESS; 421 break; 422 default: 423 break; 424 } 425 426 return (error); 427 } 428 429 430 /* 431 * hwahc_attach: 432 * Attach or resume. 433 * 434 * For attach, initialize state and device, including: 435 * state variables, locks, device node, 436 * resource initialization, event registration, 437 * device registration with system 438 * power management, hotplugging 439 * For resume, restore device and state 440 */ 441 static int 442 hwahc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 443 { 444 int instance = ddi_get_instance(dip); 445 hwahc_state_t *hwahcp = NULL; 446 usb_client_dev_data_t *dev_data; 447 struct usb_cfg_data *cfg_data; 448 usba_hcdi_register_args_t hcdi_args; 449 int rval; 450 char *pathname; 451 452 USB_DPRINTF_L3(PRINT_MASK_ATTA, NULL, "hwahc_attach: cmd=%d", cmd); 453 454 switch (cmd) { 455 case DDI_ATTACH: 456 break; 457 case DDI_RESUME: 458 (void) hwahc_cpr_resume(dip); 459 460 return (DDI_SUCCESS); 461 default: 462 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL, 463 "hwahc_attach: failed"); 464 465 return (DDI_FAILURE); 466 } 467 468 /* 469 * Allocate soft state information. 470 */ 471 rval = ddi_soft_state_zalloc(hwahc_statep, instance); 472 if (rval != DDI_SUCCESS) { 473 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL, 474 "hwahc_attach: cannot allocate soft state for instance %d", 475 instance); 476 477 return (USB_FAILURE); 478 } 479 480 hwahcp = ddi_get_soft_state(hwahc_statep, instance); 481 if (hwahcp == NULL) { 482 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL, 483 "hwahc_attach: get soft state failed for instance %d", 484 instance); 485 486 return (USB_FAILURE); 487 } 488 489 hwahcp->hwahc_log_handle = usb_alloc_log_hdl(dip, "hwahc", 490 &hwahc_errlevel, &hwahc_errmask, &hwahc_instance_debug, 0); 491 492 /* initialize hc state */ 493 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_INIT_STATE; 494 hwahcp->hwahc_dip = dip; 495 hwahcp->hwahc_instance = instance; 496 497 /* register with USBA as client driver */ 498 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 499 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 500 "hwahc_attach: client attach failed"); 501 502 goto fail; 503 } 504 505 if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) != 506 USB_SUCCESS) { 507 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 508 "hwahc_attach: cannot get dev_data"); 509 510 goto fail; 511 } 512 513 /* initialize mutex and cv */ 514 mutex_init(&hwahcp->hwahc_mutex, NULL, MUTEX_DRIVER, 515 dev_data->dev_iblock_cookie); 516 cv_init(&hwahcp->hwahc_result_thread_cv, NULL, CV_DRIVER, NULL); 517 518 hwahcp->hwahc_flags |= HWAHC_LOCK_INITED; 519 hwahcp->hwahc_dev_data = dev_data; 520 521 /* initialize data transfer function related structure */ 522 if (wusb_wa_data_init(dip, &hwahcp->hwahc_wa_data, &hwahc_cbs, 523 dev_data, PRINT_MASK_ATTA, 524 hwahcp->hwahc_log_handle) != USB_SUCCESS) { 525 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 526 "hwahc_attach: init wa data failed"); 527 528 goto fail; 529 } 530 531 hwahcp->hwahc_flags |= HWAHC_WA_INITED; 532 cfg_data = dev_data->dev_curr_cfg; 533 534 /* parse the security descrs from the configuration descr cloud */ 535 if (hwahc_parse_security_data(&hwahcp->hwahc_secrt_data, cfg_data) != 536 USB_SUCCESS) { 537 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 538 "hwahc_attach: parse security descrs failed"); 539 540 goto fail; 541 } 542 543 hwahcp->hwahc_default_pipe = dev_data->dev_default_ph; 544 hwahcp->hwahc_wa_data.wa_private_data = (void *)hwahcp; 545 hwahcp->hwahc_wa_data.wa_default_pipe = hwahcp->hwahc_default_pipe; 546 547 usb_free_descr_tree(dip, dev_data); 548 549 hwahcp->hwahc_dev_state = USB_DEV_ONLINE; 550 551 /* now create components to power manage this device */ 552 hwahc_create_pm_components(dip, hwahcp); 553 554 /* 555 * Event definition and registration 556 * 557 * allocate a new NDI event handle as a nexus driver 558 */ 559 (void) ndi_event_alloc_hdl(dip, 0, &hwahcp->hwahc_ndi_event_hdl, 560 NDI_SLEEP); 561 562 /* 563 * bind our NDI events with the event handle, 564 * i.e. Define the events set we're to support as a nexus driver. 565 * 566 * These events will be used by bus_ops functions to register callbacks. 567 */ 568 if (ndi_event_bind_set(hwahcp->hwahc_ndi_event_hdl, &hwahc_ndi_events, 569 NDI_SLEEP)) { 570 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 571 "hwahc_attach: binding event set failed"); 572 573 goto fail; 574 } 575 576 577 /* 578 * Register USB events to USBA(the parent) to get callbacks as a 579 * child of (root) hub 580 */ 581 if (usb_register_event_cbs(dip, &hwahc_events, 0) != USB_SUCCESS) { 582 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 583 "hwahc_attach: register_events failed"); 584 585 goto fail; 586 } 587 588 hwahcp->hwahc_flags |= HWAHC_EVENTS_REGISTERED; 589 590 /* create minor nodes */ 591 if (ddi_create_minor_node(dip, "hwahc", S_IFCHR, 592 instance << HWAHC_MINOR_INSTANCE_SHIFT, 593 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 594 595 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 596 "hwahc_attach: cannot create minor node"); 597 598 goto fail; 599 } 600 601 hwahcp->hwahc_flags |= HWAHC_MINOR_NODE_CREATED; 602 603 hwahcp->hwahc_hcdi_ops = hwahc_alloc_hcdi_ops(hwahcp); 604 605 /* register this hc instance with usba HCD interface */ 606 hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION; 607 hcdi_args.usba_hcdi_register_dip = dip; 608 hcdi_args.usba_hcdi_register_ops = hwahcp->hwahc_hcdi_ops; 609 610 /* use parent dma attr here */ 611 hcdi_args.usba_hcdi_register_dma_attr = usba_get_hc_dma_attr(dip); 612 hcdi_args.usba_hcdi_register_iblock_cookie = NULL; 613 614 if (usba_hcdi_register(&hcdi_args, 0) != USB_SUCCESS) { 615 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 616 "hwahc_attach: usba_hcdi_register failed"); 617 618 goto fail; 619 } 620 621 hwahcp->hwahc_flags |= HWAHC_HCDI_REGISTERED; 622 623 /* create hub minor node and register to usba HUBD interface */ 624 if (hwahc_hub_attach(hwahcp) != USB_SUCCESS) { 625 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 626 "hwahc_attach: hub attach failed"); 627 628 goto fail; 629 } 630 hwahcp->hwahc_flags |= HWAHC_HUBREG; 631 632 /* intialize WUSB host function related structure */ 633 hwahc_hc_data_init(hwahcp); 634 hwahcp->hwahc_flags |= HWAHC_HC_INITED; 635 636 /* can be combined with wusb_wa_data_init() */ 637 if (hwahc_wa_start(hwahcp) != USB_SUCCESS) { 638 639 goto fail; 640 } 641 642 hwahcp->hwahc_flags |= HWAHC_WA_STARTED; 643 644 /* report this dev */ 645 ddi_report_dev(dip); 646 647 hwahc_pm_idle_component(hwahcp); 648 649 mutex_enter(&(hwahcp->hwahc_mutex)); 650 hwahc_print_secrt_data(hwahcp); 651 mutex_exit(&(hwahcp->hwahc_mutex)); 652 653 if (uwb_dev_online(dip) != USB_SUCCESS) { 654 goto fail; 655 } 656 657 return (DDI_SUCCESS); 658 659 fail: 660 pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 661 662 /* log this message to usba_debug_buf */ 663 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 664 "cannot attach %s", ddi_pathname(dip, pathname)); 665 666 kmem_free(pathname, MAXPATHLEN); 667 668 if (hwahcp) { 669 hwahc_pm_idle_component(hwahcp); 670 671 rval = hwahc_cleanup(dip, hwahcp); 672 if (rval != USB_SUCCESS) { 673 USB_DPRINTF_L2(PRINT_MASK_ATTA, 674 hwahcp->hwahc_log_handle, 675 "failure to complete cleanup after attach failure"); 676 } 677 } 678 679 return (DDI_FAILURE); 680 } 681 682 683 /* 684 * hwahc_detach: 685 * detach or suspend driver instance 686 * 687 * Note: in detach, only contention threads is from pm and disconnnect. 688 */ 689 static int 690 hwahc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 691 { 692 int instance = ddi_get_instance(dip); 693 hwahc_state_t *hwahcp = ddi_get_soft_state(hwahc_statep, instance); 694 int rval = DDI_FAILURE; 695 696 697 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 698 "hwahc_detach: cmd = %d", cmd); 699 700 switch (cmd) { 701 case DDI_DETACH: 702 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 703 "offline uwb device for dip: 0x%p", (void *)dip); 704 /* offline the hwarc interface */ 705 (void) uwb_dev_offline(dip); 706 if (hwahcp) { 707 rval = hwahc_cleanup(dip, hwahcp); 708 } 709 710 break; 711 case DDI_SUSPEND: 712 rval = hwahc_cpr_suspend(dip); 713 714 break; 715 default: 716 717 break; 718 } 719 720 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 721 } 722 723 724 /* 725 * hwahc_cleanup: 726 * clean up on attach failure or detach 727 */ 728 static int 729 hwahc_cleanup(dev_info_t *dip, hwahc_state_t *hwahcp) 730 { 731 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 732 "hwahc_cleanup: start"); 733 734 if ((hwahcp->hwahc_flags & HWAHC_LOCK_INITED) == 0) { 735 736 goto done; 737 } 738 739 /* 740 * deallocate events, if events are still registered 741 * (ie. children still attached) then we have to fail the detach 742 */ 743 if (hwahcp->hwahc_ndi_event_hdl && 744 (ndi_event_free_hdl(hwahcp->hwahc_ndi_event_hdl) != NDI_SUCCESS)) { 745 746 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 747 "hwahc_cleanup: ndi_event_free_hdl failed"); 748 749 return (USB_FAILURE); 750 } 751 752 if (hwahcp->hwahc_flags & HWAHC_EVENTS_REGISTERED) { 753 /* unregister events */ 754 usb_unregister_event_cbs(dip, &hwahc_events); 755 } 756 757 if (hwahcp->hwahc_flags & HWAHC_HCDI_REGISTERED) { 758 /* unregister the instance with usba HCD interface */ 759 usba_hcdi_unregister(hwahcp->hwahc_dip); 760 } 761 762 mutex_enter(&hwahcp->hwahc_mutex); 763 764 if (hwahcp->hwahc_hw_state != HWAHC_HW_STOPPED) { 765 /* stop the hw if it is enabled */ 766 (void) hwahc_hc_final_stop(hwahcp); 767 } 768 769 if (hwahcp->hwahc_flags & HWAHC_WA_STARTED) { 770 /* can be combined with wusb_wa_data_fini() */ 771 mutex_exit(&hwahcp->hwahc_mutex); 772 hwahc_wa_stop(hwahcp); 773 mutex_enter(&hwahcp->hwahc_mutex); 774 } 775 776 if (hwahcp->hwahc_flags & HWAHC_HC_INITED) { 777 /* deinitialize the WUSB host function related structure */ 778 hwahc_hc_data_fini(hwahcp); 779 } 780 781 mutex_exit(&hwahcp->hwahc_mutex); 782 783 if (hwahcp->hwahc_pm) { 784 /* destroy power management components */ 785 hwahc_destroy_pm_components(hwahcp); 786 } 787 788 if (hwahcp->hwahc_flags & HWAHC_HUBREG) { 789 /* unregister the instance from usba HUBD interface */ 790 if (hwahc_hub_detach(hwahcp) != USB_SUCCESS) { 791 792 return (USB_FAILURE); 793 } 794 } 795 796 if (hwahcp->hwahc_hcdi_ops) { 797 usba_free_hcdi_ops(hwahcp->hwahc_hcdi_ops); 798 } 799 800 mutex_enter(&hwahcp->hwahc_mutex); 801 if (hwahcp->hwahc_secrt_data.secrt_encry_descr) { 802 /* free security descrs */ 803 kmem_free(hwahcp->hwahc_secrt_data.secrt_encry_descr, 804 sizeof (usb_encryption_descr_t) * 805 hwahcp->hwahc_secrt_data.secrt_n_encry); 806 } 807 808 if (hwahcp->hwahc_flags & HWAHC_WA_INITED) { 809 /* deinitialize data transfer function related structure */ 810 wusb_wa_data_fini(&hwahcp->hwahc_wa_data); 811 } 812 mutex_exit(&hwahcp->hwahc_mutex); 813 814 if (hwahcp->hwahc_flags & HWAHC_MINOR_NODE_CREATED) { 815 /* remove all the minor nodes */ 816 ddi_remove_minor_node(dip, NULL); 817 } 818 819 /* destroy mutex and cv */ 820 mutex_destroy(&hwahcp->hwahc_mutex); 821 cv_destroy(&hwahcp->hwahc_result_thread_cv); 822 823 done: 824 /* unregister the client driver from usba */ 825 usb_client_detach(dip, hwahcp->hwahc_dev_data); 826 827 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 828 "hwahc_cleanup: end"); 829 830 usb_free_log_hdl(hwahcp->hwahc_log_handle); 831 832 /* remove all properties created */ 833 ddi_prop_remove_all(dip); 834 835 /* free the soft state information */ 836 ddi_soft_state_free(hwahc_statep, ddi_get_instance(dip)); 837 838 return (USB_SUCCESS); 839 } 840 841 842 /*ARGSUSED*/ 843 static int 844 hwahc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 845 { 846 hwahc_state_t *hwahcp; 847 848 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 849 HWAHC_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) { 850 851 return (ENXIO); 852 } 853 854 USB_DPRINTF_L4(PRINT_MASK_OPEN, hwahcp->hwahc_log_handle, 855 "hwahc_open: start"); 856 857 mutex_enter(&hwahcp->hwahc_mutex); 858 /* exclusive open */ 859 if ((flag & FEXCL) && (hwahcp->hwahc_open_count > 0)) { 860 mutex_exit(&hwahcp->hwahc_mutex); 861 862 return (EBUSY); 863 } 864 865 if ((hwahcp->hwahc_dev_state == USB_DEV_DISCONNECTED) || 866 (hwahcp->hwahc_dev_state == USB_DEV_SUSPENDED)) { 867 mutex_exit(&hwahcp->hwahc_mutex); 868 869 return (EIO); 870 } 871 872 hwahcp->hwahc_open_count++; 873 874 mutex_exit(&hwahcp->hwahc_mutex); 875 876 /* raise to full power and keep it until close */ 877 hwahc_pm_busy_component(hwahcp); 878 (void) pm_raise_power(hwahcp->hwahc_dip, 0, USB_DEV_OS_FULL_PWR); 879 880 USB_DPRINTF_L4(PRINT_MASK_OPEN, hwahcp->hwahc_log_handle, 881 "hwahc_open: end"); 882 883 return (0); 884 } 885 886 887 /*ARGSUSED*/ 888 static int 889 hwahc_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 890 { 891 hwahc_state_t *hwahcp; 892 893 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 894 HWAHC_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 895 896 return (ENXIO); 897 } 898 899 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hwahcp->hwahc_log_handle, 900 "hwahc_close: start"); 901 902 mutex_enter(&hwahcp->hwahc_mutex); 903 if (hwahcp->hwahc_open_count == 0) { 904 USB_DPRINTF_L2(PRINT_MASK_CLOSE, hwahcp->hwahc_log_handle, 905 "hwahc_close: already closed"); 906 mutex_exit(&hwahcp->hwahc_mutex); 907 908 return (EINVAL); 909 } 910 911 hwahcp->hwahc_open_count--; 912 mutex_exit(&hwahcp->hwahc_mutex); 913 914 hwahc_pm_idle_component(hwahcp); 915 916 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hwahcp->hwahc_log_handle, 917 "hwahc_close: end"); 918 919 return (0); 920 } 921 922 /* retrieve port number from devctl data */ 923 static usb_port_t 924 hwahc_get_port_num(hwahc_state_t *hwahcp, struct devctl_iocdata *dcp) 925 { 926 int32_t port; 927 928 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 929 930 /* Get which port to operate on. */ 931 if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) { 932 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 933 "hwahc_get_port_num: port lookup failed"); 934 port = 0; 935 } 936 937 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 938 "hwahc_get_port_num: hwahcp=0x%p, port=%d", (void *)hwahcp, 939 port); 940 941 return ((usb_port_t)port); 942 } 943 944 /* return the child dip on a certain port */ 945 static dev_info_t * 946 hwahc_get_child_dip(hwahc_state_t *hwahcp, usb_port_t port) 947 { 948 wusb_hc_data_t *hc_data; 949 dev_info_t *child_dip; 950 951 hc_data = &hwahcp->hwahc_hc_data; 952 953 /* check port range to prevent an illegal number */ 954 if (port > hc_data->hc_num_ports) { 955 return (NULL); 956 } 957 958 mutex_enter(&hc_data->hc_mutex); 959 child_dip = hc_data->hc_children_dips[port]; 960 mutex_exit(&hc_data->hc_mutex); 961 962 return (child_dip); 963 } 964 965 /* 966 * hwahc_cfgadm_state: 967 * 968 * child_dip list child_state cfgadm_state 969 * -------------- ---------- ------------ 970 * != NULL connected configured or 971 * unconfigured 972 * != NULL not connected disconnect but 973 * busy/still referenced 974 * NULL connected logically disconnected 975 * NULL not connected empty 976 */ 977 static uint_t 978 hwahc_cfgadm_state(hwahc_state_t *hwahcp, usb_port_t port) 979 { 980 uint_t state; 981 dev_info_t *child_dip = hwahc_get_child_dip(hwahcp, port); 982 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 983 wusb_dev_info_t *dev_info; 984 985 if (child_dip == NULL) { 986 987 return (HWAHC_CFGADM_INVALID); 988 } 989 990 mutex_enter(&hc_data->hc_mutex); 991 dev_info = hc_data->hc_dev_infos[port]; 992 if (dev_info) { 993 if (dev_info->wdev_state == WUSB_STATE_CONFIGURED) { 994 if (child_dip && 995 (DEVI_IS_DEVICE_OFFLINE(child_dip) || 996 !i_ddi_devi_attached(child_dip))) { 997 state = HWAHC_CFGADM_UNCONFIGURED; 998 } else if (!child_dip) { 999 state = HWAHC_CFGADM_UNCONFIGURED; 1000 } else { 1001 state = HWAHC_CFGADM_CONFIGURED; 1002 } 1003 } else if (dev_info->wdev_state == WUSB_STATE_UNCONNTED) { 1004 if (child_dip) { 1005 state = HWAHC_CFGADM_STILL_REFERENCED; 1006 } else { 1007 state = HWAHC_CFGADM_DISCONNECTED; 1008 } 1009 } else { 1010 if (child_dip) { 1011 state = HWAHC_CFGADM_STILL_REFERENCED; 1012 } else { 1013 state = HWAHC_CFGADM_UNCONFIGURED; 1014 } 1015 } 1016 } else { 1017 state = HWAHC_CFGADM_EMPTY; 1018 } 1019 mutex_exit(&hc_data->hc_mutex); 1020 1021 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 1022 "hwahc_cfgadm_state: hwahcp=0x%p, port=%d state=0x%x", 1023 (void *) hwahcp, port, state); 1024 1025 return (state); 1026 } 1027 1028 /* cfgadm ioctl support, now only implements list function */ 1029 /* ARGSUSED */ 1030 static int 1031 hwahc_cfgadm_ioctl(hwahc_state_t *hwahcp, int cmd, intptr_t arg, 1032 int mode, cred_t *credp, int *rvalp) 1033 { 1034 dev_info_t *rh_dip; 1035 dev_info_t *child_dip; 1036 struct devctl_iocdata *dcp = NULL; 1037 usb_port_t port = 0; 1038 devctl_ap_state_t ap_state; 1039 int circ, rh_circ, prh_circ; 1040 int rv = 0; 1041 char *msg; 1042 1043 /* read devctl ioctl data */ 1044 if ((cmd != DEVCTL_AP_CONTROL) && 1045 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 1046 1047 return (EFAULT); 1048 } 1049 1050 mutex_enter(&hwahcp->hwahc_mutex); 1051 1052 rh_dip = hwahcp->hwahc_hubd->h_usba_device->usb_root_hub_dip; 1053 1054 switch (cmd) { 1055 case DEVCTL_AP_DISCONNECT: 1056 case DEVCTL_AP_UNCONFIGURE: 1057 case DEVCTL_AP_CONFIGURE: 1058 if (hwahcp->hwahc_dev_state == USB_DEV_DISCONNECTED) { 1059 USB_DPRINTF_L2(PRINT_MASK_ATTA, 1060 hwahcp->hwahc_log_handle, 1061 "hwahc_cfgadm_ioctl: dev already gone"); 1062 mutex_exit(&hwahcp->hwahc_mutex); 1063 if (dcp) { 1064 ndi_dc_freehdl(dcp); 1065 } 1066 1067 return (EIO); 1068 } 1069 /* FALLTHROUGH */ 1070 case DEVCTL_AP_GETSTATE: 1071 if ((port = hwahc_get_port_num(hwahcp, dcp)) == 0) { 1072 USB_DPRINTF_L2(PRINT_MASK_ATTA, 1073 hwahcp->hwahc_log_handle, 1074 "hwahc_cfgadm_ioctl: bad port"); 1075 mutex_exit(&hwahcp->hwahc_mutex); 1076 if (dcp) { 1077 ndi_dc_freehdl(dcp); 1078 } 1079 1080 return (EINVAL); 1081 } 1082 break; 1083 case DEVCTL_AP_CONTROL: 1084 1085 break; 1086 default: 1087 mutex_exit(&hwahcp->hwahc_mutex); 1088 if (dcp) { 1089 ndi_dc_freehdl(dcp); 1090 } 1091 1092 return (ENOTTY); 1093 } 1094 1095 /* should not happen, just in case */ 1096 if (hwahcp->hwahc_dev_state == USB_DEV_SUSPENDED) { 1097 mutex_exit(&hwahcp->hwahc_mutex); 1098 if (dcp) { 1099 ndi_dc_freehdl(dcp); 1100 } 1101 1102 return (EIO); 1103 } 1104 1105 mutex_exit(&hwahcp->hwahc_mutex); 1106 1107 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 1108 ndi_devi_enter(rh_dip, &rh_circ); 1109 ndi_devi_enter(hwahcp->hwahc_dip, &circ); 1110 1111 mutex_enter(&hwahcp->hwahc_mutex); 1112 1113 switch (cmd) { 1114 case DEVCTL_AP_DISCONNECT: 1115 /* TODO: not supported now */ 1116 rv = EIO; 1117 break; 1118 case DEVCTL_AP_UNCONFIGURE: 1119 /* TODO: not supported now */ 1120 rv = EIO; 1121 break; 1122 case DEVCTL_AP_CONFIGURE: 1123 /* TODO: not supported now */ 1124 rv = EIO; 1125 break; 1126 case DEVCTL_AP_GETSTATE: 1127 switch (hwahc_cfgadm_state(hwahcp, port)) { 1128 case HWAHC_CFGADM_DISCONNECTED: 1129 /* port previously 'disconnected' by cfgadm */ 1130 ap_state.ap_rstate = AP_RSTATE_DISCONNECTED; 1131 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 1132 ap_state.ap_condition = AP_COND_OK; 1133 1134 break; 1135 case HWAHC_CFGADM_UNCONFIGURED: 1136 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 1137 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 1138 ap_state.ap_condition = AP_COND_OK; 1139 1140 break; 1141 case HWAHC_CFGADM_CONFIGURED: 1142 ap_state.ap_rstate = AP_RSTATE_CONNECTED; 1143 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 1144 ap_state.ap_condition = AP_COND_OK; 1145 1146 break; 1147 case HWAHC_CFGADM_STILL_REFERENCED: 1148 ap_state.ap_rstate = AP_RSTATE_EMPTY; 1149 ap_state.ap_ostate = AP_OSTATE_CONFIGURED; 1150 ap_state.ap_condition = AP_COND_UNUSABLE; 1151 1152 break; 1153 case HWAHC_CFGADM_EMPTY: 1154 default: 1155 ap_state.ap_rstate = AP_RSTATE_EMPTY; 1156 ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED; 1157 ap_state.ap_condition = AP_COND_OK; 1158 1159 break; 1160 } 1161 1162 ap_state.ap_last_change = (time_t)-1; 1163 ap_state.ap_error_code = 0; 1164 ap_state.ap_in_transition = 0; 1165 1166 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 1167 "DEVCTL_AP_GETSTATE: " 1168 "ostate=0x%x, rstate=0x%x, condition=0x%x", 1169 ap_state.ap_ostate, 1170 ap_state.ap_rstate, ap_state.ap_condition); 1171 1172 /* copy the return-AP-state information to the user space */ 1173 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 1174 rv = EFAULT; 1175 } 1176 1177 break; 1178 case DEVCTL_AP_CONTROL: 1179 { 1180 /* 1181 * Generic devctl for hardware-specific functionality. 1182 * For list of sub-commands see hubd_impl.h 1183 */ 1184 hubd_ioctl_data_t ioc; /* for 64 byte copies */ 1185 1186 /* copy user ioctl data in first */ 1187 #ifdef _MULTI_DATAMODEL 1188 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1189 hubd_ioctl_data_32_t ioc32; 1190 1191 if (ddi_copyin((void *)arg, (void *)&ioc32, 1192 sizeof (ioc32), mode) != 0) { 1193 rv = EFAULT; 1194 1195 break; 1196 } 1197 ioc.cmd = (uint_t)ioc32.cmd; 1198 ioc.port = (uint_t)ioc32.port; 1199 ioc.get_size = (uint_t)ioc32.get_size; 1200 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 1201 ioc.bufsiz = (uint_t)ioc32.bufsiz; 1202 ioc.misc_arg = (uint_t)ioc32.misc_arg; 1203 } else 1204 #endif /* _MULTI_DATAMODEL */ 1205 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc), 1206 mode) != 0) { 1207 rv = EFAULT; 1208 1209 break; 1210 } 1211 1212 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 1213 "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d" 1214 "\n\tbuf=0x%p, bufsiz=%d, misc_arg=%d", ioc.cmd, 1215 ioc.port, ioc.get_size, (void *) ioc.buf, ioc.bufsiz, 1216 ioc.misc_arg); 1217 1218 /* 1219 * To avoid BE/LE and 32/64 issues, a get_size always 1220 * returns a 32-bit number. 1221 */ 1222 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) { 1223 rv = EINVAL; 1224 1225 break; 1226 } 1227 1228 switch (ioc.cmd) { 1229 case USB_DESCR_TYPE_DEV: 1230 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC"; 1231 if (ioc.get_size) { 1232 /* uint32 so this works 32/64 */ 1233 uint32_t size = sizeof (usb_dev_descr_t); 1234 1235 if (ddi_copyout((void *)&size, ioc.buf, 1236 ioc.bufsiz, mode) != 0) { 1237 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1238 hwahcp->hwahc_log_handle, 1239 "%s: get_size copyout failed", msg); 1240 rv = EIO; 1241 1242 break; 1243 } 1244 } else { /* send out the actual descr */ 1245 usb_dev_descr_t *dev_descrp; 1246 1247 /* check child_dip */ 1248 if ((child_dip = hwahc_get_child_dip(hwahcp, 1249 ioc.port)) == NULL) { 1250 rv = EINVAL; 1251 1252 break; 1253 } 1254 1255 dev_descrp = usb_get_dev_descr(child_dip); 1256 if (ioc.bufsiz != sizeof (*dev_descrp)) { 1257 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1258 hwahcp->hwahc_log_handle, 1259 "%s: bufsize passed (%d) != sizeof " 1260 "usba_device_descr_t (%d)", msg, 1261 ioc.bufsiz, dev_descrp->bLength); 1262 rv = EINVAL; 1263 1264 break; 1265 } 1266 1267 if (ddi_copyout((void *)dev_descrp, 1268 ioc.buf, ioc.bufsiz, mode) != 0) { 1269 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1270 hwahcp->hwahc_log_handle, 1271 "%s: copyout failed.", msg); 1272 rv = EIO; 1273 1274 break; 1275 } 1276 } 1277 break; 1278 case USB_DESCR_TYPE_CFG: 1279 { 1280 usba_device_t *child_ud = NULL; 1281 uint32_t idx = ioc.misc_arg; 1282 uint32_t cfg_len = 0; 1283 1284 if ((child_dip = 1285 hwahc_get_child_dip(hwahcp, ioc.port)) == NULL) { 1286 rv = EINVAL; 1287 1288 break; 1289 } 1290 child_ud = usba_get_usba_device(child_dip); 1291 cfg_len = (uint32_t)child_ud->usb_cfg_array_len[idx]; 1292 1293 msg = "DEVCTL_AP_CONTROL: GET_CONFIG_DESC"; 1294 if (ioc.get_size) { 1295 if (ddi_copyout((void *)&cfg_len, ioc.buf, 1296 ioc.bufsiz, mode) != 0) { 1297 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1298 hwahcp->hwahc_log_handle, 1299 "%s: get_size copyout failed", msg); 1300 rv = EIO; 1301 1302 break; 1303 } 1304 } else { /* send out the actual descr */ 1305 uchar_t *cfg_descr = 1306 child_ud->usb_cfg_array[idx]; 1307 1308 if (ioc.bufsiz != cfg_len) { 1309 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1310 hwahcp->hwahc_log_handle, 1311 "%s: bufsize passed (%d) != size " 1312 "of cfg_descr (%d)", msg, 1313 ioc.bufsiz, cfg_len); 1314 rv = EINVAL; 1315 1316 break; 1317 } 1318 1319 if (ddi_copyout((void *)cfg_descr, 1320 ioc.buf, ioc.bufsiz, mode) != 0) { 1321 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1322 hwahcp->hwahc_log_handle, 1323 "%s: copyout failed.", msg); 1324 rv = EIO; 1325 1326 break; 1327 } 1328 } 1329 break; 1330 } 1331 case USB_DESCR_TYPE_STRING: 1332 { 1333 char *str; 1334 uint32_t size; 1335 usba_device_t *usba_device; 1336 1337 msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR"; 1338 USB_DPRINTF_L4(PRINT_MASK_CBOPS, 1339 hwahcp->hwahc_log_handle, 1340 "%s: string request: %d", msg, ioc.misc_arg); 1341 1342 /* recheck */ 1343 if ((child_dip = 1344 hwahc_get_child_dip(hwahcp, ioc.port)) == NULL) { 1345 rv = EINVAL; 1346 1347 break; 1348 } 1349 usba_device = usba_get_usba_device(child_dip); 1350 1351 switch (ioc.misc_arg) { 1352 case HUBD_MFG_STR: 1353 str = usba_device->usb_mfg_str; 1354 1355 break; 1356 case HUBD_PRODUCT_STR: 1357 str = usba_device->usb_product_str; 1358 1359 break; 1360 case HUBD_SERIALNO_STR: 1361 str = usba_device->usb_serialno_str; 1362 1363 break; 1364 case HUBD_CFG_DESCR_STR: 1365 mutex_enter(&usba_device->usb_mutex); 1366 str = usba_device->usb_cfg_str_descr[ 1367 usba_device->usb_active_cfg_ndx]; 1368 mutex_exit(&usba_device->usb_mutex); 1369 1370 break; 1371 default: 1372 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1373 hwahcp->hwahc_log_handle, 1374 "%s: Invalid string request", msg); 1375 rv = EINVAL; 1376 1377 break; 1378 } /* end of switch */ 1379 1380 if (rv != 0) { 1381 1382 break; 1383 } 1384 1385 size = (str != NULL) ? strlen(str) + 1 : 0; 1386 if (ioc.get_size) { 1387 if (ddi_copyout((void *)&size, ioc.buf, 1388 ioc.bufsiz, mode) != 0) { 1389 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1390 hwahcp->hwahc_log_handle, 1391 "%s: copyout of size failed.", msg); 1392 rv = EIO; 1393 1394 break; 1395 } 1396 } else { 1397 if (size == 0) { 1398 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1399 hwahcp->hwahc_log_handle, 1400 "%s: String is NULL", msg); 1401 rv = EINVAL; 1402 1403 break; 1404 } 1405 1406 if (ioc.bufsiz != size) { 1407 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1408 hwahcp->hwahc_log_handle, 1409 "%s: string buf size wrong", msg); 1410 rv = EINVAL; 1411 1412 break; 1413 } 1414 1415 if (ddi_copyout((void *)str, ioc.buf, 1416 ioc.bufsiz, mode) != 0) { 1417 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1418 hwahcp->hwahc_log_handle, 1419 "%s: copyout failed.", msg); 1420 rv = EIO; 1421 1422 break; 1423 } 1424 } 1425 break; 1426 } 1427 case HUBD_GET_CFGADM_NAME: 1428 { 1429 uint32_t name_len; 1430 const char *name; 1431 1432 /* recheck */ 1433 if ((child_dip = 1434 hwahc_get_child_dip(hwahcp, ioc.port)) == NULL) { 1435 rv = EINVAL; 1436 1437 break; 1438 } 1439 name = ddi_node_name(child_dip); 1440 if (name == NULL) { 1441 name = "unsupported"; 1442 } 1443 name_len = strlen(name) + 1; 1444 1445 msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME"; 1446 USB_DPRINTF_L4(PRINT_MASK_CBOPS, 1447 hwahcp->hwahc_log_handle, 1448 "%s: name=%s name_len=%d", msg, name, name_len); 1449 1450 if (ioc.get_size) { 1451 if (ddi_copyout((void *)&name_len, 1452 ioc.buf, ioc.bufsiz, mode) != 0) { 1453 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1454 hwahcp->hwahc_log_handle, 1455 "%s: copyout of size failed", msg); 1456 rv = EIO; 1457 1458 break; 1459 } 1460 } else { 1461 if (ioc.bufsiz != name_len) { 1462 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1463 hwahcp->hwahc_log_handle, 1464 "%s: string buf length wrong", msg); 1465 rv = EINVAL; 1466 1467 break; 1468 } 1469 1470 if (ddi_copyout((void *)name, ioc.buf, 1471 ioc.bufsiz, mode) != 0) { 1472 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1473 hwahcp->hwahc_log_handle, 1474 "%s: copyout failed.", msg); 1475 rv = EIO; 1476 1477 break; 1478 } 1479 } 1480 1481 break; 1482 } 1483 1484 /* 1485 * Return the config index for the currently-configured 1486 * configuration. 1487 */ 1488 case HUBD_GET_CURRENT_CONFIG: 1489 { 1490 uint_t config_index; 1491 uint32_t size = sizeof (config_index); 1492 usba_device_t *usba_device; 1493 1494 msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG"; 1495 USB_DPRINTF_L4(PRINT_MASK_CBOPS, 1496 hwahcp->hwahc_log_handle, "%s", msg); 1497 1498 /* 1499 * Return the config index for the configuration 1500 * currently in use. 1501 * Recheck if child_dip exists 1502 */ 1503 if ((child_dip = 1504 hwahc_get_child_dip(hwahcp, ioc.port)) == NULL) { 1505 rv = EINVAL; 1506 1507 break; 1508 } 1509 1510 usba_device = usba_get_usba_device(child_dip); 1511 mutex_enter(&usba_device->usb_mutex); 1512 config_index = usba_device->usb_active_cfg_ndx; 1513 mutex_exit(&usba_device->usb_mutex); 1514 1515 if (ioc.get_size) { 1516 if (ddi_copyout((void *)&size, 1517 ioc.buf, ioc.bufsiz, mode) != 0) { 1518 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1519 hwahcp->hwahc_log_handle, 1520 "%s: copyout of size failed.", msg); 1521 rv = EIO; 1522 1523 break; 1524 } 1525 } else { 1526 if (ioc.bufsiz != size) { 1527 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1528 hwahcp->hwahc_log_handle, 1529 "%s: buffer size wrong", msg); 1530 rv = EINVAL; 1531 1532 break; 1533 } 1534 if (ddi_copyout((void *)&config_index, 1535 ioc.buf, ioc.bufsiz, mode) != 0) { 1536 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1537 hwahcp->hwahc_log_handle, 1538 "%s: copyout failed", msg); 1539 rv = EIO; 1540 } 1541 } 1542 1543 break; 1544 } 1545 case HUBD_GET_DEVICE_PATH: 1546 { 1547 char *path; 1548 uint32_t size; 1549 1550 msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH"; 1551 USB_DPRINTF_L4(PRINT_MASK_CBOPS, 1552 hwahcp->hwahc_log_handle, "%s", msg); 1553 1554 /* Recheck if child_dip exists */ 1555 if ((child_dip = 1556 hwahc_get_child_dip(hwahcp, ioc.port)) == NULL) { 1557 rv = EINVAL; 1558 1559 break; 1560 } 1561 1562 /* ddi_pathname doesn't supply /devices, so we do. */ 1563 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1564 (void) strcpy(path, "/devices"); 1565 (void) ddi_pathname(child_dip, path + strlen(path)); 1566 size = strlen(path) + 1; 1567 1568 USB_DPRINTF_L4(PRINT_MASK_CBOPS, 1569 hwahcp->hwahc_log_handle, 1570 "%s: device path=%s size=%d", msg, path, size); 1571 1572 if (ioc.get_size) { 1573 if (ddi_copyout((void *)&size, 1574 ioc.buf, ioc.bufsiz, mode) != 0) { 1575 1576 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1577 hwahcp->hwahc_log_handle, 1578 "%s: copyout of size failed.", msg); 1579 rv = EIO; 1580 } 1581 } else { 1582 if (ioc.bufsiz != size) { 1583 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1584 hwahcp->hwahc_log_handle, 1585 "%s: buffer wrong size.", msg); 1586 rv = EINVAL; 1587 } else if (ddi_copyout((void *)path, 1588 ioc.buf, ioc.bufsiz, mode) != 0) { 1589 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1590 hwahcp->hwahc_log_handle, 1591 "%s: copyout failed.", msg); 1592 rv = EIO; 1593 } 1594 } 1595 kmem_free(path, MAXPATHLEN); 1596 1597 break; 1598 } 1599 case HUBD_REFRESH_DEVDB: 1600 msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB"; 1601 USB_DPRINTF_L4(PRINT_MASK_CBOPS, 1602 hwahcp->hwahc_log_handle, "%s", msg); 1603 1604 if ((rv = usba_devdb_refresh()) != USB_SUCCESS) { 1605 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1606 hwahcp->hwahc_log_handle, 1607 "%s: Failed: %d", msg, rv); 1608 rv = EIO; 1609 } 1610 1611 break; 1612 default: 1613 rv = ENOTSUP; 1614 } /* end switch */ 1615 1616 break; 1617 } 1618 1619 default: 1620 rv = ENOTTY; 1621 } 1622 1623 if (dcp) { 1624 ndi_dc_freehdl(dcp); 1625 } 1626 1627 mutex_exit(&hwahcp->hwahc_mutex); 1628 1629 ndi_devi_exit(hwahcp->hwahc_dip, circ); 1630 ndi_devi_exit(rh_dip, rh_circ); 1631 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 1632 1633 return (rv); 1634 } 1635 1636 /* update CHID for the hc driver, return 0 on success */ 1637 static int 1638 hwahc_set_chid(hwahc_state_t *hwahcp, uint8_t *chid) 1639 { 1640 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 1641 1642 ASSERT(!mutex_owned(&hc_data->hc_mutex)); 1643 1644 /* same as the old CHID, return success */ 1645 if (memcmp(chid, hc_data->hc_chid, 16) == 0) { 1646 1647 return (0); 1648 } 1649 1650 /* 1651 * stop hw from working before updating CHID 1652 * this may not be necessary but so far we don't know 1653 * other ways to do it safely 1654 */ 1655 if (hwahcp->hwahc_hw_state == HWAHC_HW_STARTED) { 1656 /* use final_stop to fully stop the hwa */ 1657 if (hwahc_hc_final_stop(hwahcp) != USB_SUCCESS) { 1658 1659 return (EIO); 1660 } 1661 1662 mutex_enter(&hc_data->hc_mutex); 1663 (void) memcpy(hc_data->hc_chid, chid, 16); 1664 mutex_exit(&hc_data->hc_mutex); 1665 1666 /* restart the host */ 1667 if (hwahc_hc_initial_start(hwahcp) != USB_SUCCESS) { 1668 1669 return (EIO); 1670 } 1671 1672 return (0); 1673 } 1674 1675 /* hc is stopped or partially stopped, simply update */ 1676 mutex_enter(&hc_data->hc_mutex); 1677 (void) memcpy(hc_data->hc_chid, chid, 16); 1678 mutex_exit(&hc_data->hc_mutex); 1679 1680 return (0); 1681 } 1682 1683 /* 1684 * wusbadm ioctl support 1685 */ 1686 /* ARGSUSED */ 1687 static int 1688 hwahc_wusb_ioctl(hwahc_state_t *hwahcp, int cmd, intptr_t arg, 1689 int mode, cred_t *credp, int *rvalp) 1690 { 1691 int rv = 0; 1692 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 1693 1694 if (drv_priv(credp) != 0) { 1695 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 1696 "hwahc_wusb_ioctl: user must have SYS_DEVICE privilege," 1697 "cmd=%x", cmd); 1698 1699 return (EPERM); 1700 } 1701 1702 mutex_enter(&hwahcp->hwahc_mutex); 1703 1704 switch (cmd) { 1705 case WUSB_HC_GET_DSTATE: /* Get device state: wusbadm list */ 1706 { 1707 wusb_hc_get_dstate_t state; 1708 usb_port_t port = 0; 1709 1710 if (ddi_copyin((void *)arg, (void *)&state, sizeof (state), 1711 mode) != 0) { 1712 rv = EFAULT; 1713 1714 break; 1715 } 1716 1717 mutex_enter(&hc_data->hc_mutex); 1718 1719 if (wusb_hc_is_dev_connected(hc_data, &state.cdid[0], &port)) { 1720 state.state = hc_data->hc_dev_infos[port]->wdev_state; 1721 } else { 1722 /* cdid not found */ 1723 state.state = WUSB_STATE_UNCONNTED; 1724 } 1725 1726 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 1727 "hwahc_wusb_ioctl: hc_data=%p, port = %d, state=%d", 1728 (void *) hc_data, port, state.state); 1729 1730 mutex_exit(&hc_data->hc_mutex); 1731 1732 if (state.state == WUSB_STATE_CONFIGURED) { 1733 /* Get the bind device node name of this child */ 1734 (void) memset(state.nodename, 0, MAX_USB_NODENAME); 1735 (void) snprintf(state.nodename, MAX_USB_NODENAME, "%s", 1736 ddi_node_name(hwahc_get_child_dip(hwahcp, port))); 1737 1738 USB_DPRINTF_L3(PRINT_MASK_CBOPS, 1739 hwahcp->hwahc_log_handle, 1740 "WUSB_HC_GET_DSTATE: nodename %s", state.nodename); 1741 } 1742 1743 if (ddi_copyout((void *)&state, (void *)arg, 1744 sizeof (state), mode) != 0) { 1745 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1746 hwahcp->hwahc_log_handle, 1747 "WUSB_HC_GET_DSTATE: copyout failed"); 1748 rv = EIO; 1749 } 1750 1751 break; 1752 } 1753 1754 case WUSB_HC_GET_MAC_ADDR: /* Get host MAC addr */ 1755 { 1756 uint8_t mac_addr[6]; 1757 1758 bzero(mac_addr, 6); 1759 1760 /* 1761 * get UWB 48-bit mac address 1762 * Section 8.6.2.2. 1763 */ 1764 if (uwb_get_mac_addr(hwahcp->hwahc_dip, mac_addr) != 1765 USB_SUCCESS) { 1766 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1767 hwahcp->hwahc_log_handle, 1768 "WUSB_HC_GET_MAC_ADDR: get mac failed"); 1769 rv = EIO; 1770 1771 break; 1772 } 1773 1774 if (ddi_copyout((void *)mac_addr, (void *)arg, 1775 6, mode) != 0) { 1776 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1777 hwahcp->hwahc_log_handle, 1778 "WUSB_HC_GET_MAC_ADDR: copyout failed"); 1779 rv = EIO; 1780 } 1781 1782 break; 1783 } 1784 case WUSB_HC_ADD_CC: 1785 { 1786 /* 1787 * add a new device CC to host's list: wusbadm associate 1788 * Or, the application can pass in a fake CC with only CHID set 1789 * to set the host's CHID. 1790 */ 1791 wusb_hc_cc_list_t *cc_list; 1792 1793 cc_list = kmem_zalloc(sizeof (wusb_hc_cc_list_t), KM_SLEEP); 1794 1795 if (ddi_copyin((void *)arg, (void *)&cc_list->cc, 1796 sizeof (wusb_cc_t), mode) != 0) { 1797 rv = EFAULT; 1798 kmem_free(cc_list, sizeof (wusb_hc_cc_list_t)); 1799 1800 break; 1801 } 1802 1803 /* update CHID only when cc list is empty */ 1804 mutex_enter(&hc_data->hc_mutex); 1805 if (hc_data->hc_cc_list == NULL) { 1806 mutex_exit(&hc_data->hc_mutex); 1807 1808 if ((rv = hwahc_set_chid(hwahcp, 1809 cc_list->cc.CHID)) != 0) { 1810 kmem_free(cc_list, sizeof (wusb_hc_cc_list_t)); 1811 1812 break; 1813 } 1814 1815 mutex_enter(&hc_data->hc_mutex); 1816 } else { 1817 /* fail if the CHID in the new CC does not match */ 1818 if (memcmp(cc_list->cc.CHID, hc_data->hc_chid, 1819 16) != 0) { 1820 rv = EINVAL; 1821 kmem_free(cc_list, sizeof (wusb_hc_cc_list_t)); 1822 1823 mutex_exit(&hc_data->hc_mutex); 1824 break; 1825 } 1826 } 1827 cc_list->next = NULL; 1828 1829 wusb_hc_add_cc(&hc_data->hc_cc_list, cc_list); 1830 mutex_exit(&hc_data->hc_mutex); 1831 1832 break; 1833 } 1834 case WUSB_HC_REM_CC: 1835 { 1836 wusb_cc_t cc; 1837 usb_port_t port; 1838 1839 if (ddi_copyin((void *)arg, (void *)&cc, sizeof (wusb_cc_t), 1840 mode) != 0) { 1841 rv = EFAULT; 1842 1843 break; 1844 } 1845 1846 /* check if the CHID in the CC matches */ 1847 if (memcmp(cc.CHID, hc_data->hc_chid, 16) != 0) { 1848 rv = EINVAL; 1849 1850 break; 1851 } 1852 1853 /* if the device is connected, disconnect it first */ 1854 mutex_enter(&hc_data->hc_mutex); 1855 if (wusb_hc_is_dev_connected(hc_data, cc.CDID, &port)) { 1856 mutex_exit(&hc_data->hc_mutex); 1857 mutex_exit(&hwahcp->hwahc_mutex); 1858 /* 1859 * clean up host side state, device not 1860 * really disconnected. But user can safely remove 1861 * the device now. 1862 */ 1863 (void) hwahc_destroy_child(hc_data->hc_dip, port); 1864 mutex_enter(&hwahcp->hwahc_mutex); 1865 mutex_enter(&hc_data->hc_mutex); 1866 } 1867 1868 wusb_hc_rem_cc(&hc_data->hc_cc_list, &cc); 1869 mutex_exit(&hc_data->hc_mutex); 1870 1871 break; 1872 } 1873 case WUSB_HC_SET_CHANNEL: /* for debug purpose */ 1874 { 1875 uint8_t channel; 1876 1877 channel = (uint8_t)arg; 1878 1879 if (hwahcp->hwahc_hc_data.hc_channel == channel) { 1880 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1881 hwahcp->hwahc_log_handle, 1882 "WUSB_HC_SET_CHANNEL ioctl: same as existing"); 1883 1884 break; 1885 } 1886 1887 if (hwahcp->hwahc_hw_state != HWAHC_HW_STOPPED) { 1888 /* beacon is already started, stop it first */ 1889 if (uwb_stop_beacon(hwahcp->hwahc_dip) != USB_SUCCESS) { 1890 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1891 hwahcp->hwahc_log_handle, 1892 "WUSB_HC_SET_CHANNEL ioctl: " 1893 "stop beacon failed"); 1894 rv = EIO; 1895 1896 break; 1897 } 1898 /* update channel number */ 1899 hwahcp->hwahc_hc_data.hc_channel = channel; 1900 /* restart beacon on the new channel */ 1901 if (uwb_start_beacon(hwahcp->hwahc_dip, 1902 channel) != USB_SUCCESS) { 1903 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1904 hwahcp->hwahc_log_handle, 1905 "WUSB_HC_SET_CHANNEL ioctl: " 1906 "restart beacon failed"); 1907 rv = EIO; 1908 } 1909 1910 break; 1911 } 1912 1913 /* beacon is not started, simply update channel number */ 1914 hwahcp->hwahc_hc_data.hc_channel = channel; 1915 1916 break; 1917 } 1918 case WUSB_HC_START: 1919 { 1920 int flag; 1921 1922 1923 flag = (int)arg; 1924 1925 if (hwahcp->hwahc_hw_state == HWAHC_HW_STARTED) { 1926 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1927 hwahcp->hwahc_log_handle, 1928 "WUSB_HC_START ioctl: already started"); 1929 1930 break; 1931 } 1932 1933 /* 1934 * now we start hc only when the cc list is not NULL 1935 * this limitation may be removed if we support 1936 * numeric association, but CHID needs to be set 1937 * in advance for the hc to work 1938 */ 1939 mutex_enter(&hc_data->hc_mutex); 1940 if (hc_data->hc_cc_list == NULL) { 1941 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1942 hwahcp->hwahc_log_handle, 1943 "WUSB_HC_START ioctl: cc list not inited"); 1944 rv = EINVAL; 1945 1946 mutex_exit(&hc_data->hc_mutex); 1947 1948 break; 1949 } 1950 mutex_exit(&hc_data->hc_mutex); 1951 1952 /* cannot be both */ 1953 if ((flag & WUSB_HC_INITIAL_START) && (flag & 1954 WUSB_HC_CHANNEL_START)) { 1955 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1956 hwahcp->hwahc_log_handle, 1957 "WUSB_HC_START ioctl: flag cannot coexist"); 1958 rv = EINVAL; 1959 1960 break; 1961 } 1962 1963 /* 1964 * init Mac layer 16-bit dev addr. it is important for 1965 * authentication. It'd be better to let UWB provide 1966 * this address. 1967 */ 1968 mutex_enter(&hc_data->hc_mutex); 1969 if (hc_data->hc_addr == 0) { 1970 uint16_t dev_addr = HWAHC_DEV_ADDR_BASE + 1971 ddi_get_instance(hwahcp->hwahc_dip); 1972 1973 mutex_exit(&hc_data->hc_mutex); 1974 /* set UWB 16-bit dev address */ 1975 if (uwb_set_dev_addr(hwahcp->hwahc_dip, 1976 dev_addr) != USB_SUCCESS) { 1977 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1978 hwahcp->hwahc_log_handle, 1979 "WUSB_HC_START ioctl: set dev addr failed"); 1980 rv = EIO; 1981 1982 break; 1983 } 1984 1985 /* verify the dev addr is set correctly */ 1986 if (uwb_get_dev_addr(hwahcp->hwahc_dip, 1987 &dev_addr) != USB_SUCCESS) { 1988 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1989 hwahcp->hwahc_log_handle, 1990 "WUSB_HC_START ioctl: get dev addr failed"); 1991 rv = EIO; 1992 1993 break; 1994 } 1995 1996 mutex_enter(&hc_data->hc_mutex); 1997 hc_data->hc_addr = dev_addr; 1998 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 1999 hwahcp->hwahc_log_handle, 2000 "host dev addr = 0x%x", dev_addr); 2001 } 2002 mutex_exit(&hc_data->hc_mutex); 2003 2004 /* start functions of wusb host */ 2005 if ((flag & WUSB_HC_INITIAL_START) && 2006 (hwahcp->hwahc_hw_state == HWAHC_HW_STOPPED)) { 2007 if (hwahc_hc_initial_start(hwahcp) != USB_SUCCESS) { 2008 rv = EIO; 2009 } 2010 } else if ((flag & WUSB_HC_CHANNEL_START) && 2011 (hwahcp->hwahc_hw_state == HWAHC_HW_CH_STOPPED)) { 2012 if (hwahc_hc_channel_start(hwahcp) != USB_SUCCESS) { 2013 rv = EIO; 2014 } 2015 } else { 2016 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 2017 hwahcp->hwahc_log_handle, 2018 "WUSB_HC_START ioctl: unknown flag (%d) or " 2019 "state (%d)", flag, hwahcp->hwahc_hw_state); 2020 rv = EINVAL; 2021 } 2022 2023 break; 2024 } 2025 case WUSB_HC_STOP: 2026 { 2027 int flag; 2028 2029 flag = (int)arg; 2030 2031 /* cannot be both */ 2032 if ((flag & WUSB_HC_FINAL_STOP) && (flag & 2033 WUSB_HC_CHANNEL_STOP)) { 2034 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 2035 hwahcp->hwahc_log_handle, 2036 "WUSB_HC_STOP ioctl: flag cannot coexist"); 2037 rv = EINVAL; 2038 2039 break; 2040 } 2041 2042 if (flag & WUSB_HC_FINAL_STOP) { 2043 if (hwahc_hc_final_stop(hwahcp) != USB_SUCCESS) { 2044 rv = EIO; 2045 } 2046 } else if (flag & WUSB_HC_CHANNEL_STOP) { 2047 if (hwahc_hc_channel_stop(hwahcp) != USB_SUCCESS) { 2048 rv = EIO; 2049 } 2050 } else { 2051 /* must be one of the STOP flag */ 2052 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 2053 hwahcp->hwahc_log_handle, 2054 "WUSB_HC_STOP ioctl: invalid flag = %d", flag); 2055 rv = EINVAL; 2056 } 2057 2058 /* REM_ALL_CC flag is optional */ 2059 if ((rv == 0) && (flag & WUSB_HC_REM_ALL_CC)) { 2060 mutex_enter(&hc_data->hc_mutex); 2061 if (hc_data->hc_cc_list) { 2062 wusb_hc_free_cc_list(hc_data->hc_cc_list); 2063 hc_data->hc_cc_list = NULL; 2064 } 2065 mutex_exit(&hc_data->hc_mutex); 2066 } 2067 2068 break; 2069 } 2070 case WUSB_HC_GET_HSTATE: 2071 { 2072 int state; 2073 2074 if (hwahcp->hwahc_dev_state == USB_DEV_DISCONNECTED) { 2075 state = WUSB_HC_DISCONNTED; 2076 } else { 2077 switch (hwahcp->hwahc_hw_state) { 2078 case HWAHC_HW_STOPPED: 2079 state = WUSB_HC_STOPPED; 2080 break; 2081 case HWAHC_HW_STARTED: 2082 state = WUSB_HC_STARTED; 2083 break; 2084 case HWAHC_HW_CH_STOPPED: 2085 /* 2086 * app can mark the hwa as disabled 2087 * for this state 2088 */ 2089 state = WUSB_HC_CH_STOPPED; 2090 break; 2091 } 2092 } 2093 2094 if (ddi_copyout((void *)&state, (void *)arg, 2095 sizeof (int), mode) != 0) { 2096 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 2097 hwahcp->hwahc_log_handle, 2098 "WUSB_HC_GET_HSTATE: copyout failed"); 2099 rv = EIO; 2100 } 2101 2102 break; 2103 } 2104 default: 2105 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 2106 "hwahc_ioctl: unsupported command"); 2107 2108 rv = ENOTSUP; 2109 } 2110 mutex_exit(&hwahcp->hwahc_mutex); 2111 2112 return (rv); 2113 } 2114 2115 static int 2116 hwahc_ioctl(dev_t dev, int cmd, intptr_t arg, 2117 int mode, cred_t *credp, int *rvalp) 2118 { 2119 hwahc_state_t *hwahcp; 2120 int rval; 2121 2122 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2123 HWAHC_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 2124 2125 return (ENXIO); 2126 } 2127 2128 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 2129 "hwahc_ioctl: cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx", 2130 cmd, arg, mode, (void *) credp, (void *) rvalp, dev); 2131 2132 if (IS_DEVCTL(cmd)) { 2133 /* for cfgadm cmd support */ 2134 rval = hwahc_cfgadm_ioctl(hwahcp, cmd, arg, mode, credp, rvalp); 2135 } else { 2136 /* for wusbadm cmd support */ 2137 rval = hwahc_wusb_ioctl(hwahcp, cmd, arg, mode, credp, rvalp); 2138 } 2139 2140 return (rval); 2141 } 2142 2143 /* return the port number corresponding the child dip */ 2144 static usb_port_t 2145 hwahc_child_dip2port(hwahc_state_t *hwahcp, dev_info_t *dip) 2146 { 2147 usb_port_t port; 2148 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 2149 2150 mutex_enter(&hc_data->hc_mutex); 2151 for (port = 1; port <= hc_data->hc_num_ports; port++) { 2152 if (hc_data->hc_children_dips[port] == dip) { 2153 2154 break; 2155 } 2156 } 2157 ASSERT(port <= hc_data->hc_num_ports); 2158 mutex_exit(&hc_data->hc_mutex); 2159 2160 return (port); 2161 } 2162 2163 /* 2164 * child post attach/detach notification 2165 */ 2166 static void 2167 hwahc_post_attach(hwahc_state_t *hwahcp, dev_info_t *rdip, 2168 struct attachspec *as) 2169 { 2170 /* we don't need additional process for post-attach now */ 2171 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2172 "hwahc_post_attach: rdip = 0x%p result = %d", (void *) rdip, 2173 as->result); 2174 } 2175 2176 static void 2177 hwahc_post_detach(hwahc_state_t *hwahcp, dev_info_t *rdip, 2178 struct detachspec *as) 2179 { 2180 /* we don't need additional process for post-detach now */ 2181 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2182 "hwahc_post_detach: rdip = 0x%p result = %d", (void *) rdip, 2183 as->result); 2184 } 2185 2186 /* 2187 * bus ctl support. 2188 * To support different operations, such as a PreAttach preparation, 2189 * PostAttach operations. HWA only process the interested operations. 2190 * Other general ones are processed by usba_bus_ctl(). 2191 */ 2192 static int 2193 hwahc_bus_ctl(dev_info_t *dip, /* dip could be the parent */ 2194 dev_info_t *rdip, /* rdip is the dev node to be operated */ 2195 ddi_ctl_enum_t op, 2196 void *arg, 2197 void *result) 2198 { 2199 usba_device_t *usba_device = usba_get_usba_device(rdip); 2200 dev_info_t *hubdip = usba_device->usb_root_hub_dip; 2201 hwahc_state_t *hwahcp; 2202 struct attachspec *as; 2203 struct detachspec *ds; 2204 2205 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2206 ddi_get_instance(dip))) == NULL) { 2207 2208 return (DDI_FAILURE); 2209 } 2210 2211 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2212 "hwahc_bus_ctl:\n\t" 2213 "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p", 2214 (void *) dip, (void *) rdip, op, (void *) arg); 2215 2216 switch (op) { 2217 case DDI_CTLOPS_ATTACH: 2218 as = (struct attachspec *)arg; 2219 2220 switch (as->when) { 2221 case DDI_PRE : 2222 /* nothing to do basically */ 2223 USB_DPRINTF_L2(PRINT_MASK_EVENTS, 2224 hwahcp->hwahc_log_handle, 2225 "DDI_PRE DDI_CTLOPS_ATTACH"); 2226 break; 2227 case DDI_POST : 2228 hwahc_post_attach(hwahcp, rdip, 2229 (struct attachspec *)arg); 2230 break; 2231 } 2232 2233 break; 2234 case DDI_CTLOPS_DETACH: 2235 ds = (struct detachspec *)arg; 2236 2237 switch (ds->when) { 2238 case DDI_PRE : 2239 /* nothing to do basically */ 2240 USB_DPRINTF_L2(PRINT_MASK_EVENTS, 2241 hwahcp->hwahc_log_handle, 2242 "DDI_PRE DDI_CTLOPS_DETACH"); 2243 break; 2244 case DDI_POST : 2245 hwahc_post_detach(hwahcp, rdip, 2246 (struct detachspec *)arg); 2247 break; 2248 } 2249 2250 break; 2251 case DDI_CTLOPS_REPORTDEV: /* the workhorse behind ddi_report_dev */ 2252 { 2253 char *name, compat_name[64]; 2254 2255 if (usb_owns_device(rdip)) { 2256 (void) snprintf(compat_name, 2257 sizeof (compat_name), 2258 "usb%x,%x", 2259 usba_device->usb_dev_descr->idVendor, 2260 usba_device->usb_dev_descr->idProduct); 2261 } else if (usba_owns_ia(rdip)) { 2262 (void) snprintf(compat_name, 2263 sizeof (compat_name), 2264 "usbia%x,%x.config%x.%x", 2265 usba_device->usb_dev_descr->idVendor, 2266 usba_device->usb_dev_descr->idProduct, 2267 usba_device->usb_cfg_value, 2268 usb_get_if_number(rdip)); 2269 } else { 2270 (void) snprintf(compat_name, 2271 sizeof (compat_name), 2272 "usbif%x,%x.config%x.%x", 2273 usba_device->usb_dev_descr->idVendor, 2274 usba_device->usb_dev_descr->idProduct, 2275 usba_device->usb_cfg_value, 2276 usb_get_if_number(rdip)); 2277 } 2278 2279 cmn_err(CE_CONT, 2280 "?USB %x.%x %s (%s) operating wirelessly with " 2281 "HWA device: " 2282 "%s@%s, %s%d at bus address %d\n", 2283 (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8, 2284 usba_device->usb_dev_descr->bcdUSB & 0xff, 2285 (usb_owns_device(rdip) ? "device" : 2286 ((usba_owns_ia(rdip) ? "interface-association" : 2287 "interface"))), 2288 compat_name, 2289 ddi_node_name(rdip), ddi_get_name_addr(rdip), 2290 ddi_driver_name(rdip), 2291 ddi_get_instance(rdip), usba_device->usb_addr); 2292 2293 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 2294 (void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN); 2295 if (name[0] != '\0') { 2296 cmn_err(CE_CONT, "?\t%s\n", name); 2297 } 2298 kmem_free(name, MAXNAMELEN); 2299 2300 break; 2301 } 2302 default: 2303 /* pass to usba to handle */ 2304 return (usba_bus_ctl(hubdip, rdip, op, arg, result)); 2305 } 2306 2307 return (DDI_SUCCESS); 2308 } 2309 2310 /* 2311 * bus enumeration entry points 2312 * Configures the named device(BUS_CONFIG_ONE) or all devices under 2313 * the nexus(BUS_CONFIG_ALL). Drives devinfo state to DS_READY,i.e.device 2314 * is fully operational. 2315 * 2316 * This operation is driven from devfs(reading /devices), devctl, libdevinfo; 2317 * or from within the kernel to attach a boot device or layered underlying 2318 * driver. 2319 */ 2320 static int 2321 hwahc_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 2322 void *arg, dev_info_t **child) 2323 { 2324 hwahc_state_t *hwahcp; 2325 int rval, circ; 2326 2327 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2328 ddi_get_instance(dip))) == NULL) { 2329 2330 return (NDI_FAILURE); 2331 } 2332 2333 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2334 "hwahc_bus_config: op=%d", op); 2335 2336 if (hwahc_bus_config_debug) { 2337 flag |= NDI_DEVI_DEBUG; 2338 } 2339 2340 ndi_devi_enter(dip, &circ); 2341 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 2342 ndi_devi_exit(dip, circ); 2343 2344 return (rval); 2345 } 2346 2347 /* 2348 * Unconfigures the named device or all devices under the nexus. The 2349 * devinfo state is not DS_READY anymore. 2350 * This operations is driven by modunload, devctl or DR branch removal or 2351 * rem_drv(1M). 2352 */ 2353 static int 2354 hwahc_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 2355 void *arg) 2356 { 2357 hwahc_state_t *hwahcp; 2358 wusb_hc_data_t *hc_data; 2359 dev_info_t *cdip; 2360 usb_port_t port; 2361 int rval, circ; 2362 2363 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2364 ddi_get_instance(dip))) == NULL) { 2365 2366 return (NDI_FAILURE); 2367 } 2368 2369 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2370 "hwahc_bus_unconfig: op=%d", op); 2371 2372 if (hwahc_bus_config_debug) { 2373 flag |= NDI_DEVI_DEBUG; 2374 } 2375 2376 if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) { 2377 flag |= NDI_DEVI_REMOVE; 2378 } 2379 2380 /* serialize access */ 2381 ndi_devi_enter(dip, &circ); 2382 2383 /* unconfig children, detach them */ 2384 rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 2385 2386 /* logically zap children's list */ 2387 hc_data = &hwahcp->hwahc_hc_data; 2388 2389 mutex_enter(&hc_data->hc_mutex); 2390 for (port = 1; port <= hc_data->hc_num_ports; port++) { 2391 hc_data->hc_children_state[port] |= WUSB_CHILD_ZAP; 2392 } 2393 mutex_exit(&hc_data->hc_mutex); 2394 2395 /* fill in what's left */ 2396 for (cdip = ddi_get_child(dip); cdip; 2397 cdip = ddi_get_next_sibling(cdip)) { 2398 usba_device_t *usba_device = usba_get_usba_device(cdip); 2399 2400 if (usba_device == NULL) { 2401 2402 continue; 2403 } 2404 mutex_enter(&hc_data->hc_mutex); 2405 port = usba_device->usb_port; 2406 hc_data->hc_children_dips[port] = cdip; 2407 hc_data->hc_children_state[port] &= ~WUSB_CHILD_ZAP; 2408 mutex_exit(&hc_data->hc_mutex); 2409 } 2410 2411 /* physically zap the children we didn't find */ 2412 mutex_enter(&hc_data->hc_mutex); 2413 for (port = 1; port <= hc_data->hc_num_ports; port++) { 2414 if (hc_data->hc_children_state[port] & WUSB_CHILD_ZAP) { 2415 wusb_dev_info_t *dev_info; 2416 wusb_secrt_data_t *csecrt_data; 2417 usba_device_t *child_ud; 2418 2419 USB_DPRINTF_L3(PRINT_MASK_EVENTS, 2420 hwahcp->hwahc_log_handle, 2421 "hwahc_bus_unconfig: physically zap port %d", port); 2422 2423 child_ud = hc_data->hc_usba_devices[port]; 2424 mutex_exit(&hc_data->hc_mutex); 2425 /* zap the dip and usba_device structure as well */ 2426 usba_free_usba_device(child_ud); 2427 mutex_enter(&hc_data->hc_mutex); 2428 hc_data->hc_usba_devices[port] = NULL; 2429 2430 /* dip freed in usba_destroy_child_devi */ 2431 hc_data->hc_children_dips[port] = NULL; 2432 hc_data->hc_children_state[port] &= ~WUSB_CHILD_ZAP; 2433 2434 /* free hc_dev_infos[port] */ 2435 dev_info = hc_data->hc_dev_infos[port]; 2436 if (dev_info == NULL) { 2437 2438 continue; 2439 } 2440 2441 /* stop the device's trust timer before deallocate it */ 2442 hwahc_stop_trust_timer(dev_info); 2443 2444 if (dev_info->wdev_secrt_data.secrt_encry_descr) { 2445 csecrt_data = &dev_info->wdev_secrt_data; 2446 kmem_free(csecrt_data->secrt_encry_descr, 2447 sizeof (usb_encryption_descr_t) * 2448 csecrt_data->secrt_n_encry); 2449 } 2450 if (dev_info->wdev_uwb_descr) { 2451 kmem_free(dev_info->wdev_uwb_descr, 2452 sizeof (usb_uwb_cap_descr_t)); 2453 } 2454 kmem_free(dev_info, sizeof (wusb_dev_info_t)); 2455 hc_data->hc_dev_infos[port] = NULL; 2456 } 2457 } 2458 mutex_exit(&hc_data->hc_mutex); 2459 2460 ndi_devi_exit(dip, circ); 2461 2462 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2463 "hwahc_bus_unconfig: rval=%d", rval); 2464 2465 return (rval); 2466 } 2467 2468 /* 2469 * busctl event support 2470 * 2471 * Called by ndi_busop_get_eventcookie(). Return a event cookie 2472 * associated with one event name. 2473 * The eventname should be the one we defined in hwahc_ndi_event_defs 2474 */ 2475 static int 2476 hwahc_busop_get_eventcookie(dev_info_t *dip, 2477 dev_info_t *rdip, 2478 char *eventname, 2479 ddi_eventcookie_t *cookie) 2480 { 2481 hwahc_state_t *hwahcp; 2482 2483 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2484 ddi_get_instance(dip))) == NULL) { 2485 2486 return (NDI_FAILURE); 2487 } 2488 2489 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2490 "hwahc_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 2491 "event=%s", (void *)dip, (void *)rdip, eventname); 2492 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2493 "(dip=%s%d, rdip=%s%d)", 2494 ddi_driver_name(dip), ddi_get_instance(dip), 2495 ddi_driver_name(rdip), ddi_get_instance(rdip)); 2496 2497 /* return event cookie, iblock cookie, and level */ 2498 return (ndi_event_retrieve_cookie(hwahcp->hwahc_ndi_event_hdl, 2499 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 2500 } 2501 2502 /* 2503 * Add event handler for a given event cookie 2504 */ 2505 static int 2506 hwahc_busop_add_eventcall(dev_info_t *dip, 2507 dev_info_t *rdip, 2508 ddi_eventcookie_t cookie, 2509 void (*callback)(dev_info_t *dip, 2510 ddi_eventcookie_t cookie, void *arg, 2511 void *bus_impldata), 2512 void *arg, ddi_callback_id_t *cb_id) 2513 { 2514 hwahc_state_t *hwahcp; 2515 usb_port_t port; 2516 2517 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2518 ddi_get_instance(dip))) == NULL) { 2519 2520 return (NDI_FAILURE); 2521 } 2522 2523 port = hwahc_child_dip2port(hwahcp, rdip); 2524 2525 mutex_enter(&hwahcp->hwahc_mutex); 2526 2527 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2528 "hwahc_busop_add_eventcall: dip=0x%p, rdip=0x%p " 2529 "cookie=0x%p, cb=0x%p, arg=0x%p", 2530 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 2531 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2532 "(dip=%s%d, rdip=%s%d, event=%s)", 2533 ddi_driver_name(dip), ddi_get_instance(dip), 2534 ddi_driver_name(rdip), ddi_get_instance(rdip), 2535 ndi_event_cookie_to_name(hwahcp->hwahc_ndi_event_hdl, cookie)); 2536 2537 /* Set flag on children registering events */ 2538 switch (ndi_event_cookie_to_tag(hwahcp->hwahc_ndi_event_hdl, cookie)) { 2539 case USBA_EVENT_TAG_HOT_REMOVAL: 2540 hwahcp->hwahc_child_events[port] |= 2541 HWAHC_CHILD_EVENT_DISCONNECT; 2542 2543 break; 2544 case USBA_EVENT_TAG_PRE_SUSPEND: 2545 hwahcp->hwahc_child_events[port] |= 2546 HWAHC_CHILD_EVENT_PRESUSPEND; 2547 2548 break; 2549 default: 2550 2551 break; 2552 } 2553 2554 mutex_exit(&hwahcp->hwahc_mutex); 2555 2556 /* add callback to our event set */ 2557 return (ndi_event_add_callback(hwahcp->hwahc_ndi_event_hdl, 2558 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 2559 2560 } 2561 2562 2563 /* 2564 * Remove a callback previously added by bus_add_eventcall() 2565 */ 2566 static int 2567 hwahc_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 2568 { 2569 hwahc_state_t *hwahcp; 2570 ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id; 2571 2572 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 2573 ddi_get_instance(dip))) == NULL) { 2574 2575 return (NDI_FAILURE); 2576 } 2577 2578 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2579 "hwahc_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 2580 "cookie=0x%p", (void *)dip, (void *) id->ndi_evtcb_dip, 2581 (void *)id->ndi_evtcb_cookie); 2582 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2583 "(dip=%s%d, rdip=%s%d, event=%s)", 2584 ddi_driver_name(dip), ddi_get_instance(dip), 2585 ddi_driver_name(id->ndi_evtcb_dip), 2586 ddi_get_instance(id->ndi_evtcb_dip), 2587 ndi_event_cookie_to_name(hwahcp->hwahc_ndi_event_hdl, 2588 id->ndi_evtcb_cookie)); 2589 2590 /* remove event registration from our event set */ 2591 return (ndi_event_remove_callback(hwahcp->hwahc_ndi_event_hdl, cb_id)); 2592 } 2593 2594 /* 2595 * hwahc_post_event 2596 * post event to a single child on the port depending on the type, i.e. 2597 * to invoke the child's registered callback. 2598 */ 2599 static void 2600 hwahc_post_event(hwahc_state_t *hwahcp, usb_port_t port, usba_event_t type) 2601 { 2602 int rval; 2603 dev_info_t *dip; 2604 usba_device_t *usba_device; 2605 ddi_eventcookie_t cookie, rm_cookie, suspend_cookie; 2606 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 2607 2608 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2609 "hwahc_post_event: port=%d event=%s", port, 2610 ndi_event_tag_to_name(hwahcp->hwahc_ndi_event_hdl, type)); 2611 2612 cookie = ndi_event_tag_to_cookie(hwahcp->hwahc_ndi_event_hdl, type); 2613 rm_cookie = ndi_event_tag_to_cookie(hwahcp->hwahc_ndi_event_hdl, 2614 USBA_EVENT_TAG_HOT_REMOVAL); 2615 suspend_cookie = ndi_event_tag_to_cookie(hwahcp->hwahc_ndi_event_hdl, 2616 USBA_EVENT_TAG_PRE_SUSPEND); 2617 2618 /* 2619 * Hotplug daemon may be attaching a driver that may be registering 2620 * event callbacks. So it already has got the device tree lock and 2621 * event handle mutex. So to prevent a deadlock while posting events, 2622 * we grab and release the locks in the same order. 2623 */ 2624 mutex_enter(&hwahcp->hwahc_mutex); 2625 dip = hwahcp->hwahc_hc_data.hc_children_dips[port]; 2626 usba_device = hwahcp->hwahc_hc_data.hc_usba_devices[port]; 2627 mutex_exit((&hwahcp->hwahc_mutex)); 2628 2629 switch (type) { 2630 case USBA_EVENT_TAG_HOT_REMOVAL: 2631 /* stop this device's timer to prevent its further process */ 2632 mutex_enter(&hc_data->hc_mutex); 2633 2634 hwahc_stop_trust_timer(hc_data->hc_dev_infos[port]); 2635 mutex_exit(&hc_data->hc_mutex); 2636 2637 /* Clear the registered event flag */ 2638 mutex_enter(&hwahcp->hwahc_mutex); 2639 hwahcp->hwahc_child_events[port] &= 2640 ~HWAHC_CHILD_EVENT_DISCONNECT; 2641 mutex_exit(&hwahcp->hwahc_mutex); 2642 2643 (void) ndi_event_do_callback(hwahcp->hwahc_ndi_event_hdl, 2644 dip, cookie, NULL); 2645 usba_persistent_pipe_close(usba_device); 2646 2647 /* 2648 * Mark the dip for deletion only after the driver has 2649 * seen the disconnect event to prevent cleanup thread 2650 * from stepping in between. 2651 */ 2652 #ifndef __lock_lint 2653 mutex_enter(&DEVI(dip)->devi_lock); 2654 DEVI_SET_DEVICE_REMOVED(dip); 2655 mutex_exit(&DEVI(dip)->devi_lock); 2656 #endif 2657 2658 break; 2659 case USBA_EVENT_TAG_PRE_SUSPEND: 2660 mutex_enter(&hwahcp->hwahc_mutex); 2661 hwahcp->hwahc_child_events[port] &= 2662 ~HWAHC_CHILD_EVENT_PRESUSPEND; 2663 mutex_exit(&hwahcp->hwahc_mutex); 2664 2665 (void) ndi_event_do_callback(hwahcp->hwahc_ndi_event_hdl, 2666 dip, cookie, NULL); 2667 /* 2668 * persistent pipe close for this event is taken care by the 2669 * caller after verfying that all children can suspend 2670 */ 2671 2672 break; 2673 case USBA_EVENT_TAG_HOT_INSERTION: 2674 /* 2675 * Check if this child has missed the disconnect event before 2676 * it registered for event callbacks 2677 */ 2678 mutex_enter(&hwahcp->hwahc_mutex); 2679 if (hwahcp->hwahc_child_events[port] & 2680 HWAHC_CHILD_EVENT_DISCONNECT) { 2681 /* clear the flag and post disconnect event */ 2682 hwahcp->hwahc_child_events[port] &= 2683 ~HWAHC_CHILD_EVENT_DISCONNECT; 2684 mutex_exit(&hwahcp->hwahc_mutex); 2685 2686 (void) ndi_event_do_callback( 2687 hwahcp->hwahc_ndi_event_hdl, 2688 dip, rm_cookie, NULL); 2689 usba_persistent_pipe_close(usba_device); 2690 mutex_enter(&hwahcp->hwahc_mutex); 2691 } 2692 mutex_exit(&hwahcp->hwahc_mutex); 2693 2694 /* 2695 * Mark the dip as reinserted to prevent cleanup thread 2696 * from stepping in. 2697 */ 2698 #ifndef __lock_lint 2699 mutex_enter(&(DEVI(dip)->devi_lock)); 2700 DEVI_SET_DEVICE_REINSERTED(dip); 2701 mutex_exit(&(DEVI(dip)->devi_lock)); 2702 #endif 2703 2704 rval = usba_persistent_pipe_open(usba_device); 2705 if (rval != USB_SUCCESS) { 2706 USB_DPRINTF_L2(PRINT_MASK_EVENTS, 2707 hwahcp->hwahc_log_handle, 2708 "failed to reopen all pipes on reconnect"); 2709 } 2710 2711 (void) ndi_event_do_callback(hwahcp->hwahc_ndi_event_hdl, 2712 dip, cookie, NULL); 2713 2714 /* 2715 * We might see a connect event only if hotplug thread for 2716 * disconnect event don't run in time. 2717 * Set the flag again, so we don't miss posting a 2718 * disconnect event. 2719 */ 2720 mutex_enter(&hwahcp->hwahc_mutex); 2721 hwahcp->hwahc_child_events[port] |= 2722 HWAHC_CHILD_EVENT_DISCONNECT; 2723 mutex_exit(&hwahcp->hwahc_mutex); 2724 2725 break; 2726 case USBA_EVENT_TAG_POST_RESUME: 2727 /* 2728 * Check if this child has missed the pre-suspend event before 2729 * it registered for event callbacks 2730 */ 2731 mutex_enter(&hwahcp->hwahc_mutex); 2732 if (hwahcp->hwahc_child_events[port] & 2733 HWAHC_CHILD_EVENT_PRESUSPEND) { 2734 /* clear the flag and post pre_suspend event */ 2735 hwahcp->hwahc_child_events[port] &= 2736 ~HWAHC_CHILD_EVENT_PRESUSPEND; 2737 mutex_exit(&hwahcp->hwahc_mutex); 2738 (void) ndi_event_do_callback( 2739 hwahcp->hwahc_ndi_event_hdl, 2740 dip, suspend_cookie, NULL); 2741 mutex_enter(&hwahcp->hwahc_mutex); 2742 } 2743 mutex_exit(&hwahcp->hwahc_mutex); 2744 2745 mutex_enter(&usba_device->usb_mutex); 2746 usba_device->usb_no_cpr = 0; 2747 mutex_exit(&usba_device->usb_mutex); 2748 2749 /* 2750 * Since the pipe has already been opened by whub 2751 * at DDI_RESUME time, there is no need for a 2752 * persistent pipe open 2753 */ 2754 (void) ndi_event_do_callback(hwahcp->hwahc_ndi_event_hdl, 2755 dip, cookie, NULL); 2756 2757 /* 2758 * Set the flag again, so we don't miss posting a 2759 * pre-suspend event. This enforces a tighter 2760 * dev_state model. 2761 */ 2762 mutex_enter(&hwahcp->hwahc_mutex); 2763 hwahcp->hwahc_child_events[port] |= 2764 HWAHC_CHILD_EVENT_PRESUSPEND; 2765 mutex_exit(&hwahcp->hwahc_mutex); 2766 break; 2767 } 2768 } 2769 2770 /* 2771 * hwahc_run_callbacks: 2772 * Send an event to all children 2773 */ 2774 static void 2775 hwahc_run_callbacks(hwahc_state_t *hwahcp, usba_event_t type) 2776 { 2777 usb_port_t port; 2778 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 2779 2780 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2781 "hwahc_run_callbacks:"); 2782 2783 mutex_enter(&hc_data->hc_mutex); 2784 for (port = 1; port <= hc_data->hc_num_ports; port++) { 2785 if (hc_data->hc_children_dips[port]) { 2786 mutex_exit(&hc_data->hc_mutex); 2787 hwahc_post_event(hwahcp, port, type); 2788 mutex_enter(&hc_data->hc_mutex); 2789 } 2790 } 2791 mutex_exit(&hc_data->hc_mutex); 2792 } 2793 2794 /* 2795 * hwahc_disconnect_event_cb: 2796 * Called when hwa device hotplug-removed. 2797 * Close pipes 2798 * Post event to child 2799 * Set state to DISCONNECTED 2800 */ 2801 static int 2802 hwahc_disconnect_event_cb(dev_info_t *dip) 2803 { 2804 int instance = ddi_get_instance(dip); 2805 hwahc_state_t *hwahcp; 2806 int circ; 2807 2808 if ((hwahcp = ddi_get_soft_state(hwahc_statep, instance)) == NULL) { 2809 2810 return (USB_FAILURE); 2811 } 2812 2813 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2814 "hwahc_disconnect_event_cb: dip = 0x%p", (void *)dip); 2815 2816 ndi_devi_enter(dip, &circ); 2817 2818 mutex_enter(&hwahcp->hwahc_mutex); 2819 2820 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2821 "hwahc_disconnect_event_cb: devstate= %d hw-state=%d", 2822 hwahcp->hwahc_dev_state, hwahcp->hwahc_hw_state); 2823 switch (hwahcp->hwahc_dev_state) { 2824 case USB_DEV_ONLINE: 2825 case USB_DEV_PWRED_DOWN: 2826 hwahcp->hwahc_dev_state = USB_DEV_DISCONNECTED; 2827 2828 if (hwahcp->hwahc_hw_state != HWAHC_HW_STOPPED) { 2829 mutex_exit(&hwahcp->hwahc_mutex); 2830 wusb_wa_stop_nep(&hwahcp->hwahc_wa_data); 2831 mutex_enter(&hwahcp->hwahc_mutex); 2832 hwahc_stop_result_thread(hwahcp); 2833 hwahc_drain_notif_queue(hwahcp); 2834 } 2835 /* FALLTHROUGH */ 2836 case USB_DEV_SUSPENDED: 2837 /* remain in this state */ 2838 mutex_exit(&hwahcp->hwahc_mutex); 2839 hwahc_run_callbacks(hwahcp, USBA_EVENT_TAG_HOT_REMOVAL); 2840 mutex_enter(&hwahcp->hwahc_mutex); 2841 2842 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_INIT_STATE; 2843 2844 break; 2845 case USB_DEV_DISCONNECTED: 2846 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2847 "hwahc_disconnect_event_cb: already disconnected"); 2848 2849 break; 2850 default: 2851 USB_DPRINTF_L2(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2852 "hwahc_disconnect_event_cb: illegal devstate=%d", 2853 hwahcp->hwahc_dev_state); 2854 2855 break; 2856 } 2857 mutex_exit(&hwahcp->hwahc_mutex); 2858 2859 ndi_devi_exit(dip, circ); 2860 2861 return (USB_SUCCESS); 2862 } 2863 2864 2865 /* 2866 * hwahc_reconnect_event_cb: 2867 * Called with device hotplug-inserted 2868 * Restore state 2869 */ 2870 static int 2871 hwahc_reconnect_event_cb(dev_info_t *dip) 2872 { 2873 int instance = ddi_get_instance(dip); 2874 hwahc_state_t *hwahcp; 2875 int circ; 2876 2877 2878 if ((hwahcp = ddi_get_soft_state(hwahc_statep, instance)) == NULL) { 2879 2880 return (USB_FAILURE); 2881 } 2882 2883 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 2884 "hwahc_reconnect_event_cb: dip = 0x%p", (void *)dip); 2885 2886 ndi_devi_enter(dip, &circ); 2887 hwahc_restore_device_state(dip, hwahcp); 2888 ndi_devi_exit(dip, circ); 2889 2890 return (USB_SUCCESS); 2891 } 2892 2893 2894 /* 2895 * hwahc_pre_suspend_event_cb: 2896 * Called before HWA device suspend 2897 */ 2898 static int 2899 hwahc_pre_suspend_event_cb(dev_info_t *dip) 2900 { 2901 int instance = ddi_get_instance(dip); 2902 hwahc_state_t *hwahcp; 2903 int circ; 2904 2905 if ((hwahcp = ddi_get_soft_state(hwahc_statep, instance)) == NULL) { 2906 2907 return (USB_FAILURE); 2908 } 2909 2910 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2911 "hwahc_pre_suspend_event_cb: dip = 0x%p", (void *)dip); 2912 2913 mutex_enter(&hwahcp->hwahc_mutex); 2914 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 2915 "hwahc_pre_suspend_event_cb: start, hw state = %d, softstate = %d", 2916 hwahcp->hwahc_hw_state, hwahcp->hwahc_hc_soft_state); 2917 mutex_exit(&hwahcp->hwahc_mutex); 2918 2919 /* keep PM out till we see a cpr resume */ 2920 (void) hwahc_pm_busy_component(hwahcp); 2921 (void) pm_raise_power(hwahcp->hwahc_dip, 0, USB_DEV_OS_FULL_PWR); 2922 2923 ndi_devi_enter(dip, &circ); 2924 hwahc_run_callbacks(hwahcp, USBA_EVENT_TAG_PRE_SUSPEND); 2925 ndi_devi_exit(dip, circ); 2926 2927 /* 2928 * rc driver is always suspended first, that fails the hc suspend. 2929 * need to suspend hc before rc is suspended, so move the suspend 2930 * operations here 2931 */ 2932 mutex_enter(&hwahcp->hwahc_mutex); 2933 if (hwahcp->hwahc_dev_state != USB_DEV_ONLINE) { 2934 USB_DPRINTF_L3(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2935 "hwahc_pre_suspend_event_cb: dev_state = %d", 2936 hwahcp->hwahc_dev_state); 2937 mutex_exit(&hwahcp->hwahc_mutex); 2938 2939 return (USB_SUCCESS); 2940 } 2941 2942 if (hwahcp->hwahc_hw_state == HWAHC_HW_STARTED) { 2943 /* 2944 * notify children the host is going to stop 2945 */ 2946 (void) hwahc_hc_channel_suspend(hwahcp); 2947 } 2948 2949 /* stop the hc from functioning */ 2950 if (hwahcp->hwahc_hw_state != HWAHC_HW_STOPPED) { 2951 mutex_exit(&hwahcp->hwahc_mutex); 2952 wusb_wa_stop_nep(&hwahcp->hwahc_wa_data); 2953 2954 mutex_enter(&hwahcp->hwahc_mutex); 2955 hwahc_stop_result_thread(hwahcp); 2956 hwahc_drain_notif_queue(hwahcp); 2957 2958 mutex_exit(&hwahcp->hwahc_mutex); 2959 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 2960 hwahcp->hwahc_default_pipe); 2961 mutex_enter(&hwahcp->hwahc_mutex); 2962 2963 } 2964 2965 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 2966 "hwahc_pre_suspend_event_cb: end, devstate=%d " 2967 "hwstate=%d softstate = %d", 2968 hwahcp->hwahc_dev_state, hwahcp->hwahc_hw_state, 2969 hwahcp->hwahc_hc_soft_state); 2970 2971 mutex_exit(&hwahcp->hwahc_mutex); 2972 2973 return (USB_SUCCESS); 2974 } 2975 2976 2977 /* 2978 * hwahc_post_resume_event_cb: 2979 * Call after HWA device resume 2980 */ 2981 static int 2982 hwahc_post_resume_event_cb(dev_info_t *dip) 2983 { 2984 int instance = ddi_get_instance(dip); 2985 hwahc_state_t *hwahcp; 2986 int circ; 2987 2988 if ((hwahcp = ddi_get_soft_state(hwahc_statep, instance)) == NULL) { 2989 2990 return (USB_FAILURE); 2991 } 2992 2993 USB_DPRINTF_L4(PRINT_MASK_EVENTS, hwahcp->hwahc_log_handle, 2994 "hwahc_post_resume_event_cb: dip = 0x%p", (void *)dip); 2995 2996 mutex_enter(&hwahcp->hwahc_mutex); 2997 2998 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 2999 "hwahc_post_resume_event_cb: start, hw state = %d, softstate = %d", 3000 hwahcp->hwahc_hw_state, hwahcp->hwahc_hc_soft_state); 3001 mutex_exit(&hwahcp->hwahc_mutex); 3002 3003 ndi_devi_enter(dip, &circ); 3004 3005 /* need to place hc restore here to make sure rc has resumed */ 3006 hwahc_restore_device_state(dip, hwahcp); 3007 3008 hwahc_run_callbacks(hwahcp, USBA_EVENT_TAG_POST_RESUME); 3009 3010 ndi_devi_exit(dip, circ); 3011 3012 /* enable PM */ 3013 (void) hwahc_pm_idle_component(hwahcp); 3014 3015 return (USB_SUCCESS); 3016 } 3017 3018 3019 /* 3020 * hwahc_restore_device_state: 3021 * Called during hotplug-reconnect and resume. 3022 * re-enable power management 3023 * Verify the device is the same as before the disconnect/suspend. 3024 * Restore device state 3025 * Thaw any IO which was frozen. 3026 * Quiesce device. (Other routines will activate if thawed IO.) 3027 * Set device online. 3028 * Leave device disconnected if there are problems. 3029 */ 3030 static void 3031 hwahc_restore_device_state(dev_info_t *dip, hwahc_state_t *hwahcp) 3032 { 3033 int rval; 3034 int old_hw_state; 3035 3036 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3037 "hwahc_restore_device_state: dip = 0x%p", (void *)dip); 3038 3039 mutex_enter(&hwahcp->hwahc_mutex); 3040 3041 ASSERT((hwahcp->hwahc_dev_state == USB_DEV_DISCONNECTED) || 3042 (hwahcp->hwahc_dev_state == USB_DEV_SUSPENDED)); 3043 3044 /* raise power */ 3045 mutex_exit(&hwahcp->hwahc_mutex); 3046 hwahc_pm_busy_component(hwahcp); 3047 (void) pm_raise_power(hwahcp->hwahc_dip, 0, USB_DEV_OS_FULL_PWR); 3048 3049 /* 3050 * Check if we are talking to the same device 3051 * Some host controllers may see all devices disconnected 3052 * when they just resume. This may be a cause of not 3053 * finding the same device. 3054 * 3055 * Some HWA devices need to download firmware when it is 3056 * powered on. Before the firmware is downloaded, the device 3057 * will look differently. 3058 */ 3059 if (usb_check_same_device(dip, hwahcp->hwahc_log_handle, 3060 USB_LOG_L0, PRINT_MASK_ALL, 3061 USB_CHK_BASIC | USB_CHK_SERIAL | USB_CHK_VIDPID, NULL) != 3062 USB_SUCCESS) { 3063 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3064 "hwahc_restore_device_state: not the same device"); 3065 /* change the device state from suspended to disconnected */ 3066 mutex_enter(&hwahcp->hwahc_mutex); 3067 hwahcp->hwahc_dev_state = USB_DEV_DISCONNECTED; 3068 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_ERROR_STATE; 3069 mutex_exit(&hwahcp->hwahc_mutex); 3070 hwahc_pm_idle_component(hwahcp); 3071 3072 return; 3073 } 3074 3075 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3076 "hwahc_restore_device_state: Hwahc has been reconnected but" 3077 " data may have been lost"); 3078 3079 mutex_enter(&hwahcp->hwahc_mutex); 3080 3081 /* reinitialize the hw */ 3082 hwahcp->hwahc_dev_state = USB_DEV_ONLINE; 3083 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_INIT_STATE; 3084 3085 if (hwahcp->hwahc_hw_state == HWAHC_HW_STOPPED) { 3086 mutex_exit(&hwahcp->hwahc_mutex); 3087 /* no need to start hc */ 3088 hwahc_pm_idle_component(hwahcp); 3089 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3090 "hwahc_restore_device_state: stopped hwa"); 3091 3092 return; 3093 } 3094 3095 3096 rval = wusb_hc_set_cluster_id(&hwahcp->hwahc_hc_data, 3097 hwahcp->hwahc_hc_data.hc_cluster_id); 3098 3099 if (rval != USB_SUCCESS) { 3100 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3101 "hwahc_restore_device_state: set cluster id fails"); 3102 3103 goto err; 3104 } 3105 3106 if (hwahcp->hwahc_hw_state == HWAHC_HW_STARTED) { 3107 old_hw_state = hwahcp->hwahc_hw_state; 3108 hwahcp->hwahc_hw_state = HWAHC_HW_CH_STOPPED; 3109 rval = hwahc_hc_channel_start(hwahcp); 3110 if (rval != USB_SUCCESS) { 3111 USB_DPRINTF_L2(PRINT_MASK_ATTA, 3112 hwahcp->hwahc_log_handle, 3113 "hwahc_restore_device_state: start hc fails"); 3114 hwahcp->hwahc_hw_state = old_hw_state; 3115 3116 goto err; 3117 } 3118 hwahcp->hwahc_hw_state = old_hw_state; 3119 } 3120 3121 rval = wusb_hc_set_num_dnts(&hwahcp->hwahc_hc_data, 3122 HWAHC_DEFAULT_DNTS_INTERVAL, HWAHC_DEFAULT_DNTS_SLOT_NUM); 3123 if (rval != USB_SUCCESS) { 3124 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3125 "hwahc_restore_device_state: set num dnts fails"); 3126 3127 goto err; 3128 } 3129 3130 /* set default GTK */ 3131 rval = wusb_hc_set_gtk(&hwahcp->hwahc_hc_data, dft_gtk, dft_gtkid); 3132 if (rval != USB_SUCCESS) { 3133 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3134 "hwahc_restore_device_state: set gtk fails"); 3135 3136 goto err; 3137 } 3138 3139 mutex_exit(&hwahcp->hwahc_mutex); 3140 3141 rval = wusb_wa_enable(&hwahcp->hwahc_wa_data, 3142 hwahcp->hwahc_default_pipe); 3143 mutex_enter(&hwahcp->hwahc_mutex); 3144 if (rval != USB_SUCCESS) { 3145 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3146 "hwahc_restore_device_state: enable wa fails"); 3147 3148 goto err; 3149 } 3150 3151 /* 3152 * This is a workaround, sometimes the ioctl and reconnect will 3153 * happen at the sametime, so the ioctl will start nep which makes 3154 * the below sart nep fail. Need more work to do to avoid such 3155 * issues 3156 */ 3157 (void) wusb_wa_stop_nep(&hwahcp->hwahc_wa_data); 3158 3159 rval = wusb_wa_start_nep(&hwahcp->hwahc_wa_data, USB_FLAGS_SLEEP); 3160 if (rval != USB_SUCCESS) { 3161 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3162 "hwahc_restore_device_state: start notifep fails rval =%d", 3163 rval); 3164 mutex_exit(&hwahcp->hwahc_mutex); 3165 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 3166 hwahcp->hwahc_default_pipe); 3167 mutex_enter(&hwahcp->hwahc_mutex); 3168 3169 goto err; 3170 } 3171 3172 /* Handle transfer results on bulk-in ep */ 3173 rval = hwahc_start_result_thread(hwahcp); 3174 if (rval != USB_SUCCESS) { 3175 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3176 "hwahc_restore_device_state: start result thread fails"); 3177 mutex_exit(&hwahcp->hwahc_mutex); 3178 wusb_wa_stop_nep(&hwahcp->hwahc_wa_data); 3179 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 3180 hwahcp->hwahc_default_pipe); 3181 mutex_enter(&hwahcp->hwahc_mutex); 3182 3183 goto err; 3184 } 3185 3186 /* if the device had remote wakeup earlier, enable it again */ 3187 if (hwahcp->hwahc_pm && hwahcp->hwahc_pm->hwahc_wakeup_enabled) { 3188 mutex_exit(&hwahcp->hwahc_mutex); 3189 (void) usb_handle_remote_wakeup(hwahcp->hwahc_dip, 3190 USB_REMOTE_WAKEUP_ENABLE); 3191 mutex_enter(&hwahcp->hwahc_mutex); 3192 } 3193 3194 hwahcp->hwahc_hw_state = HWAHC_HW_STARTED; 3195 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_OPERATIONAL_STATE; 3196 mutex_exit(&hwahcp->hwahc_mutex); 3197 hwahc_pm_idle_component(hwahcp); 3198 3199 return; 3200 3201 err: 3202 hwahcp->hwahc_hw_state = HWAHC_HW_STOPPED; 3203 mutex_exit(&hwahcp->hwahc_mutex); 3204 hwahc_pm_idle_component(hwahcp); 3205 } 3206 3207 3208 /* 3209 * hwahc_cpr_suspend: 3210 * Clean up device. 3211 * Wait for any IO to finish, then close pipes. 3212 * Quiesce device. 3213 * due to the dependency on hwarc, the actual suspend operations are 3214 * moved to hwahc_pre_suspend_event_cb function. 3215 */ 3216 static int 3217 hwahc_cpr_suspend(dev_info_t *dip) 3218 { 3219 int instance = ddi_get_instance(dip); 3220 hwahc_state_t *hwahcp = ddi_get_soft_state(hwahc_statep, instance); 3221 3222 if (hwahcp == NULL) { 3223 3224 return (USB_FAILURE); 3225 } 3226 3227 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3228 "hwahc_cpr_suspend: start"); 3229 3230 mutex_enter(&hwahcp->hwahc_mutex); 3231 3232 /* Don't suspend if the device is open. */ 3233 if (hwahcp->hwahc_open_count > 0) { 3234 USB_DPRINTF_L2(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3235 "hwahc_cpr_suspend: Device is open, cannot suspend"); 3236 mutex_exit(&hwahcp->hwahc_mutex); 3237 3238 return (USB_FAILURE); 3239 } 3240 3241 mutex_exit(&hwahcp->hwahc_mutex); 3242 /* raise power */ 3243 hwahc_pm_busy_component(hwahcp); 3244 (void) pm_raise_power(hwahcp->hwahc_dip, 0, USB_DEV_OS_FULL_PWR); 3245 3246 mutex_enter(&hwahcp->hwahc_mutex); 3247 switch (hwahcp->hwahc_dev_state) { 3248 case USB_DEV_ONLINE: 3249 /* real suspend operations put in pre_suspend function */ 3250 /* FALLTHRU */ 3251 case USB_DEV_DISCONNECTED: 3252 case USB_DEV_PWRED_DOWN: 3253 hwahcp->hwahc_dev_state = USB_DEV_SUSPENDED; 3254 hwahcp->hwahc_hw_state = HWAHC_HW_CH_SUSPEND; 3255 3256 break; 3257 case USB_DEV_SUSPENDED: 3258 default: 3259 USB_DPRINTF_L2(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3260 "hwahc_cpr_suspend: illegal dev state=%d", 3261 hwahcp->hwahc_dev_state); 3262 3263 break; 3264 } 3265 3266 mutex_exit(&hwahcp->hwahc_mutex); 3267 hwahc_pm_idle_component(hwahcp); 3268 3269 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3270 "hwahc_cpr_suspend: end"); 3271 3272 return (USB_SUCCESS); 3273 } 3274 3275 3276 /* 3277 * hwahc_cpr_resume: 3278 * 3279 * hwahc_restore_device_state marks success by putting device back online 3280 */ 3281 static int 3282 hwahc_cpr_resume(dev_info_t *dip) 3283 { 3284 int instance = ddi_get_instance(dip); 3285 hwahc_state_t *hwahcp = ddi_get_soft_state(hwahc_statep, instance); 3286 3287 if (hwahcp == NULL) { 3288 3289 return (USB_FAILURE); 3290 } 3291 3292 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3293 "hwahc_cpr_resume: hw state = %d, softstate = %d", 3294 hwahcp->hwahc_hw_state, hwahcp->hwahc_hc_soft_state); 3295 3296 /* 3297 * rc is always resumed after hc. restoring hc before rc would fail. 3298 * move the restoring operations to hwahc_post_resume_event_cb. 3299 */ 3300 3301 return (USB_SUCCESS); 3302 } 3303 3304 /* 3305 * hwahc_create_pm_components: 3306 * Create power managements components 3307 */ 3308 static void 3309 hwahc_create_pm_components(dev_info_t *dip, hwahc_state_t *hwahcp) 3310 { 3311 hwahc_power_t *hwahcpm; 3312 uint_t pwr_states; 3313 3314 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3315 "hwahc_create_pm_components: Begin"); 3316 3317 /* Allocate the state structure */ 3318 hwahcpm = kmem_zalloc(sizeof (hwahc_power_t), KM_SLEEP); 3319 hwahcp->hwahc_pm = hwahcpm; 3320 hwahcpm->hwahc_state = hwahcp; 3321 hwahcpm->hwahc_pm_capabilities = 0; 3322 hwahcpm->hwahc_current_power = USB_DEV_OS_FULL_PWR; 3323 3324 if (usb_create_pm_components(dip, &pwr_states) == USB_SUCCESS) { 3325 USB_DPRINTF_L3(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3326 "hwahc_create_pm_components: created PM components"); 3327 3328 if (usb_handle_remote_wakeup(dip, 3329 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 3330 hwahcpm->hwahc_wakeup_enabled = 1; 3331 } 3332 hwahcpm->hwahc_pwr_states = (uint8_t)pwr_states; 3333 /* make device busy till end of attach */ 3334 hwahc_pm_busy_component(hwahcp); 3335 (void) pm_raise_power(hwahcp->hwahc_dip, 0, 3336 USB_DEV_OS_FULL_PWR); 3337 } else { 3338 USB_DPRINTF_L3(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3339 "hwahc_create_pm_components: failed"); 3340 } 3341 3342 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3343 "hwahc_create_pm_components: End"); 3344 } 3345 3346 /* 3347 * hwahc_destroy_pm_components: 3348 * Shut down and destroy power management and remote wakeup functionality 3349 */ 3350 static void 3351 hwahc_destroy_pm_components(hwahc_state_t *hwahcp) 3352 { 3353 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3354 "hwahc_destroy_pm_components: Begin"); 3355 3356 ASSERT(!mutex_owned(&hwahcp->hwahc_mutex)); 3357 3358 mutex_enter(&hwahcp->hwahc_mutex); 3359 if (hwahcp->hwahc_pm && (hwahcp->hwahc_dev_state != 3360 USB_DEV_DISCONNECTED)) { 3361 mutex_exit(&hwahcp->hwahc_mutex); 3362 hwahc_pm_busy_component(hwahcp); 3363 mutex_enter(&hwahcp->hwahc_mutex); 3364 3365 if (hwahcp->hwahc_pm->hwahc_wakeup_enabled) { 3366 int rval; 3367 3368 mutex_exit(&hwahcp->hwahc_mutex); 3369 (void) pm_raise_power(hwahcp->hwahc_dip, 0, 3370 USB_DEV_OS_FULL_PWR); 3371 3372 if ((rval = usb_handle_remote_wakeup( 3373 hwahcp->hwahc_dip, 3374 USB_REMOTE_WAKEUP_DISABLE)) != 3375 USB_SUCCESS) { 3376 USB_DPRINTF_L3(PRINT_MASK_PM, 3377 hwahcp->hwahc_log_handle, 3378 "hwahc_destroy_pm_components: " 3379 "Error disabling rmt wakeup: rval = %d", 3380 rval); 3381 } 3382 } else { 3383 mutex_exit(&hwahcp->hwahc_mutex); 3384 } 3385 3386 /* 3387 * Since remote wakeup is disabled now, 3388 * no one can raise power and get to device 3389 * once power is lowered here. 3390 */ 3391 (void) pm_lower_power(hwahcp->hwahc_dip, 0, USB_DEV_OS_PWR_OFF); 3392 3393 hwahc_pm_idle_component(hwahcp); 3394 mutex_enter(&hwahcp->hwahc_mutex); 3395 } 3396 3397 if (hwahcp->hwahc_pm) { 3398 kmem_free(hwahcp->hwahc_pm, sizeof (hwahc_power_t)); 3399 hwahcp->hwahc_pm = NULL; 3400 } 3401 mutex_exit(&hwahcp->hwahc_mutex); 3402 3403 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3404 "hwahc_destroy_pm_components: End"); 3405 } 3406 3407 /* mark component busy */ 3408 static void 3409 hwahc_pm_busy_component(hwahc_state_t *hwahcp) 3410 { 3411 ASSERT(!mutex_owned(&hwahcp->hwahc_mutex)); 3412 3413 if (hwahcp->hwahc_pm != NULL) { 3414 mutex_enter(&hwahcp->hwahc_mutex); 3415 hwahcp->hwahc_pm->hwahc_pm_busy++; 3416 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3417 "hwahc_pm_busy_component: %d", 3418 hwahcp->hwahc_pm->hwahc_pm_busy); 3419 mutex_exit(&hwahcp->hwahc_mutex); 3420 3421 if (pm_busy_component(hwahcp->hwahc_dip, 0) != 3422 DDI_SUCCESS) { 3423 mutex_enter(&hwahcp->hwahc_mutex); 3424 hwahcp->hwahc_pm->hwahc_pm_busy--; 3425 USB_DPRINTF_L2(PRINT_MASK_PM, 3426 hwahcp->hwahc_log_handle, 3427 "hwahc_pm_busy_component failed: %d", 3428 hwahcp->hwahc_pm->hwahc_pm_busy); 3429 mutex_exit(&hwahcp->hwahc_mutex); 3430 } 3431 } 3432 } 3433 3434 /* mark component idle */ 3435 static void 3436 hwahc_pm_idle_component(hwahc_state_t *hwahcp) 3437 { 3438 ASSERT(!mutex_owned(&hwahcp->hwahc_mutex)); 3439 3440 if (hwahcp->hwahc_pm != NULL) { 3441 3442 if (pm_idle_component(hwahcp->hwahc_dip, 0) == 3443 DDI_SUCCESS) { 3444 mutex_enter(&hwahcp->hwahc_mutex); 3445 ASSERT(hwahcp->hwahc_pm->hwahc_pm_busy > 0); 3446 hwahcp->hwahc_pm->hwahc_pm_busy--; 3447 USB_DPRINTF_L4(PRINT_MASK_PM, 3448 hwahcp->hwahc_log_handle, 3449 "hwahc_pm_idle_component: %d", 3450 hwahcp->hwahc_pm->hwahc_pm_busy); 3451 mutex_exit(&hwahcp->hwahc_mutex); 3452 } 3453 } 3454 } 3455 3456 /* 3457 * hwahc_power : 3458 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 3459 * usb_req_raise_power and usb_req_lower_power. 3460 */ 3461 /* ARGSUSED */ 3462 static int 3463 hwahc_power(dev_info_t *dip, int comp, int level) 3464 { 3465 hwahc_state_t *hwahcp; 3466 hwahc_power_t *pm; 3467 int rval = USB_FAILURE; 3468 3469 hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip)); 3470 3471 if (hwahcp == NULL) { 3472 3473 return (DDI_FAILURE); 3474 } 3475 3476 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3477 "hwahc_power: dip = 0x%p", (void *)dip); 3478 3479 mutex_enter(&hwahcp->hwahc_mutex); 3480 3481 if (hwahcp->hwahc_pm == NULL) { 3482 3483 goto done; 3484 } 3485 3486 pm = hwahcp->hwahc_pm; 3487 3488 /* Check if we are transitioning to a legal power level */ 3489 if (USB_DEV_PWRSTATE_OK(pm->hwahc_pwr_states, level)) { 3490 USB_DPRINTF_L2(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3491 "hwahc_power: illegal power level = %d " 3492 "pwr_states: %x", level, pm->hwahc_pwr_states); 3493 3494 goto done; 3495 } 3496 3497 switch (level) { 3498 case USB_DEV_OS_PWR_OFF : 3499 rval = hwahc_pwrlvl0(hwahcp); 3500 3501 break; 3502 case USB_DEV_OS_PWR_1: 3503 rval = hwahc_pwrlvl1(hwahcp); 3504 3505 break; 3506 case USB_DEV_OS_PWR_2: 3507 rval = hwahc_pwrlvl2(hwahcp); 3508 3509 break; 3510 case USB_DEV_OS_FULL_PWR : 3511 rval = hwahc_pwrlvl3(hwahcp); 3512 3513 break; 3514 } 3515 done: 3516 mutex_exit(&hwahcp->hwahc_mutex); 3517 3518 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 3519 } 3520 3521 /* 3522 * hwahc_pwrlvl0: 3523 * Functions to handle power transition for OS levels 0 -> 3 3524 * OS 0 <--> USB D3, no or minimal power 3525 */ 3526 static int 3527 hwahc_pwrlvl0(hwahc_state_t *hwahcp) 3528 { 3529 int rval; 3530 3531 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3532 "hwahc_pwrlvl0: %d", hwahcp->hwahc_pm->hwahc_pm_busy); 3533 3534 switch (hwahcp->hwahc_dev_state) { 3535 case USB_DEV_ONLINE: 3536 /* Deny the powerdown request if the device is busy */ 3537 if (hwahcp->hwahc_pm->hwahc_pm_busy != 0) { 3538 USB_DPRINTF_L2(PRINT_MASK_PM, 3539 hwahcp->hwahc_log_handle, 3540 "hwahc_pwrlvl0: hwahc_pm is busy"); 3541 3542 return (USB_FAILURE); 3543 } 3544 /* 3545 * only when final_stop gets called, we allow the system 3546 * to do PM on us. At this moment, we don't need to do 3547 * more operations other than those in final_stop. 3548 */ 3549 3550 /* Issue USB D3 command to the device here */ 3551 rval = usb_set_device_pwrlvl3(hwahcp->hwahc_dip); 3552 ASSERT(rval == USB_SUCCESS); 3553 3554 hwahcp->hwahc_dev_state = USB_DEV_PWRED_DOWN; 3555 3556 hwahcp->hwahc_pm->hwahc_current_power = USB_DEV_OS_PWR_OFF; 3557 3558 break; 3559 case USB_DEV_DISCONNECTED: 3560 case USB_DEV_SUSPENDED: 3561 case USB_DEV_PWRED_DOWN: 3562 default: 3563 break; 3564 } 3565 3566 return (USB_SUCCESS); 3567 } 3568 3569 /* 3570 * hwahc_pwrlvl1: 3571 * Functions to handle power transition to OS levels -> 2 3572 * OS level 1 <--> D2 3573 */ 3574 static int 3575 hwahc_pwrlvl1(hwahc_state_t *hwahcp) 3576 { 3577 int rval; 3578 3579 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3580 "hwahc_pwrlvl1:"); 3581 3582 /* Issue USB D2 command to the device here */ 3583 rval = usb_set_device_pwrlvl2(hwahcp->hwahc_dip); 3584 ASSERT(rval == USB_SUCCESS); 3585 3586 return (USB_FAILURE); 3587 } 3588 3589 /* 3590 * hwahc_pwrlvl2: 3591 * Functions to handle power transition to OS levels -> 1 3592 * OS leve 2 <--> D1 3593 */ 3594 static int 3595 hwahc_pwrlvl2(hwahc_state_t *hwahcp) 3596 { 3597 int rval; 3598 3599 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3600 "hwahc_pwrlvl2:"); 3601 3602 /* Issue USB D1 command to the device here */ 3603 rval = usb_set_device_pwrlvl1(hwahcp->hwahc_dip); 3604 ASSERT(rval == USB_SUCCESS); 3605 3606 return (USB_FAILURE); 3607 } 3608 3609 3610 /* 3611 * hwahc_pwrlvl3: 3612 * Functions to handle power transition to OS level -> 0 3613 * OS level 3 <--> D0 (full power) 3614 */ 3615 static int 3616 hwahc_pwrlvl3(hwahc_state_t *hwahcp) 3617 { 3618 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3619 "hwahc_pwrlvl3: %d", hwahcp->hwahc_pm->hwahc_pm_busy); 3620 3621 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 3622 3623 switch (hwahcp->hwahc_dev_state) { 3624 case USB_DEV_PWRED_DOWN: 3625 /* Issue USB D0 command to the device here */ 3626 (void) usb_set_device_pwrlvl0(hwahcp->hwahc_dip); 3627 3628 /* 3629 * Due to our current PM policy, it's not possible 3630 * for hwa to be in USB_DEV_PWRED_DOWN between 3631 * initial_start and final_stop. If it's PWRED_DOWN, 3632 * it should not start. We don't need to resume 3633 * soft or hardware state in this case. 3634 */ 3635 if (hwahcp->hwahc_hw_state == HWAHC_HW_STOPPED) { 3636 /* no need to start hc */ 3637 hwahcp->hwahc_dev_state = USB_DEV_ONLINE; 3638 hwahcp->hwahc_pm->hwahc_current_power = 3639 USB_DEV_OS_FULL_PWR; 3640 3641 return (USB_SUCCESS); 3642 } 3643 3644 hwahcp->hwahc_pm->hwahc_current_power = USB_DEV_OS_FULL_PWR; 3645 3646 /* FALLTHRU */ 3647 case USB_DEV_ONLINE: 3648 /* we are already in full power */ 3649 /* FALLTHRU */ 3650 case USB_DEV_DISCONNECTED: 3651 case USB_DEV_SUSPENDED: 3652 /* 3653 * PM framework tries to put you in full power 3654 * during system shutdown. If we are disconnected 3655 * return success. Also, we should not change state 3656 * when we are disconnected or suspended or about to 3657 * transition to that state 3658 */ 3659 3660 return (USB_SUCCESS); 3661 default: 3662 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3663 "hwahc_pwrlvl3: illegal dev_state=%d", 3664 hwahcp->hwahc_dev_state); 3665 3666 3667 return (USB_FAILURE); 3668 } 3669 } 3670 3671 /* 3672 * Host power management: stop channel 3673 * See Section 4.16.2.1 for details 3674 * See Section 8.1.0 for HWA suspend/resume 3675 */ 3676 static int 3677 hwahc_hc_channel_suspend(hwahc_state_t *hwahcp) 3678 { 3679 int rval; 3680 3681 USB_DPRINTF_L4(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3682 "hwahc_hc_channel_suspend:"); 3683 3684 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 3685 3686 /* no need to suspend if host hw was not started */ 3687 if (hwahcp->hwahc_hw_state != HWAHC_HW_STARTED) { 3688 USB_DPRINTF_L3(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3689 "hwahc_hc_channel_suspend: hw already stopped"); 3690 3691 return (USB_SUCCESS); 3692 } 3693 3694 if (hwahcp->hwahc_hw_state == HWAHC_HW_CH_SUSPEND) { 3695 USB_DPRINTF_L3(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3696 "hwahc_hc_channel_suspend: already suspended"); 3697 3698 return (USB_SUCCESS); 3699 } 3700 3701 mutex_exit(&hwahcp->hwahc_mutex); 3702 /* suspend host, refer to WUSB 1.0 spec 8.5.3.14 */ 3703 rval = wusb_hc_stop_ch(&hwahcp->hwahc_hc_data, 10000); /* 10ms */ 3704 mutex_enter(&hwahcp->hwahc_mutex); 3705 if (rval != USB_SUCCESS) { 3706 USB_DPRINTF_L2(PRINT_MASK_PM, hwahcp->hwahc_log_handle, 3707 "hwahc_hc_channel_suspend: wusb channel stop fails"); 3708 3709 return (rval); 3710 } 3711 3712 hwahcp->hwahc_hw_state = HWAHC_HW_CH_SUSPEND; 3713 3714 return (USB_SUCCESS); 3715 } 3716 3717 /* 3718 * Parse security descriptors, see T.8-43 3719 * put result in secrt_data 3720 */ 3721 static int 3722 hwahc_parse_security_data(wusb_secrt_data_t *secrt_data, 3723 usb_cfg_data_t *cfg_data) 3724 { 3725 int i, j; 3726 usb_cvs_data_t *cvs_data; 3727 size_t count, len; 3728 3729 if ((secrt_data == NULL) || (cfg_data == NULL)) { 3730 return (USB_INVALID_ARGS); 3731 } 3732 3733 for (i = 0; i < cfg_data->cfg_n_cvs; i++) { 3734 cvs_data = &cfg_data->cfg_cvs[i]; 3735 if (cvs_data == NULL) { 3736 continue; 3737 } 3738 if (cvs_data->cvs_buf[1] == USB_DESCR_TYPE_SECURITY) { 3739 count = usb_parse_data("ccsc", 3740 cvs_data->cvs_buf, cvs_data->cvs_buf_len, 3741 (void *)&secrt_data->secrt_descr, 3742 (size_t)USB_SECURITY_DESCR_SIZE); 3743 if (count != USB_SECURITY_DESCR_SIZE) { 3744 3745 return (USB_FAILURE); 3746 } else { 3747 secrt_data->secrt_n_encry = 3748 secrt_data->secrt_descr.bNumEncryptionTypes; 3749 len = sizeof (usb_encryption_descr_t) * 3750 secrt_data->secrt_n_encry; 3751 3752 secrt_data->secrt_encry_descr = 3753 (usb_encryption_descr_t *)kmem_alloc(len, 3754 KM_SLEEP); 3755 3756 for (j = 0; j < secrt_data->secrt_n_encry; 3757 j++) { 3758 cvs_data = 3759 &cfg_data->cfg_cvs[i + j + 1]; 3760 if (cvs_data->cvs_buf[1] != 3761 USB_DESCR_TYPE_ENCRYPTION) { 3762 kmem_free(secrt_data-> 3763 secrt_encry_descr, len); 3764 3765 return (USB_FAILURE); 3766 } 3767 3768 /* Table 7-34 */ 3769 count = usb_parse_data("ccccc", 3770 cvs_data->cvs_buf, 3771 cvs_data->cvs_buf_len, 3772 (void *)&secrt_data-> 3773 secrt_encry_descr[j], 3774 USB_ENCRYPTION_DESCR_SIZE); 3775 if (count != 3776 USB_ENCRYPTION_DESCR_SIZE) { 3777 kmem_free(secrt_data-> 3778 secrt_encry_descr, len); 3779 3780 return (USB_FAILURE); 3781 3782 } 3783 } 3784 return (USB_SUCCESS); 3785 } 3786 } 3787 } 3788 3789 return (USB_FAILURE); 3790 } 3791 3792 /* initialize wusb_hc_data_t structure */ 3793 static void 3794 hwahc_hc_data_init(hwahc_state_t *hwahcp) 3795 { 3796 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 3797 3798 hc_data->hc_dip = hwahcp->hwahc_dip; 3799 hc_data->hc_private_data = (void *)hwahcp; 3800 3801 (void) memset(hc_data->hc_chid, 0, sizeof (hc_data->hc_chid)); 3802 3803 hc_data->hc_num_mmcies = hwahcp->hwahc_wa_data.wa_descr.bNumMMCIEs; 3804 3805 ASSERT(hc_data->hc_num_mmcies != 0); 3806 3807 hc_data->hc_mmcie_list = kmem_zalloc((hc_data->hc_num_mmcies * 3808 sizeof (wusb_ie_header_t *)), KM_SLEEP); 3809 3810 /* initialize frequently used IE */ 3811 hc_data->hc_alive_ie.bIEIdentifier = WUSB_IE_DEV_KEEPALIVE; 3812 3813 /* register callbacks */ 3814 hc_data->disconnect_dev = hwahc_disconnect_dev; 3815 hc_data->reconnect_dev = hwahc_reconnect_dev; 3816 hc_data->create_child = hwahc_create_child; 3817 hc_data->destroy_child = hwahc_destroy_child; 3818 3819 /* HWA HC operation functions */ 3820 hc_data->set_encrypt = hwahc_set_encrypt; 3821 hc_data->set_ptk = hwahc_set_ptk; 3822 hc_data->set_gtk = hwahc_set_gtk; 3823 hc_data->set_device_info = hwahc_set_device_info; 3824 hc_data->set_cluster_id = hwahc_set_cluster_id; 3825 hc_data->set_stream_idx = hwahc_set_stream_idx; 3826 hc_data->set_wusb_mas = hwahc_set_wusb_mas; 3827 hc_data->add_mmc_ie = hwahc_add_mmc_ie; 3828 hc_data->rem_mmc_ie = hwahc_remove_mmc_ie; 3829 hc_data->stop_ch = hwahc_stop_ch; 3830 hc_data->set_num_dnts = hwahc_set_num_dnts; 3831 hc_data->get_time = hwahc_get_time; 3832 3833 hc_data->hc_num_ports = hwahcp->hwahc_wa_data.wa_descr.bNumPorts; 3834 3835 hc_data->hc_cd_list_length = (sizeof (dev_info_t **)) * 3836 (hc_data->hc_num_ports + 1); 3837 3838 hc_data->hc_children_dips = (dev_info_t **)kmem_zalloc( 3839 hc_data->hc_cd_list_length, KM_SLEEP); 3840 hc_data->hc_usba_devices = (usba_device_t **)kmem_zalloc( 3841 hc_data->hc_cd_list_length, KM_SLEEP); 3842 hc_data->hc_dev_infos = (wusb_dev_info_t **)kmem_zalloc( 3843 hc_data->hc_cd_list_length, KM_SLEEP); 3844 3845 mutex_init(&hc_data->hc_mutex, NULL, MUTEX_DRIVER, NULL); 3846 } 3847 3848 /* deinitialize wusb_hc_data_t structure */ 3849 static void 3850 hwahc_hc_data_fini(hwahc_state_t *hwahcp) 3851 { 3852 int i; 3853 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 3854 wusb_ie_header_t *hdr; 3855 3856 #ifdef DEBUG 3857 usb_port_t port; 3858 #endif 3859 3860 if (hc_data->hc_mmcie_list) { 3861 /* Free all recorded IEs except statically allocated IEs */ 3862 for (i = 0; i < hc_data->hc_num_mmcies; i++) { 3863 if (hc_data->hc_mmcie_list[i] != NULL) { 3864 hdr = hc_data->hc_mmcie_list[i]; 3865 if ((hdr->bIEIdentifier != 3866 WUSB_IE_DEV_KEEPALIVE)) { 3867 kmem_free(hdr, hdr->bLength); 3868 } 3869 hc_data->hc_mmcie_list[i] = NULL; 3870 } 3871 } 3872 3873 kmem_free(hc_data->hc_mmcie_list, 3874 hc_data->hc_num_mmcies * sizeof (wusb_ie_header_t *)); 3875 } 3876 3877 if (hc_data->hc_cluster_id) { 3878 wusb_hc_free_cluster_id(hc_data->hc_cluster_id); 3879 } 3880 3881 if (hc_data->hc_cc_list) { 3882 wusb_hc_free_cc_list(hc_data->hc_cc_list); 3883 } 3884 3885 #ifdef DEBUG 3886 for (port = 1; port <= hc_data->hc_num_ports; port++) { 3887 ASSERT(hc_data->hc_usba_devices[port] == NULL); 3888 ASSERT(hc_data->hc_children_dips[port] == NULL); 3889 ASSERT(hc_data->hc_dev_infos[port] == NULL); 3890 } 3891 #endif 3892 3893 kmem_free(hc_data->hc_children_dips, hc_data->hc_cd_list_length); 3894 kmem_free(hc_data->hc_usba_devices, hc_data->hc_cd_list_length); 3895 kmem_free(hc_data->hc_dev_infos, hc_data->hc_cd_list_length); 3896 3897 mutex_destroy(&hc_data->hc_mutex); 3898 } 3899 3900 /* fully start the HWA hw */ 3901 static int 3902 hwahc_hc_initial_start(hwahc_state_t *hwahcp) 3903 { 3904 uint8_t stream_idx; 3905 uint8_t mas[WUSB_SET_WUSB_MAS_LEN]; 3906 int rval; 3907 uint8_t cluster_id = 0; 3908 3909 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3910 "hwahc_hc_initial_start:"); 3911 3912 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 3913 3914 if (hwahcp->hwahc_dev_state != USB_DEV_ONLINE) { 3915 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3916 "hwahc_hc_initial_start: invalid dev state = %d", 3917 hwahcp->hwahc_dev_state); 3918 3919 return (USB_INVALID_REQUEST); 3920 } 3921 3922 if (hwahcp->hwahc_hw_state != HWAHC_HW_STOPPED) { 3923 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3924 "hwahc_hc_initial_start: invalid hw state"); 3925 3926 return (USB_INVALID_REQUEST); 3927 } 3928 3929 /* 3930 * start beacon of radio layer 3931 * We're not sure if previouse channel is occupied or not. So, let 3932 * UWB allocates a free channel for this hwa. Then we can start 3933 * beacon. 3934 */ 3935 hwahcp->hwahc_hc_data.hc_channel = 3936 uwb_allocate_channel(hwahcp->hwahc_dip); 3937 if (hwahcp->hwahc_hc_data.hc_channel == 0) { 3938 USB_DPRINTF_L2(PRINT_MASK_ATTA, 3939 hwahcp->hwahc_log_handle, 3940 "wusb_hc_initial_start: channel = %d", 3941 hwahcp->hwahc_hc_data.hc_channel); 3942 return (USB_FAILURE); 3943 } 3944 3945 if ((rval = uwb_start_beacon(hwahcp->hwahc_dip, 3946 hwahcp->hwahc_hc_data.hc_channel)) != USB_SUCCESS) { 3947 USB_DPRINTF_L2(PRINT_MASK_ATTA, 3948 hwahcp->hwahc_log_handle, 3949 "wusb_hc_initial_start: start uwb beacon failed"); 3950 3951 return (rval); 3952 } 3953 3954 mutex_exit(&hwahcp->hwahc_mutex); 3955 /* reset wire adapter */ 3956 rval = wusb_wa_reset(&hwahcp->hwahc_wa_data, 3957 hwahcp->hwahc_default_pipe); 3958 mutex_enter(&hwahcp->hwahc_mutex); 3959 if (rval != SUCCESS) { 3960 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3961 "hwahc_hc_initial_start: reset wa fails"); 3962 3963 goto err; 3964 } 3965 3966 /* reuse the old cluster id or assign one */ 3967 if (hwahcp->hwahc_hc_data.hc_cluster_id) { 3968 cluster_id = hwahcp->hwahc_hc_data.hc_cluster_id; 3969 } else { 3970 cluster_id = wusb_hc_get_cluster_id(); 3971 if (cluster_id == 0) { 3972 USB_DPRINTF_L2(PRINT_MASK_ATTA, 3973 hwahcp->hwahc_log_handle, 3974 "hwahc_hc_initial_start: cannot get cluster id"); 3975 rval = USB_NO_RESOURCES; 3976 3977 goto err; 3978 } 3979 } 3980 3981 mutex_exit(&hwahcp->hwahc_mutex); 3982 /* set cluster id for the wusb channel */ 3983 rval = wusb_hc_set_cluster_id(&hwahcp->hwahc_hc_data, cluster_id); 3984 if (rval != USB_SUCCESS) { 3985 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3986 "hwahc_hc_initial_start: set cluster id %d fails", 3987 cluster_id); 3988 mutex_enter(&hwahcp->hwahc_mutex); 3989 3990 goto err; 3991 } 3992 3993 /* UWB should be responsible for assigning stream index */ 3994 stream_idx = 1; 3995 3996 rval = wusb_hc_set_stream_idx(&hwahcp->hwahc_hc_data, stream_idx); 3997 if (rval != USB_SUCCESS) { 3998 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 3999 "hwahc_hc_initial_start: set stream idx %d fails", 4000 stream_idx); 4001 mutex_enter(&hwahcp->hwahc_mutex); 4002 4003 goto err; 4004 } 4005 4006 /* set dnts slot */ 4007 rval = wusb_hc_set_num_dnts(&hwahcp->hwahc_hc_data, 4008 HWAHC_DEFAULT_DNTS_INTERVAL, HWAHC_DEFAULT_DNTS_SLOT_NUM); 4009 4010 if (rval != USB_SUCCESS) { 4011 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4012 "hwahc_hc_initial_start: set num dnts fails"); 4013 mutex_enter(&hwahcp->hwahc_mutex); 4014 4015 goto err; 4016 } 4017 4018 /* set host info IE */ 4019 rval = wusb_hc_add_host_info(&hwahcp->hwahc_hc_data, stream_idx); 4020 if (rval != USB_SUCCESS) { 4021 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4022 "hwahc_hc_initial_start: add hostinfo ie fails"); 4023 mutex_enter(&hwahcp->hwahc_mutex); 4024 4025 goto err; 4026 } 4027 4028 /* reserve MAS slots for the host, need a way to assign */ 4029 (void) memset(mas, 0xff, WUSB_SET_WUSB_MAS_LEN); 4030 mas[0] = 0xf0; /* the first 4 slots are for beacons */ 4031 rval = wusb_hc_set_wusb_mas(&hwahcp->hwahc_hc_data, mas); 4032 mutex_enter(&hwahcp->hwahc_mutex); 4033 if (rval != USB_SUCCESS) { 4034 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4035 "hwahc_hc_initial_start: set wusb mas fails"); 4036 4037 goto err; 4038 } 4039 4040 /* record the available MAS slots */ 4041 (void) memcpy(hwahcp->hwahc_hc_data.hc_mas, mas, WUSB_SET_WUSB_MAS_LEN); 4042 4043 /* Set initial GTK/TKID to random values */ 4044 (void) random_get_pseudo_bytes(dft_gtk, 16); 4045 (void) random_get_pseudo_bytes(dft_gtkid, 3); 4046 4047 /* set default GTK, need a way to dynamically compute it */ 4048 mutex_exit(&hwahcp->hwahc_mutex); 4049 rval = wusb_hc_set_gtk(&hwahcp->hwahc_hc_data, dft_gtk, dft_gtkid); 4050 if (rval != USB_SUCCESS) { 4051 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4052 "hwahc_hc_initial_start: set gtk fails"); 4053 mutex_enter(&hwahcp->hwahc_mutex); 4054 4055 goto err; 4056 } 4057 4058 /* enable wire adapter */ 4059 rval = wusb_wa_enable(&hwahcp->hwahc_wa_data, 4060 hwahcp->hwahc_default_pipe); 4061 if (rval != USB_SUCCESS) { 4062 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4063 "hwahc_hc_initial_start: enable wa fails"); 4064 mutex_enter(&hwahcp->hwahc_mutex); 4065 4066 goto err; 4067 } 4068 4069 /* Start Notification endpoint */ 4070 rval = wusb_wa_start_nep(&hwahcp->hwahc_wa_data, USB_FLAGS_SLEEP); 4071 4072 if (rval != USB_SUCCESS) { 4073 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4074 "hwahc_hc_initial_start: start notification ep fails"); 4075 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 4076 hwahcp->hwahc_default_pipe); 4077 4078 mutex_enter(&hwahcp->hwahc_mutex); 4079 4080 goto err; 4081 } 4082 4083 mutex_enter(&hwahcp->hwahc_mutex); 4084 4085 /* 4086 * Handle transfer results on bulk-in ep 4087 * The bulk-in ep needs to be polled no matter the completion 4088 * notification is received or not to avoid miss result. 4089 */ 4090 rval = hwahc_start_result_thread(hwahcp); 4091 if (rval != USB_SUCCESS) { 4092 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4093 "hwahc_hc_initial_start: start result thread fails, " 4094 "rval = %d", rval); 4095 mutex_exit(&hwahcp->hwahc_mutex); 4096 wusb_wa_stop_nep(&hwahcp->hwahc_wa_data); 4097 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 4098 hwahcp->hwahc_default_pipe); 4099 mutex_enter(&hwahcp->hwahc_mutex); 4100 4101 goto err; 4102 } 4103 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4104 "hwahc_hc_initial_start: start result thread success"); 4105 4106 hwahcp->hwahc_hw_state = HWAHC_HW_STARTED; 4107 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_OPERATIONAL_STATE; 4108 4109 /* Don't do PM on an active beacon hwa until explicitly stopped */ 4110 mutex_exit(&hwahcp->hwahc_mutex); 4111 hwahc_pm_busy_component(hwahcp); 4112 mutex_enter(&hwahcp->hwahc_mutex); 4113 4114 return (USB_SUCCESS); 4115 4116 err: 4117 if (cluster_id != 0) { 4118 wusb_hc_free_cluster_id(cluster_id); 4119 } 4120 4121 mutex_exit(&hwahcp->hwahc_mutex); 4122 (void) uwb_stop_beacon(hwahcp->hwahc_dip); 4123 mutex_enter(&hwahcp->hwahc_mutex); 4124 4125 return (rval); 4126 } 4127 4128 /* entirely stop the HWA from working */ 4129 static int 4130 hwahc_hc_final_stop(hwahc_state_t *hwahcp) 4131 { 4132 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4133 "hwahc_hc_final_stop:"); 4134 4135 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 4136 4137 if (hwahcp->hwahc_hw_state == HWAHC_HW_STOPPED) { 4138 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4139 "hwahc_hc_final_stop: already stopped"); 4140 4141 return (USB_SUCCESS); 4142 } 4143 4144 if (hwahcp->hwahc_dev_state == USB_DEV_SUSPENDED) { 4145 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4146 "hwahc_hc_final_stop: invalid dev state = %d", 4147 hwahcp->hwahc_dev_state); 4148 4149 return (USB_INVALID_REQUEST); 4150 } 4151 4152 /* might have been powered down before detaching */ 4153 mutex_exit(&hwahcp->hwahc_mutex); 4154 (void) pm_raise_power(hwahcp->hwahc_dip, 0, USB_DEV_OS_FULL_PWR); 4155 mutex_enter(&hwahcp->hwahc_mutex); 4156 4157 if (hwahcp->hwahc_dev_state != USB_DEV_DISCONNECTED) { 4158 /* notify children the host is going to stop */ 4159 (void) hwahc_hc_channel_suspend(hwahcp); 4160 4161 /* release mutex here to avoid deadlock with exc_cb */ 4162 mutex_exit(&hwahcp->hwahc_mutex); 4163 4164 /* stop notification endpoint */ 4165 wusb_wa_stop_nep(&hwahcp->hwahc_wa_data); 4166 mutex_enter(&hwahcp->hwahc_mutex); 4167 4168 /* stop bulk-in ept from listening result */ 4169 hwahc_stop_result_thread(hwahcp); 4170 4171 /* drain the device notifications */ 4172 hwahc_drain_notif_queue(hwahcp); 4173 4174 /* disable wire adapter */ 4175 mutex_exit(&hwahcp->hwahc_mutex); 4176 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 4177 hwahcp->hwahc_default_pipe); 4178 4179 /* stop beaconing. Not necessary to unreserve mas */ 4180 (void) uwb_stop_beacon(hwahcp->hwahc_dip); 4181 4182 wusb_hc_rem_host_info(&hwahcp->hwahc_hc_data); 4183 4184 /* Manually remove all connected children */ 4185 hwahc_run_callbacks(hwahcp, USBA_EVENT_TAG_HOT_REMOVAL); 4186 4187 /* delete all the children */ 4188 (void) hwahc_cleanup_child(hwahcp->hwahc_dip); 4189 mutex_enter(&hwahcp->hwahc_mutex); 4190 } 4191 4192 /* 4193 * we make it busy at hwahc_hc_initial_start(). This idle operation 4194 * is to match that busy operation. 4195 * All other busy/idle operations should have been matched. 4196 */ 4197 if ((hwahcp->hwahc_hw_state == HWAHC_HW_STARTED) && 4198 (hwahcp->hwahc_hc_soft_state == HWAHC_CTRL_OPERATIONAL_STATE)) { 4199 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4200 "hwahc_hc_final_stop: pm_busy=%d", 4201 hwahcp->hwahc_pm->hwahc_pm_busy); 4202 mutex_exit(&hwahcp->hwahc_mutex); 4203 hwahc_pm_idle_component(hwahcp); 4204 mutex_enter(&hwahcp->hwahc_mutex); 4205 } 4206 4207 hwahcp->hwahc_hw_state = HWAHC_HW_STOPPED; 4208 if (hwahcp->hwahc_hc_soft_state == HWAHC_CTRL_OPERATIONAL_STATE) { 4209 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_INIT_STATE; 4210 } 4211 4212 return (USB_SUCCESS); 4213 } 4214 4215 /* 4216 * init WUSB channel, this is only part of the full hw start operations 4217 * including setting wusb channel stream idx, wusb MAS slots reservation 4218 * and adding host info IE 4219 */ 4220 static int 4221 hwahc_hc_channel_start(hwahc_state_t *hwahcp) 4222 { 4223 uint8_t stream_idx; 4224 uint8_t mas[WUSB_SET_WUSB_MAS_LEN]; 4225 int rval; 4226 4227 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4228 "hwahc_hc_channel_start:"); 4229 4230 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 4231 4232 if (hwahcp->hwahc_dev_state != USB_DEV_ONLINE) { 4233 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4234 "hwahc_hc_channel_start: invalid dev_state = %d", 4235 hwahcp->hwahc_dev_state); 4236 4237 return (USB_INVALID_REQUEST); 4238 } 4239 4240 if (hwahcp->hwahc_hw_state != HWAHC_HW_CH_STOPPED) { 4241 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4242 "hwahc_hc_channel_start: invalid hw state"); 4243 4244 return (USB_INVALID_REQUEST); 4245 } 4246 4247 /* set stream idx */ 4248 stream_idx = 1; 4249 4250 mutex_exit(&hwahcp->hwahc_mutex); 4251 rval = wusb_hc_set_stream_idx(&hwahcp->hwahc_hc_data, stream_idx); 4252 if (rval != USB_SUCCESS) { 4253 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4254 "hwahc_hc_channel_start: set stream idx %d fails", 4255 stream_idx); 4256 mutex_enter(&hwahcp->hwahc_mutex); 4257 4258 return (rval); 4259 } 4260 4261 /* reserve MAS slots for the host. Should be allocated by UWB */ 4262 (void) memset(mas, 0xff, WUSB_SET_WUSB_MAS_LEN); 4263 mas[0] = 0xf0; /* for beacons */ 4264 rval = wusb_hc_set_wusb_mas(&hwahcp->hwahc_hc_data, mas); 4265 4266 if (rval != USB_SUCCESS) { 4267 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4268 "hwahc_hc_channel_start: set wusb mas fails"); 4269 mutex_enter(&hwahcp->hwahc_mutex); 4270 4271 return (rval); 4272 } 4273 (void) memcpy(hwahcp->hwahc_hc_data.hc_mas, mas, WUSB_SET_WUSB_MAS_LEN); 4274 4275 /* set host info IE */ 4276 rval = wusb_hc_add_host_info(&hwahcp->hwahc_hc_data, stream_idx); 4277 4278 if (rval != USB_SUCCESS) { 4279 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4280 "hwahc_hc_channel_start: add hostinfo ie fails"); 4281 mutex_enter(&hwahcp->hwahc_mutex); 4282 4283 return (rval); 4284 } 4285 4286 mutex_enter(&hwahcp->hwahc_mutex); 4287 hwahcp->hwahc_hw_state = HWAHC_HW_STARTED; 4288 hwahcp->hwahc_hc_soft_state = HWAHC_CTRL_OPERATIONAL_STATE; 4289 4290 /* do not PM this device, once we're ready to accept DN */ 4291 mutex_exit(&hwahcp->hwahc_mutex); 4292 hwahc_pm_busy_component(hwahcp); 4293 mutex_enter(&hwahcp->hwahc_mutex); 4294 4295 return (USB_SUCCESS); 4296 } 4297 4298 /* 4299 * stop WUSB channel, this only stops part of the hw function 4300 * it mainly unreserve the MAS slots and remove the host info IE 4301 */ 4302 static int 4303 hwahc_hc_channel_stop(hwahc_state_t *hwahcp) 4304 { 4305 uint8_t stream_idx; 4306 uint8_t mas[WUSB_SET_WUSB_MAS_LEN]; 4307 int rval; 4308 4309 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4310 "hwahc_hc_channel_stop:"); 4311 4312 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 4313 4314 if (hwahcp->hwahc_dev_state != USB_DEV_ONLINE) { 4315 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4316 "hwahc_hc_channel_stop: invalid dev state %d", 4317 hwahcp->hwahc_dev_state); 4318 4319 return (USB_INVALID_REQUEST); 4320 } 4321 4322 if (hwahcp->hwahc_hw_state == HWAHC_HW_CH_STOPPED) { 4323 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4324 "hwahc_hc_channel_stop: already partially stopped"); 4325 4326 return (USB_SUCCESS); 4327 } 4328 4329 if (hwahcp->hwahc_hw_state == HWAHC_HW_STOPPED) { 4330 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4331 "hwahc_hc_channel_stop: already stopped, invalid state"); 4332 4333 return (USB_INVALID_REQUEST); 4334 } 4335 4336 /* send host disconect IE so that the children know to disconnect */ 4337 mutex_exit(&hwahcp->hwahc_mutex); 4338 rval = wusb_hc_send_host_disconnect(&hwahcp->hwahc_hc_data); 4339 if (rval != USB_SUCCESS) { 4340 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4341 "hwahc_hc_channel_stop: send host disconnect ie fails"); 4342 4343 mutex_enter(&hwahcp->hwahc_mutex); 4344 4345 return (rval); 4346 } 4347 4348 /* remove host info IE */ 4349 wusb_hc_rem_host_info(&hwahcp->hwahc_hc_data); 4350 4351 /* unset stream idx */ 4352 stream_idx = 0; 4353 4354 rval = wusb_hc_set_stream_idx(&hwahcp->hwahc_hc_data, stream_idx); 4355 if (rval != USB_SUCCESS) { 4356 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4357 "hwahc_hc_channel_stop: set stream idx 0 fails"); 4358 mutex_enter(&hwahcp->hwahc_mutex); 4359 4360 return (rval); 4361 } 4362 4363 /* unreserve MAS slots */ 4364 (void) memset(mas, 0, WUSB_SET_WUSB_MAS_LEN); 4365 rval = wusb_hc_set_wusb_mas(&hwahcp->hwahc_hc_data, mas); 4366 4367 if (rval != USB_SUCCESS) { 4368 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4369 "hwahc_hc_channel_stop: set null wusb mas fails"); 4370 mutex_enter(&hwahcp->hwahc_mutex); 4371 4372 return (rval); 4373 } 4374 4375 mutex_enter(&hwahcp->hwahc_mutex); 4376 (void) memcpy(hwahcp->hwahc_hc_data.hc_mas, mas, WUSB_SET_WUSB_MAS_LEN); 4377 4378 hwahcp->hwahc_hw_state = HWAHC_HW_CH_STOPPED; 4379 4380 /* Channel is stopped, can be PM'ed */ 4381 mutex_exit(&hwahcp->hwahc_mutex); 4382 hwahc_pm_idle_component(hwahcp); 4383 mutex_enter(&hwahcp->hwahc_mutex); 4384 4385 return (USB_SUCCESS); 4386 } 4387 4388 /* initialize data transfer related resources */ 4389 static int 4390 hwahc_wa_start(hwahc_state_t *hwahcp) 4391 { 4392 int rval; 4393 4394 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4395 "hwahc_wa_start:"); 4396 4397 /* get all rpipe descrs */ 4398 if ((rval = wusb_wa_get_rpipe_descrs(&hwahcp->hwahc_wa_data, 4399 hwahcp->hwahc_default_pipe, PRINT_MASK_ATTA, 4400 hwahcp->hwahc_log_handle)) != USB_SUCCESS) { 4401 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4402 "hwahc_wa_start: get rpipe descrs fails, rval=%d", rval); 4403 4404 return (rval); 4405 } 4406 4407 /* open all data transfer epts */ 4408 if ((rval = wusb_wa_open_pipes(&hwahcp->hwahc_wa_data)) != 4409 USB_SUCCESS) { 4410 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4411 "hwahc_wa_start: open pipes fails, rval=%d", rval); 4412 (void) wusb_wa_disable(&hwahcp->hwahc_wa_data, 4413 hwahcp->hwahc_default_pipe); 4414 4415 return (rval); 4416 } 4417 4418 /* init notification list */ 4419 usba_init_list(&hwahcp->hwahc_dn_notif_queue, NULL, 4420 hwahcp->hwahc_dev_data->dev_iblock_cookie); 4421 4422 return (USB_SUCCESS); 4423 } 4424 4425 /* deinitialize data transfer related resources */ 4426 static void 4427 hwahc_wa_stop(hwahc_state_t *hwahcp) 4428 { 4429 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4430 "hwahc_wa_stop:"); 4431 4432 usba_destroy_list(&hwahcp->hwahc_dn_notif_queue); 4433 wusb_wa_close_pipes(&hwahcp->hwahc_wa_data); 4434 } 4435 4436 /* 4437 * HUBD related initialization 4438 * To mimic standard hub attach process to create a fake "root hub" 4439 * for HWA 4440 */ 4441 static int 4442 hwahc_hub_attach(hwahc_state_t *hwahcp) 4443 { 4444 hubd_t *hubd = NULL; 4445 dev_info_t *dip = hwahcp->hwahc_dip; 4446 int instance = ddi_get_instance(dip); 4447 int i; 4448 int rval; 4449 4450 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4451 "hwahc_hub_attach:"); 4452 4453 if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 4454 "wire-adapter") != NDI_SUCCESS) { 4455 4456 return (USB_FAILURE); 4457 } 4458 4459 /* allocate hubd structure */ 4460 hubd = hwahcp->hwahc_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP); 4461 4462 hubd->h_log_handle = usb_alloc_log_hdl(dip, "husb", &hubd_errlevel, 4463 &hubd_errmask, &hubd_instance_debug, 0); 4464 hubd->h_usba_device = usba_get_usba_device(dip); 4465 hubd->h_usba_device->usb_is_wa = TRUE; 4466 hubd->h_dip = dip; 4467 hubd->h_instance = instance; 4468 hubd->h_ignore_pwr_budget = B_TRUE; 4469 hubd->h_cleanup_child = hwahc_cleanup_child; 4470 4471 mutex_enter(&hubd->h_usba_device->usb_mutex); 4472 hubd->h_usba_device->usb_root_hubd = hubd; 4473 mutex_exit(&hubd->h_usba_device->usb_mutex); 4474 4475 if (usb_get_dev_data(dip, &hubd->h_dev_data, 4476 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) { 4477 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 4478 "cannot get dev_data"); 4479 4480 goto fail; 4481 } 4482 4483 /* init hubd mutex */ 4484 mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER, 4485 hubd->h_dev_data->dev_iblock_cookie); 4486 4487 usb_free_descr_tree(dip, hubd->h_dev_data); 4488 4489 hubd->h_init_state |= HUBD_LOCKS_DONE; 4490 4491 /* register the instance to usba HUBDI */ 4492 rval = usba_hubdi_register(dip, 0); 4493 if (rval != USB_SUCCESS) { 4494 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 4495 "usba_hubdi_register failed"); 4496 4497 goto fail; 4498 } 4499 4500 mutex_enter(HUBD_MUTEX(hubd)); 4501 hubd->h_init_state |= HUBD_HUBDI_REGISTERED; 4502 4503 hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, 4504 KM_SLEEP); 4505 hubd_get_ancestry_str(hubd); 4506 4507 /* create cfgadm minor nodes */ 4508 for (i = 1; i <= hwahcp->hwahc_wa_data.wa_descr.bNumPorts; i++) { 4509 char ap_name[HUBD_APID_NAMELEN]; 4510 4511 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d", 4512 hubd->h_ancestry_str, i); 4513 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4514 "ap_name=%s", ap_name); 4515 4516 if (ddi_create_minor_node(dip, ap_name, S_IFCHR, 4517 (instance << HWAHC_MINOR_INSTANCE_SHIFT) | i, 4518 DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 4519 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 4520 "cannot create attachment point node (%d)", 4521 instance); 4522 mutex_exit(HUBD_MUTEX(hubd)); 4523 4524 goto fail; 4525 } 4526 } 4527 i = hwahcp->hwahc_wa_data.wa_descr.bNumPorts; 4528 mutex_exit(HUBD_MUTEX(hubd)); 4529 4530 /* create hubd minor node */ 4531 if (ddi_create_minor_node(dip, "hubd", S_IFCHR, 4532 instance << HWAHC_MINOR_INSTANCE_SHIFT, 4533 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 4534 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 4535 "cannot create devctl minor node (%d)", instance); 4536 4537 goto fail; 4538 } 4539 4540 mutex_enter(HUBD_MUTEX(hubd)); 4541 hubd->h_init_state |= HUBD_MINOR_NODE_CREATED; 4542 mutex_exit(HUBD_MUTEX(hubd)); 4543 4544 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, 4545 "usb-port-count", i) != DDI_PROP_SUCCESS) { 4546 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle, 4547 "usb-port-count update failed"); 4548 } 4549 4550 return (USB_SUCCESS); 4551 4552 fail: 4553 if (hwahc_hub_detach(hwahcp) != USB_SUCCESS) { 4554 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4555 "fail to cleanup after hub attach failure"); 4556 } 4557 4558 return (USB_FAILURE); 4559 } 4560 4561 /* HUBD related deinitialization */ 4562 static int 4563 hwahc_hub_detach(hwahc_state_t *hwahcp) 4564 { 4565 hubd_t *hubd = hwahcp->hwahc_hubd; 4566 dev_info_t *dip = hwahcp->hwahc_dip; 4567 4568 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4569 "hwahc_hub_detach:"); 4570 4571 if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) { 4572 goto done; 4573 } 4574 4575 if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) { 4576 /* remove minor nodes */ 4577 ddi_remove_minor_node(dip, NULL); 4578 } 4579 4580 if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) { 4581 /* unregister with usba HUBDI */ 4582 (void) usba_hubdi_unregister(dip); 4583 } 4584 4585 if (hubd->h_init_state & HUBD_LOCKS_DONE) { 4586 mutex_destroy(HUBD_MUTEX(hubd)); 4587 } 4588 4589 if (hubd->h_ancestry_str) { 4590 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN); 4591 } 4592 4593 done: 4594 if (hubd->h_dev_data) { 4595 /* unregister client from usba */ 4596 usb_client_detach(dip, hubd->h_dev_data); 4597 } 4598 4599 usb_free_log_hdl(hubd->h_log_handle); 4600 kmem_free(hubd, sizeof (hubd_t)); 4601 ddi_prop_remove_all(dip); 4602 4603 return (USB_SUCCESS); 4604 } 4605 4606 /* print security descrs */ 4607 static void 4608 hwahc_print_secrt_data(hwahc_state_t *hwahcp) 4609 { 4610 int i; 4611 wusb_secrt_data_t *secrt_data = &hwahcp->hwahc_secrt_data; 4612 4613 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4614 "The Host Wire Adapter security descriptor:"); 4615 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4616 "bLength = 0x%x\t\t bDescriptorType = 0x%x", 4617 secrt_data->secrt_descr.bLength, 4618 secrt_data->secrt_descr.bDescriptorType); 4619 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4620 "wTotalLength = 0x%x\t bNumEncryptionTypes = 0x%x", 4621 secrt_data->secrt_descr.wTotalLength, 4622 secrt_data->secrt_descr.bNumEncryptionTypes); 4623 4624 for (i = 0; i < secrt_data->secrt_n_encry; i++) { 4625 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4626 "The Host Wire Adapter encryption descriptor %d:", i + 1); 4627 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4628 "bLength = 0x%x\t\t bDescriptorType = 0x%x", 4629 secrt_data->secrt_encry_descr[i].bLength, 4630 secrt_data->secrt_encry_descr[i].bDescriptorType); 4631 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4632 "bEncryptionType = 0x%x\t bEncryptionValue = 0x%x", 4633 secrt_data->secrt_encry_descr[i].bEncryptionType, 4634 secrt_data->secrt_encry_descr[i].bEncryptionValue); 4635 USB_DPRINTF_L3(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4636 "bAuthKeyIndex = 0x%x", 4637 secrt_data->secrt_encry_descr[i].bAuthKeyIndex); 4638 } 4639 } 4640 4641 /* drain device notifications */ 4642 static void 4643 hwahc_drain_notif_queue(hwahc_state_t *hwahcp) 4644 { 4645 int i; 4646 4647 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 4648 4649 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 4650 "hwahc_drain_notif_queue: started"); 4651 4652 if ((hwahcp->hwahc_notif_thread_id == NULL) && 4653 (usba_list_entry_count(&hwahcp->hwahc_dn_notif_queue) != 0)) { 4654 /* kick off a notif thread to drain the queue */ 4655 if (usb_async_req(hwahcp->hwahc_dip, hwahc_notif_thread, 4656 (void *)hwahcp, 0) != USB_SUCCESS) { 4657 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 4658 hwahcp->hwahc_log_handle, 4659 "hwahc_drain_notif_queue: no notif thread started"); 4660 } else { 4661 hwahcp->hwahc_notif_thread_id = (kthread_t *)1; 4662 } 4663 } 4664 4665 for (i = 0; i < HWAHC_NOTIF_DRAIN_TIMEOUT; i++) { 4666 /* loop until the queue is completed or it timeouts */ 4667 if ((hwahcp->hwahc_notif_thread_id == NULL) && 4668 (usba_list_entry_count(&hwahcp->hwahc_dn_notif_queue) == 4669 0)) { 4670 4671 break; 4672 } 4673 mutex_exit(&hwahcp->hwahc_mutex); 4674 delay(drv_usectohz(1000000)); 4675 mutex_enter(&hwahcp->hwahc_mutex); 4676 } 4677 4678 /* cleanup the queue if not completed */ 4679 while (usba_list_entry_count(&hwahcp->hwahc_dn_notif_queue) != 0) { 4680 hwahc_dn_notif_list_t *nlist; 4681 4682 nlist = (hwahc_dn_notif_list_t *)usba_rm_first_pvt_from_list( 4683 &hwahcp->hwahc_dn_notif_queue); 4684 ASSERT(nlist != NULL); 4685 ASSERT(nlist->dn_notif != NULL); 4686 usba_destroy_list(&nlist->notif_list); 4687 kmem_free(nlist->dn_notif, nlist->dn_notif->bLength); 4688 kmem_free(nlist, sizeof (hwahc_dn_notif_list_t)); 4689 } 4690 4691 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 4692 "hwahc_drain_notif_queue: ended"); 4693 } 4694 4695 4696 /* normal callback for notification ept */ 4697 static void 4698 hwahc_intr_cb(usb_pipe_handle_t ph, struct usb_intr_req *reqp) 4699 { 4700 dev_info_t *dip = (USBA_REQ2WRP(reqp))->wr_dip; 4701 hwahc_state_t *hwahcp; 4702 mblk_t *data = reqp->intr_data; 4703 4704 ASSERT(dip != NULL); 4705 hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip)); 4706 ASSERT(hwahcp != NULL); 4707 4708 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 4709 "hwahc_intr_cb: ph = 0x%p reqp = 0x%p", (void *)ph, 4710 (void *)reqp); 4711 4712 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 4713 4714 if (data == NULL) { 4715 usb_free_intr_req(reqp); 4716 4717 return; 4718 } 4719 4720 /* handle the notification */ 4721 hwahc_handle_notif(hwahcp, data); 4722 4723 usb_free_intr_req(reqp); 4724 } 4725 4726 /* 4727 * See Section 8.3.3.3 for Transfer Notification format and 4728 * Section 8.5.4 for HWA specific notifications. 4729 * Three kinds of Notifications: 4730 * - Transfer Completion 4731 * - DN Received 4732 * - BPST ADJ 4733 */ 4734 /* handle the notification according to notification type */ 4735 static void 4736 hwahc_handle_notif(hwahc_state_t *hwahcp, mblk_t *data) 4737 { 4738 int len; 4739 uint8_t *p; 4740 wa_notif_header_t *hdr; 4741 4742 if (data == NULL) { 4743 4744 return; 4745 } 4746 4747 len = MBLKL(data); 4748 p = data->b_rptr; 4749 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 4750 "hwahc_handle_notif: data len = %d", len); 4751 4752 /* 4753 * according to WUSB 1.0/8.1.2, multiple notifications might be sent 4754 * at a time, need to parse one by one 4755 */ 4756 while (len > 0) { 4757 if (len < 2) { 4758 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 4759 hwahcp->hwahc_log_handle, 4760 "hwahc_handle_notif: short packet len = %d", 4761 len); 4762 4763 break; 4764 } 4765 4766 hdr = (wa_notif_header_t *)p; 4767 if (len < hdr->bLength) { 4768 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 4769 hwahcp->hwahc_log_handle, 4770 "hwahc_handle_notif: length not match, " 4771 "hdr length = %d, actual length = %d", 4772 hdr->bLength, len); 4773 4774 break; 4775 } 4776 4777 switch (hdr->bNotifyType) { 4778 case WA_NOTIF_TYPE_TRANSFER: 4779 { 4780 uint8_t ept = p[2]; 4781 4782 /* deal with transfer completion notification */ 4783 hwahc_handle_xfer_result(hwahcp, ept); 4784 4785 break; 4786 } 4787 case HWA_NOTIF_TYPE_DN_RECEIVED: 4788 { 4789 hwa_notif_dn_recvd_t *dn_notif; 4790 4791 dn_notif = kmem_alloc(hdr->bLength, KM_NOSLEEP); 4792 (void) memcpy(dn_notif, p, hdr->bLength); 4793 4794 /* deal with device notification */ 4795 hwahc_handle_dn_notif(hwahcp, dn_notif); 4796 4797 break; 4798 } 4799 case HWA_NOTIF_TYPE_BPST_ADJ: 4800 USB_DPRINTF_L3(PRINT_MASK_CBOPS, 4801 hwahcp->hwahc_log_handle, 4802 "hwahc_handle_notif: received BPST adjust " 4803 "notification, bAdjustment = %d", p[2]); 4804 4805 break; 4806 default: 4807 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 4808 hwahcp->hwahc_log_handle, 4809 "hwahc_handle_notif: unknown notification 0x%x", 4810 hdr->bNotifyType); 4811 4812 break; 4813 } 4814 p += hdr->bLength; 4815 len -= hdr->bLength; 4816 } 4817 } 4818 4819 /* 4820 * start listening on bulk-in ept for transfer result 4821 * 4822 * Dispatches a task to read the BULK IN endpoint to get the result of 4823 * last request. usb_async_req() will have system_taskq to process the tasks. 4824 */ 4825 int 4826 hwahc_start_result_thread(hwahc_state_t *hwahcp) 4827 { 4828 wusb_wa_data_t *wa_data; 4829 4830 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4831 "hwahc_start_result_thread:"); 4832 4833 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 4834 4835 if (hwahcp->hwahc_result_thread_id != 0) { 4836 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4837 "hwahc_start_result_thread: already started"); 4838 4839 return (USB_SUCCESS); 4840 } 4841 4842 wa_data = &hwahcp->hwahc_wa_data; 4843 4844 mutex_enter(&wa_data->wa_mutex); 4845 if ((wa_data->wa_bulkin_ph != NULL) && 4846 (wa_data->wa_bulkin_pipe_state != WA_PIPE_STOPPED)) { 4847 mutex_exit(&wa_data->wa_mutex); 4848 4849 return (USB_INVALID_PIPE); 4850 } 4851 mutex_exit(&wa_data->wa_mutex); 4852 4853 if (wa_data->wa_bulkin_ph == NULL) { 4854 mutex_exit(&hwahcp->hwahc_mutex); 4855 if (usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkin_ept, 4856 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP, 4857 &wa_data->wa_bulkin_ph) != USB_SUCCESS) { 4858 USB_DPRINTF_L2(PRINT_MASK_ATTA, 4859 hwahcp->hwahc_log_handle, 4860 "hwahc_start_result_thread: open pipe failed"); 4861 4862 4863 mutex_enter(&hwahcp->hwahc_mutex); 4864 return (USB_FAILURE); 4865 } 4866 mutex_enter(&hwahcp->hwahc_mutex); 4867 4868 mutex_enter(&wa_data->wa_mutex); 4869 wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED; 4870 mutex_exit(&wa_data->wa_mutex); 4871 } 4872 4873 /* kick off an asynchronous thread to handle transfer result */ 4874 if (usb_async_req(hwahcp->hwahc_dip, hwahc_result_thread, 4875 (void *)hwahcp, 0) != USB_SUCCESS) { 4876 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4877 "hwahc_start_result_thread: failed to start result thread"); 4878 4879 return (USB_FAILURE); 4880 } 4881 hwahcp->hwahc_result_thread_id = (kthread_t *)1; 4882 4883 /* pipe state is active while the result thread is on */ 4884 mutex_enter(&wa_data->wa_mutex); 4885 wa_data->wa_bulkin_pipe_state = WA_PIPE_ACTIVE; 4886 mutex_exit(&wa_data->wa_mutex); 4887 4888 return (USB_SUCCESS); 4889 } 4890 4891 /* stop the bulk-in ept from listening */ 4892 static void 4893 hwahc_stop_result_thread(hwahc_state_t *hwahcp) 4894 { 4895 wusb_wa_data_t *wa_data; 4896 4897 ASSERT(mutex_owned(&hwahcp->hwahc_mutex)); 4898 4899 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4900 "hwahc_stop_result_thread:"); 4901 4902 if (hwahcp->hwahc_result_thread_id == 0) { 4903 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4904 "hwahc_stop_result_thread: already stopped"); 4905 4906 return; 4907 } 4908 4909 wa_data = &hwahcp->hwahc_wa_data; 4910 mutex_enter(&wa_data->wa_mutex); 4911 if ((wa_data->wa_bulkin_ph == NULL) || 4912 (wa_data->wa_bulkin_pipe_state != WA_PIPE_ACTIVE)) { 4913 USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4914 "hwahc_stop_result_thread: invalid pipe state"); 4915 4916 mutex_exit(&wa_data->wa_mutex); 4917 4918 return; 4919 } 4920 mutex_exit(&wa_data->wa_mutex); 4921 4922 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4923 "hwahc_stop_result_thread: reset hwa bulk-in pipe"); 4924 mutex_exit(&hwahcp->hwahc_mutex); 4925 usb_pipe_reset(wa_data->wa_dip, wa_data->wa_bulkin_ph, 4926 USB_FLAGS_SLEEP, NULL, NULL); 4927 4928 /* 4929 * have to close pipe here to fail the bulk-in transfer 4930 * that never timeouts 4931 */ 4932 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4933 "hwahc_stop_result_thread: close hwa bulk-in pipe"); 4934 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph, 4935 USB_FLAGS_SLEEP, NULL, NULL); 4936 mutex_enter(&hwahcp->hwahc_mutex); 4937 4938 mutex_enter(&wa_data->wa_mutex); 4939 wa_data->wa_bulkin_ph = NULL; 4940 wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED; 4941 mutex_exit(&wa_data->wa_mutex); 4942 4943 while (hwahcp->hwahc_result_thread_id != 0) { 4944 /* wait the result thread to exit */ 4945 cv_wait(&hwahcp->hwahc_result_thread_cv, &hwahcp->hwahc_mutex); 4946 } 4947 } 4948 4949 /* 4950 * keep listening for transfer result by setting timeout to 0 while the 4951 * bulk-in pipe is active 4952 * the thread would be stopped by closing bulk-in pipe or encountering 4953 * transaction error, eg, hot-removal of hwa device 4954 */ 4955 static void 4956 hwahc_result_thread(void *arg) 4957 { 4958 hwahc_state_t *hwahcp = (hwahc_state_t *)arg; 4959 wusb_wa_data_t *wa_data = &hwahcp->hwahc_wa_data; 4960 int rval; 4961 uint8_t retry = 0; 4962 4963 mutex_enter(&hwahcp->hwahc_mutex); 4964 ASSERT(hwahcp->hwahc_result_thread_id == (kthread_t *)1); 4965 hwahcp->hwahc_result_thread_id = curthread; 4966 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 4967 "hwahc_result_thread: started, thread_id=0x%p", 4968 (void *)hwahcp->hwahc_result_thread_id); 4969 4970 /* keep polling the bulk IN endpoint to get the result */ 4971 mutex_enter(&wa_data->wa_mutex); 4972 while (wa_data->wa_bulkin_pipe_state == WA_PIPE_ACTIVE) { 4973 mutex_exit(&wa_data->wa_mutex); 4974 mutex_exit(&hwahcp->hwahc_mutex); 4975 4976 if ((rval = wusb_wa_get_xfer_result(wa_data)) != USB_SUCCESS) { 4977 retry++; 4978 USB_DPRINTF_L2(PRINT_MASK_ATTA, 4979 hwahcp->hwahc_log_handle, 4980 "hwahc_result_thread: get xfer result failed, " 4981 "rval = %d, retry = %d", rval, retry); 4982 4983 /* retry 3 times upon failure */ 4984 if (retry >= 3) { 4985 mutex_enter(&hwahcp->hwahc_mutex); 4986 mutex_enter(&wa_data->wa_mutex); 4987 4988 break; 4989 } 4990 } 4991 4992 mutex_enter(&hwahcp->hwahc_mutex); 4993 mutex_enter(&wa_data->wa_mutex); 4994 } 4995 4996 hwahcp->hwahc_result_thread_id = 0; 4997 wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED; 4998 mutex_exit(&wa_data->wa_mutex); 4999 5000 /* signal to the thread requesting stopping if any */ 5001 cv_signal(&hwahcp->hwahc_result_thread_cv); 5002 5003 USB_DPRINTF_L4(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle, 5004 "hwahc_result_thread: ended"); 5005 5006 mutex_exit(&hwahcp->hwahc_mutex); 5007 } 5008 5009 /* 5010 * nothing to do here, just check if the ept number in the transfer 5011 * completion notification is valid 5012 * the actual handling of transfer result is performed by the result thread 5013 */ 5014 static void 5015 hwahc_handle_xfer_result(hwahc_state_t *hwahcp, uint8_t ept) 5016 { 5017 usb_ep_descr_t *epdt; 5018 5019 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5020 "hwahc_handle_xfer_result: result on ept %d", ept); 5021 5022 epdt = &hwahcp->hwahc_wa_data.wa_bulkin_ept; 5023 5024 /* the result should be on the bulk-in ept */ 5025 if ((epdt->bEndpointAddress & USB_EP_NUM_MASK) != ept) { 5026 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5027 "hwahc_handle_xfer_result: ept number not match"); 5028 5029 return; 5030 } 5031 } 5032 5033 5034 /* 5035 * Section 8.5.4.2. 5036 * Copy the DN Notification and add it to the instance's global 5037 * nofication list. If the worker thread is not started yet, start 5038 * it. 5039 */ 5040 static void 5041 hwahc_handle_dn_notif(hwahc_state_t *hwahcp, hwa_notif_dn_recvd_t *dn_notif) 5042 { 5043 hwahc_dn_notif_list_t *nlist; 5044 5045 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5046 "hwahc_handle_dn_notif: notif = 0x%p", (void *)dn_notif); 5047 5048 nlist = kmem_zalloc(sizeof (hwahc_dn_notif_list_t), KM_NOSLEEP); 5049 5050 mutex_enter(&hwahcp->hwahc_mutex); 5051 nlist->dn_notif = dn_notif; 5052 5053 usba_init_list(&nlist->notif_list, (usb_opaque_t)nlist, 5054 hwahcp->hwahc_dev_data->dev_iblock_cookie); 5055 5056 /* queue the new notification to the list */ 5057 usba_add_to_list(&hwahcp->hwahc_dn_notif_queue, &nlist->notif_list); 5058 5059 /* handle the notification queue with an asynchronous thread */ 5060 if (hwahcp->hwahc_notif_thread_id == 0) { 5061 if (usb_async_req(hwahcp->hwahc_dip, hwahc_notif_thread, 5062 (void *)hwahcp, 0) != USB_SUCCESS) { 5063 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5064 hwahcp->hwahc_log_handle, 5065 "hwahc_handle_dn_notif: no notif thread started"); 5066 mutex_exit(&hwahcp->hwahc_mutex); 5067 5068 return; 5069 } 5070 hwahcp->hwahc_notif_thread_id = (kthread_t *)1; 5071 } 5072 5073 mutex_exit(&hwahcp->hwahc_mutex); 5074 } 5075 5076 /* handle the notifications in the notification queue in sequence */ 5077 static void 5078 hwahc_notif_thread(void *arg) 5079 { 5080 hwahc_state_t *hwahcp = (hwahc_state_t *)arg; 5081 hwahc_dn_notif_list_t *nlist; 5082 hwa_notif_dn_recvd_t *dn_notif; 5083 5084 mutex_enter(&hwahcp->hwahc_mutex); 5085 ASSERT(hwahcp->hwahc_notif_thread_id == (kthread_t *)1); 5086 hwahcp->hwahc_notif_thread_id = curthread; 5087 5088 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5089 "hwahc_notif_thread: started, thread_id=0x%p", 5090 (void *)hwahcp->hwahc_notif_thread_id); 5091 5092 while (usba_list_entry_count(&hwahcp->hwahc_dn_notif_queue) != 0) { 5093 /* 5094 * first in first out, only one notification will be handled 5095 * at a time, so it assures no racing in attach or detach 5096 */ 5097 if ((nlist = 5098 (hwahc_dn_notif_list_t *)usba_rm_first_pvt_from_list( 5099 &hwahcp->hwahc_dn_notif_queue)) == NULL) { 5100 5101 continue; 5102 } 5103 dn_notif = nlist->dn_notif; 5104 mutex_exit(&hwahcp->hwahc_mutex); 5105 hwahc_handle_dn(hwahcp, dn_notif); 5106 usba_destroy_list(&nlist->notif_list); 5107 kmem_free(nlist, sizeof (hwahc_dn_notif_list_t)); 5108 mutex_enter(&hwahcp->hwahc_mutex); 5109 } 5110 5111 hwahcp->hwahc_notif_thread_id = 0; 5112 5113 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5114 "hwahc_notif_thread: ended"); 5115 5116 mutex_exit(&hwahcp->hwahc_mutex); 5117 } 5118 5119 /* Set the child device's active bit to 1 */ 5120 static void 5121 hwahc_set_device_active(hwahc_state_t *hwahcp, uint8_t devaddr) 5122 { 5123 wusb_dev_info_t *dev_info; 5124 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 5125 int i; 5126 5127 mutex_enter(&hc_data->hc_mutex); 5128 for (i = 1; i <= hc_data->hc_num_ports; i++) { 5129 dev_info = hc_data->hc_dev_infos[i]; 5130 if ((dev_info != NULL) && (dev_info->wdev_addr == devaddr)) { 5131 dev_info->wdev_active = 1; 5132 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, 5133 hwahcp->hwahc_log_handle, 5134 "hwahc_set_device_active:device(%p) updated ", 5135 (void *)dev_info); 5136 5137 break; 5138 } 5139 } 5140 mutex_exit(&hc_data->hc_mutex); 5141 } 5142 5143 /* 5144 * handle a specific device notification 5145 * assuming the raw data in HWA DN_RECEIVED notification pkt includes 5146 * no more than one dn pkt 5147 */ 5148 static void 5149 hwahc_handle_dn(hwahc_state_t *hwahcp, hwa_notif_dn_recvd_t *dn_notif) 5150 { 5151 uint8_t *p; 5152 size_t len; 5153 uint8_t dntype; 5154 int circ; 5155 wusb_hc_data_t *hc_data = &hwahcp->hwahc_hc_data; 5156 5157 if (dn_notif->bLength < 4) { 5158 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5159 "hwahc_handle_dn: bLength too short %d", dn_notif->bLength); 5160 kmem_free(dn_notif, dn_notif->bLength); 5161 5162 return; 5163 } 5164 5165 p = dn_notif->notifdata; 5166 len = dn_notif->bLength - 4; 5167 5168 /* 5169 * WUSB Errata 06.12 specifies that the raw data in the DN_RECEIVED 5170 * notification must not include the WUSB header, but only the bType 5171 * and Notification specific data 5172 */ 5173 if (len == 0) { 5174 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5175 "hwahc_handle_dn: no raw data"); 5176 kmem_free(dn_notif, dn_notif->bLength); 5177 5178 return; 5179 } 5180 dntype = *p; 5181 5182 /* update the device's status bit, no matter what the DN is */ 5183 hwahc_set_device_active(hwahcp, dn_notif->bSourceDeviceAddr); 5184 5185 ndi_devi_enter(hwahcp->hwahc_dip, &circ); 5186 switch (dntype) { 5187 case WUSB_DN_CONNECT: 5188 /* DN_Connect */ 5189 wusb_hc_handle_dn_connect( 5190 hc_data, hwahcp->hwahc_default_pipe, 5191 hwahcp->hwahc_wa_data.wa_ifno, p, len, 5192 &hwahcp->hwahc_secrt_data); 5193 5194 break; 5195 case WUSB_DN_DISCONNECT: 5196 /* DN_Disconnect */ 5197 wusb_hc_handle_dn_disconnect( 5198 hc_data, dn_notif->bSourceDeviceAddr, 5199 p, len); 5200 5201 break; 5202 case WUSB_DN_ALIVE: 5203 /* We only send KeepAlive IE to one device at a comment */ 5204 mutex_enter(&hc_data->hc_mutex); 5205 if (dn_notif->bSourceDeviceAddr == 5206 hc_data->hc_alive_ie.bDeviceAddress[0]) { 5207 mutex_exit(&hc_data->hc_mutex); 5208 wusb_hc_rem_ie(hc_data, 5209 (wusb_ie_header_t *)&hc_data->hc_alive_ie); 5210 mutex_enter(&hc_data->hc_mutex); 5211 } 5212 mutex_exit(&hc_data->hc_mutex); 5213 5214 break; 5215 case WUSB_DN_EPRDY: 5216 case WUSB_DN_MASAVAILCHANGED: 5217 case WUSB_DN_REMOTEWAKEUP: 5218 case WUSB_DN_SLEEP: 5219 default: 5220 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5221 "hwahc_handle_dn: dn type 0x%x not supported yet", 5222 dntype); 5223 5224 break; 5225 } 5226 5227 kmem_free(dn_notif, dn_notif->bLength); 5228 ndi_devi_exit(hwahcp->hwahc_dip, circ); 5229 } 5230 5231 /* exceptional callback for notification ept */ 5232 /* ARGSUSED */ 5233 static void 5234 hwahc_intr_exc_cb(usb_pipe_handle_t ph, struct usb_intr_req *reqp) 5235 { 5236 dev_info_t *dip = (USBA_REQ2WRP(reqp))->wr_dip; 5237 hwahc_state_t *hwahcp; 5238 5239 ASSERT(dip != NULL); 5240 hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip)); 5241 ASSERT(hwahcp != NULL); 5242 5243 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5244 "hwahc_intr_exc_cb: receive intr exception cb, cr=%d", 5245 reqp->intr_completion_reason); 5246 5247 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 5248 5249 mutex_enter(&hwahcp->hwahc_mutex); 5250 5251 switch (reqp->intr_completion_reason) { 5252 case USB_CR_PIPE_RESET: 5253 /* only restart nep after autoclearing */ 5254 if (hwahcp->hwahc_dev_state == USB_DEV_ONLINE) { 5255 hwahcp->hwahc_wa_data.wa_intr_pipe_state = 5256 WA_PIPE_STOPPED; 5257 mutex_exit(&hwahcp->hwahc_mutex); 5258 (void) wusb_wa_start_nep(&hwahcp->hwahc_wa_data, 5259 USB_FLAGS_NOSLEEP); 5260 mutex_enter(&hwahcp->hwahc_mutex); 5261 } 5262 5263 break; 5264 case USB_CR_DEV_NOT_RESP: 5265 case USB_CR_STOPPED_POLLING: 5266 case USB_CR_PIPE_CLOSING: 5267 case USB_CR_UNSPECIFIED_ERR: 5268 /* never restart nep on these conditions */ 5269 default: 5270 /* for all others, wait for the autoclearing PIPE_RESET cb */ 5271 5272 break; 5273 } 5274 5275 usb_free_intr_req(reqp); 5276 mutex_exit(&hwahcp->hwahc_mutex); 5277 } 5278 5279 /* 5280 * callback function called by WA to resubmit a periodic request for 5281 * interrupt polling or isochronous transfer. 5282 */ 5283 static int 5284 hwahc_pipe_submit_periodic_req(wusb_wa_data_t *wa_data, 5285 usba_pipe_handle_data_t *ph) 5286 { 5287 hwahc_state_t *hwahcp = wa_data->wa_private_data; 5288 hwahc_pipe_private_t *pp = (hwahc_pipe_private_t *)ph->p_hcd_private; 5289 int rval; 5290 5291 mutex_enter(&hwahcp->hwahc_mutex); 5292 5293 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5294 "hwahc_pipe_submit_periodic_req: hwahcp=0x%p, pp=0x%p," 5295 " pipe state = %d", (void *)hwahcp, (void *)pp, pp->pp_state); 5296 5297 if (pp->pp_state != HWAHC_PIPE_STATE_ACTIVE) { 5298 /* pipe error or pipe closing, don't resubmit any more */ 5299 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5300 "hwahc_pipe_submit_periodic_req: pipe not active = %d", 5301 pp->pp_state); 5302 5303 mutex_exit(&hwahcp->hwahc_mutex); 5304 5305 return (USB_PIPE_ERROR); 5306 } 5307 5308 mutex_exit(&hwahcp->hwahc_mutex); 5309 5310 /* re-submit the original request */ 5311 rval = wusb_wa_intr_xfer(wa_data, pp->pp_rp, ph, 5312 (usb_intr_req_t *)pp->pp_client_periodic_in_reqp, 0); 5313 5314 return (rval); 5315 } 5316 5317 /* call HCD callback for completion handling */ 5318 static void 5319 hwahc_rpipe_xfer_cb(dev_info_t *dip, usba_pipe_handle_data_t *ph, 5320 wusb_wa_trans_wrapper_t *wr, usb_cr_t cr) 5321 { 5322 hwahc_state_t *hwahcp; 5323 hwahc_pipe_private_t *pp; 5324 usb_opaque_t req; 5325 wusb_hc_data_t *hc_data; 5326 5327 hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip)); 5328 if (hwahcp == NULL) { 5329 5330 return; 5331 } 5332 5333 hc_data = &hwahcp->hwahc_hc_data; 5334 5335 mutex_enter(&hwahcp->hwahc_mutex); 5336 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5337 "hwahc_rpipe_xfer_cb: ph = 0x%p, wr = 0x%p cr = 0x%x", 5338 (void *)ph, (void *)wr, cr); 5339 5340 pp = (hwahc_pipe_private_t *)ph->p_hcd_private; 5341 5342 mutex_enter(&hc_data->hc_mutex); 5343 pp->pp_wdev->wdev_active = 1; /* this device is active on xfer */ 5344 mutex_exit(&hc_data->hc_mutex); 5345 5346 switch (cr) { 5347 case USB_CR_OK: 5348 break; 5349 case USB_CR_NOT_SUPPORTED: 5350 case USB_CR_NO_RESOURCES: 5351 case USB_CR_PIPE_RESET: 5352 case USB_CR_STOPPED_POLLING: 5353 pp->pp_state = HWAHC_PIPE_STATE_IDLE; 5354 break; 5355 case USB_CR_PIPE_CLOSING: 5356 break; 5357 default: 5358 pp->pp_state = HWAHC_PIPE_STATE_ERROR; 5359 5360 break; 5361 } 5362 5363 if (wr && wr->wr_reqp) { 5364 req = wr->wr_reqp; 5365 5366 mutex_enter(&wr->wr_rp->rp_mutex); 5367 wr->wr_reqp = NULL; 5368 mutex_exit(&wr->wr_rp->rp_mutex); 5369 5370 } else { /* periodic pipe cleanup */ 5371 5372 /* the original request is cleared and returned to client */ 5373 req = pp->pp_client_periodic_in_reqp; 5374 pp->pp_client_periodic_in_reqp = NULL; 5375 } 5376 5377 mutex_exit(&hwahcp->hwahc_mutex); 5378 5379 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5380 "hwahc_rpipe_xfer_cb: call usba_hcdi_cb for req= 0x%p", 5381 (void *)req); 5382 5383 usba_hcdi_cb(ph, req, cr); 5384 } 5385 5386 /* post disconnect event to child on a certain port */ 5387 static void 5388 hwahc_disconnect_dev(dev_info_t *dip, usb_port_t port) 5389 { 5390 hwahc_state_t *hwahcp; 5391 int circ; 5392 dev_info_t *child_dip; 5393 5394 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 5395 ddi_get_instance(dip))) == NULL) { 5396 5397 return; 5398 } 5399 5400 ndi_devi_enter(dip, &circ); 5401 mutex_enter(&hwahcp->hwahc_mutex); 5402 5403 child_dip = hwahcp->hwahc_hc_data.hc_children_dips[port]; 5404 if ((hwahcp->hwahc_dev_state == USB_DEV_ONLINE) && child_dip) { 5405 mutex_exit(&hwahcp->hwahc_mutex); 5406 5407 /* if the child driver remains attached */ 5408 if (i_ddi_devi_attached(child_dip)) { 5409 hwahc_post_event(hwahcp, port, 5410 USBA_EVENT_TAG_HOT_REMOVAL); 5411 } 5412 mutex_enter(&hwahcp->hwahc_mutex); 5413 } 5414 5415 mutex_exit(&hwahcp->hwahc_mutex); 5416 ndi_devi_exit(dip, circ); 5417 } 5418 5419 /* post reconect event to child on a certain port */ 5420 static void 5421 hwahc_reconnect_dev(dev_info_t *dip, usb_port_t port) 5422 { 5423 hwahc_state_t *hwahcp; 5424 int circ; 5425 5426 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 5427 ddi_get_instance(dip))) == NULL) { 5428 5429 return; 5430 } 5431 ndi_devi_enter(dip, &circ); 5432 mutex_enter(&hwahcp->hwahc_mutex); 5433 5434 if ((hwahcp->hwahc_dev_state == USB_DEV_ONLINE) && 5435 (hwahcp->hwahc_hc_data.hc_children_dips[port])) { 5436 mutex_exit(&hwahcp->hwahc_mutex); 5437 hwahc_post_event(hwahcp, port, USBA_EVENT_TAG_HOT_INSERTION); 5438 mutex_enter(&hwahcp->hwahc_mutex); 5439 } 5440 5441 mutex_exit(&hwahcp->hwahc_mutex); 5442 ndi_devi_exit(dip, circ); 5443 } 5444 5445 5446 /* 5447 * Device TrustTimeout timer operations: 5448 * hwahc_start_trust_timer: start the trust timer for a newly connected device 5449 * hwahc_trust_timeout_handler: timer handler 5450 * hwahc_stop_trust_timer: stop a device's trust timer 5451 */ 5452 static void 5453 hwahc_start_trust_timer(wusb_dev_info_t *dev) 5454 { 5455 if (hwahc_enable_trust_timeout == 0) { 5456 5457 return; 5458 } 5459 5460 if (dev->wdev_trust_timer == NULL) { 5461 dev->wdev_trust_timer = timeout(hwahc_trust_timeout_handler, 5462 (void *)dev, drv_usectohz(WUSB_TRUST_TIMEOUT_US)); 5463 } 5464 } 5465 5466 /* timeout handler for device TrustTimeout. See section 4.14 */ 5467 static void 5468 hwahc_trust_timeout_handler(void *arg) 5469 { 5470 wusb_dev_info_t *dev = (wusb_dev_info_t *)arg; 5471 usb_port_t port; 5472 uint16_t dev_addr; 5473 wusb_hc_data_t *hc_data = dev->wdev_hc; 5474 uint8_t retry = 3; 5475 int rval; 5476 5477 mutex_enter(&hc_data->hc_mutex); 5478 5479 dev->wdev_trust_timer = 0; 5480 dev_addr = dev->wdev_addr; 5481 5482 if (dev->wdev_active == 1) { 5483 /* device is active during the past period. Restart the timer */ 5484 dev->wdev_active = 0; /* expect device DN set it to 1 */ 5485 } else { 5486 /* send a KeepAlive IE to query the device */ 5487 for (retry = 0; retry < 3; retry++) { 5488 mutex_exit(&hc_data->hc_mutex); 5489 rval = wusb_hc_send_keepalive_ie(hc_data, 5490 dev_addr); 5491 mutex_enter(&hc_data->hc_mutex); 5492 5493 if (rval == USB_SUCCESS) { 5494 break; 5495 } 5496 /* retry 3 times if fail to send KeepAlive IE */ 5497 } 5498 5499 if (dev->wdev_active == 0) { 5500 /* still no activity! Delete this device */ 5501 if (wusb_hc_is_dev_connected(hc_data, dev->wdev_cdid, 5502 &port)) { 5503 mutex_exit(&hc_data->hc_mutex); 5504 (void) hwahc_destroy_child(hc_data->hc_dip, 5505 port); 5506 5507 /* the device comes to the end of its life */ 5508 return; 5509 } 5510 } 5511 } 5512 5513 /* active or we received DN during query */ 5514 hwahc_start_trust_timer(dev); 5515 5516 mutex_exit(&hc_data->hc_mutex); 5517 } 5518 5519 /* stop a child device's trust timeout handler */ 5520 void 5521 hwahc_stop_trust_timer(wusb_dev_info_t *dev) 5522 { 5523 timeout_id_t tid; 5524 wusb_hc_data_t *hc_data = dev->wdev_hc; 5525 5526 ASSERT(mutex_owned(&hc_data->hc_mutex)); 5527 5528 if (hwahc_enable_trust_timeout == 0) { 5529 return; 5530 } 5531 5532 tid = dev->wdev_trust_timer; 5533 5534 dev->wdev_trust_timer = NULL; 5535 mutex_exit(&hc_data->hc_mutex); 5536 5537 if (tid != NULL) { 5538 (void) untimeout(tid); 5539 } 5540 5541 mutex_enter(&hc_data->hc_mutex); 5542 } 5543 5544 /* configure child device and attach child on a certain port */ 5545 static int 5546 hwahc_create_child(dev_info_t *dip, usb_port_t port) 5547 { 5548 hwahc_state_t *hwahcp; 5549 wusb_hc_data_t *hc_data; 5550 wusb_dev_info_t *dev_info; 5551 usb_pipe_handle_t ph; 5552 int rval; 5553 dev_info_t *child_dip; 5554 usba_device_t *child_ud = NULL; 5555 mblk_t *pdata = NULL; 5556 usb_cr_t completion_reason; 5557 usb_cb_flags_t cb_flags; 5558 size_t size; 5559 uint8_t address; 5560 int user_conf_index; 5561 uint_t config_index; 5562 int prh_circ, rh_circ, circ; 5563 dev_info_t *rh_dip; 5564 usb_dev_descr_t usb_dev_descr; 5565 5566 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 5567 ddi_get_instance(dip))) == NULL) { 5568 5569 return (USB_INVALID_ARGS); 5570 } 5571 5572 rh_dip = hwahcp->hwahc_hubd->h_usba_device->usb_root_hub_dip; 5573 ndi_hold_devi(dip); /* avoid racing with dev detach */ 5574 /* exclude other threads */ 5575 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ); 5576 ndi_devi_enter(rh_dip, &rh_circ); 5577 ndi_devi_enter(dip, &circ); 5578 5579 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dev_info)); 5580 5581 hc_data = &hwahcp->hwahc_hc_data; 5582 mutex_enter(&hc_data->hc_mutex); 5583 dev_info = hc_data->hc_dev_infos[port]; 5584 5585 /* Created in whcdi.c before authed */ 5586 child_dip = hc_data->hc_children_dips[port]; 5587 5588 child_ud = usba_get_usba_device(child_dip); 5589 ph = dev_info->wdev_ph; 5590 5591 mutex_exit(&hc_data->hc_mutex); 5592 /* 5593 * HWA maintains the address space as a separate bus and 5594 * will not occupy parent's address space 5595 */ 5596 address = child_ud->usb_addr; 5597 if (address < 0x80) { 5598 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5599 "hwahc_create_child: reconnecting, address = %d", 5600 address); 5601 5602 } else { 5603 /* SetAddress(0) */ 5604 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5605 USB_DEV_REQ_HOST_TO_DEV, 5606 USB_REQ_SET_ADDRESS, /* bRequest */ 5607 0, /* wValue */ 5608 0, /* wIndex */ 5609 0, /* wLength */ 5610 NULL, 0, 5611 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5612 char buffer[64]; 5613 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5614 hwahcp->hwahc_log_handle, 5615 "setting address failed (cr=%s cb_flags=%s " 5616 "rval=%d)", usb_str_cr(completion_reason), 5617 usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)), 5618 rval); 5619 5620 goto done; 5621 } 5622 5623 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5624 "set address 0 done"); 5625 5626 usb_pipe_close(child_dip, ph, 5627 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 5628 5629 child_ud->usb_addr = 0; 5630 dev_info->wdev_addr = 0; 5631 dev_info->wdev_ph = NULL; 5632 5633 /* need to be called each time dev addr is changed */ 5634 if ((rval = wusb_hc_set_device_info(&hwahcp->hwahc_hc_data, 5635 port)) != USB_SUCCESS) { 5636 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5637 hwahcp->hwahc_log_handle, 5638 "update device info failed, rval = %d", rval); 5639 5640 goto done; 5641 } 5642 5643 /* new ph is stored in usba_device */ 5644 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5645 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != 5646 USB_SUCCESS) { 5647 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5648 hwahcp->hwahc_log_handle, 5649 "usb_pipe_open failed (%d)", rval); 5650 5651 goto done; 5652 } 5653 5654 /* provide at least 2ms time for address change, 7.3.1.3 */ 5655 delay(drv_usectohz(2000)); 5656 5657 /* start normal enumeration process */ 5658 /* 5659 * wusb bus address has 1:1 relationship with port number 5660 * and wusb bus address starts from 2, so as to follow 5661 * the convention that USB bus address 1 is reserved for 5662 * host controller device. As such, only 126 WUSB devices 5663 * are supported on a WUSB host 5664 */ 5665 address = port + 1; 5666 if (address >= 0x80) { 5667 USB_DPRINTF_L3(PRINT_MASK_CBOPS, 5668 hwahcp->hwahc_log_handle, 5669 "hwahc_create_child: address for port %d exceeds " 5670 "0x80", port); 5671 rval = USB_FAILURE; 5672 5673 goto done; 5674 } 5675 /* Set the address of the device */ 5676 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5677 USB_DEV_REQ_HOST_TO_DEV, 5678 USB_REQ_SET_ADDRESS, /* bRequest */ 5679 address, /* wValue */ 5680 0, /* wIndex */ 5681 0, /* wLength */ 5682 NULL, 0, 5683 &completion_reason, &cb_flags, 0)) != USB_SUCCESS) { 5684 char buffer[64]; 5685 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5686 hwahcp->hwahc_log_handle, 5687 "setting address failed (cr=%s cb_flags=%s " 5688 "rval=%d)", usb_str_cr(completion_reason), 5689 usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)), 5690 rval); 5691 5692 goto done; 5693 } 5694 5695 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5696 "set address 0x%x done", address); 5697 5698 usb_pipe_close(child_dip, ph, 5699 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 5700 5701 child_ud->usb_addr = address; 5702 dev_info->wdev_addr = address; 5703 dev_info->wdev_ph = NULL; 5704 5705 if ((rval = wusb_hc_set_device_info(&hwahcp->hwahc_hc_data, 5706 port)) != USB_SUCCESS) { 5707 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5708 hwahcp->hwahc_log_handle, 5709 "update device info failed, rval = %d", rval); 5710 5711 goto done; 5712 } 5713 5714 /* new ph is stored in usba_device */ 5715 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5716 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != 5717 USB_SUCCESS) { 5718 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5719 hwahcp->hwahc_log_handle, 5720 "usb_pipe_open failed (%d)", rval); 5721 5722 goto done; 5723 } 5724 5725 /* provide at least 2ms time for address change, 7.3.1.3 */ 5726 delay(drv_usectohz(2000)); 5727 } 5728 5729 /* get device descriptor ignoring device reconnection */ 5730 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph, 5731 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD, 5732 USB_REQ_GET_DESCR, /* bRequest */ 5733 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 5734 0, /* wIndex */ 5735 512, /* wLength */ 5736 &pdata, USB_ATTRS_SHORT_XFER_OK, 5737 &completion_reason, &cb_flags, 0); 5738 5739 if (rval != USB_SUCCESS) { 5740 if (pdata) { 5741 freemsg(pdata); 5742 pdata = NULL; 5743 } 5744 5745 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5746 "hwahc_create_child: get device descriptor failed " 5747 "(%s 0x%x %d)", usb_str_cr(completion_reason), 5748 cb_flags, rval); 5749 5750 goto done; 5751 } 5752 5753 ASSERT(pdata != NULL); 5754 size = usb_parse_dev_descr( 5755 pdata->b_rptr, 5756 MBLKL(pdata), 5757 &usb_dev_descr, 5758 sizeof (usb_dev_descr_t)); 5759 freemsg(pdata); 5760 5761 if (size < USB_DEV_DESCR_SIZE) { 5762 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5763 "hwahc_create_child: get device descriptor size = %lu " 5764 "expected size = %u", size, USB_DEV_DESCR_SIZE); 5765 rval = USB_FAILURE; 5766 5767 goto done; 5768 } 5769 5770 bcopy(&usb_dev_descr, child_ud->usb_dev_descr, 5771 sizeof (usb_dev_descr_t)); 5772 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations; 5773 5774 if (usb_dev_descr.bNumConfigurations == 0) { 5775 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5776 "device descriptor:\n\t" 5777 "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t" 5778 "protocol=0x%x maxpktsize=0x%x " 5779 "Vid=0x%x Pid=0x%x rel=0x%x\n\t" 5780 "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x", 5781 usb_dev_descr.bLength, usb_dev_descr.bDescriptorType, 5782 usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass, 5783 usb_dev_descr.bDeviceSubClass, 5784 usb_dev_descr.bDeviceProtocol, 5785 usb_dev_descr.bMaxPacketSize0, 5786 usb_dev_descr.idVendor, 5787 usb_dev_descr.idProduct, usb_dev_descr.bcdDevice, 5788 usb_dev_descr.iManufacturer, usb_dev_descr.iProduct, 5789 usb_dev_descr.iSerialNumber, 5790 usb_dev_descr.bNumConfigurations); 5791 5792 rval = USB_FAILURE; 5793 5794 goto done; 5795 } 5796 5797 /* get the device string descriptor(s) */ 5798 usba_get_dev_string_descrs(child_dip, child_ud); 5799 5800 /* retrieve config cloud for all configurations */ 5801 rval = hubd_get_all_device_config_cloud(hwahcp->hwahc_hubd, 5802 child_dip, child_ud); 5803 if (rval != USB_SUCCESS) { 5804 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5805 "failed to get configuration descriptor(s)"); 5806 5807 goto done; 5808 } 5809 5810 /* get the preferred configuration for this device */ 5811 user_conf_index = hubd_select_device_configuration(hwahcp->hwahc_hubd, 5812 port, child_dip, child_ud); 5813 5814 /* Check if the user selected configuration index is in range */ 5815 if ((user_conf_index >= usb_dev_descr.bNumConfigurations) || 5816 (user_conf_index < 0)) { 5817 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5818 "Configuration index for device idVendor=%d " 5819 "idProduct=%d is=%d, and is out of range[0..%d]", 5820 usb_dev_descr.idVendor, usb_dev_descr.idProduct, 5821 user_conf_index, usb_dev_descr.bNumConfigurations - 1); 5822 5823 /* treat this as user didn't specify configuration */ 5824 user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED; 5825 } 5826 5827 if (user_conf_index == USBA_DEV_CONFIG_INDEX_UNDEFINED) { 5828 if (child_ud->usb_preferred_driver) { 5829 /* 5830 * It is the job of the "preferred driver" to put the 5831 * device in the desired configuration. Till then 5832 * put the device in config index 0. 5833 */ 5834 /* h_ignore_pwr_budget = TRUE, not care the power */ 5835 if ((rval = usba_hubdi_check_power_budget(dip, child_ud, 5836 USB_DEV_DEFAULT_CONFIG_INDEX)) != USB_SUCCESS) { 5837 5838 goto done; 5839 } 5840 5841 child_dip = hubd_ready_device(hwahcp->hwahc_hubd, 5842 child_dip, child_ud, USB_DEV_DEFAULT_CONFIG_INDEX); 5843 5844 /* 5845 * Assign the dip before onlining to avoid race 5846 * with busctl 5847 */ 5848 mutex_enter(&hc_data->hc_mutex); 5849 hc_data->hc_children_dips[port] = child_dip; 5850 mutex_exit(&hc_data->hc_mutex); 5851 5852 (void) usba_bind_driver(child_dip); 5853 } else { 5854 /* 5855 * loop through all the configurations to see if we 5856 * can find a driver for any one config. If not, set 5857 * the device in config_index 0 5858 */ 5859 rval = USB_FAILURE; 5860 for (config_index = 0; 5861 (config_index < usb_dev_descr.bNumConfigurations) && 5862 (rval != USB_SUCCESS); config_index++) { 5863 5864 child_dip = hubd_ready_device( 5865 hwahcp->hwahc_hubd, 5866 child_dip, child_ud, config_index); 5867 5868 /* 5869 * Assign the dip before onlining to avoid race 5870 * with busctl 5871 */ 5872 mutex_enter(&hc_data->hc_mutex); 5873 hc_data->hc_children_dips[port] = child_dip; 5874 mutex_exit(&hc_data->hc_mutex); 5875 5876 rval = usba_bind_driver(child_dip); 5877 5878 if (rval == USB_SUCCESS) { 5879 /* always succeed for WUSB device */ 5880 if ((usba_hubdi_check_power_budget(dip, 5881 child_ud, config_index)) != 5882 USB_SUCCESS) { 5883 rval = USB_FAILURE; 5884 5885 goto done; 5886 } 5887 } 5888 } 5889 5890 if (rval != USB_SUCCESS) { 5891 if ((usba_hubdi_check_power_budget(dip, 5892 child_ud, 0)) != USB_SUCCESS) { 5893 5894 goto done; 5895 } 5896 5897 child_dip = hubd_ready_device( 5898 hwahcp->hwahc_hubd, 5899 child_dip, child_ud, 0); 5900 mutex_enter(&hc_data->hc_mutex); 5901 hc_data->hc_children_dips[port] = child_dip; 5902 mutex_exit(&hc_data->hc_mutex); 5903 } 5904 } /* end else loop all configs */ 5905 } else { 5906 if ((usba_hubdi_check_power_budget(dip, child_ud, 5907 (uint_t)user_conf_index)) != USB_SUCCESS) { 5908 rval = USB_FAILURE; 5909 5910 goto done; 5911 } 5912 5913 child_dip = hubd_ready_device(hwahcp->hwahc_hubd, child_dip, 5914 child_ud, (uint_t)user_conf_index); 5915 5916 /* 5917 * Assign the dip before onlining to avoid race 5918 * with busctl 5919 */ 5920 mutex_enter(&hc_data->hc_mutex); 5921 hc_data->hc_children_dips[port] = child_dip; 5922 mutex_exit(&hc_data->hc_mutex); 5923 5924 (void) usba_bind_driver(child_dip); 5925 5926 rval = USB_SUCCESS; 5927 } 5928 5929 /* workaround for non response after ctrl write */ 5930 usb_pipe_close(child_dip, ph, 5931 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL); 5932 5933 if ((rval = usb_pipe_open(child_dip, NULL, NULL, 5934 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != 5935 USB_SUCCESS) { 5936 USB_DPRINTF_L2(PRINT_MASK_CBOPS, 5937 hwahcp->hwahc_log_handle, 5938 "usb_pipe_open failed (%d)", rval); 5939 5940 goto done; 5941 } 5942 5943 done: 5944 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dev_info)); 5945 5946 ndi_devi_exit(dip, circ); 5947 ndi_devi_exit(rh_dip, rh_circ); 5948 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ); 5949 5950 (void) devfs_clean(rh_dip, NULL, 0); 5951 5952 if (rval == USB_SUCCESS) { 5953 (void) ndi_devi_online(child_dip, 0); 5954 5955 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5956 "hwahc_create_child: create timer for child %p", 5957 (void *)dev_info); 5958 5959 mutex_enter(&hc_data->hc_mutex); 5960 hwahc_start_trust_timer(dev_info); 5961 mutex_exit(&hc_data->hc_mutex); 5962 } 5963 5964 ndi_rele_devi(dip); 5965 5966 return (rval); 5967 } 5968 5969 /* offline child on a certain port */ 5970 static int 5971 hwahc_destroy_child(dev_info_t *dip, usb_port_t port) 5972 { 5973 hwahc_state_t *hwahcp; 5974 5975 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 5976 ddi_get_instance(dip))) == NULL) { 5977 5978 return (USB_INVALID_ARGS); 5979 } 5980 5981 hwahc_post_event(hwahcp, port, USBA_EVENT_TAG_HOT_REMOVAL); 5982 5983 USB_DPRINTF_L3(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 5984 "hwahc_destroy_child: scheduling cleanup"); 5985 5986 /* schedule cleanup thread */ 5987 hubd_schedule_cleanup(hwahcp->hwahc_hubd->h_usba_device-> 5988 usb_root_hub_dip); 5989 5990 return (USB_SUCCESS); 5991 } 5992 5993 /* 5994 * called by cleanup thread to offline child and cleanup child resources 5995 * Child's callback functions have been called before calling this routine. 5996 * dip - hwahc's dip 5997 */ 5998 static int 5999 hwahc_cleanup_child(dev_info_t *dip) 6000 { 6001 hwahc_state_t *hwahcp; 6002 wusb_hc_data_t *hc_data; 6003 usb_port_t port; 6004 6005 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 6006 ddi_get_instance(dip))) == NULL) { 6007 6008 return (USB_INVALID_ARGS); 6009 } 6010 6011 hc_data = &hwahcp->hwahc_hc_data; 6012 mutex_enter(&hc_data->hc_mutex); 6013 for (port = 1; port <= hc_data->hc_num_ports; port++) { 6014 dev_info_t *cdip = hc_data->hc_children_dips[port]; 6015 6016 if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) { 6017 6018 continue; 6019 } 6020 6021 /* 6022 * child's callback has been called and its dip has been 6023 * marked REMOVED. Do further cleanup in hwa driver for 6024 * this child. 6025 */ 6026 mutex_exit(&hc_data->hc_mutex); 6027 (void) hwahc_delete_child(dip, port, NDI_DEVI_REMOVE, B_TRUE); 6028 mutex_enter(&hc_data->hc_mutex); 6029 } 6030 mutex_exit(&hc_data->hc_mutex); 6031 6032 return (USB_SUCCESS); 6033 } 6034 6035 /* offline child and cleanup child resources */ 6036 static int 6037 hwahc_delete_child(dev_info_t *dip, usb_port_t port, uint_t flag, 6038 boolean_t retry) 6039 { 6040 hwahc_state_t *hwahcp; 6041 dev_info_t *child_dip; 6042 usba_device_t *usba_device; 6043 wusb_hc_data_t *hc_data; 6044 int rval; 6045 6046 if ((hwahcp = ddi_get_soft_state(hwahc_statep, 6047 ddi_get_instance(dip))) == NULL) { 6048 6049 return (USB_INVALID_ARGS); 6050 } 6051 6052 child_dip = hwahc_get_child_dip(hwahcp, port); 6053 if (child_dip == NULL) { 6054 6055 return (USB_SUCCESS); 6056 } 6057 6058 usba_device = usba_get_usba_device(child_dip); 6059 hc_data = &hwahcp->hwahc_hc_data; 6060 6061 USB_DPRINTF_L4(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle, 6062 "hwahc_delete_child: port=%d, dip=0x%p usba_device=0x%p", 6063 port, (void *)child_dip, (void *)usba_device); 6064 6065 if (usba_device) { 6066 usba_hubdi_incr_power_budget(dip, usba_device); 6067 } 6068 6069 /* remove this child's dip. If it's <DS_INITIALIZED, free it */ 6070 rval = usba_destroy_child_devi(child_dip, flag); 6071 6072 if ((rval == USB_SUCCESS) && (flag & NDI_DEVI_REMOVE)) { 6073 /* 6074 * if the child was still < DS_INITIALIZED 6075 * then our bus_unconfig was not called and 6076 * we have to zap the child here 6077 */ 6078 mutex_enter(&hc_data->hc_mutex); 6079 if (hc_data->hc_children_dips[port] == child_dip) { 6080 usba_device_t *ud = hc_data->hc_usba_devices[port]; 6081 wusb_dev_info_t *dev_info = hc_data->hc_dev_infos[port]; 6082 6083 hc_data->hc_children_dips[port] = NULL; 6084 if (ud) { 6085 mutex_exit(&hc_data->hc_mutex); 6086 6087 mutex_enter(&ud->usb_mutex); 6088 ud->usb_ref_count = 0; 6089 mutex_exit(&ud->usb_mutex); 6090 6091 usba_free_usba_device(ud); 6092 mutex_enter(&hc_data->hc_mutex); 6093 hc_data->hc_usba_devices[port] = NULL; 6094 } 6095 6096 /* free the child's wusb_dev_info data */ 6097 if (dev_info) { 6098 wusb_secrt_data_t *secrt_data; 6099 6100 if (dev_info-> 6101 wdev_secrt_data.secrt_encry_descr) { 6102 secrt_data = &dev_info->wdev_secrt_data; 6103 kmem_free(secrt_data->secrt_encry_descr, 6104 sizeof (usb_encryption_descr_t) * 6105 secrt_data->secrt_n_encry); 6106 } 6107 if (dev_info->wdev_uwb_descr) { 6108 kmem_free(dev_info->wdev_uwb_descr, 6109 sizeof (usb_uwb_cap_descr_t)); 6110 } 6111 kmem_free(dev_info, sizeof (wusb_dev_info_t)); 6112 hc_data->hc_dev_infos[port] = NULL; 6113 } 6114 } 6115 mutex_exit(&hc_data->hc_mutex); 6116 } 6117 6118 if ((rval != USB_SUCCESS) && retry) { 6119 6120 hubd_schedule_cleanup(usba_device->usb_root_hub_dip); 6121 } 6122 6123 return (rval); 6124 } 6125 6126 /* 6127 * Set encryption type for WUSB host, refer to WUSB 1.0/8.5.3.6 6128 * index = port number - 1 6129 */ 6130 int 6131 hwahc_set_dev_encrypt(usb_pipe_handle_t ph, uint8_t ifc, 6132 usb_port_t index, wusb_secrt_data_t *secrt_data, uint8_t type) 6133 { 6134 int16_t value; 6135 usb_ctrl_setup_t setup; 6136 usb_cr_t cr; 6137 usb_cb_flags_t cb_flags; 6138 6139 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 6140 "hwahc_set_dev_encrypt: device index = %d", index); 6141 6142 if (type == USB_ENC_TYPE_UNSECURE) { 6143 value = 0; 6144 } else if (type == USB_ENC_TYPE_CCM_1) { 6145 if (secrt_data == NULL) { 6146 6147 return (USB_INVALID_ARGS); 6148 } 6149 6150 value = wusb_get_ccm_encryption_value(secrt_data); 6151 if (value == -1) { 6152 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 6153 "hwahc_set_dev_encrypt: cannot find ccm " 6154 "encryption type"); 6155 6156 return (USB_FAILURE); 6157 } 6158 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 6159 "hwahc_set_dev_encrypt: ccm encryption value is %d", 6160 value); 6161 } else { 6162 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 6163 "hwahc_set_dev_encrypt: unsupported encryption type %d", 6164 type); 6165 6166 return (USB_INVALID_ARGS); 6167 } 6168 6169 setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV | 6170 USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF; 6171 setup.bRequest = USB_REQ_SET_ENCRYPTION; 6172 setup.wValue = (uint16_t)value; 6173 setup.wIndex = (index << 8) | ifc; 6174 setup.wLength = 0; 6175 setup.attrs = USB_ATTRS_NONE; 6176 6177 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 6178 "bmRequestType=0x%x, bRequest=0x%x, wValue=0x%x, wIndex=0x%x", 6179 setup.bmRequestType, setup.bRequest, setup.wValue, setup.wIndex); 6180 6181 return (usb_pipe_ctrl_xfer_wait(ph, &setup, NULL, 6182 &cr, &cb_flags, USB_FLAGS_SLEEP)); 6183 }