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