1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Universal Host Controller Driver (UHCI) 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * The UHCI driver is a driver which interfaces to the Universal 33*7c478bd9Sstevel@tonic-gate * Serial Bus Driver (USBA) and the Host Controller (HC). The interface to 34*7c478bd9Sstevel@tonic-gate * the Host Controller is defined by the Universal Host Controller Interface. 35*7c478bd9Sstevel@tonic-gate * This file contains the code for HCDI entry points. 36*7c478bd9Sstevel@tonic-gate */ 37*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcitgt.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h> 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate /* function prototypes */ 42*7c478bd9Sstevel@tonic-gate static int uhci_pipe_send_isoc_data(uhci_state_t *uhcip, 43*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, usb_isoc_req_t *isoc_req, 44*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 45*7c478bd9Sstevel@tonic-gate static int uhci_send_intr_data(uhci_state_t *uhcip, 46*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *pipe_handle, 47*7c478bd9Sstevel@tonic-gate usb_intr_req_t *req, 48*7c478bd9Sstevel@tonic-gate usb_flags_t flags); 49*7c478bd9Sstevel@tonic-gate static int uhci_start_periodic_pipe_polling(uhci_state_t *uhcip, 50*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 51*7c478bd9Sstevel@tonic-gate usb_opaque_t reqp, 52*7c478bd9Sstevel@tonic-gate usb_flags_t flags); 53*7c478bd9Sstevel@tonic-gate static int uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip, 54*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 55*7c478bd9Sstevel@tonic-gate usb_flags_t flags); 56*7c478bd9Sstevel@tonic-gate static void uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, 57*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp); 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* Maximum bulk transfer size */ 61*7c478bd9Sstevel@tonic-gate static int uhci_bulk_transfer_size = UHCI_BULK_MAX_XFER_SIZE; 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* 64*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_open: 65*7c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during client specific pipe open 66*7c478bd9Sstevel@tonic-gate * Add the pipe to the data structure representing the device and allocate 67*7c478bd9Sstevel@tonic-gate * bandwidth for the pipe if it is a interrupt or isochronous endpoint. 68*7c478bd9Sstevel@tonic-gate */ 69*7c478bd9Sstevel@tonic-gate int 70*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t flags) 71*7c478bd9Sstevel@tonic-gate { 72*7c478bd9Sstevel@tonic-gate uint_t node = 0; 73*7c478bd9Sstevel@tonic-gate usb_addr_t usb_addr; 74*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip; 75*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp; 76*7c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate ASSERT(ph); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate usb_addr = ph->p_usba_device->usb_addr; 81*7c478bd9Sstevel@tonic-gate uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 84*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: addr = 0x%x, ep%d", usb_addr, 85*7c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK); 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate sema_p(&uhcip->uhci_ocsem); 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* 90*7c478bd9Sstevel@tonic-gate * Return failure immediately for any other pipe open on the root hub 91*7c478bd9Sstevel@tonic-gate * except control or interrupt pipe. 92*7c478bd9Sstevel@tonic-gate */ 93*7c478bd9Sstevel@tonic-gate if (usb_addr == ROOT_HUB_ADDR) { 94*7c478bd9Sstevel@tonic-gate switch (UHCI_XFER_TYPE(&ph->p_ep)) { 95*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 96*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 97*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: Root hub control pipe"); 98*7c478bd9Sstevel@tonic-gate break; 99*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 100*7c478bd9Sstevel@tonic-gate ASSERT(UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN); 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 103*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_intr_pipe_handle = ph; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * Set the state of the root hub interrupt 107*7c478bd9Sstevel@tonic-gate * pipe as IDLE. 108*7c478bd9Sstevel@tonic-gate */ 109*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state = 110*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_IDLE; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL); 113*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req = NULL; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate ASSERT(uhcip->uhci_root_hub.rh_curr_intr_reqp == NULL); 116*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL; 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 119*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: Root hub interrupt " 120*7c478bd9Sstevel@tonic-gate "pipe open succeeded"); 121*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 122*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 125*7c478bd9Sstevel@tonic-gate default: 126*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 127*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: Root hub pipe open failed"); 128*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate /* 135*7c478bd9Sstevel@tonic-gate * A portion of the bandwidth is reserved for the non-periodic 136*7c478bd9Sstevel@tonic-gate * transfers i.e control and bulk transfers in each of one 137*7c478bd9Sstevel@tonic-gate * mill second frame period & usually it will be 10% of frame 138*7c478bd9Sstevel@tonic-gate * period. Hence there is no need to check for the available 139*7c478bd9Sstevel@tonic-gate * bandwidth before adding the control or bulk endpoints. 140*7c478bd9Sstevel@tonic-gate * 141*7c478bd9Sstevel@tonic-gate * There is a need to check for the available bandwidth before 142*7c478bd9Sstevel@tonic-gate * adding the periodic transfers i.e interrupt & isochronous, since 143*7c478bd9Sstevel@tonic-gate * all these periodic transfers are guaranteed transfers. Usually, 144*7c478bd9Sstevel@tonic-gate * 90% of the total frame time is reserved for periodic transfers. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 147*7c478bd9Sstevel@tonic-gate /* Zero Max Packet size endpoints are not supported */ 148*7c478bd9Sstevel@tonic-gate if (ph->p_ep.wMaxPacketSize == 0) { 149*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 150*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: Zero length packet"); 151*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 157*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate error = uhci_allocate_bandwidth(uhcip, ph, &node); 160*7c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 163*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: Bandwidth allocation failed"); 164*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 165*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 166*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate return (error); 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 172*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* Create the HCD pipe private structure */ 176*7c478bd9Sstevel@tonic-gate pp = kmem_zalloc(sizeof (uhci_pipe_private_t), 177*7c478bd9Sstevel@tonic-gate (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 178*7c478bd9Sstevel@tonic-gate if (pp == NULL) { 179*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 180*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: pp allocation failure"); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 183*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 184*7c478bd9Sstevel@tonic-gate uhci_deallocate_bandwidth(uhcip, ph); 185*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 193*7c478bd9Sstevel@tonic-gate pp->pp_node = node; /* Store the node in the interrupt lattice */ 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* Initialize frame number */ 196*7c478bd9Sstevel@tonic-gate pp->pp_frame_num = INVALID_FRNUM; 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* Set the state of pipe as IDLE */ 199*7c478bd9Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_IDLE; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* Store a pointer to the pipe handle */ 202*7c478bd9Sstevel@tonic-gate pp->pp_pipe_handle = ph; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate /* Store the pointer in the pipe handle */ 205*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 206*7c478bd9Sstevel@tonic-gate ph->p_hcd_private = (usb_opaque_t)pp; 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* Store a copy of the pipe policy */ 209*7c478bd9Sstevel@tonic-gate bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t)); 210*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate /* don't check for ROOT_HUB here anymore */ 213*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(&ph->p_ep) != USB_EP_ATTR_ISOCH) { 214*7c478bd9Sstevel@tonic-gate /* Allocate the host controller endpoint descriptor */ 215*7c478bd9Sstevel@tonic-gate pp->pp_qh = uhci_alloc_queue_head(uhcip); 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if (pp->pp_qh == NULL) { 218*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 219*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: QH allocation failed"); 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate /* 224*7c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion 225*7c478bd9Sstevel@tonic-gate * of the pipe handle. 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, 228*7c478bd9Sstevel@tonic-gate sizeof (uhci_pipe_private_t)); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * Set the private structure in the 232*7c478bd9Sstevel@tonic-gate * pipe handle equal to NULL. 233*7c478bd9Sstevel@tonic-gate */ 234*7c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL; 235*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 238*7c478bd9Sstevel@tonic-gate uhci_deallocate_bandwidth(uhcip, ph); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* 248*7c478bd9Sstevel@tonic-gate * Insert the endpoint onto the host controller's 249*7c478bd9Sstevel@tonic-gate * appropriate endpoint list. The host controller 250*7c478bd9Sstevel@tonic-gate * will not schedule this endpoint until there are 251*7c478bd9Sstevel@tonic-gate * any TD's to process. 252*7c478bd9Sstevel@tonic-gate */ 253*7c478bd9Sstevel@tonic-gate uhci_insert_qh(uhcip, ph); 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * Restore the data toggle from usb device structure. 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 260*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate pp->pp_data_toggle = usba_hcdi_get_data_toggle( 263*7c478bd9Sstevel@tonic-gate ph->p_usba_device, ph->p_ep.bEndpointAddress); 264*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 268*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 271*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_open: ph = 0x%p", ph); 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate /* 278*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_close: 279*7c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during the client specific pipe 280*7c478bd9Sstevel@tonic-gate * close. Remove the pipe to the data structure representing the device 281*7c478bd9Sstevel@tonic-gate * deallocate bandwidth for the pipe if it is an intr or isoch endpoint. 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate int 284*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) 285*7c478bd9Sstevel@tonic-gate { 286*7c478bd9Sstevel@tonic-gate usb_addr_t usb_addr; 287*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip; 288*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 289*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 292*7c478bd9Sstevel@tonic-gate pp = (uhci_pipe_private_t *)ph->p_hcd_private; 293*7c478bd9Sstevel@tonic-gate usb_addr = ph->p_usba_device->usb_addr; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 296*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_close: addr = 0x%x, ep%d, flags = 0x%x", usb_addr, 297*7c478bd9Sstevel@tonic-gate eptd->bEndpointAddress, usb_flags); 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate sema_p(&uhcip->uhci_ocsem); 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate * Check whether the pipe is a root hub 305*7c478bd9Sstevel@tonic-gate */ 306*7c478bd9Sstevel@tonic-gate if (usb_addr == ROOT_HUB_ADDR) { 307*7c478bd9Sstevel@tonic-gate switch (UHCI_XFER_TYPE(eptd)) { 308*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 309*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 310*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_close: Root hub control pipe " 311*7c478bd9Sstevel@tonic-gate "close succeeded"); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate break; 314*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 315*7c478bd9Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & 316*7c478bd9Sstevel@tonic-gate USB_EP_NUM_MASK) == 1); 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate ASSERT(uhcip->uhci_root_hub.rh_pipe_state == 319*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_ACTIVE); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */ 322*7c478bd9Sstevel@tonic-gate uhci_root_hub_intr_pipe_cleanup(uhcip, 323*7c478bd9Sstevel@tonic-gate USB_CR_PIPE_CLOSING); 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate ASSERT(uhcip->uhci_root_hub.rh_pipe_state == 326*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_IDLE); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_intr_pipe_handle = NULL; 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 331*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_close: Root hub interrupt " 332*7c478bd9Sstevel@tonic-gate "pipe close succeeded"); 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state = 335*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_IDLE; 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 338*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate } else { 343*7c478bd9Sstevel@tonic-gate /* 344*7c478bd9Sstevel@tonic-gate * Stop all the transactions if it is not the root hub. 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) { 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * Stop polling on the pipe to prevent any subsequently 349*7c478bd9Sstevel@tonic-gate * queued tds (while we're waiting for SOF, below) 350*7c478bd9Sstevel@tonic-gate * from being executed 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_IDLE; 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* Disable all outstanding tds */ 356*7c478bd9Sstevel@tonic-gate uhci_modify_td_active_bits(uhcip, pp); 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* Prevent this queue from being executed */ 359*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) { 360*7c478bd9Sstevel@tonic-gate UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* Wait for the next start of frame */ 364*7c478bd9Sstevel@tonic-gate (void) uhci_wait_for_sof(uhcip); 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate ASSERT(eptd != NULL); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate switch (UHCI_XFER_TYPE(eptd)) { 369*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 370*7c478bd9Sstevel@tonic-gate uhci_update_intr_td_data_toggle(uhcip, pp); 371*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 372*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 373*7c478bd9Sstevel@tonic-gate uhci_remove_tds_tws(uhcip, ph); 374*7c478bd9Sstevel@tonic-gate break; 375*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 376*7c478bd9Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr, 377*7c478bd9Sstevel@tonic-gate TD_PADDR(pp->pp_qh->td_tailp)); 378*7c478bd9Sstevel@tonic-gate uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_CLOSE); 379*7c478bd9Sstevel@tonic-gate uhci_save_data_toggle(pp); 380*7c478bd9Sstevel@tonic-gate break; 381*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 382*7c478bd9Sstevel@tonic-gate uhci_remove_isoc_tds_tws(uhcip, pp); 383*7c478bd9Sstevel@tonic-gate break; 384*7c478bd9Sstevel@tonic-gate default: 385*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 386*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_close: Unknown xfer type"); 387*7c478bd9Sstevel@tonic-gate break; 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* 391*7c478bd9Sstevel@tonic-gate * Remove the endoint descriptor from Host Controller's 392*7c478bd9Sstevel@tonic-gate * appropriate endpoint list. Isochronous pipes dont have 393*7c478bd9Sstevel@tonic-gate * any queue heads attached to it. 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) { 396*7c478bd9Sstevel@tonic-gate uhci_remove_qh(uhcip, pp); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate /* 400*7c478bd9Sstevel@tonic-gate * Do the callback for the original client 401*7c478bd9Sstevel@tonic-gate * periodic IN request. 402*7c478bd9Sstevel@tonic-gate */ 403*7c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) { 404*7c478bd9Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, ph, NULL, 405*7c478bd9Sstevel@tonic-gate USB_CR_PIPE_CLOSING); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 409*7c478bd9Sstevel@tonic-gate if (UHCI_PERIODIC_ENDPOINT(eptd)) { 410*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 411*7c478bd9Sstevel@tonic-gate uhci_deallocate_bandwidth(uhcip, ph); 412*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* Deallocate the hcd private portion of the pipe handle. */ 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 419*7c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (uhci_pipe_private_t)); 420*7c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL; 421*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 424*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_close: ph = 0x%p", ph); 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 427*7c478bd9Sstevel@tonic-gate sema_v(&uhcip->uhci_ocsem); 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* 434*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_reset: 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate int 437*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_reset(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state( 440*7c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 441*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 442*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 445*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_reset: usb_flags = 0x%x", usb_flags); 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * Return failure immediately for any other pipe reset on the root 449*7c478bd9Sstevel@tonic-gate * hub except control or interrupt pipe. 450*7c478bd9Sstevel@tonic-gate */ 451*7c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 452*7c478bd9Sstevel@tonic-gate switch (UHCI_XFER_TYPE(&ph->p_ep)) { 453*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 454*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 455*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_reset: Pipe reset for root" 456*7c478bd9Sstevel@tonic-gate "hub control pipe successful"); 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate break; 459*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 460*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 461*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state = 462*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_IDLE; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */ 465*7c478bd9Sstevel@tonic-gate uhci_root_hub_intr_pipe_cleanup(uhcip, 466*7c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET); 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 469*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_reset: Pipe reset for " 470*7c478bd9Sstevel@tonic-gate "root hub interrupt pipe successful"); 471*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate break; 474*7c478bd9Sstevel@tonic-gate default: 475*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 476*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_close: Root hub pipe reset failed"); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * Set the active bit in to INACTIVE for all the remaining TD's of 488*7c478bd9Sstevel@tonic-gate * this end point. Set the active bit for the dummy td. This will 489*7c478bd9Sstevel@tonic-gate * generate an interrupt at the end of the frame. After receiving 490*7c478bd9Sstevel@tonic-gate * the interrupt, it is safe to to manipulate the lattice. 491*7c478bd9Sstevel@tonic-gate */ 492*7c478bd9Sstevel@tonic-gate uhci_modify_td_active_bits(uhcip, pp); 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate /* Initialize the element pointer */ 495*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) { 496*7c478bd9Sstevel@tonic-gate UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 497*7c478bd9Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr, 498*7c478bd9Sstevel@tonic-gate TD_PADDR(pp->pp_qh->td_tailp)); 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate (void) uhci_wait_for_sof(uhcip); 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate /* 504*7c478bd9Sstevel@tonic-gate * Save the data toggle and clear the pipe. 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate switch (UHCI_XFER_TYPE(eptd)) { 507*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 508*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 509*7c478bd9Sstevel@tonic-gate uhci_remove_tds_tws(uhcip, ph); 510*7c478bd9Sstevel@tonic-gate break; 511*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 512*7c478bd9Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr, 513*7c478bd9Sstevel@tonic-gate TD_PADDR(pp->pp_qh->td_tailp)); 514*7c478bd9Sstevel@tonic-gate uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_RESET); 515*7c478bd9Sstevel@tonic-gate break; 516*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 517*7c478bd9Sstevel@tonic-gate uhci_remove_isoc_tds_tws(uhcip, pp); 518*7c478bd9Sstevel@tonic-gate break; 519*7c478bd9Sstevel@tonic-gate default: 520*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 521*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_reset: Unknown xfer type"); 522*7c478bd9Sstevel@tonic-gate break; 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Do the callback for the original client 527*7c478bd9Sstevel@tonic-gate * periodic IN request. 528*7c478bd9Sstevel@tonic-gate */ 529*7c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) { 530*7c478bd9Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_PIPE_RESET); 531*7c478bd9Sstevel@tonic-gate } 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate /* 534*7c478bd9Sstevel@tonic-gate * Since the endpoint is stripped of Transfer Descriptors (TD), 535*7c478bd9Sstevel@tonic-gate * reset the state of the periodic pipe to IDLE. 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_IDLE; 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_ctrl_xfer: 547*7c478bd9Sstevel@tonic-gate */ 548*7c478bd9Sstevel@tonic-gate int 549*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_ctrl_xfer( 550*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 551*7c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 552*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 553*7c478bd9Sstevel@tonic-gate { 554*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state( 555*7c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 556*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 557*7c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 560*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_ctrl_xfer: req=0x%p, ph=0x%p, flags=0x%x", 561*7c478bd9Sstevel@tonic-gate ctrl_reqp, ph, flags); 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate ASSERT(pp->pp_state == UHCI_PIPE_STATE_IDLE); 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate /* 568*7c478bd9Sstevel@tonic-gate * Check and handle root hub control request. 569*7c478bd9Sstevel@tonic-gate */ 570*7c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 571*7c478bd9Sstevel@tonic-gate error = uhci_handle_root_hub_request(uhcip, ph, ctrl_reqp); 572*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate return (error); 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate /* Insert the td's on the endpoint */ 578*7c478bd9Sstevel@tonic-gate if ((error = uhci_insert_ctrl_td(uhcip, ph, ctrl_reqp, flags)) != 579*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 580*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 581*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_ctrl_xfer: No resources"); 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate return (error); 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_bulk_xfer: 591*7c478bd9Sstevel@tonic-gate */ 592*7c478bd9Sstevel@tonic-gate int 593*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *pipe_handle, 594*7c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags) 595*7c478bd9Sstevel@tonic-gate { 596*7c478bd9Sstevel@tonic-gate int error; 597*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip; 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate uhcip = uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 602*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_bulk_xfer: Flags = 0x%x", usb_flags); 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate /* Check the size of bulk request */ 605*7c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_len > UHCI_BULK_MAX_XFER_SIZE) { 606*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 607*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_bulk_xfer: req size 0x%x is more than 0x%x", 608*7c478bd9Sstevel@tonic-gate bulk_reqp->bulk_len, UHCI_BULK_MAX_XFER_SIZE); 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* Add the TD into the Host Controller's bulk list */ 616*7c478bd9Sstevel@tonic-gate if ((error = uhci_insert_bulk_td(uhcip, pipe_handle, bulk_reqp, 617*7c478bd9Sstevel@tonic-gate usb_flags)) != USB_SUCCESS) { 618*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 619*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_bulk_xfer: uhci_insert_bulk_td failed"); 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate return (error); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate /* 628*7c478bd9Sstevel@tonic-gate * uhci_hcdi_bulk_transfer_size: 629*7c478bd9Sstevel@tonic-gate * Return maximum bulk transfer size 630*7c478bd9Sstevel@tonic-gate */ 631*7c478bd9Sstevel@tonic-gate int 632*7c478bd9Sstevel@tonic-gate uhci_hcdi_bulk_transfer_size( 633*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device, 634*7c478bd9Sstevel@tonic-gate size_t *size) 635*7c478bd9Sstevel@tonic-gate { 636*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip); 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 639*7c478bd9Sstevel@tonic-gate "uhci_hcdi_bulk_transfer_size:"); 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate *size = uhci_bulk_transfer_size; 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate /* 648*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_intr_xfer: 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate int 651*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_intr_xfer( 652*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 653*7c478bd9Sstevel@tonic-gate usb_intr_req_t *req, 654*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 655*7c478bd9Sstevel@tonic-gate { 656*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state( 657*7c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 660*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_intr_xfer: req=0x%p, uf=0x%x", req, flags); 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) { 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate return (uhci_start_periodic_pipe_polling(uhcip, ph, 665*7c478bd9Sstevel@tonic-gate (usb_opaque_t)req, flags)); 666*7c478bd9Sstevel@tonic-gate } else { 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate return (uhci_send_intr_data(uhcip, ph, req, flags)); 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* 674*7c478bd9Sstevel@tonic-gate * uhci_send_intr_data(): 675*7c478bd9Sstevel@tonic-gate * send data to interrupt out pipe 676*7c478bd9Sstevel@tonic-gate */ 677*7c478bd9Sstevel@tonic-gate static int 678*7c478bd9Sstevel@tonic-gate uhci_send_intr_data( 679*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip, 680*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *pipe_handle, 681*7c478bd9Sstevel@tonic-gate usb_intr_req_t *req, 682*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 683*7c478bd9Sstevel@tonic-gate { 684*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 687*7c478bd9Sstevel@tonic-gate "uhci_send_intr_data:"); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate /* Add the TD into the Host Controller's interrupt list */ 692*7c478bd9Sstevel@tonic-gate if ((rval = uhci_insert_intr_td(uhcip, pipe_handle, req, flags)) != 693*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 694*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 695*7c478bd9Sstevel@tonic-gate "uhci_send_intr_data: No resources"); 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate return (rval); 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate /* 704*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_stop_intr_polling() 705*7c478bd9Sstevel@tonic-gate */ 706*7c478bd9Sstevel@tonic-gate int 707*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_stop_intr_polling( 708*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *pipe_handle, 709*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 710*7c478bd9Sstevel@tonic-gate { 711*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = 712*7c478bd9Sstevel@tonic-gate uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip); 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 715*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x", 716*7c478bd9Sstevel@tonic-gate (void *)pipe_handle, flags); 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate return (uhci_stop_periodic_pipe_polling(uhcip, pipe_handle, flags)); 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate /* 723*7c478bd9Sstevel@tonic-gate * uhci_hcdi_get_current_frame_number 724*7c478bd9Sstevel@tonic-gate * Returns the current frame number 725*7c478bd9Sstevel@tonic-gate */ 726*7c478bd9Sstevel@tonic-gate usb_frame_number_t 727*7c478bd9Sstevel@tonic-gate uhci_hcdi_get_current_frame_number(usba_device_t *usba_device) 728*7c478bd9Sstevel@tonic-gate { 729*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip); 730*7c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 733*7c478bd9Sstevel@tonic-gate frame_number = uhci_get_sw_frame_number(uhcip); 734*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 737*7c478bd9Sstevel@tonic-gate "uhci_hcdi_get_current_frame_number: %llx", frame_number); 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate return (frame_number); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate /* 744*7c478bd9Sstevel@tonic-gate * uhci_hcdi_get_max_isoc_pkts 745*7c478bd9Sstevel@tonic-gate * Returns the maximum number of isoc packets per USB Isoch request 746*7c478bd9Sstevel@tonic-gate */ 747*7c478bd9Sstevel@tonic-gate uint_t 748*7c478bd9Sstevel@tonic-gate uhci_hcdi_get_max_isoc_pkts(usba_device_t *usba_device) 749*7c478bd9Sstevel@tonic-gate { 750*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip); 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 753*7c478bd9Sstevel@tonic-gate "uhci_hcdi_get_max_isoc_pkts: 0x%x", UHCI_MAX_ISOC_PKTS); 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate return (UHCI_MAX_ISOC_PKTS); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate /* 760*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_isoc_xfer: 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate int 763*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_isoc_xfer( 764*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 765*7c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 766*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 767*7c478bd9Sstevel@tonic-gate { 768*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip; 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 771*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 772*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_isoc_xfer: req=0x%p, uf=0x%x", isoc_reqp, flags); 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) { 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate return (uhci_start_periodic_pipe_polling(uhcip, ph, 777*7c478bd9Sstevel@tonic-gate (usb_opaque_t)isoc_reqp, flags)); 778*7c478bd9Sstevel@tonic-gate } else { 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate return (uhci_pipe_send_isoc_data(uhcip, ph, isoc_reqp, flags)); 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate /* 786*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_stop_isoc_polling() 787*7c478bd9Sstevel@tonic-gate */ 788*7c478bd9Sstevel@tonic-gate int 789*7c478bd9Sstevel@tonic-gate uhci_hcdi_pipe_stop_isoc_polling( 790*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 791*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 792*7c478bd9Sstevel@tonic-gate { 793*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = 794*7c478bd9Sstevel@tonic-gate uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 797*7c478bd9Sstevel@tonic-gate "uhci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", 798*7c478bd9Sstevel@tonic-gate (void *)ph, flags); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate return (uhci_stop_periodic_pipe_polling(uhcip, ph, flags)); 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate /* 805*7c478bd9Sstevel@tonic-gate * uhci_start_periodic_pipe_polling: 806*7c478bd9Sstevel@tonic-gate */ 807*7c478bd9Sstevel@tonic-gate static int 808*7c478bd9Sstevel@tonic-gate uhci_start_periodic_pipe_polling( 809*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip, 810*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 811*7c478bd9Sstevel@tonic-gate usb_opaque_t in_reqp, 812*7c478bd9Sstevel@tonic-gate usb_flags_t flags) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate int n, num_tds; 815*7c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 816*7c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp = (usb_intr_req_t *)in_reqp; 817*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 818*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 821*7c478bd9Sstevel@tonic-gate "uhci_start_periodic_pipe_polling: flags: 0x%x, ep%d", 822*7c478bd9Sstevel@tonic-gate flags, eptd->bEndpointAddress); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 827*7c478bd9Sstevel@tonic-gate uint_t pipe_state = uhcip->uhci_root_hub.rh_pipe_state; 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate ASSERT(pipe_state == UHCI_PIPE_STATE_IDLE); 830*7c478bd9Sstevel@tonic-gate ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN); 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate /* ONE_XFER not supported */ 833*7c478bd9Sstevel@tonic-gate ASSERT((intr_reqp->intr_attributes & 834*7c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) == 0); 835*7c478bd9Sstevel@tonic-gate ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL); 836*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req = intr_reqp; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate if ((error = uhci_root_hub_allocate_intr_pipe_resource( 839*7c478bd9Sstevel@tonic-gate uhcip, flags)) != USB_SUCCESS) { 840*7c478bd9Sstevel@tonic-gate /* reset the client interrupt request pointer */ 841*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req = NULL; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate return (error); 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state = USB_PIPE_STATE_ACTIVE; 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 851*7c478bd9Sstevel@tonic-gate "uhci_start_periodic_pipe_polling: " 852*7c478bd9Sstevel@tonic-gate "Start intr polling for root hub successful"); 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate /* check if we need to send the reset data up? */ 855*7c478bd9Sstevel@tonic-gate if (uhcip->uhci_root_hub.rh_status) { 856*7c478bd9Sstevel@tonic-gate uhci_root_hub_reset_occurred(uhcip, 857*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_status - 1); 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_status = 0; 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate return (error); 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate /* save the original client's periodic IN request */ 867*7c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = in_reqp; 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate ASSERT(pp->pp_state != UHCI_PIPE_STATE_ACTIVE); 870*7c478bd9Sstevel@tonic-gate /* 871*7c478bd9Sstevel@tonic-gate * 872*7c478bd9Sstevel@tonic-gate * This pipe is uninitialized. If it is an isoc 873*7c478bd9Sstevel@tonic-gate * receive request, insert four times the same 874*7c478bd9Sstevel@tonic-gate * request so that we do not lose any frames. 875*7c478bd9Sstevel@tonic-gate */ 876*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) { 877*7c478bd9Sstevel@tonic-gate for (n = 0; n < 5; n++) { 878*7c478bd9Sstevel@tonic-gate if ((error = uhci_start_isoc_receive_polling( 879*7c478bd9Sstevel@tonic-gate uhcip, ph, NULL, flags)) != USB_SUCCESS) { 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 882*7c478bd9Sstevel@tonic-gate uhcip->uhci_log_hdl, 883*7c478bd9Sstevel@tonic-gate "uhci_start_periodic_pipe_polling: " 884*7c478bd9Sstevel@tonic-gate "Start isoc polling failed %d", n); 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 887*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate return (error); 890*7c478bd9Sstevel@tonic-gate } 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) { 895*7c478bd9Sstevel@tonic-gate if ((pp->pp_node < POLLING_FREQ_7MS) && 896*7c478bd9Sstevel@tonic-gate (!(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER))) { 897*7c478bd9Sstevel@tonic-gate num_tds = 5; 898*7c478bd9Sstevel@tonic-gate } else { 899*7c478bd9Sstevel@tonic-gate num_tds = 1; 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* 903*7c478bd9Sstevel@tonic-gate * This pipe is uninitialized. 904*7c478bd9Sstevel@tonic-gate * Insert a TD on the interrupt ED. 905*7c478bd9Sstevel@tonic-gate */ 906*7c478bd9Sstevel@tonic-gate for (n = 0; n < num_tds; n++) { 907*7c478bd9Sstevel@tonic-gate if ((error = uhci_insert_intr_td(uhcip, ph, NULL, 908*7c478bd9Sstevel@tonic-gate flags)) != USB_SUCCESS) { 909*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 910*7c478bd9Sstevel@tonic-gate uhcip->uhci_log_hdl, 911*7c478bd9Sstevel@tonic-gate "uhci_start_periodic_pipe_polling: " 912*7c478bd9Sstevel@tonic-gate "Start polling failed"); 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 915*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate return (error); 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate } 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_ACTIVE; 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate return (error); 927*7c478bd9Sstevel@tonic-gate } 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate /* 931*7c478bd9Sstevel@tonic-gate * uhci_hcdi_periodic_pipe_stop_polling: 932*7c478bd9Sstevel@tonic-gate */ 933*7c478bd9Sstevel@tonic-gate static int 934*7c478bd9Sstevel@tonic-gate uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip, 935*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, usb_flags_t flags) 936*7c478bd9Sstevel@tonic-gate { 937*7c478bd9Sstevel@tonic-gate uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 938*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 941*7c478bd9Sstevel@tonic-gate "uhci_stop_periodic_pipe_polling: flags = 0x%x", flags); 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 944*7c478bd9Sstevel@tonic-gate ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN); 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 947*7c478bd9Sstevel@tonic-gate if (uhcip->uhci_root_hub.rh_pipe_state == 948*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_ACTIVE) { 949*7c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state = 950*7c478bd9Sstevel@tonic-gate UHCI_PIPE_STATE_IDLE; 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */ 953*7c478bd9Sstevel@tonic-gate uhci_root_hub_intr_pipe_cleanup(uhcip, 954*7c478bd9Sstevel@tonic-gate USB_CR_STOPPED_POLLING); 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 957*7c478bd9Sstevel@tonic-gate "uhci_stop_periodic_pipe_polling: Stop intr " 958*7c478bd9Sstevel@tonic-gate "polling for root hub successful"); 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate } else { 961*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 962*7c478bd9Sstevel@tonic-gate "uhci_stop_periodic_pipe_polling: " 963*7c478bd9Sstevel@tonic-gate "Intr polling for root hub is already stopped"); 964*7c478bd9Sstevel@tonic-gate } 965*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate if (pp->pp_state != UHCI_PIPE_STATE_ACTIVE) { 973*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 974*7c478bd9Sstevel@tonic-gate "uhci_stop_periodic_pipe_polling: Polling already stopped"); 975*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate /* 981*7c478bd9Sstevel@tonic-gate * Set the terminate bits in all the tds in the queue and 982*7c478bd9Sstevel@tonic-gate * in the element_ptr. 983*7c478bd9Sstevel@tonic-gate * Do not deallocate the bandwidth or tear down the DMA 984*7c478bd9Sstevel@tonic-gate */ 985*7c478bd9Sstevel@tonic-gate uhci_modify_td_active_bits(uhcip, pp); 986*7c478bd9Sstevel@tonic-gate (void) uhci_wait_for_sof(uhcip); 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) { 989*7c478bd9Sstevel@tonic-gate uhci_remove_isoc_tds_tws(uhcip, pp); 990*7c478bd9Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_IDLE; 991*7c478bd9Sstevel@tonic-gate } else { 992*7c478bd9Sstevel@tonic-gate UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 993*7c478bd9Sstevel@tonic-gate uhci_update_intr_td_data_toggle(uhcip, pp); 994*7c478bd9Sstevel@tonic-gate SetQH32(uhcip, pp->pp_qh->element_ptr, 995*7c478bd9Sstevel@tonic-gate TD_PADDR(pp->pp_qh->td_tailp)); 996*7c478bd9Sstevel@tonic-gate uhci_remove_tds_tws(uhcip, ph); 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate pp->pp_state = UHCI_PIPE_STATE_IDLE; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) { 1002*7c478bd9Sstevel@tonic-gate uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_STOPPED_POLLING); 1003*7c478bd9Sstevel@tonic-gate } 1004*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1007*7c478bd9Sstevel@tonic-gate } 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate /* 1011*7c478bd9Sstevel@tonic-gate * uhci_hcdi_pipe_send_isoc_data: 1012*7c478bd9Sstevel@tonic-gate * Handles the isoc write request. 1013*7c478bd9Sstevel@tonic-gate */ 1014*7c478bd9Sstevel@tonic-gate static int 1015*7c478bd9Sstevel@tonic-gate uhci_pipe_send_isoc_data( 1016*7c478bd9Sstevel@tonic-gate uhci_state_t *uhcip, 1017*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1018*7c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_req, 1019*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 1020*7c478bd9Sstevel@tonic-gate { 1021*7c478bd9Sstevel@tonic-gate int error; 1022*7c478bd9Sstevel@tonic-gate size_t max_isoc_xfer_sz, length; 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1025*7c478bd9Sstevel@tonic-gate "uhci_pipe_send_isoc_data: isoc_req = %p flags = %x", 1026*7c478bd9Sstevel@tonic-gate isoc_req, usb_flags); 1027*7c478bd9Sstevel@tonic-gate 1028*7c478bd9Sstevel@tonic-gate ASSERT(isoc_req->isoc_pkts_count < UHCI_MAX_ISOC_PKTS); 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate /* Calculate the maximum isochronous transfer size */ 1031*7c478bd9Sstevel@tonic-gate max_isoc_xfer_sz = UHCI_MAX_ISOC_PKTS * ph->p_ep.wMaxPacketSize; 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate /* Check the size of isochronous request */ 1034*7c478bd9Sstevel@tonic-gate ASSERT(isoc_req->isoc_data != NULL); 1035*7c478bd9Sstevel@tonic-gate length = isoc_req->isoc_data->b_wptr - isoc_req->isoc_data->b_rptr; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate if (length > max_isoc_xfer_sz) { 1038*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1039*7c478bd9Sstevel@tonic-gate "uhci_pipe_send_isoc_data: Maximum isoc request size %lx " 1040*7c478bd9Sstevel@tonic-gate "Given isoc request size %lx", max_isoc_xfer_sz, length); 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate return (USB_INVALID_REQUEST); 1043*7c478bd9Sstevel@tonic-gate } 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate /* 1047*7c478bd9Sstevel@tonic-gate * Check whether we can insert these tds? 1048*7c478bd9Sstevel@tonic-gate * At any point of time, we can insert maximum of 1024 isoc td's, 1049*7c478bd9Sstevel@tonic-gate * size of frame list table. 1050*7c478bd9Sstevel@tonic-gate */ 1051*7c478bd9Sstevel@tonic-gate if (isoc_req->isoc_pkts_count > UHCI_MAX_ISOC_PKTS) { 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl, 1054*7c478bd9Sstevel@tonic-gate "uhci_pipe_send_isoc_data: request too big"); 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate return (USB_INVALID_REQUEST); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate /* Add the TD into the Host Controller's isoc list */ 1060*7c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex); 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate if ((error = uhci_insert_isoc_td(uhcip, ph, isoc_req, 1063*7c478bd9Sstevel@tonic-gate length, usb_flags)) != USB_SUCCESS) { 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl, 1066*7c478bd9Sstevel@tonic-gate "uhci_pipe_send_isoc_data: Unable to insert the isoc_req," 1067*7c478bd9Sstevel@tonic-gate "Error = %d", error); 1068*7c478bd9Sstevel@tonic-gate } 1069*7c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex); 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate return (error); 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate /* 1076*7c478bd9Sstevel@tonic-gate * uhci_update_intr_td_data_toggle 1077*7c478bd9Sstevel@tonic-gate * Update the data toggle and save in the usba_device structure 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate static void 1080*7c478bd9Sstevel@tonic-gate uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, uhci_pipe_private_t *pp) 1081*7c478bd9Sstevel@tonic-gate { 1082*7c478bd9Sstevel@tonic-gate uint32_t paddr_tail, element_ptr; 1083*7c478bd9Sstevel@tonic-gate uhci_td_t *next_td; 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate /* Find the next td that would have been executed */ 1086*7c478bd9Sstevel@tonic-gate element_ptr = GetQH32(uhcip, pp->pp_qh->element_ptr) & 1087*7c478bd9Sstevel@tonic-gate QH_ELEMENT_PTR_MASK; 1088*7c478bd9Sstevel@tonic-gate next_td = TD_VADDR(element_ptr); 1089*7c478bd9Sstevel@tonic-gate paddr_tail = TD_PADDR(pp->pp_qh->td_tailp); 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate /* 1092*7c478bd9Sstevel@tonic-gate * If element_ptr points to the dummy td, then the data toggle in 1093*7c478bd9Sstevel@tonic-gate * pp_data_toggle is correct. Otherwise update the data toggle in 1094*7c478bd9Sstevel@tonic-gate * the pipe private 1095*7c478bd9Sstevel@tonic-gate */ 1096*7c478bd9Sstevel@tonic-gate if (element_ptr != paddr_tail) { 1097*7c478bd9Sstevel@tonic-gate pp->pp_data_toggle = GetTD_dtogg(uhcip, next_td); 1098*7c478bd9Sstevel@tonic-gate } 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1101*7c478bd9Sstevel@tonic-gate "uhci_update_intr_td_data_toggle: " 1102*7c478bd9Sstevel@tonic-gate "pp %p toggle %x element ptr %x ptail %x", 1103*7c478bd9Sstevel@tonic-gate pp, pp->pp_data_toggle, element_ptr, paddr_tail); 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate uhci_save_data_toggle(pp); 1106*7c478bd9Sstevel@tonic-gate } 1107