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  * This file mainly contains the entries for HCDI interfaces.
  30  */
  31 #include <sys/usb/usba/usba_impl.h> /* usba_get_dip */
  32 #include <sys/usb/hwa/hwahc/hwahc.h>
  33 #include <sys/usb/hwa/hwahc/hwahc_util.h>
  34 #include <sys/strsubr.h>
  35 #include <sys/strsun.h> /* MBLKL */
  36 
  37 #define WUSB_GTK 1
  38 #define WUSB_PTK 2
  39 
  40 /* function prototypes */
  41 static int hwahc_state_is_operational(hwahc_state_t *hwahcp);
  42 static hwahc_state_t *hwahc_obtain_state(dev_info_t *dip);
  43 static void hwahc_wait_for_xfer_completion(hwahc_state_t *hwahcp,
  44         hwahc_pipe_private_t *pp);
  45 static void hwahc_traverse_requests(hwahc_state_t *hwahcp,
  46         hwahc_pipe_private_t *pp);
  47 static void hwahc_pipe_cleanup(hwahc_state_t *hwahcp,
  48         usba_pipe_handle_data_t *ph);
  49 int hwahc_set_dev_encrypt(usb_pipe_handle_t ph, uint8_t ifc,
  50         usb_port_t index, wusb_secrt_data_t *secrt_data, uint8_t type);
  51 
  52 static int hwahc_hcdi_pm_support(dev_info_t *dip);
  53 static int hwahc_hcdi_pipe_open(usba_pipe_handle_data_t *ph,
  54         usb_flags_t flags);
  55 static int hwahc_hcdi_pipe_close(usba_pipe_handle_data_t *ph,
  56         usb_flags_t flags);
  57 static int hwahc_hcdi_pipe_reset(usba_pipe_handle_data_t *ph,
  58         usb_flags_t flags);
  59 static void hwahc_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t *ph);
  60 static int hwahc_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t *ph,
  61         usb_ctrl_req_t *ctrl_reqp, usb_flags_t usb_flags);
  62 static int hwahc_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *ph,
  63         usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags);
  64 static int hwahc_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t *ph,
  65         usb_intr_req_t *intr_reqp, usb_flags_t usb_flags);
  66 static int hwahc_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t *ph,
  67         usb_isoc_req_t *isoc_reqp, usb_flags_t usb_flags);
  68 static int hwahc_hcdi_bulk_transfer_size(usba_device_t *usba_device,
  69         size_t *size);
  70 static int hwahc_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t *ph,
  71         usb_flags_t flags);
  72 static int hwahc_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t *ph,
  73         usb_flags_t flags);
  74 static int hwahc_hcdi_get_current_frame_number(usba_device_t *usba_device,
  75         usb_frame_number_t *frame_number);
  76 static int hwahc_hcdi_get_max_isoc_pkts(usba_device_t *usba_device,
  77         uint_t *max_pkts);
  78 static int hwahc_hcdi_polled_input_init(usba_pipe_handle_data_t *ph,
  79         uchar_t **polled_buf, usb_console_info_impl_t *console_input_info);
  80 static int hwahc_hcdi_polled_input_fini(usb_console_info_impl_t *info);
  81 static int hwahc_hcdi_polled_input_enter(usb_console_info_impl_t *info);
  82 static int hwahc_hcdi_polled_input_exit(usb_console_info_impl_t *info);
  83 static int hwahc_hcdi_polled_read(usb_console_info_impl_t *info,
  84         uint_t *num_characters);
  85 usba_hcdi_ops_t *hwahc_alloc_hcdi_ops(hwahc_state_t *hwahcp);
  86 
  87 extern void *hwahc_statep;
  88 
  89 /* Check the Host controller state and return proper values */
  90 static int
  91 hwahc_state_is_operational(hwahc_state_t *hwahcp)
  92 {
  93         int     rval;
  94 
  95         ASSERT(mutex_owned(&hwahcp->hwahc_mutex));
  96 
  97         if (hwahcp->hwahc_dev_state != USB_DEV_ONLINE) {
  98 
  99                 return (USB_FAILURE);
 100         }
 101 
 102         switch (hwahcp->hwahc_hc_soft_state) {
 103         case HWAHC_CTRL_INIT_STATE:
 104                 rval = USB_FAILURE;
 105                 break;
 106         case HWAHC_CTRL_OPERATIONAL_STATE:
 107                 /* still need to check if channel is operational */
 108                 if (hwahcp->hwahc_hw_state != HWAHC_HW_STARTED) {
 109                         rval = USB_FAILURE;
 110                 } else {
 111                         rval = USB_SUCCESS;
 112                 }
 113 
 114                 break;
 115         case HWAHC_CTRL_ERROR_STATE:
 116                 rval = USB_HC_HARDWARE_ERROR;
 117                 break;
 118         default:
 119                 rval = USB_FAILURE;
 120                 break;
 121         }
 122 
 123         return (rval);
 124 }
 125 
 126 /* get soft state pointer */
 127 hwahc_state_t *
 128 hwahc_obtain_state(dev_info_t *dip)
 129 {
 130         int instance = ddi_get_instance(dip);
 131 
 132         hwahc_state_t *hwahcp = ddi_get_soft_state(hwahc_statep, instance);
 133 
 134         ASSERT(hwahcp != NULL);
 135 
 136         return (hwahcp);
 137 }
 138 
 139 
 140 /*
 141  * Do not support wusb bus PM now
 142  */
 143 /* ARGSUSED */
 144 static int
 145 hwahc_hcdi_pm_support(dev_info_t *dip)
 146 {
 147         return (USB_FAILURE);
 148 }
 149 
 150 static void
 151 /* ARGSUSED */
 152 hwahc_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t *ph)
 153 {
 154         /* don't do anything now */
 155 }
 156 
 157 /* Wait for processing all completed transfers and to send results */
 158 static void
 159 hwahc_wait_for_xfer_completion(hwahc_state_t *hwahcp, hwahc_pipe_private_t *pp)
 160 {
 161         wusb_wa_rpipe_hdl_t     *hdl = pp->pp_rp;
 162 
 163         mutex_enter(&hdl->rp_mutex);
 164         if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) {
 165                 mutex_exit(&hdl->rp_mutex);
 166 
 167                 return;
 168         }
 169         mutex_exit(&hdl->rp_mutex);
 170 
 171         /* wait 3s */
 172         (void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &hwahcp->hwahc_mutex,
 173             drv_usectohz(3000000), TR_CLOCK_TICK);
 174 
 175         mutex_enter(&hdl->rp_mutex);
 176         if (hdl->rp_state == WA_RPIPE_STATE_ACTIVE) {
 177                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 178                     "hwahc_wait_for_xfer_completion: no transfer completion "
 179                     "confirmation received");
 180         }
 181         mutex_exit(&hdl->rp_mutex);
 182 }
 183 
 184 /* remove all the unprocessed requests and do callback */
 185 /* ARGSUSED */
 186 static void
 187 hwahc_traverse_requests(hwahc_state_t *hwahcp, hwahc_pipe_private_t *pp)
 188 {
 189         wusb_wa_rpipe_hdl_t     *hdl = pp->pp_rp;
 190         wusb_wa_trans_wrapper_t *wr;
 191 
 192         mutex_enter(&hdl->rp_mutex);
 193 
 194         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 195             "hwahc_traverse_requests: pp = 0x%p, wr=%p", (void*)pp,
 196             (void *)hdl->rp_curr_wr);
 197 
 198         wr = hdl->rp_curr_wr;
 199         if (wr != NULL) {
 200                 wusb_wa_stop_xfer_timer(wr);
 201                 hdl->rp_state = WA_RPIPE_STATE_IDLE;
 202                 hdl->rp_curr_wr = NULL;
 203                 wr->wr_state = WR_ABORTED;
 204                 mutex_exit(&hdl->rp_mutex);
 205 
 206                 mutex_exit(&hwahcp->hwahc_mutex);
 207 
 208                 /*
 209                  * This CR is to tell USBA to mark this pipe as IDLE,
 210                  * so that do not queue client requests at USBA. Requests
 211                  * sent after pipe close/reset will be handled by hwahc.
 212                  */
 213                 wr->wr_cb(wr->wr_wa_data, wr, USB_CR_NOT_SUPPORTED, 0);
 214 
 215                 mutex_enter(&hwahcp->hwahc_mutex);
 216                 mutex_enter(&hdl->rp_mutex);
 217         }
 218         mutex_exit(&hdl->rp_mutex);
 219 }
 220 
 221 /* process periodic(INTR/ISOC) requests */
 222 static void
 223 hwahc_do_client_periodic_in_req_callback(hwahc_state_t *hwahcp,
 224         hwahc_pipe_private_t *pp, usb_cr_t completion_reason)
 225 {
 226         usb_ep_descr_t  *eptd;
 227 
 228         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 229             "hwahc_do_client_periodic_in_req_callback: enter");
 230 
 231         /*
 232          * Check for Interrupt/Isochronous IN, whether we need to do
 233          * callback for the original client's periodic IN request.
 234          */
 235         eptd = &(pp->pp_pipe_handle->p_ep);
 236         if (pp->pp_client_periodic_in_reqp) {
 237                 if (WUSB_ISOC_ENDPOINT(eptd)) {
 238                         /* not supported */
 239                         USB_DPRINTF_L4(PRINT_MASK_HCDI,
 240                             hwahcp->hwahc_log_handle,
 241                             "hwahc_do_client_periodic_in_req_callback: "
 242                             "ISOC xfer not support");
 243                 } else {
 244                         /*
 245                          * NULL wr to tell the function that we're done and
 246                          * should clear pipe's pp_client_periodic_in_reqp
 247                          */
 248                         wusb_wa_callback(&hwahcp->hwahc_wa_data,
 249                             pp->pp_pipe_handle, NULL, completion_reason);
 250                 }
 251         }
 252 
 253         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 254             "hwahc_do_client_periodic_in_req_callback: end");
 255 }
 256 
 257 /*
 258  * clean up the pipe, called by pipe_close/pipe_reset
 259  *      - Abort RPipe operation
 260  *      - Clean pending requests queueing on this pipe
 261  */
 262 static void
 263 hwahc_pipe_cleanup(hwahc_state_t *hwahcp, usba_pipe_handle_data_t *ph)
 264 {
 265         hwahc_pipe_private_t    *pp;
 266         wusb_wa_rpipe_hdl_t     *hdl;
 267         int                     rval;
 268         usb_ep_descr_t          *eptd;
 269         usb_cr_t                completion_reason;
 270 
 271         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 272 
 273         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 274             "hwahc_pipe_cleanup: ph = 0x%p, p_req_cnt, ep=0x%02x,"
 275             " state=%d", (void *) ph, ph->p_ep.bEndpointAddress,
 276             pp->pp_state);
 277 
 278         ASSERT(mutex_owned(&hwahcp->hwahc_mutex));
 279         ASSERT(!servicing_interrupt());
 280 
 281         hdl = pp->pp_rp;
 282 
 283         if (hwahcp->hwahc_dev_state == USB_DEV_ONLINE) {
 284                 /* abort rpipe */
 285                 mutex_enter(&hdl->rp_mutex);
 286 
 287                 /* if active, abort the requests */
 288                 if (hdl->rp_state == WA_RPIPE_STATE_ACTIVE) {
 289                         mutex_exit(&hdl->rp_mutex);
 290                         mutex_exit(&hwahcp->hwahc_mutex);
 291                         rval = wusb_wa_rpipe_abort(hwahcp->hwahc_dip,
 292                             hwahcp->hwahc_default_pipe, hdl);
 293                         mutex_enter(&hwahcp->hwahc_mutex);
 294                         mutex_enter(&hdl->rp_mutex);
 295                 }
 296                 mutex_exit(&hdl->rp_mutex);
 297 
 298                 /* wait for transfers to complete */
 299                 hwahc_wait_for_xfer_completion(hwahcp, pp);
 300         }
 301 
 302         /* remove all unprocessed requests on this pipe and do callback */
 303         hwahc_traverse_requests(hwahcp, pp);
 304 
 305         switch (pp->pp_state) {
 306         case HWAHC_PIPE_STATE_CLOSE:
 307                 completion_reason = USB_CR_PIPE_CLOSING;
 308 
 309                 mutex_exit(&hwahcp->hwahc_mutex);
 310                 (void) wusb_wa_rpipe_reset(hwahcp->hwahc_dip, ph, hdl, 0);
 311                 mutex_enter(&hwahcp->hwahc_mutex);
 312 
 313                 break;
 314         case HWAHC_PIPE_STATE_RESET:
 315         case HWAHC_PIPE_STATE_ERROR:
 316                 completion_reason = USB_CR_PIPE_RESET;
 317                 if (hwahcp->hwahc_dev_state == USB_DEV_ONLINE) {
 318                         mutex_exit(&hwahcp->hwahc_mutex);
 319                         /*
 320                          * reset WA's RPipe.
 321                          * If this pipe is not bound to the default endpoint,
 322                          * also send a clear_feature request to that ep.
 323                          */
 324                         rval = wusb_wa_rpipe_reset(hwahcp->hwahc_dip,
 325                             ph, hdl, 1);
 326                         mutex_enter(&hwahcp->hwahc_mutex);
 327 
 328                         USB_DPRINTF_L4(PRINT_MASK_HCDI,
 329                             hwahcp->hwahc_log_handle,
 330                             "hwahc_pipe_cleanup: rp reset, rv=%d",
 331                             rval);
 332 
 333                         pp->pp_state = HWAHC_PIPE_STATE_IDLE;
 334                 }
 335 
 336                 break;
 337         case HWAHC_PIPE_STATE_STOP_POLLING:
 338                 completion_reason = USB_CR_STOPPED_POLLING;
 339                 pp->pp_state = HWAHC_PIPE_STATE_IDLE;
 340 
 341                 break;
 342         }
 343 
 344         /*
 345          * Do the callback for the original client
 346          * periodic IN request.
 347          */
 348         eptd = &ph->p_ep;
 349 
 350         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 351             "hwahc_pipe_cleanup: end");
 352 
 353         if ((WUSB_PERIODIC_ENDPOINT(eptd)) &&
 354             ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
 355             USB_EP_DIR_IN)) {
 356                 mutex_exit(&hwahcp->hwahc_mutex);
 357 
 358                 hwahc_do_client_periodic_in_req_callback(
 359                     hwahcp, pp, completion_reason);
 360 
 361                 mutex_enter(&hwahcp->hwahc_mutex);
 362         }
 363 }
 364 
 365 /*
 366  * set the pipe's parent device information
 367  */
 368 static int
 369 hwahc_set_pipe_dev_info(hwahc_state_t *hwahcp,
 370     usba_pipe_handle_data_t *ph, hwahc_pipe_private_t *pp)
 371 {
 372         dev_info_t *dip = NULL;
 373         wusb_hc_data_t *hc_data;
 374         int i;
 375 
 376         dip = usba_get_dip((usb_pipe_handle_t)ph->p_ph_impl);
 377         if (dip == NULL) {
 378 
 379                 return (USB_FAILURE);
 380         }
 381 
 382         hc_data = &hwahcp->hwahc_hc_data;
 383 
 384         mutex_enter(&hc_data->hc_mutex);
 385         for (i = 1; i <= hc_data->hc_num_ports; i++) {
 386                 if ((dip == hc_data->hc_children_dips[i])) {
 387                         pp->pp_wdev = hc_data->hc_dev_infos[i];
 388 
 389                         USB_DPRINTF_L3(DPRINT_MASK_HCDI,
 390                             hwahcp->hwahc_log_handle,
 391                             "hwahc_set_pipe_dev_info: pp(%p) device(%p) set",
 392                             (void *) pp, (void *) pp->pp_wdev);
 393 
 394                         break;
 395                 }
 396         }
 397 
 398         mutex_exit(&hc_data->hc_mutex);
 399 
 400         if (pp->pp_wdev) {
 401                 return (USB_SUCCESS);
 402         } else {
 403                 return (USB_FAILURE);
 404         }
 405 }
 406 
 407 /*
 408  * HWA HCDI entry points
 409  *
 410  * The Host Controller Driver Interfaces (HCDI) are the software interfaces
 411  * between the Universal Serial Bus Layer (USBA) and the Host Controller
 412  * Driver (HCD). The HCDI interfaces or entry points are subject to change.
 413  */
 414 
 415 /*
 416  * hwahc_hcdi_pipe_open:
 417  * Member of HCD Ops structure and called during client specific pipe open.
 418  * Assign rpipe for wireless transaction to work.
 419  * The rpipe is assigned to an endpoint until the endpoint is closed.
 420  */
 421 static int
 422 hwahc_hcdi_pipe_open(
 423         usba_pipe_handle_data_t *ph,
 424         usb_flags_t             flags)
 425 {
 426         int                     rval;
 427         hwahc_state_t           *hwahcp;
 428         int                     kmflag;
 429         hwahc_pipe_private_t    *pp;
 430         usb_ep_descr_t          *epdt = &ph->p_ep;
 431         uint8_t                 type;
 432         wusb_wa_data_t          *wa;
 433 
 434         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 435         wa = &hwahcp->hwahc_wa_data;
 436 
 437         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 438             "hwahc_hcdi_pipe_open: hwahc=0x%p, ph=0x%p,"
 439             " addr = 0x%x, ep=0x%02X", (void *) hwahcp, (void *) ph,
 440             ph->p_usba_device->usb_addr, epdt->bEndpointAddress);
 441 
 442         kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
 443 
 444         if (ph->p_hcd_private) {
 445                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 446                     "hwahc_hcdi_pipe_open: Pipe is already opened");
 447 
 448                 return (USB_FAILURE);
 449         }
 450 
 451         pp = kmem_zalloc(sizeof (hwahc_pipe_private_t), kmflag);
 452         if (pp == NULL) {
 453                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 454                     "hwahc_hcdi_pipe_open: alloc pp failed");
 455 
 456                 return (USB_NO_RESOURCES);
 457         }
 458 
 459         mutex_enter(&hwahcp->hwahc_mutex);
 460 
 461         if (hwahc_set_pipe_dev_info(hwahcp, ph, pp) < 0) {
 462                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 463                     "hwahc_hcdi_pipe_open: set pipe dev_info failed");
 464                 mutex_exit(&hwahcp->hwahc_mutex);
 465 
 466                 return (USB_FAILURE);
 467         }
 468 
 469         rval = hwahc_state_is_operational(hwahcp);
 470         if (rval != USB_SUCCESS) {
 471                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 472                     "hwahc_hcdi_pipe_open: state error: %d", rval);
 473                 kmem_free(pp, sizeof (hwahc_pipe_private_t));
 474                 mutex_exit(&hwahcp->hwahc_mutex);
 475 
 476                 return (rval);
 477         }
 478 
 479         /* assign rpipe to the endpoint */
 480         type = epdt->bmAttributes & USB_EP_ATTR_MASK;
 481         rval = wusb_wa_get_rpipe(&hwahcp->hwahc_wa_data,
 482             hwahcp->hwahc_default_pipe, type, &pp->pp_rp,
 483             PRINT_MASK_HCDI, hwahcp->hwahc_log_handle);
 484         if (rval != USB_SUCCESS) {
 485                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 486                     "hwahc_hcdi_pipe_open: getting rpipe failed");
 487                 kmem_free(pp, sizeof (hwahc_pipe_private_t));
 488                 mutex_exit(&hwahcp->hwahc_mutex);
 489 
 490                 return (USB_NO_RESOURCES);
 491         }
 492 
 493         mutex_exit(&hwahcp->hwahc_mutex);
 494         /* target the rpipe to the endpoint */
 495         rval = wusb_wa_set_rpipe_target(hwahcp->hwahc_dip, wa,
 496             hwahcp->hwahc_default_pipe, ph, pp->pp_rp);
 497         mutex_enter(&hwahcp->hwahc_mutex);
 498 
 499         if (rval != USB_SUCCESS) {
 500                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 501                     "hwahc_hcdi_pipe_open: set target for rpipe failed");
 502                 (void) wusb_wa_release_rpipe(wa, pp->pp_rp);
 503                 kmem_free(pp, sizeof (hwahc_pipe_private_t));
 504                 mutex_exit(&hwahcp->hwahc_mutex);
 505 
 506                 return (USB_FAILURE);
 507         }
 508 
 509         pp->pp_pipe_handle = ph;
 510         cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL);
 511 
 512         mutex_enter(&ph->p_mutex);
 513         ph->p_hcd_private = (usb_opaque_t)pp;
 514         bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
 515         mutex_exit(&ph->p_mutex);
 516 
 517         pp->pp_state = HWAHC_PIPE_STATE_IDLE;
 518         hwahcp->hwahc_open_pipe_count++;
 519         mutex_exit(&hwahcp->hwahc_mutex);
 520 
 521         return (USB_SUCCESS);
 522 }
 523 
 524 
 525 /*
 526  * hwahc_hcdi_pipe_close:
 527  * Member of HCD Ops structure and called during the client specific pipe
 528  * close.
 529  * Remove unprocessed transfers from the pipe and free rpipe resource.
 530  */
 531 /* ARGSUSED */
 532 static int
 533 hwahc_hcdi_pipe_close(
 534         usba_pipe_handle_data_t *ph,
 535         usb_flags_t             flags)
 536 {
 537         hwahc_state_t           *hwahcp;
 538         hwahc_pipe_private_t    *pp;
 539         usb_ep_descr_t          *epdt = &ph->p_ep;
 540 
 541         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 542 
 543         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 544             "hwahc_hcdi_pipe_close:ph=0x%p addr = 0x%x, ep = 0x%x",
 545             (void *) ph, ph->p_usba_device->usb_addr,
 546             epdt->bEndpointAddress);
 547 
 548         ASSERT(ph->p_hcd_private != NULL);
 549         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 550 
 551         mutex_enter(&hwahcp->hwahc_mutex);
 552 
 553         pp->pp_state = HWAHC_PIPE_STATE_CLOSE;
 554 
 555         hwahc_pipe_cleanup(hwahcp, ph);
 556 
 557         mutex_exit(&hwahcp->hwahc_mutex);
 558 
 559         wusb_wa_clear_dev_ep(ph); /* clear the remote dev's endpoint */
 560         mutex_enter(&hwahcp->hwahc_mutex);
 561 
 562         (void) wusb_wa_release_rpipe(&hwahcp->hwahc_wa_data, pp->pp_rp);
 563 
 564         mutex_enter(&ph->p_mutex);
 565         cv_destroy(&pp->pp_xfer_cmpl_cv);
 566         kmem_free(pp, sizeof (hwahc_pipe_private_t));
 567         ph->p_hcd_private = NULL;
 568         mutex_exit(&ph->p_mutex);
 569         hwahcp->hwahc_open_pipe_count--;
 570         mutex_exit(&hwahcp->hwahc_mutex);
 571 
 572         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 573             "hwahc_hcdi_pipe_close: end");
 574 
 575         return (USB_SUCCESS);
 576 }
 577 
 578 
 579 /*
 580  * hwahc_hcdi_pipe_reset:
 581  *      - clean up this pipe and change its state
 582  */
 583 /* ARGSUSED */
 584 static int
 585 hwahc_hcdi_pipe_reset(
 586         usba_pipe_handle_data_t *ph,
 587         usb_flags_t             flags)
 588 {
 589         hwahc_state_t           *hwahcp;
 590         hwahc_pipe_private_t    *pp;
 591 
 592         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 593 
 594         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 595             "hwahc_hcdi_pipe_reset: ph = 0x%p, ep=0x%02x",
 596             (void *) ph, ph->p_ep.bEndpointAddress);
 597 
 598         ASSERT(ph->p_hcd_private != NULL);
 599         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 600 
 601         mutex_enter(&hwahcp->hwahc_mutex);
 602         pp->pp_state = HWAHC_PIPE_STATE_RESET;
 603         hwahc_pipe_cleanup(hwahcp, ph);
 604         mutex_exit(&hwahcp->hwahc_mutex);
 605 
 606         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 607             "hwahc_hcdi_pipe_reset: end");
 608 
 609         return (USB_SUCCESS);
 610 }
 611 
 612 
 613 /*
 614  * hwahc_hcdi_pipe_ctrl_xfer:
 615  *      - usba_hcdi_pipe_ctrl_xfer entry
 616  *      - check pipe state
 617  *      - call wa_xfer to do this request
 618  */
 619 static int
 620 hwahc_hcdi_pipe_ctrl_xfer(
 621         usba_pipe_handle_data_t *ph,
 622         usb_ctrl_req_t          *ctrl_reqp,
 623         usb_flags_t             usb_flags)
 624 {
 625         hwahc_state_t           *hwahcp;
 626         hwahc_pipe_private_t    *pp;
 627         int                     rval;
 628         uint8_t                 ep_addr = ph->p_ep.bEndpointAddress;
 629 
 630         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 631 
 632         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 633             "hwahc_hcdi_pipe_ctrl_xfer: hwahcp=0x%p ph = 0x%p"
 634             " reqp = 0x%p flags = %x", (void *) hwahcp, (void *) ph,
 635             (void *) ctrl_reqp, usb_flags);
 636 
 637         ASSERT(ph->p_hcd_private != NULL);
 638         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 639 
 640         mutex_enter(&hwahcp->hwahc_mutex);
 641         rval = hwahc_state_is_operational(hwahcp);
 642         if (rval != USB_SUCCESS) {
 643                 mutex_exit(&hwahcp->hwahc_mutex);
 644 
 645                 return (rval);
 646         }
 647 
 648         /*
 649          * if doing ctrl transfer on non-zero pipe and its state is error
 650          * The default endpoint is critical for any other operations.
 651          * We should not depend on upper layer to reset it.
 652          */
 653         if ((pp->pp_state == HWAHC_PIPE_STATE_ERROR)) {
 654                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 655                     "hwahc_hcdi_pipe_ctrl_xfer: Pipe(%d) is in error"
 656                     " state, need pipe reset to continue", ep_addr);
 657 
 658                 if (ep_addr == 0) {
 659                         /*
 660                          * some error with the RPipe of EP 0,
 661                          * we need to reset this RPipe by ourself
 662                          */
 663                         mutex_exit(&hwahcp->hwahc_mutex);
 664                         (void) wusb_wa_rpipe_reset(hwahcp->hwahc_dip, ph,
 665                             pp->pp_rp, 1);
 666                         mutex_enter(&hwahcp->hwahc_mutex);
 667                         pp->pp_state = 0;
 668                 } else {
 669                 /* client driver should clear non-default endpoint's state */
 670                         mutex_exit(&hwahcp->hwahc_mutex);
 671 
 672                         return (USB_FAILURE);
 673                 }
 674         } else if ((pp->pp_state != HWAHC_PIPE_STATE_IDLE) &&
 675             (pp->pp_state != HWAHC_PIPE_STATE_ERROR)) {
 676                         mutex_exit(&hwahcp->hwahc_mutex);
 677 
 678                         return (USB_PIPE_ERROR);
 679         }
 680 
 681         mutex_exit(&hwahcp->hwahc_mutex);
 682 
 683         rval = wusb_wa_ctrl_xfer(&hwahcp->hwahc_wa_data, pp->pp_rp, ph,
 684             ctrl_reqp, usb_flags);
 685         if (rval != USB_SUCCESS) {
 686                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 687                     "hwahc_hcdi_pipe_ctrl_xfer failed, rval = %d", rval);
 688         }
 689 
 690 
 691         return (rval);
 692 }
 693 
 694 
 695 /*
 696  * hwahc_hcdi_pipe_bulk_xfer:
 697  *      - usba_hcid_pipe_bulk_xfer entry
 698  *      - check the target pipe status first
 699  *      - process this request
 700  */
 701 static int
 702 hwahc_hcdi_pipe_bulk_xfer(
 703         usba_pipe_handle_data_t *ph,
 704         usb_bulk_req_t          *bulk_reqp,
 705         usb_flags_t             usb_flags)
 706 {
 707         hwahc_state_t           *hwahcp;
 708         hwahc_pipe_private_t    *pp;
 709         int                     rval;
 710 
 711         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 712 
 713         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 714             "hwahc_hcdi_pipe_bulk_xfer: hwahcp=0x%p ph = 0x%p reqp = 0x%p"
 715             " flags = %x", (void *) hwahcp, (void *) ph,
 716             (void *) bulk_reqp, usb_flags);
 717 
 718         ASSERT(ph->p_hcd_private != NULL);
 719 
 720         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 721 
 722         mutex_enter(&hwahcp->hwahc_mutex);
 723         rval = hwahc_state_is_operational(hwahcp);
 724         if (rval != USB_SUCCESS) {
 725                 mutex_exit(&hwahcp->hwahc_mutex);
 726 
 727                 return (rval);
 728         }
 729 
 730         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 731             "hwahc_hcdi_pipe_bulk_xfer: pp = 0x%p state= %x", (void *) pp,
 732             pp->pp_state);
 733 
 734         if (pp->pp_state == HWAHC_PIPE_STATE_ERROR) {
 735                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 736                     "hwahc_hcdi_pipe_bulk_xfer: "
 737                     "Pipe is in error state, need pipe reset to continue");
 738 
 739                 mutex_exit(&hwahcp->hwahc_mutex);
 740 
 741                 return (USB_FAILURE);
 742         }
 743 
 744         mutex_exit(&hwahcp->hwahc_mutex);
 745         rval = wusb_wa_bulk_xfer(&hwahcp->hwahc_wa_data, pp->pp_rp, ph,
 746             bulk_reqp, usb_flags);
 747         mutex_enter(&hwahcp->hwahc_mutex);
 748         if (rval != USB_SUCCESS) {
 749                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 750                     "hwahc_hcdi_pipe_bulk_xfer failed, rval = %d", rval);
 751         }
 752         mutex_exit(&hwahcp->hwahc_mutex);
 753 
 754         return (rval);
 755 }
 756 
 757 /*
 758  * hwahc_hcdi_pipe_intr_xfer:
 759  *      - usba_hcdi_pipe_intr_xfer entry
 760  *      - check pipe state
 761  *      - process this request
 762  */
 763 static int
 764 hwahc_hcdi_pipe_intr_xfer(
 765         usba_pipe_handle_data_t *ph,
 766         usb_intr_req_t          *intr_reqp,
 767         usb_flags_t             usb_flags)
 768 {
 769         hwahc_state_t           *hwahcp;
 770         hwahc_pipe_private_t    *pp;
 771         int                     rval, pipe_dir;
 772 
 773         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 774 
 775         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 776             "hwahc_hcdi_pipe_intr_xfer: hwahcp=0x%p ph = 0x%p"
 777             " reqp = 0x%p flags = %x", (void *) hwahcp, (void *) ph,
 778             (void *) intr_reqp, usb_flags);
 779 
 780         ASSERT(ph->p_hcd_private != NULL);
 781         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 782 
 783         mutex_enter(&hwahcp->hwahc_mutex);
 784         rval = hwahc_state_is_operational(hwahcp);
 785         if (rval != USB_SUCCESS) {
 786                 mutex_exit(&hwahcp->hwahc_mutex);
 787 
 788                 return (rval);
 789         }
 790 
 791         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 792             "hwahc_hcdi_pipe_intr_xfer: pp = 0x%p state= %x", (void *) pp,
 793             pp->pp_state);
 794 
 795         if (pp->pp_state == HWAHC_PIPE_STATE_ERROR) {
 796                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 797                     "hwahc_hcdi_pipe_intr_xfer: "
 798                     "Pipe is in error state, need pipe reset to continue");
 799 
 800                 mutex_exit(&hwahcp->hwahc_mutex);
 801 
 802                 return (USB_FAILURE);
 803         }
 804 
 805         pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
 806 
 807 
 808         mutex_exit(&hwahcp->hwahc_mutex);
 809         rval = wusb_wa_intr_xfer(&hwahcp->hwahc_wa_data, pp->pp_rp, ph,
 810             intr_reqp, usb_flags);
 811         mutex_enter(&hwahcp->hwahc_mutex);
 812         if (rval != USB_SUCCESS) {
 813                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 814                     "hwahc_hcdi_pipe_intr_xfer failed, rval = %d", rval);
 815         }
 816 
 817         if ((pipe_dir == USB_EP_DIR_IN) &&(rval == USB_SUCCESS)) {
 818                 /*
 819                  * the request has been submitted successfully,
 820                  * save the original one; free this request when polling
 821                  * stopped
 822                  */
 823                 pp->pp_client_periodic_in_reqp = (usb_opaque_t)intr_reqp;
 824                 pp->pp_state = HWAHC_PIPE_STATE_ACTIVE;
 825         }
 826 
 827         mutex_exit(&hwahcp->hwahc_mutex);
 828 
 829         return (rval);
 830 }
 831 
 832 /*
 833  * hwahc_hcdi_pipe_isoc_xfer:
 834  */
 835 /* ARGSUSED */
 836 static int
 837 hwahc_hcdi_pipe_isoc_xfer(
 838         usba_pipe_handle_data_t *ph,
 839         usb_isoc_req_t          *isoc_reqp,
 840         usb_flags_t             usb_flags)
 841 {
 842         return (USB_NOT_SUPPORTED);
 843 }
 844 
 845 
 846 /*
 847  * hwahc_hcdi_bulk_transfer_size:
 848  *
 849  * Return maximum bulk transfer size
 850  */
 851 /* ARGSUSED */
 852 static int
 853 hwahc_hcdi_bulk_transfer_size(
 854         usba_device_t   *usba_device,
 855         size_t          *size)
 856 {
 857         hwahc_state_t           *hwahcp;
 858         int                     rval;
 859 
 860         hwahcp = hwahc_obtain_state(usba_device->usb_root_hub_dip);
 861 
 862         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 863             "hwahc_hcdi_bulk_transfer_size:");
 864 
 865         mutex_enter(&hwahcp->hwahc_mutex);
 866         rval = hwahc_state_is_operational(hwahcp);
 867         mutex_exit(&hwahcp->hwahc_mutex);
 868 
 869         if (rval != USB_SUCCESS) {
 870 
 871                 return (rval);
 872         }
 873 
 874         *size = WA_MAX_SEG_COUNT * 1024;
 875 
 876         return (USB_SUCCESS);
 877 }
 878 
 879 /*
 880  * hwahc_hcdi_pipe_stop_intr_polling()
 881  */
 882 /* ARGSUSED */
 883 static int
 884 hwahc_hcdi_pipe_stop_intr_polling(
 885         usba_pipe_handle_data_t *ph,
 886         usb_flags_t             flags)
 887 {
 888         hwahc_state_t           *hwahcp;
 889         hwahc_pipe_private_t    *pp;
 890 
 891         hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
 892 
 893         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 894             "hwahc_hcdi_pipe_stop_intr_polling: hwahcp=0x%p ph = 0x%p"
 895             " flags = %x", (void *) hwahcp, (void *) ph, flags);
 896 
 897         ASSERT(ph->p_hcd_private != NULL);
 898 
 899         mutex_enter(&hwahcp->hwahc_mutex);
 900         pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
 901 
 902         if (pp->pp_state != HWAHC_PIPE_STATE_ACTIVE) {
 903                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
 904                     "hwahc_hcdi_pipe_stop_intr_polling: "
 905                     "Polling already stopped");
 906                 mutex_exit(&hwahcp->hwahc_mutex);
 907 
 908                 return (USB_SUCCESS);
 909         }
 910 
 911         pp->pp_state = HWAHC_PIPE_STATE_STOP_POLLING;
 912 
 913         hwahc_pipe_cleanup(hwahcp, ph);
 914 
 915         mutex_exit(&hwahcp->hwahc_mutex);
 916 
 917         return (USB_SUCCESS);
 918 }
 919 
 920 
 921 /*
 922  * hwahc_hcdi_pipe_stop_isoc_polling()
 923  */
 924 /*ARGSUSED*/
 925 static int
 926 hwahc_hcdi_pipe_stop_isoc_polling(
 927         usba_pipe_handle_data_t *ph,
 928         usb_flags_t             flags)
 929 {
 930         return (USB_NOT_SUPPORTED);
 931 }
 932 
 933 
 934 /*
 935  * hwahc_hcdi_get_current_frame_number:
 936  *
 937  * Get the current usb frame number.
 938  * Return whether the request is handled successfully
 939  */
 940 /* ARGSUSED */
 941 static int
 942 hwahc_hcdi_get_current_frame_number(
 943         usba_device_t           *usba_device,
 944         usb_frame_number_t      *frame_number)
 945 {
 946         return (USB_NOT_SUPPORTED);
 947 }
 948 
 949 
 950 /*
 951  * hwahc_hcdi_get_max_isoc_pkts:
 952  *
 953  * Get maximum isochronous packets per usb isochronous request.
 954  * Return whether the request is handled successfully
 955  */
 956 /* ARGSUSED */
 957 static int
 958 hwahc_hcdi_get_max_isoc_pkts(
 959         usba_device_t   *usba_device,
 960         uint_t          *max_pkts)
 961 {
 962         return (USB_NOT_SUPPORTED);
 963 }
 964 
 965 
 966 /*
 967  * POLLED entry points
 968  *
 969  * These functions are entry points into the POLLED code.
 970  */
 971 /*
 972  * hwahc_hcdi_polled_input_init:
 973  *
 974  * This is the initialization routine for handling the USB keyboard
 975  * in POLLED mode.  This routine is not called from POLLED mode, so
 976  * it is OK to acquire mutexes.
 977  */
 978 /* ARGSUSED */
 979 static int
 980 hwahc_hcdi_polled_input_init(
 981         usba_pipe_handle_data_t *ph,
 982         uchar_t                 **polled_buf,
 983         usb_console_info_impl_t *console_input_info)
 984 {
 985         return (USB_FAILURE);
 986 }
 987 
 988 
 989 /*
 990  * hwahc_hcdi_polled_input_fini:
 991  */
 992 /* ARGSUSED */
 993 static int
 994 hwahc_hcdi_polled_input_fini(usb_console_info_impl_t *info)
 995 {
 996         return (USB_FAILURE);
 997 }
 998 
 999 
1000 /*
1001  * hwahc_hcdi_polled_input_enter:
1002  *
1003  * This is where we enter into POLLED mode.  This routine sets up
1004  * everything so that calls to  hwahc_hcdi_polled_read will return
1005  * characters.
1006  */
1007 /* ARGSUSED */
1008 static int
1009 hwahc_hcdi_polled_input_enter(usb_console_info_impl_t *info)
1010 {
1011         return (USB_FAILURE);
1012 }
1013 
1014 
1015 /*
1016  * hwahc_hcdi_polled_input_exit:
1017  *
1018  * This is where we exit POLLED mode. This routine restores
1019  * everything that is needed to continue operation.
1020  */
1021 /* ARGSUSED */
1022 static int
1023 hwahc_hcdi_polled_input_exit(usb_console_info_impl_t *info)
1024 {
1025         return (USB_FAILURE);
1026 }
1027 
1028 
1029 /*
1030  * hwahc_hcdi_polled_read:
1031  *
1032  * Get a key character
1033  */
1034 /* ARGSUSED */
1035 static int
1036 hwahc_hcdi_polled_read(
1037         usb_console_info_impl_t *info,
1038         uint_t                  *num_characters)
1039 {
1040         return (USB_FAILURE);
1041 }
1042 
1043 
1044 /*
1045  * hwahc_alloc_hcdi_ops:
1046  *
1047  * The HCDI interfaces or entry points are the software interfaces used by
1048  * the Universal Serial Bus Driver  (USBA) to  access the services of the
1049  * Host Controller Driver (HCD).  During HCD initialization, inform  USBA
1050  * about all available HCDI interfaces or entry points.
1051  */
1052 usba_hcdi_ops_t *
1053 hwahc_alloc_hcdi_ops(hwahc_state_t *hwahcp)
1054 {
1055         usba_hcdi_ops_t                 *usba_hcdi_ops;
1056 
1057         USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle,
1058             "hwahc_alloc_hcdi_ops:");
1059 
1060         usba_hcdi_ops = usba_alloc_hcdi_ops();
1061 
1062         usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
1063 
1064         usba_hcdi_ops->usba_hcdi_pm_support = hwahc_hcdi_pm_support;
1065         usba_hcdi_ops->usba_hcdi_pipe_open = hwahc_hcdi_pipe_open;
1066         usba_hcdi_ops->usba_hcdi_pipe_close = hwahc_hcdi_pipe_close;
1067 
1068         usba_hcdi_ops->usba_hcdi_pipe_reset = hwahc_hcdi_pipe_reset;
1069         usba_hcdi_ops->usba_hcdi_pipe_reset_data_toggle =
1070             hwahc_hcdi_pipe_reset_data_toggle;
1071 
1072         usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = hwahc_hcdi_pipe_ctrl_xfer;
1073         usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = hwahc_hcdi_pipe_bulk_xfer;
1074         usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = hwahc_hcdi_pipe_intr_xfer;
1075         usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = hwahc_hcdi_pipe_isoc_xfer;
1076 
1077         usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
1078             hwahc_hcdi_bulk_transfer_size;
1079 
1080         usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
1081             hwahc_hcdi_pipe_stop_intr_polling;
1082         usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
1083             hwahc_hcdi_pipe_stop_isoc_polling;
1084 
1085         usba_hcdi_ops->usba_hcdi_get_current_frame_number =
1086             hwahc_hcdi_get_current_frame_number;
1087         usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
1088             hwahc_hcdi_get_max_isoc_pkts;
1089 
1090         usba_hcdi_ops->usba_hcdi_console_input_init =
1091             hwahc_hcdi_polled_input_init;
1092         usba_hcdi_ops->usba_hcdi_console_input_enter =
1093             hwahc_hcdi_polled_input_enter;
1094         usba_hcdi_ops->usba_hcdi_console_read =
1095             hwahc_hcdi_polled_read;
1096         usba_hcdi_ops->usba_hcdi_console_input_exit =
1097             hwahc_hcdi_polled_input_exit;
1098         usba_hcdi_ops->usba_hcdi_console_input_fini =
1099             hwahc_hcdi_polled_input_fini;
1100 
1101         return (usba_hcdi_ops);
1102 }
1103 
1104 
1105 /*
1106  * Set cluster ID.
1107  * see 8.5.3.11
1108  */
1109 int
1110 hwahc_set_cluster_id(dev_info_t *dip, uint8_t cluster_id)
1111 {
1112         usb_cr_t        completion_reason;
1113         usb_cb_flags_t  cb_flags;
1114         int             rval;
1115         hwahc_state_t   *hwahcp;
1116 
1117         if (dip == NULL) {
1118 
1119                 return (USB_INVALID_ARGS);
1120         }
1121 
1122         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1123         if (hwahcp == NULL) {
1124 
1125                 return (USB_INVALID_ARGS);
1126         }
1127 
1128         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1129             WUSB_CLASS_IF_REQ_OUT_TYPE,
1130             HWA_REQ_SET_CLUSTER_ID,
1131             cluster_id,
1132             hwahcp->hwahc_wa_data.wa_ifno,
1133             0,
1134             NULL, 0,
1135             &completion_reason, &cb_flags, 0);
1136 
1137         if (rval != USB_SUCCESS) {
1138                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1139                     "Set_Cluster_ID fails: rval=%d cr=%d cb=0x%x",
1140                     rval, completion_reason, cb_flags);
1141         }
1142 
1143         return (rval);
1144 }
1145 
1146 /*
1147  * Set WUSB Stream Index. see 8.5.3.13
1148  */
1149 int
1150 hwahc_set_stream_idx(dev_info_t *dip, uint8_t stream_idx)
1151 {
1152         usb_cr_t        completion_reason;
1153         usb_cb_flags_t  cb_flags;
1154         int             rval;
1155         hwahc_state_t   *hwahcp;
1156 
1157         if ((dip == NULL))  {
1158 
1159                 return (USB_INVALID_ARGS);
1160         }
1161 
1162         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1163         if (hwahcp == NULL) {
1164 
1165                 return (USB_INVALID_ARGS);
1166         }
1167 
1168         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1169             WUSB_CLASS_IF_REQ_OUT_TYPE,
1170             HWA_REQ_SET_STREAM_IDX,
1171             stream_idx,
1172             hwahcp->hwahc_wa_data.wa_ifno,
1173             0, NULL, 0, &completion_reason,
1174             &cb_flags, 0);
1175 
1176         if (rval != USB_SUCCESS) {
1177                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1178                     "Set_Stream_Idx fails: rval=%d cr=%d cb=0x%x",
1179                     rval, completion_reason, cb_flags);
1180         }
1181 
1182         return (rval);
1183 }
1184 
1185 /*
1186  * 8.5.3.12 - Set WUSB MAS
1187  *      Caller must ensure the data is WUSB_SET_WUSB_MAS_LEN long.
1188  */
1189 int
1190 hwahc_set_wusb_mas(dev_info_t *dip, uint8_t *data)
1191 {
1192         usb_cr_t        completion_reason;
1193         usb_cb_flags_t  cb_flags;
1194         mblk_t          *blk;
1195         int             rval, i;
1196         hwahc_state_t   *hwahcp;
1197 
1198         if ((dip == NULL))  {
1199 
1200                 return (USB_INVALID_ARGS);
1201         }
1202 
1203         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1204         if (hwahcp == NULL) {
1205 
1206                 return (USB_INVALID_ARGS);
1207         }
1208 
1209         blk = allocb_wait(WUSB_SET_WUSB_MAS_LEN, BPRI_LO, STR_NOSIG, NULL);
1210 
1211         for (i = 0; i < WUSB_SET_WUSB_MAS_LEN; i++) {
1212                 *blk->b_wptr++ = data[i];
1213         }
1214 
1215         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1216             WUSB_CLASS_IF_REQ_OUT_TYPE,
1217             HWA_REQ_SET_WUSB_MAS,
1218             0,
1219             hwahcp->hwahc_wa_data.wa_ifno,
1220             WUSB_SET_WUSB_MAS_LEN,
1221             &blk, 0,
1222             &completion_reason, &cb_flags, 0);
1223 
1224         if (rval != USB_SUCCESS) {
1225                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1226                     "Set_WUSB_MAS fails: rval=%d cr=%d cb=0x%x",
1227                     rval, completion_reason, cb_flags);
1228         }
1229         freemsg(blk);
1230 
1231         return (rval);
1232 }
1233 
1234 /* 8.5.3.1 - Add MMC IE */
1235 int
1236 hwahc_add_mmc_ie(dev_info_t *dip, uint8_t interval, uint8_t rcnt,
1237         uint8_t iehdl, uint16_t len, uint8_t *data)
1238 {
1239         usb_cr_t        completion_reason;
1240         usb_cb_flags_t  cb_flags;
1241         mblk_t          *blk;
1242         int             i, rval;
1243         hwahc_state_t   *hwahcp;
1244 
1245         if (dip == NULL)  {
1246 
1247                 return (USB_INVALID_ARGS);
1248         }
1249 
1250         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1251         if (hwahcp == NULL) {
1252 
1253                 return (USB_INVALID_ARGS);
1254         }
1255 
1256         blk = allocb_wait(len, BPRI_LO, STR_NOSIG, NULL);
1257 
1258         for (i = 0; i < len; i++) {
1259                 *blk->b_wptr++ = data[i];
1260         }
1261 
1262         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1263             WUSB_CLASS_IF_REQ_OUT_TYPE,
1264             HWA_REQ_ADD_MMC_IE,
1265             (interval << 8) | rcnt,
1266             (iehdl << 8) | hwahcp->hwahc_wa_data.wa_ifno,
1267             len,
1268             &blk, 0,
1269             &completion_reason, &cb_flags, 0);
1270 
1271         if (rval != USB_SUCCESS) {
1272                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1273                     "Add_MMC_IE fails: rval=%d cr=%d cb=0x%x",
1274                     rval, completion_reason, cb_flags);
1275         }
1276 
1277         freemsg(blk);
1278 
1279         return (rval);
1280 }
1281 
1282 /* 8.5.3.5 - Remove MMC IE */
1283 int
1284 hwahc_remove_mmc_ie(dev_info_t *dip, uint8_t iehdl)
1285 {
1286         usb_cr_t        completion_reason;
1287         usb_cb_flags_t  cb_flags;
1288         int             rval;
1289         hwahc_state_t   *hwahcp;
1290 
1291         if (dip == NULL) {
1292 
1293                 return (USB_INVALID_ARGS);
1294         }
1295 
1296         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1297         if (hwahcp == NULL) {
1298                 return (USB_INVALID_ARGS);
1299         }
1300 
1301         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1302             WUSB_CLASS_IF_REQ_OUT_TYPE,
1303             HWA_REQ_REMOVE_MMC_IE,
1304             0,
1305             (iehdl << 8) | hwahcp->hwahc_wa_data.wa_ifno,
1306             0,
1307             NULL, 0,
1308             &completion_reason, &cb_flags, 0);
1309 
1310         if (rval != USB_SUCCESS) {
1311                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1312                     "Remove_MMC_IE fails: rval=%d cr=%d cb=0x%x",
1313                     rval, completion_reason, cb_flags);
1314         }
1315 
1316         return (rval);
1317 }
1318 
1319 /* 8.5.3.14 - WUSB Channel Stop */
1320 int
1321 hwahc_stop_ch(dev_info_t *dip, uint32_t timeoff)
1322 {
1323         int             rval;
1324         usb_cr_t        completion_reason;
1325         usb_cb_flags_t  cb_flags;
1326         hwahc_state_t   *hwahcp;
1327 
1328         if (dip == NULL) {
1329 
1330                 return (USB_INVALID_ARGS);
1331         }
1332 
1333         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1334         if (hwahcp == NULL) {
1335 
1336                 return (USB_INVALID_ARGS);
1337         }
1338 
1339         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1340             WUSB_CLASS_IF_REQ_OUT_TYPE,
1341             HWA_REQ_CH_STOP,
1342             timeoff & 0x00ffffff,
1343             hwahcp->hwahc_wa_data.wa_ifno,
1344             0,
1345             NULL, 0,
1346             &completion_reason, &cb_flags, 0);
1347 
1348         if (rval != USB_SUCCESS) {
1349                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1350                     "WUSB_Ch_Stop fails: rval=%d cr=%d cb=0x%x",
1351                     rval, completion_reason, cb_flags);
1352         }
1353 
1354         return (rval);
1355 }
1356 
1357 /* 8.5. 3.10 - Set Num DNTS Slots */
1358 int
1359 hwahc_set_num_dnts(dev_info_t *dip, uint8_t interval, uint8_t nslots)
1360 {
1361         usb_cr_t        completion_reason;
1362         usb_cb_flags_t  cb_flags;
1363         int             rval;
1364         hwahc_state_t   *hwahcp;
1365 
1366         if (dip == NULL) {
1367 
1368                 return (USB_INVALID_ARGS);
1369         }
1370 
1371         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1372         if (hwahcp == NULL) {
1373 
1374                 return (USB_INVALID_ARGS);
1375         }
1376 
1377         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1378             WUSB_CLASS_IF_REQ_OUT_TYPE,
1379             HWA_REQ_SET_NUM_DNTS,
1380             (interval << 8) | nslots,
1381             hwahcp->hwahc_wa_data.wa_ifno,
1382             0,
1383             NULL, 0,
1384             &completion_reason, &cb_flags, 0);
1385 
1386         if (rval != USB_SUCCESS) {
1387                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1388                     "Set_Num_DNTS fails: rval=%d cr=%d cb=0x%x",
1389                     rval, completion_reason, cb_flags);
1390         }
1391 
1392         return (rval);
1393 }
1394 
1395 /* set encryptiion type for host */
1396 int
1397 hwahc_set_encrypt(dev_info_t *dip, usb_port_t port, uint8_t type)
1398 {
1399         hwahc_state_t   *hwahcp;
1400         int             rval;
1401 
1402         if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1403             ddi_get_instance(dip))) == NULL) {
1404 
1405                 return (USB_INVALID_ARGS);
1406         }
1407         /* DEVICE INDEX */
1408         rval = hwahc_set_dev_encrypt(hwahcp->hwahc_default_pipe,
1409             hwahcp->hwahc_wa_data.wa_ifno, port - 1,
1410             &hwahcp->hwahc_secrt_data, type);
1411         if (rval != USB_SUCCESS) {
1412                 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle,
1413                     "hwahc_set_encrypt: set device encryption for port %d "
1414                     "failed", port);
1415         }
1416 
1417         return (rval);
1418 }
1419 
1420 
1421 /*
1422  * Set Device Key for WUSB host, refer to WUSB 1.0/8.5.3.8
1423  *
1424  * Set group/device key:
1425  * devindex = actual port number - 1, so it is zero based
1426  *
1427  */
1428 int hwahc_set_keys(hwahc_state_t *hwahcp, usb_key_descr_t *key_descr,
1429     size_t klen, uint8_t devindex, uint8_t keydex, uint8_t flag)
1430 {
1431         usb_ctrl_setup_t        setup;
1432         usb_cr_t                cr;
1433         usb_cb_flags_t          cb_flags;
1434         mblk_t                  *pdata;
1435         int                     rval;
1436         uint8_t                 keyindex;
1437 
1438         USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1439             "hwahc_set_keys: klen = %d, devindex = %d", (int)klen,
1440             devindex);
1441 
1442         /* Table 7-21 and Errata 2005/07 */
1443         if (flag == WUSB_GTK) {
1444                 if (devindex != 0) {
1445                         return (USB_FAILURE);
1446                 }
1447 
1448                 /* See 7.3.2.4 for key index format */
1449                 keyindex = (1 << 5) | keydex;
1450         } else if (flag == WUSB_PTK) {
1451 
1452                 keyindex = keydex;
1453         } else {
1454 
1455                 return (USB_FAILURE);
1456         }
1457 
1458         setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
1459             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1460         setup.bRequest = USB_REQ_SET_DESCR;
1461         setup.wValue = (USB_DESCR_TYPE_KEY << 8) | keyindex;
1462         setup.wIndex = devindex << 8 | hwahcp->hwahc_wa_data.wa_ifno;
1463         setup.wLength = (uint16_t)klen;
1464         setup.attrs = USB_ATTRS_NONE;
1465 
1466         if ((pdata = allocb(klen, BPRI_HI)) == NULL) {
1467 
1468                 return (USB_FAILURE);
1469         }
1470         bcopy(key_descr, pdata->b_wptr, klen);
1471         pdata->b_wptr += klen;
1472 
1473         rval = usb_pipe_ctrl_xfer_wait(hwahcp->hwahc_default_pipe, &setup,
1474             &pdata, &cr, &cb_flags, USB_FLAGS_SLEEP);
1475 
1476         if (rval != USB_SUCCESS) {
1477                 USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1478                     "hwahc_set_keys:fail, rv=%d,cr=%d,cb=%d", rval, cr,
1479                     cb_flags);
1480         }
1481 
1482         freemsg(pdata);
1483 
1484         return (rval);
1485 }
1486 
1487 /* set PTK for host */
1488 int
1489 hwahc_set_ptk(dev_info_t *dip, usb_key_descr_t *key_descr, size_t klen,
1490         usb_port_t port)
1491 {
1492         hwahc_state_t   *hwahcp;
1493         int             rval;
1494         uint8_t         keyindex = 1;
1495 
1496         if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1497             ddi_get_instance(dip))) == NULL) {
1498 
1499                 return (USB_INVALID_ARGS);
1500         }
1501         /* DEVICE INDEX */
1502         rval = hwahc_set_keys(hwahcp, key_descr, klen, port - 1, keyindex,
1503             WUSB_PTK);
1504         if (rval != USB_SUCCESS) {
1505                 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle,
1506                     "hwahc_set_ptk: set device key descr for port %d "
1507                     "failed", port);
1508         }
1509 
1510         return (rval);
1511 }
1512 
1513 /* set GTK for host */
1514 int
1515 hwahc_set_gtk(dev_info_t *dip, usb_key_descr_t *key_descr, size_t klen)
1516 {
1517         hwahc_state_t           *hwahcp;
1518         int                     rval;
1519 
1520         if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1521             ddi_get_instance(dip))) == NULL) {
1522 
1523                 return (USB_INVALID_ARGS);
1524         }
1525 
1526         rval = hwahc_set_keys(hwahcp, key_descr, klen, 0, 0, WUSB_GTK);
1527         if (rval != USB_SUCCESS) {
1528                 USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle,
1529                     "hwahc_set_gtk: set group key descr failed");
1530         }
1531 
1532         return (rval);
1533 }
1534 
1535 /*
1536  * set device info for host
1537  * Section 8.5.3.7.
1538  */
1539 int
1540 hwahc_set_device_info(dev_info_t *dip, wusb_dev_info_t *dev_info,
1541         usb_port_t port)
1542 {
1543         hwahc_state_t           *hwahcp;
1544         int                     rval;
1545         hwa_dev_info_t          info;
1546         usb_ctrl_setup_t        setup;
1547         usb_cr_t                cr;
1548         usb_cb_flags_t          cb_flags;
1549         mblk_t                  *pdata;
1550 
1551         if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1552             ddi_get_instance(dip))) == NULL) {
1553 
1554                 return (USB_INVALID_ARGS);
1555         }
1556 
1557         /* the device can use all the host's reserved MASes to communicate */
1558         (void) memcpy(info.bmDeviceAvailablilityInfo,
1559             hwahcp->hwahc_hc_data.hc_mas, WUSB_SET_WUSB_MAS_LEN);
1560 
1561         info.bDeviceAddress = dev_info->wdev_addr;
1562 
1563         /* To tell HWA device what data rates this child device supports */
1564         if (dev_info->wdev_uwb_descr == NULL) {
1565                 /* bitmap, see7.4.1.1. Must support 53.3/106.7/200 Mbps */
1566                 info.wPHYRates[0] = WUSB_DATA_RATE_BIT_53 |
1567                     WUSB_DATA_RATE_BIT_106 | WUSB_DATA_RATE_BIT_200;
1568                 info.wPHYRates[1] = 0;
1569         } else {
1570                 info.wPHYRates[0] =
1571                     dev_info->wdev_uwb_descr->wPHYRates && 0xff;
1572                 info.wPHYRates[1] =
1573                     (dev_info->wdev_uwb_descr->wPHYRates >> 8) && 0xff;
1574         }
1575         info.bmDeviceAttribute = 0;
1576 
1577         setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
1578             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1579         setup.bRequest = HWA_REQ_SET_DEVICE_INFO;
1580         setup.wValue = 0;
1581 
1582         /* DEVICE INDEX */
1583         setup.wIndex = (port - 1) << 8 | hwahcp->hwahc_wa_data.wa_ifno;
1584         setup.wLength = WUSB_SET_DEV_INFO_LEN;
1585         setup.attrs = USB_ATTRS_NONE;
1586 
1587         if ((pdata = allocb(WUSB_SET_DEV_INFO_LEN, BPRI_HI)) == NULL) {
1588 
1589                 return (USB_FAILURE);
1590         }
1591         bcopy(&info, pdata->b_wptr, WUSB_SET_DEV_INFO_LEN);
1592         pdata->b_wptr += WUSB_SET_DEV_INFO_LEN;
1593 
1594         rval = usb_pipe_ctrl_xfer_wait(hwahcp->hwahc_default_pipe, &setup,
1595             &pdata, &cr, &cb_flags, USB_FLAGS_SLEEP);
1596 
1597         freemsg(pdata);
1598 
1599         return (rval);
1600 }
1601 
1602 /*
1603  * 8.5.3.2 - 8.5.3.4 Get Time
1604  * time_type:
1605  *      WUSB_TIME_ADJ   - Get BPST Adjustment
1606  *      WUSB_TIME_BPST  - Get BPST Time
1607  *      WUSB_TIME_WUSB  - Get WUSB Time
1608  */
1609 int
1610 hwahc_get_time(dev_info_t *dip, uint8_t time_type,
1611     uint16_t len, uint32_t *time)
1612 {
1613         usb_cr_t        completion_reason;
1614         usb_cb_flags_t  cb_flags;
1615         mblk_t          *blk = NULL;
1616         int             rval;
1617         uint8_t         *data;
1618         uint16_t        length;
1619         hwahc_state_t   *hwahcp = NULL;
1620 
1621         if (dip == NULL) {
1622 
1623                 return (USB_INVALID_ARGS);
1624         }
1625 
1626         hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1627         if (hwahcp == NULL) {
1628 
1629                 return (USB_INVALID_ARGS);
1630         }
1631 
1632         /* according to WUSB 8.5.3, len is 1 or 3 */
1633         if ((len != 1) && (len != 3)) {
1634 
1635                 return (USB_INVALID_ARGS);
1636         }
1637 
1638         rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1639             WUSB_CLASS_IF_REQ_OUT_TYPE, HWA_REQ_GET_TIME,
1640             time_type, hwahcp->hwahc_wa_data.wa_ifno,
1641             len, &blk, 0, &completion_reason, &cb_flags, 0);
1642 
1643         if (rval != USB_SUCCESS) {
1644                 freemsg(blk);
1645 
1646                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1647                     "Get_Time fails: rval=%d cr=%d cb=0x%x",
1648                     rval, completion_reason, cb_flags);
1649 
1650                 return (rval);
1651         } else if (blk == NULL) {
1652                 USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1653                     "Get_Time returns null data");
1654 
1655                 return (USB_FAILURE);
1656         } else {
1657                 length = MBLKL(blk);
1658 
1659                 if (length < len) {
1660                         freemsg(blk);
1661 
1662                         USB_DPRINTF_L2(PRINT_MASK_HCDI,
1663                             hwahcp->hwahc_log_handle,
1664                             "Get_Time returns short length %d", length);
1665 
1666                         return (USB_FAILURE);
1667                 }
1668 
1669                 data = blk->b_rptr;
1670                 if (len == 1) {
1671                         *time = *data;
1672                 } else {
1673                         *time = (data[2] << 16) | (data[1] << 8) | data[0];
1674                 }
1675                 freemsg(blk);
1676 
1677                 return (USB_SUCCESS);
1678         }
1679 }