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 * EHCI Host Controller Driver (EHCI) 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 33*7c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 34*7c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * This module contains the EHCI driver interrupt code, which handles all 37*7c478bd9Sstevel@tonic-gate * Checking of status of USB transfers, error recovery and callbacks. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* 45*7c478bd9Sstevel@tonic-gate * EHCI Interrupt Handling functions. 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate void ehci_handle_ue(ehci_state_t *ehcip); 48*7c478bd9Sstevel@tonic-gate void ehci_handle_frame_list_rollover( 49*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 50*7c478bd9Sstevel@tonic-gate void ehci_handle_endpoint_reclaimation( 51*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 52*7c478bd9Sstevel@tonic-gate void ehci_traverse_active_qtd_list( 53*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 54*7c478bd9Sstevel@tonic-gate static ehci_qtd_t *ehci_create_done_qtd_list( 55*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 56*7c478bd9Sstevel@tonic-gate static usb_cr_t ehci_parse_error( 57*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 58*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 59*7c478bd9Sstevel@tonic-gate usb_cr_t ehci_check_for_error( 60*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 61*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 62*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 63*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 64*7c478bd9Sstevel@tonic-gate uint_t ctrl); 65*7c478bd9Sstevel@tonic-gate static usb_cr_t ehci_check_for_short_xfer( 66*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 67*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 68*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 69*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 70*7c478bd9Sstevel@tonic-gate void ehci_handle_error( 71*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 72*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 73*7c478bd9Sstevel@tonic-gate usb_cr_t error); 74*7c478bd9Sstevel@tonic-gate static void ehci_cleanup_data_underrun( 75*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 76*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 77*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 78*7c478bd9Sstevel@tonic-gate static void ehci_handle_normal_qtd( 79*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 80*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 81*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 82*7c478bd9Sstevel@tonic-gate void ehci_handle_ctrl_qtd( 83*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 84*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 85*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 86*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 87*7c478bd9Sstevel@tonic-gate void *); 88*7c478bd9Sstevel@tonic-gate void ehci_handle_bulk_qtd( 89*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 90*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 91*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 92*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 93*7c478bd9Sstevel@tonic-gate void *); 94*7c478bd9Sstevel@tonic-gate void ehci_handle_intr_qtd( 95*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 96*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 97*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 98*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 99*7c478bd9Sstevel@tonic-gate void *); 100*7c478bd9Sstevel@tonic-gate static void ehci_handle_one_xfer_completion( 101*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 102*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 103*7c478bd9Sstevel@tonic-gate static void ehci_sendup_qtd_message( 104*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 105*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 106*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 107*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 108*7c478bd9Sstevel@tonic-gate usb_cr_t error); 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate /* 112*7c478bd9Sstevel@tonic-gate * Interrupt Handling functions 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* 116*7c478bd9Sstevel@tonic-gate * ehci_handle_ue: 117*7c478bd9Sstevel@tonic-gate * 118*7c478bd9Sstevel@tonic-gate * Handling of Unrecoverable Error interrupt (UE). 119*7c478bd9Sstevel@tonic-gate */ 120*7c478bd9Sstevel@tonic-gate void 121*7c478bd9Sstevel@tonic-gate ehci_handle_ue(ehci_state_t *ehcip) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 128*7c478bd9Sstevel@tonic-gate "ehci_handle_ue: Handling of UE interrupt"); 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate * First check whether current UE error occurred due to USB or 132*7c478bd9Sstevel@tonic-gate * due to some other subsystem. This can be verified by reading 133*7c478bd9Sstevel@tonic-gate * usb frame numbers before & after a delay of few milliseconds. 134*7c478bd9Sstevel@tonic-gate * If usb frame number read after delay is greater than the one 135*7c478bd9Sstevel@tonic-gate * read before delay, then, USB subsystem is fine. In this case, 136*7c478bd9Sstevel@tonic-gate * disable UE error interrupt and return without shutdowning the 137*7c478bd9Sstevel@tonic-gate * USB subsystem. 138*7c478bd9Sstevel@tonic-gate * 139*7c478bd9Sstevel@tonic-gate * Otherwise, if usb frame number read after delay is less than 140*7c478bd9Sstevel@tonic-gate * or equal to one read before the delay, then, current UE error 141*7c478bd9Sstevel@tonic-gate * occurred from USB subsystem. In this case,go ahead with actual 142*7c478bd9Sstevel@tonic-gate * UE error recovery procedure. 143*7c478bd9Sstevel@tonic-gate * 144*7c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few 145*7c478bd9Sstevel@tonic-gate * milliseconds. 146*7c478bd9Sstevel@tonic-gate */ 147*7c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 150*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_TIMEWAIT); 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* 153*7c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 154*7c478bd9Sstevel@tonic-gate * milliseconds. 155*7c478bd9Sstevel@tonic-gate */ 156*7c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 159*7c478bd9Sstevel@tonic-gate "ehci_handle_ue: Before Frame Number 0x%llx " 160*7c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", before_frame_number, 161*7c478bd9Sstevel@tonic-gate after_frame_number); 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate if (after_frame_number > before_frame_number) { 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 166*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) & 167*7c478bd9Sstevel@tonic-gate ~EHCI_INTR_HOST_SYSTEM_ERROR)); 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate return; 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * This UE is due to USB hardware error. Reset ehci controller 174*7c478bd9Sstevel@tonic-gate * and reprogram to bring it back to functional state. 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 179*7c478bd9Sstevel@tonic-gate "Unrecoverable USB Hardware Error"); 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 182*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) & 183*7c478bd9Sstevel@tonic-gate ~EHCI_INTR_HOST_SYSTEM_ERROR)); 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* Route all Root hub ports to Classic host controller */ 186*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 189*7c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate /* 195*7c478bd9Sstevel@tonic-gate * ehci_handle_frame_list_rollover: 196*7c478bd9Sstevel@tonic-gate * 197*7c478bd9Sstevel@tonic-gate * Update software based usb frame number part on every frame number 198*7c478bd9Sstevel@tonic-gate * overflow interrupt. 199*7c478bd9Sstevel@tonic-gate * 200*7c478bd9Sstevel@tonic-gate * Refer ehci spec 1.0, section 2.3.2, page 21 for more details. 201*7c478bd9Sstevel@tonic-gate * 202*7c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate void 205*7c478bd9Sstevel@tonic-gate ehci_handle_frame_list_rollover(ehci_state_t *ehcip) 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate ehcip->ehci_fno += (0x4000 - 208*7c478bd9Sstevel@tonic-gate (((Get_OpReg(ehci_frame_index) & 0x3FFF) ^ 209*7c478bd9Sstevel@tonic-gate ehcip->ehci_fno) & 0x2000)); 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 212*7c478bd9Sstevel@tonic-gate "ehci_handle_frame_list_rollover:" 213*7c478bd9Sstevel@tonic-gate "Frame Number Higher Part 0x%llx\n", ehcip->ehci_fno); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * ehci_handle_endpoint_reclamation: 219*7c478bd9Sstevel@tonic-gate * 220*7c478bd9Sstevel@tonic-gate * Reclamation of Host Controller (HC) Endpoint Descriptors (QH). 221*7c478bd9Sstevel@tonic-gate */ 222*7c478bd9Sstevel@tonic-gate void 223*7c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehci_state_t *ehcip) 224*7c478bd9Sstevel@tonic-gate { 225*7c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number; 226*7c478bd9Sstevel@tonic-gate usb_frame_number_t endpoint_frame_number; 227*7c478bd9Sstevel@tonic-gate ehci_qh_t *reclaim_qh; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 230*7c478bd9Sstevel@tonic-gate "ehci_handle_endpoint_reclamation:"); 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate current_frame_number = ehci_get_current_frame_number(ehcip); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * Deallocate all Endpoint Descriptors (QH) which are on the 238*7c478bd9Sstevel@tonic-gate * reclamation list. These QH's are already removed from the 239*7c478bd9Sstevel@tonic-gate * interrupt lattice tree. 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate while (ehcip->ehci_reclaim_list) { 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate reclaim_qh = ehcip->ehci_reclaim_list; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate endpoint_frame_number = (usb_frame_number_t)(uintptr_t) 246*7c478bd9Sstevel@tonic-gate (EHCI_LOOKUP_ID(Get_QH(reclaim_qh->qh_reclaim_frame))); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 249*7c478bd9Sstevel@tonic-gate "ehci_handle_endpoint_reclamation:" 250*7c478bd9Sstevel@tonic-gate "current frame number 0x%llx endpoint frame number 0x%llx", 251*7c478bd9Sstevel@tonic-gate current_frame_number, endpoint_frame_number); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate /* 254*7c478bd9Sstevel@tonic-gate * Deallocate current endpoint only if endpoint's usb frame 255*7c478bd9Sstevel@tonic-gate * number is less than or equal to current usb frame number. 256*7c478bd9Sstevel@tonic-gate * 257*7c478bd9Sstevel@tonic-gate * If endpoint's usb frame number is greater than the current 258*7c478bd9Sstevel@tonic-gate * usb frame number, ignore rest of the endpoints in the list 259*7c478bd9Sstevel@tonic-gate * since rest of the endpoints are inserted into the reclaim 260*7c478bd9Sstevel@tonic-gate * list later than the current reclaim endpoint. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate if (endpoint_frame_number > current_frame_number) { 263*7c478bd9Sstevel@tonic-gate break; 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate /* Get the next endpoint from the rec. list */ 267*7c478bd9Sstevel@tonic-gate ehcip->ehci_reclaim_list = ehci_qh_iommu_to_cpu( 268*7c478bd9Sstevel@tonic-gate ehcip, Get_QH(reclaim_qh->qh_reclaim_next)); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 271*7c478bd9Sstevel@tonic-gate EHCI_FREE_ID((uint32_t)Get_QH(reclaim_qh->qh_reclaim_frame)); 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* Deallocate the endpoint */ 274*7c478bd9Sstevel@tonic-gate ehci_deallocate_qh(ehcip, reclaim_qh); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate /* 280*7c478bd9Sstevel@tonic-gate * ehci_traverse_active_qtd_list: 281*7c478bd9Sstevel@tonic-gate */ 282*7c478bd9Sstevel@tonic-gate void 283*7c478bd9Sstevel@tonic-gate ehci_traverse_active_qtd_list( 284*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 285*7c478bd9Sstevel@tonic-gate { 286*7c478bd9Sstevel@tonic-gate uint_t state; /* QTD state */ 287*7c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd = NULL; /* QTD pointers */ 288*7c478bd9Sstevel@tonic-gate ehci_qtd_t *next_qtd = NULL; /* QTD pointers */ 289*7c478bd9Sstevel@tonic-gate usb_cr_t error; /* Error from QTD */ 290*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw = NULL; /* Transfer wrapper */ 291*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = NULL; /* Pipe private field */ 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 294*7c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list:"); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* Sync QH and QTD pool */ 299*7c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* Create done qtd list */ 302*7c478bd9Sstevel@tonic-gate curr_qtd = ehci_create_done_qtd_list(ehcip); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */ 305*7c478bd9Sstevel@tonic-gate while (curr_qtd) { 306*7c478bd9Sstevel@tonic-gate /* Get next qtd from the active qtd list */ 307*7c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 308*7c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* Check for QTD state */ 311*7c478bd9Sstevel@tonic-gate state = Get_QTD(curr_qtd->qtd_state); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 314*7c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list:\n\t" 315*7c478bd9Sstevel@tonic-gate "curr_qtd = 0x%p state = 0x%x", (void *)curr_qtd, state); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper for this QTD */ 318*7c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID( 319*7c478bd9Sstevel@tonic-gate (uint32_t)Get_QTD(curr_qtd->qtd_trans_wrapper)); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 326*7c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list: " 327*7c478bd9Sstevel@tonic-gate "PP = 0x%p TW = 0x%p", pp, tw); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * A QTD that is marked as RECLAIM has already been 331*7c478bd9Sstevel@tonic-gate * processed by QTD timeout handler & client driver 332*7c478bd9Sstevel@tonic-gate * has been informed through exception callback. 333*7c478bd9Sstevel@tonic-gate */ 334*7c478bd9Sstevel@tonic-gate if (state != EHCI_QTD_RECLAIM) { 335*7c478bd9Sstevel@tonic-gate /* Look at the error status */ 336*7c478bd9Sstevel@tonic-gate error = ehci_parse_error(ehcip, curr_qtd); 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) { 339*7c478bd9Sstevel@tonic-gate ehci_handle_normal_qtd(ehcip, curr_qtd, tw); 340*7c478bd9Sstevel@tonic-gate } else { 341*7c478bd9Sstevel@tonic-gate /* handle the error condition */ 342*7c478bd9Sstevel@tonic-gate ehci_handle_error(ehcip, curr_qtd, error); 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate } else { 345*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 346*7c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list: " 347*7c478bd9Sstevel@tonic-gate "QTD State = %d", state); 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 351*7c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, curr_qtd); 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate /* 354*7c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more 355*7c478bd9Sstevel@tonic-gate * QTD's for the transfer wrapper. ehci_deallocate_tw() 356*7c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic endpoint 357*7c478bd9Sstevel@tonic-gate * since it will always have a QTD attached to it. 358*7c478bd9Sstevel@tonic-gate */ 359*7c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate curr_qtd = next_qtd; 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* 367*7c478bd9Sstevel@tonic-gate * ehci_create_done_qtd_list: 368*7c478bd9Sstevel@tonic-gate * 369*7c478bd9Sstevel@tonic-gate * Create done qtd list from active qtd list. 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate ehci_qtd_t * 372*7c478bd9Sstevel@tonic-gate ehci_create_done_qtd_list( 373*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 374*7c478bd9Sstevel@tonic-gate { 375*7c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd = NULL, *next_qtd = NULL; 376*7c478bd9Sstevel@tonic-gate ehci_qtd_t *done_qtd_list = NULL, *last_done_qtd = NULL; 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 379*7c478bd9Sstevel@tonic-gate "ehci_create_done_qtd_list:"); 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate curr_qtd = ehcip->ehci_active_qtd_list; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate while (curr_qtd) { 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate /* Get next qtd from the active qtd list */ 388*7c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 389*7c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* Check this QTD has been processed by Host Controller */ 392*7c478bd9Sstevel@tonic-gate if (!(Get_QTD(curr_qtd->qtd_ctrl) & 393*7c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_ACTIVE_XACT)) { 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate /* Remove this QTD from active QTD list */ 396*7c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list(ehcip, curr_qtd); 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate Set_QTD(curr_qtd->qtd_active_qtd_next, NULL); 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate if (done_qtd_list) { 401*7c478bd9Sstevel@tonic-gate Set_QTD(last_done_qtd->qtd_active_qtd_next, 402*7c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, curr_qtd)); 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate last_done_qtd = curr_qtd; 405*7c478bd9Sstevel@tonic-gate } else { 406*7c478bd9Sstevel@tonic-gate done_qtd_list = curr_qtd; 407*7c478bd9Sstevel@tonic-gate last_done_qtd = curr_qtd; 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate curr_qtd = next_qtd; 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate return (done_qtd_list); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate /* 419*7c478bd9Sstevel@tonic-gate * ehci_parse_error: 420*7c478bd9Sstevel@tonic-gate * 421*7c478bd9Sstevel@tonic-gate * Parse the result for any errors. 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate static usb_cr_t 424*7c478bd9Sstevel@tonic-gate ehci_parse_error( 425*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 426*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate uint_t ctrl; 429*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 430*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 431*7c478bd9Sstevel@tonic-gate uint_t flag; 432*7c478bd9Sstevel@tonic-gate usb_cr_t error; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 435*7c478bd9Sstevel@tonic-gate "ehci_parse_error:"); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate ASSERT(qtd != NULL); 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the QTD */ 442*7c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 443*7c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper)); 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 448*7c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 451*7c478bd9Sstevel@tonic-gate "ehci_parse_error: PP 0x%p TW 0x%p", pp, tw); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate ctrl = (uint_t)Get_QTD(qtd->qtd_ctrl); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate /* 456*7c478bd9Sstevel@tonic-gate * Check the condition code of completed QTD and report errors 457*7c478bd9Sstevel@tonic-gate * if any. This checking will be done both for the general and 458*7c478bd9Sstevel@tonic-gate * the isochronous QTDs. 459*7c478bd9Sstevel@tonic-gate */ 460*7c478bd9Sstevel@tonic-gate if ((error = ehci_check_for_error(ehcip, pp, tw, qtd, ctrl)) != 461*7c478bd9Sstevel@tonic-gate USB_CR_OK) { 462*7c478bd9Sstevel@tonic-gate flag = EHCI_REMOVE_XFER_ALWAYS; 463*7c478bd9Sstevel@tonic-gate } else { 464*7c478bd9Sstevel@tonic-gate flag = EHCI_REMOVE_XFER_IFLAST; 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* Stop the transfer timer */ 468*7c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, flag); 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate return (error); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * ehci_check_for_error: 476*7c478bd9Sstevel@tonic-gate * 477*7c478bd9Sstevel@tonic-gate * Check for any errors. 478*7c478bd9Sstevel@tonic-gate * 479*7c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 480*7c478bd9Sstevel@tonic-gate */ 481*7c478bd9Sstevel@tonic-gate usb_cr_t 482*7c478bd9Sstevel@tonic-gate ehci_check_for_error( 483*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 484*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 485*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 486*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 487*7c478bd9Sstevel@tonic-gate uint_t ctrl) 488*7c478bd9Sstevel@tonic-gate { 489*7c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK; 490*7c478bd9Sstevel@tonic-gate uint_t status, speed, mask; 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 493*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: qtd = 0x%p ctrl = 0x%x", 494*7c478bd9Sstevel@tonic-gate qtd, ctrl); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * Find the usb device speed and get the corresponding 498*7c478bd9Sstevel@tonic-gate * error status mask. 499*7c478bd9Sstevel@tonic-gate */ 500*7c478bd9Sstevel@tonic-gate speed = Get_QH(pp->pp_qh->qh_ctrl) & EHCI_QH_CTRL_ED_SPEED; 501*7c478bd9Sstevel@tonic-gate mask = (speed == EHCI_QH_CTRL_ED_HIGH_SPEED)? 502*7c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_HS_XACT_STATUS : EHCI_QTD_CTRL_NON_HS_XACT_STATUS; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* Exclude halted transaction error condition */ 505*7c478bd9Sstevel@tonic-gate status = ctrl & EHCI_QTD_CTRL_XACT_STATUS & ~EHCI_QTD_CTRL_HALTED_XACT; 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate switch (status & mask) { 508*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_NO_ERROR: 509*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 510*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: No Error"); 511*7c478bd9Sstevel@tonic-gate error = USB_CR_OK; 512*7c478bd9Sstevel@tonic-gate break; 513*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_ACTIVE_XACT: 514*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 515*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Not accessed"); 516*7c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED; 517*7c478bd9Sstevel@tonic-gate break; 518*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_HALTED_XACT: 519*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 520*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Halted"); 521*7c478bd9Sstevel@tonic-gate error = USB_CR_STALL; 522*7c478bd9Sstevel@tonic-gate break; 523*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_DATA_BUFFER_ERROR: 524*7c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 525*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 526*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Buffer Overrun"); 527*7c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_OVERRUN; 528*7c478bd9Sstevel@tonic-gate } else { 529*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 530*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Buffer Underrun"); 531*7c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_UNDERRUN; 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate break; 534*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_BABBLE_DETECTED: 535*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 536*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Babble Detected"); 537*7c478bd9Sstevel@tonic-gate error = USB_CR_DATA_OVERRUN; 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_XACT_ERROR: 540*7c478bd9Sstevel@tonic-gate /* 541*7c478bd9Sstevel@tonic-gate * An xacterr bit of one is not necessarily an error, 542*7c478bd9Sstevel@tonic-gate * the transaction might have completed successfully 543*7c478bd9Sstevel@tonic-gate * after some retries. 544*7c478bd9Sstevel@tonic-gate * 545*7c478bd9Sstevel@tonic-gate * Try to detect the case when the queue is halted, 546*7c478bd9Sstevel@tonic-gate * because the error counter was decremented from one 547*7c478bd9Sstevel@tonic-gate * down to zero after a transaction error. 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate if (ctrl & EHCI_QTD_CTRL_HALTED_XACT && (ctrl & 550*7c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_ERR_COUNT_MASK) == 0) { 551*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 552*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Transaction Error"); 553*7c478bd9Sstevel@tonic-gate error = USB_CR_DEV_NOT_RESP; 554*7c478bd9Sstevel@tonic-gate } else { 555*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 556*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: No Error"); 557*7c478bd9Sstevel@tonic-gate error = USB_CR_OK; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate break; 560*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_MISSED_uFRAME: 561*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 562*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Missed uFrame"); 563*7c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED; 564*7c478bd9Sstevel@tonic-gate break; 565*7c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_PRD_SPLIT_XACT_ERR: 566*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 567*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Periodic split-transaction " 568*7c478bd9Sstevel@tonic-gate "receives an error handshake"); 569*7c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR; 570*7c478bd9Sstevel@tonic-gate break; 571*7c478bd9Sstevel@tonic-gate default: 572*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 573*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Unspecified Error"); 574*7c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR; 575*7c478bd9Sstevel@tonic-gate break; 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * Check for halted transaction error condition. 580*7c478bd9Sstevel@tonic-gate * Under short xfer conditions, EHCI HC will not return an error 581*7c478bd9Sstevel@tonic-gate * or halt the QH. This is done manually later in 582*7c478bd9Sstevel@tonic-gate * ehci_check_for_short_xfer. 583*7c478bd9Sstevel@tonic-gate */ 584*7c478bd9Sstevel@tonic-gate if ((ctrl & EHCI_QTD_CTRL_HALTED_XACT) && (error == USB_CR_OK)) { 585*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 586*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Halted"); 587*7c478bd9Sstevel@tonic-gate error = USB_CR_STALL; 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) { 591*7c478bd9Sstevel@tonic-gate error = ehci_check_for_short_xfer(ehcip, pp, tw, qtd); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate if (error) { 595*7c478bd9Sstevel@tonic-gate uint_t qh_ctrl = Get_QH(pp->pp_qh->qh_ctrl); 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 598*7c478bd9Sstevel@tonic-gate "ehci_check_for_error: Error %d Device address %d " 599*7c478bd9Sstevel@tonic-gate "Endpoint number %d", error, 600*7c478bd9Sstevel@tonic-gate (qh_ctrl & EHCI_QH_CTRL_DEVICE_ADDRESS), 601*7c478bd9Sstevel@tonic-gate ((qh_ctrl & EHCI_QH_CTRL_ED_NUMBER) >> 602*7c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_ED_NUMBER_SHIFT)); 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate return (error); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* 609*7c478bd9Sstevel@tonic-gate * ehci_check_for_short_xfer: 610*7c478bd9Sstevel@tonic-gate * 611*7c478bd9Sstevel@tonic-gate * Check to see if there was a short xfer condition. 612*7c478bd9Sstevel@tonic-gate * 613*7c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 614*7c478bd9Sstevel@tonic-gate * But it doesn't do anything. 615*7c478bd9Sstevel@tonic-gate */ 616*7c478bd9Sstevel@tonic-gate static usb_cr_t 617*7c478bd9Sstevel@tonic-gate ehci_check_for_short_xfer( 618*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 619*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 620*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 621*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 622*7c478bd9Sstevel@tonic-gate { 623*7c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK; 624*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd; 625*7c478bd9Sstevel@tonic-gate uchar_t attributes; 626*7c478bd9Sstevel@tonic-gate uint32_t residue = 0; 627*7c478bd9Sstevel@tonic-gate usb_req_attrs_t xfer_attrs; 628*7c478bd9Sstevel@tonic-gate size_t length; 629*7c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 630*7c478bd9Sstevel@tonic-gate usb_opaque_t xfer_reqp; 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 633*7c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer:"); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate if (pp->pp_flag == EHCI_POLLED_MODE_FLAG) { 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate return (error); 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate /* 641*7c478bd9Sstevel@tonic-gate * Check for short xfer error. If this is a control pipe, only check 642*7c478bd9Sstevel@tonic-gate * if it is in the data phase. 643*7c478bd9Sstevel@tonic-gate */ 644*7c478bd9Sstevel@tonic-gate eptd = &pp->pp_pipe_handle->p_ep; 645*7c478bd9Sstevel@tonic-gate attributes = eptd->bmAttributes & USB_EP_ATTR_MASK; 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate switch (attributes) { 648*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 649*7c478bd9Sstevel@tonic-gate if (Get_QTD(qtd->qtd_ctrl_phase) != 650*7c478bd9Sstevel@tonic-gate EHCI_CTRL_DATA_PHASE) { 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate break; 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 655*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 656*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate * If "Total bytes of xfer" in control field of 659*7c478bd9Sstevel@tonic-gate * Transfer Descriptor (QTD) is not equal to zero, 660*7c478bd9Sstevel@tonic-gate * then, we sent/received less data from the usb 661*7c478bd9Sstevel@tonic-gate * device than requested. In that case, get the 662*7c478bd9Sstevel@tonic-gate * actual received data size. 663*7c478bd9Sstevel@tonic-gate */ 664*7c478bd9Sstevel@tonic-gate residue = (Get_QTD(qtd->qtd_ctrl) & 665*7c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_BYTES_TO_XFER) >> 666*7c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT; 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate break; 669*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate break; 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate if (residue) { 675*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 676*7c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer: residue=%d direction=0x%x", 677*7c478bd9Sstevel@tonic-gate residue, tw->tw_direction); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate length = (Get_QTD(qtd->qtd_xfer_addr) + 680*7c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_xfer_len) - residue) - 681*7c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address; 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 684*7c478bd9Sstevel@tonic-gate xfer_attrs = ehci_get_xfer_attrs(ehcip, pp, tw); 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) { 687*7c478bd9Sstevel@tonic-gate ehci_cleanup_data_underrun(ehcip, tw, qtd); 688*7c478bd9Sstevel@tonic-gate } else { 689*7c478bd9Sstevel@tonic-gate /* Halt the pipe to mirror OHCI behavior */ 690*7c478bd9Sstevel@tonic-gate Set_QH(pp->pp_qh->qh_status, 691*7c478bd9Sstevel@tonic-gate ((Get_QH(pp->pp_qh->qh_status) & 692*7c478bd9Sstevel@tonic-gate ~EHCI_QH_STS_ACTIVE) | 693*7c478bd9Sstevel@tonic-gate EHCI_QH_STS_HALTED)); 694*7c478bd9Sstevel@tonic-gate error = USB_CR_DATA_UNDERRUN; 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 698*7c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer: requested data=%lu " 699*7c478bd9Sstevel@tonic-gate "received data=%lu", tw->tw_length, length); 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate switch (attributes) { 702*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 703*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 704*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 705*7c478bd9Sstevel@tonic-gate /* Save the actual received length */ 706*7c478bd9Sstevel@tonic-gate tw->tw_length = length; 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate break; 709*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 710*7c478bd9Sstevel@tonic-gate default: 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate break; 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate } else { 715*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 716*7c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer: requested data=%lu " 717*7c478bd9Sstevel@tonic-gate "sent data=%lu", tw->tw_length, length); 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate xfer_reqp = tw->tw_curr_xfer_reqp; 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate switch (attributes) { 722*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate break; 725*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 726*7c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_bulk_req_t *) 727*7c478bd9Sstevel@tonic-gate (xfer_reqp))->bulk_data; 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate /* Increment the read pointer */ 730*7c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 734*7c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_intr_req_t *) 735*7c478bd9Sstevel@tonic-gate (xfer_reqp))->intr_data; 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate /* Increment the read pointer */ 738*7c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length; 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate break; 741*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 742*7c478bd9Sstevel@tonic-gate default: 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate break; 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate return (error); 750*7c478bd9Sstevel@tonic-gate } 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate /* 753*7c478bd9Sstevel@tonic-gate * ehci_handle_error: 754*7c478bd9Sstevel@tonic-gate * 755*7c478bd9Sstevel@tonic-gate * Inform USBA about occurred transaction errors by calling the USBA callback 756*7c478bd9Sstevel@tonic-gate * routine. 757*7c478bd9Sstevel@tonic-gate */ 758*7c478bd9Sstevel@tonic-gate void 759*7c478bd9Sstevel@tonic-gate ehci_handle_error( 760*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 761*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 762*7c478bd9Sstevel@tonic-gate usb_cr_t error) 763*7c478bd9Sstevel@tonic-gate { 764*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 765*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph; 766*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 767*7c478bd9Sstevel@tonic-gate ehci_qtd_t *tw_qtd = qtd; 768*7c478bd9Sstevel@tonic-gate uchar_t attributes; 769*7c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 772*7c478bd9Sstevel@tonic-gate "ehci_handle_error: error = 0x%x", error); 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate ASSERT(qtd != NULL); 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* Print the values in the qtd */ 779*7c478bd9Sstevel@tonic-gate ehci_print_qtd(ehcip, qtd); 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the QTD */ 782*7c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 783*7c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper)); 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 788*7c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate ph = tw->tw_pipe_private->pp_pipe_handle; 791*7c478bd9Sstevel@tonic-gate attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK; 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate /* 794*7c478bd9Sstevel@tonic-gate * Mark all QTDs belongs to this TW as RECLAIM 795*7c478bd9Sstevel@tonic-gate * so that we don't process them by mistake. 796*7c478bd9Sstevel@tonic-gate */ 797*7c478bd9Sstevel@tonic-gate while (tw_qtd) { 798*7c478bd9Sstevel@tonic-gate /* Set QTD state to RECLAIM */ 799*7c478bd9Sstevel@tonic-gate Set_QTD(tw_qtd->qtd_state, EHCI_QTD_RECLAIM); 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate /* Get the next QTD from the wrapper */ 802*7c478bd9Sstevel@tonic-gate tw_qtd = ehci_qtd_iommu_to_cpu(ehcip, 803*7c478bd9Sstevel@tonic-gate Get_QTD(tw_qtd->qtd_tw_next_qtd)); 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate /* 807*7c478bd9Sstevel@tonic-gate * Special error handling 808*7c478bd9Sstevel@tonic-gate */ 809*7c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate switch (attributes) { 812*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 813*7c478bd9Sstevel@tonic-gate if (((ph->p_ep.bmAttributes & 814*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == 815*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) && 816*7c478bd9Sstevel@tonic-gate (Get_QTD(qtd->qtd_ctrl_phase) == 817*7c478bd9Sstevel@tonic-gate EHCI_CTRL_SETUP_PHASE)) { 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate break; 820*7c478bd9Sstevel@tonic-gate } 821*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 822*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 823*7c478bd9Sstevel@tonic-gate /* 824*7c478bd9Sstevel@tonic-gate * Call ehci_sendup_qtd_message 825*7c478bd9Sstevel@tonic-gate * to send message to upstream. 826*7c478bd9Sstevel@tonic-gate */ 827*7c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, pp, tw, qtd, error); 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate return; 830*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 831*7c478bd9Sstevel@tonic-gate curr_intr_reqp = 832*7c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & 835*7c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion(ehcip, tw); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 841*7c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 842*7c478bd9Sstevel@tonic-gate break; 843*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 844*7c478bd9Sstevel@tonic-gate break; 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, error); 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 851*7c478bd9Sstevel@tonic-gate ehci_check_for_transfers_completion(ehcip, pp); 852*7c478bd9Sstevel@tonic-gate } 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate /* 855*7c478bd9Sstevel@tonic-gate * ehci_cleanup_data_underrun: 856*7c478bd9Sstevel@tonic-gate * 857*7c478bd9Sstevel@tonic-gate * Cleans up resources when a short xfer occurs. Will only do cleanup if 858*7c478bd9Sstevel@tonic-gate * this pipe supports alternate_qtds. 859*7c478bd9Sstevel@tonic-gate * 860*7c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate static void 863*7c478bd9Sstevel@tonic-gate ehci_cleanup_data_underrun( 864*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 865*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 866*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 867*7c478bd9Sstevel@tonic-gate { 868*7c478bd9Sstevel@tonic-gate ehci_qtd_t *next_qtd, *temp_qtd; 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 871*7c478bd9Sstevel@tonic-gate "ehci_cleanup_data_underrun: qtd=0x%p, tw=0x%p", qtd, tw); 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* 874*7c478bd9Sstevel@tonic-gate * Check if this transfer doesn't supports short_xfer or 875*7c478bd9Sstevel@tonic-gate * if this QTD is the last qtd in the tw. If so there is 876*7c478bd9Sstevel@tonic-gate * no need for cleanup. 877*7c478bd9Sstevel@tonic-gate */ 878*7c478bd9Sstevel@tonic-gate if ((tw->tw_alt_qtd == NULL) || (qtd == tw->tw_qtd_tail)) { 879*7c478bd9Sstevel@tonic-gate /* There is no need for cleanup */ 880*7c478bd9Sstevel@tonic-gate return; 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate /* Start removing all the unused QTDs from the TW */ 884*7c478bd9Sstevel@tonic-gate next_qtd = (ehci_qtd_t *)ehci_qtd_iommu_to_cpu(ehcip, 885*7c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_tw_next_qtd)); 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate while (next_qtd) { 888*7c478bd9Sstevel@tonic-gate tw->tw_num_qtds--; 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list(ehcip, next_qtd); 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate temp_qtd = next_qtd; 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 895*7c478bd9Sstevel@tonic-gate Get_QTD(next_qtd->qtd_tw_next_qtd)); 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, temp_qtd); 898*7c478bd9Sstevel@tonic-gate } 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate ASSERT(tw->tw_num_qtds == 1); 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate /* 904*7c478bd9Sstevel@tonic-gate * ehci_handle_normal_qtd: 905*7c478bd9Sstevel@tonic-gate */ 906*7c478bd9Sstevel@tonic-gate static void 907*7c478bd9Sstevel@tonic-gate ehci_handle_normal_qtd( 908*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 909*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 910*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 911*7c478bd9Sstevel@tonic-gate { 912*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; /* Pipe private field */ 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 915*7c478bd9Sstevel@tonic-gate "ehci_handle_normal_qtd:"); 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 918*7c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 921*7c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate (*tw->tw_handle_qtd)(ehcip, pp, tw, 924*7c478bd9Sstevel@tonic-gate qtd, tw->tw_handle_callback_value); 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 927*7c478bd9Sstevel@tonic-gate ehci_check_for_transfers_completion(ehcip, pp); 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /* 932*7c478bd9Sstevel@tonic-gate * ehci_handle_ctrl_qtd: 933*7c478bd9Sstevel@tonic-gate * 934*7c478bd9Sstevel@tonic-gate * Handle a control Transfer Descriptor (QTD). 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 937*7c478bd9Sstevel@tonic-gate void 938*7c478bd9Sstevel@tonic-gate ehci_handle_ctrl_qtd( 939*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 940*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 941*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 942*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 943*7c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 944*7c478bd9Sstevel@tonic-gate { 945*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 948*7c478bd9Sstevel@tonic-gate "ehci_handle_ctrl_qtd: pp = 0x%p tw = 0x%p qtd = 0x%p state = 0x%x", 949*7c478bd9Sstevel@tonic-gate (void *)pp, (void *)tw, (void *)qtd, Get_QTD(qtd->qtd_ctrl_phase)); 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate /* 954*7c478bd9Sstevel@tonic-gate * A control transfer consists of three phases: 955*7c478bd9Sstevel@tonic-gate * 956*7c478bd9Sstevel@tonic-gate * Setup 957*7c478bd9Sstevel@tonic-gate * Data (optional) 958*7c478bd9Sstevel@tonic-gate * Status 959*7c478bd9Sstevel@tonic-gate * 960*7c478bd9Sstevel@tonic-gate * There is a QTD per phase. A QTD for a given phase isn't 961*7c478bd9Sstevel@tonic-gate * enqueued until the previous phase is finished. EHCI 962*7c478bd9Sstevel@tonic-gate * spec allows more than one control transfer on a pipe 963*7c478bd9Sstevel@tonic-gate * within a frame. However, we've found that some devices 964*7c478bd9Sstevel@tonic-gate * can't handle this. 965*7c478bd9Sstevel@tonic-gate */ 966*7c478bd9Sstevel@tonic-gate tw->tw_num_qtds--; 967*7c478bd9Sstevel@tonic-gate switch (Get_QTD(qtd->qtd_ctrl_phase)) { 968*7c478bd9Sstevel@tonic-gate case EHCI_CTRL_SETUP_PHASE: 969*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 970*7c478bd9Sstevel@tonic-gate "Setup complete: pp 0x%p qtd 0x%p", 971*7c478bd9Sstevel@tonic-gate (void *)pp, (void *)qtd); 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate break; 974*7c478bd9Sstevel@tonic-gate case EHCI_CTRL_DATA_PHASE: 975*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 976*7c478bd9Sstevel@tonic-gate "Data complete: pp 0x%p qtd 0x%p", 977*7c478bd9Sstevel@tonic-gate (void *)pp, (void *)qtd); 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate break; 980*7c478bd9Sstevel@tonic-gate case EHCI_CTRL_STATUS_PHASE: 981*7c478bd9Sstevel@tonic-gate if ((tw->tw_length) && 982*7c478bd9Sstevel@tonic-gate (tw->tw_direction == EHCI_QTD_CTRL_IN_PID)) { 983*7c478bd9Sstevel@tonic-gate /* 984*7c478bd9Sstevel@tonic-gate * Call ehci_sendup_qtd_message 985*7c478bd9Sstevel@tonic-gate * to send message to upstream. 986*7c478bd9Sstevel@tonic-gate */ 987*7c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, 988*7c478bd9Sstevel@tonic-gate pp, tw, qtd, USB_CR_OK); 989*7c478bd9Sstevel@tonic-gate } else { 990*7c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, USB_CR_OK); 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 994*7c478bd9Sstevel@tonic-gate "Status complete: pp 0x%p qtd 0x%p", 995*7c478bd9Sstevel@tonic-gate (void *)pp, (void *)qtd); 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate break; 998*7c478bd9Sstevel@tonic-gate } 999*7c478bd9Sstevel@tonic-gate } 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate /* 1003*7c478bd9Sstevel@tonic-gate * ehci_handle_bulk_qtd: 1004*7c478bd9Sstevel@tonic-gate * 1005*7c478bd9Sstevel@tonic-gate * Handle a bulk Transfer Descriptor (QTD). 1006*7c478bd9Sstevel@tonic-gate */ 1007*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1008*7c478bd9Sstevel@tonic-gate void 1009*7c478bd9Sstevel@tonic-gate ehci_handle_bulk_qtd( 1010*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1011*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1012*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1013*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 1014*7c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 1015*7c478bd9Sstevel@tonic-gate { 1016*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1017*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1020*7c478bd9Sstevel@tonic-gate "ehci_handle_bulk_qtd:"); 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate /* 1025*7c478bd9Sstevel@tonic-gate * Decrement the QTDs counter and check whether all the bulk 1026*7c478bd9Sstevel@tonic-gate * data has been send or received. If QTDs counter reaches 1027*7c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 1028*7c478bd9Sstevel@tonic-gate * bulk request. Other wise wait for completion of other bulk 1029*7c478bd9Sstevel@tonic-gate * QTDs or transactions on this pipe. 1030*7c478bd9Sstevel@tonic-gate */ 1031*7c478bd9Sstevel@tonic-gate if (--tw->tw_num_qtds != 0) { 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1034*7c478bd9Sstevel@tonic-gate "ehci_handle_bulk_qtd: Number of QTDs %d", tw->tw_num_qtds); 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate return; 1037*7c478bd9Sstevel@tonic-gate } 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate /* 1040*7c478bd9Sstevel@tonic-gate * If this is a bulk in pipe, return the data to the client. 1041*7c478bd9Sstevel@tonic-gate * For a bulk out pipe, there is no need to do anything. 1042*7c478bd9Sstevel@tonic-gate */ 1043*7c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & 1044*7c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1047*7c478bd9Sstevel@tonic-gate "ehci_handle_bulk_qtd: Bulk out pipe"); 1048*7c478bd9Sstevel@tonic-gate 1049*7c478bd9Sstevel@tonic-gate /* Do the callback */ 1050*7c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, USB_CR_OK); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate return; 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate /* Call ehci_sendup_qtd_message to send message to upstream */ 1056*7c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate /* 1061*7c478bd9Sstevel@tonic-gate * ehci_handle_intr_qtd: 1062*7c478bd9Sstevel@tonic-gate * 1063*7c478bd9Sstevel@tonic-gate * Handle a interrupt Transfer Descriptor (QTD). 1064*7c478bd9Sstevel@tonic-gate */ 1065*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1066*7c478bd9Sstevel@tonic-gate void 1067*7c478bd9Sstevel@tonic-gate ehci_handle_intr_qtd( 1068*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1069*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1070*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1071*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 1072*7c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 1073*7c478bd9Sstevel@tonic-gate { 1074*7c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 1075*7c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 1076*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1077*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 1078*7c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs; 1079*7c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1082*7c478bd9Sstevel@tonic-gate "ehci_handle_intr_qtd:"); 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate /* Get the interrupt xfer attributes */ 1087*7c478bd9Sstevel@tonic-gate attrs = curr_intr_reqp->intr_attributes; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate /* 1090*7c478bd9Sstevel@tonic-gate * For a Interrupt OUT pipe, we just callback and we are done 1091*7c478bd9Sstevel@tonic-gate */ 1092*7c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 1093*7c478bd9Sstevel@tonic-gate 1094*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1095*7c478bd9Sstevel@tonic-gate "ehci_handle_intr_qtd: Intr out pipe, intr_reqp=0x%p," 1096*7c478bd9Sstevel@tonic-gate "data=0x%p", curr_intr_reqp, curr_intr_reqp->intr_data); 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate /* Do the callback */ 1099*7c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, USB_CR_OK); 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate return; 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate /* Decrement number of interrupt request count */ 1105*7c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate /* 1108*7c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_XFER flag is set 1109*7c478bd9Sstevel@tonic-gate * and if so, free duplicate request. 1110*7c478bd9Sstevel@tonic-gate */ 1111*7c478bd9Sstevel@tonic-gate if (attrs & USB_ATTRS_ONE_XFER) { 1112*7c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion(ehcip, tw); 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate /* Call ehci_sendup_qtd_message to callback into client */ 1116*7c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK); 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate /* 1119*7c478bd9Sstevel@tonic-gate * If interrupt pipe state is still active, insert next Interrupt 1120*7c478bd9Sstevel@tonic-gate * request into the Host Controller's Interrupt list. Otherwise 1121*7c478bd9Sstevel@tonic-gate * you are done. 1122*7c478bd9Sstevel@tonic-gate */ 1123*7c478bd9Sstevel@tonic-gate if ((pp->pp_state != EHCI_PIPE_STATE_ACTIVE) || 1124*7c478bd9Sstevel@tonic-gate (ehci_state_is_operational(ehcip) != USB_SUCCESS)) { 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate return; 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_intr_in_resource(ehcip, pp, tw, 0)) == 1130*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1131*7c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp != NULL); 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate tw->tw_num_qtds = 1; 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate if (ehci_allocate_tds_for_tw(ehcip, pp, tw, tw->tw_num_qtds) != 1138*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1139*7c478bd9Sstevel@tonic-gate ehci_deallocate_intr_in_resource(ehcip, pp, tw); 1140*7c478bd9Sstevel@tonic-gate error = USB_FAILURE; 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 1145*7c478bd9Sstevel@tonic-gate /* 1146*7c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 1147*7c478bd9Sstevel@tonic-gate * resource. Don't insert any more interrupt polling 1148*7c478bd9Sstevel@tonic-gate * requests. 1149*7c478bd9Sstevel@tonic-gate */ 1150*7c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING; 1151*7c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 1152*7c478bd9Sstevel@tonic-gate } else { 1153*7c478bd9Sstevel@tonic-gate ehci_insert_intr_req(ehcip, pp, tw, 0); 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate /* Increment number of interrupt request count */ 1156*7c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 1159*7c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate 1164*7c478bd9Sstevel@tonic-gate /* 1165*7c478bd9Sstevel@tonic-gate * ehci_handle_one_xfer_completion: 1166*7c478bd9Sstevel@tonic-gate */ 1167*7c478bd9Sstevel@tonic-gate static void 1168*7c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion( 1169*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1170*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 1171*7c478bd9Sstevel@tonic-gate { 1172*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = tw->tw_pipe_private->pp_pipe_handle; 1173*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = tw->tw_pipe_private; 1174*7c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 1175*7c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 1176*7c478bd9Sstevel@tonic-gate 1177*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1178*7c478bd9Sstevel@tonic-gate "ehci_handle_one_xfer_completion: tw = 0x%p", tw); 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1181*7c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER); 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_IDLE; 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate /* 1186*7c478bd9Sstevel@tonic-gate * For one xfer, we need to copy back data ptr 1187*7c478bd9Sstevel@tonic-gate * and free current request 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))-> 1190*7c478bd9Sstevel@tonic-gate intr_data = ((usb_intr_req_t *) 1191*7c478bd9Sstevel@tonic-gate (tw->tw_curr_xfer_reqp))->intr_data; 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL; 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate /* Now free duplicate current request */ 1196*7c478bd9Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp); 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 1199*7c478bd9Sstevel@tonic-gate ph->p_req_count--; 1200*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate /* Make client's request the current request */ 1203*7c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 1204*7c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate /* 1209*7c478bd9Sstevel@tonic-gate * ehci_sendup_qtd_message: 1210*7c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback 1211*7c478bd9Sstevel@tonic-gate */ 1212*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1213*7c478bd9Sstevel@tonic-gate static void 1214*7c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message( 1215*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1216*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1217*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1218*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 1219*7c478bd9Sstevel@tonic-gate usb_cr_t error) 1220*7c478bd9Sstevel@tonic-gate { 1221*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 1222*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1223*7c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp; 1224*7c478bd9Sstevel@tonic-gate size_t skip_len = 0; 1225*7c478bd9Sstevel@tonic-gate size_t length; 1226*7c478bd9Sstevel@tonic-gate uchar_t *buf; 1227*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1228*7c478bd9Sstevel@tonic-gate 1229*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1232*7c478bd9Sstevel@tonic-gate "ehci_sendup_qtd_message:"); 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 1235*7c478bd9Sstevel@tonic-gate 1236*7c478bd9Sstevel@tonic-gate length = tw->tw_length; 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) { 1239*7c478bd9Sstevel@tonic-gate /* Get the correct length */ 1240*7c478bd9Sstevel@tonic-gate length = length - SETUP_SIZE; 1241*7c478bd9Sstevel@tonic-gate 1242*7c478bd9Sstevel@tonic-gate /* Set the length of the buffer to skip */ 1243*7c478bd9Sstevel@tonic-gate skip_len = SETUP_SIZE; 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */ 1247*7c478bd9Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf + skip_len; 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1250*7c478bd9Sstevel@tonic-gate "ehci_sendup_qtd_message: length %ld error %d", length, error); 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate /* Get the message block */ 1253*7c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 1254*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 1255*7c478bd9Sstevel@tonic-gate mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data; 1256*7c478bd9Sstevel@tonic-gate break; 1257*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 1258*7c478bd9Sstevel@tonic-gate mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data; 1259*7c478bd9Sstevel@tonic-gate break; 1260*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 1261*7c478bd9Sstevel@tonic-gate mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data; 1262*7c478bd9Sstevel@tonic-gate break; 1263*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 1264*7c478bd9Sstevel@tonic-gate /* Isoc messages must not go through this path */ 1265*7c478bd9Sstevel@tonic-gate mp = NULL; 1266*7c478bd9Sstevel@tonic-gate break; 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate 1269*7c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate if (length) { 1272*7c478bd9Sstevel@tonic-gate /* 1273*7c478bd9Sstevel@tonic-gate * Update kstat byte counts 1274*7c478bd9Sstevel@tonic-gate * The control endpoints don't have direction bits so in 1275*7c478bd9Sstevel@tonic-gate * order for control stats to be counted correctly an in 1276*7c478bd9Sstevel@tonic-gate * bit must be faked on a control read. 1277*7c478bd9Sstevel@tonic-gate */ 1278*7c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 1279*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) { 1280*7c478bd9Sstevel@tonic-gate ehci_do_byte_stats(ehcip, length, 1281*7c478bd9Sstevel@tonic-gate eptd->bmAttributes, USB_EP_DIR_IN); 1282*7c478bd9Sstevel@tonic-gate } else { 1283*7c478bd9Sstevel@tonic-gate ehci_do_byte_stats(ehcip, length, 1284*7c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate /* Sync IO buffer */ 1288*7c478bd9Sstevel@tonic-gate Sync_IO_Buffer(tw->tw_dmahandle, length); 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate /* since we specified NEVERSWAP, we can just use bcopy */ 1291*7c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_rptr, length); 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate /* Increment the write pointer */ 1294*7c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length; 1295*7c478bd9Sstevel@tonic-gate } else { 1296*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1297*7c478bd9Sstevel@tonic-gate "ehci_sendup_qtd_message: Zero length packet"); 1298*7c478bd9Sstevel@tonic-gate } 1299*7c478bd9Sstevel@tonic-gate 1300*7c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, error); 1301*7c478bd9Sstevel@tonic-gate } 1302