17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3304303fSsl * Common Development and Distribution License (the "License"). 6*3304303fSsl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*3304303fSsl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI) 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 327c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 337c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * This module contains the EHCI driver interrupt code, which handles all 367c478bd9Sstevel@tonic-gate * Checking of status of USB transfers, error recovery and callbacks. 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h> 417c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* 447c478bd9Sstevel@tonic-gate * EHCI Interrupt Handling functions. 457c478bd9Sstevel@tonic-gate */ 467c478bd9Sstevel@tonic-gate void ehci_handle_ue(ehci_state_t *ehcip); 477c478bd9Sstevel@tonic-gate void ehci_handle_frame_list_rollover( 487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 497c478bd9Sstevel@tonic-gate void ehci_handle_endpoint_reclaimation( 507c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 517c478bd9Sstevel@tonic-gate void ehci_traverse_active_qtd_list( 527c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 537c478bd9Sstevel@tonic-gate static ehci_qtd_t *ehci_create_done_qtd_list( 547c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 557c478bd9Sstevel@tonic-gate static usb_cr_t ehci_parse_error( 567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 577c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 587c478bd9Sstevel@tonic-gate usb_cr_t ehci_check_for_error( 597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 607c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 617c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 627c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 637c478bd9Sstevel@tonic-gate uint_t ctrl); 647c478bd9Sstevel@tonic-gate static usb_cr_t ehci_check_for_short_xfer( 657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 667c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 677c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 687c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 697c478bd9Sstevel@tonic-gate void ehci_handle_error( 707c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 717c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 727c478bd9Sstevel@tonic-gate usb_cr_t error); 737c478bd9Sstevel@tonic-gate static void ehci_cleanup_data_underrun( 747c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 757c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 767c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 777c478bd9Sstevel@tonic-gate static void ehci_handle_normal_qtd( 787c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 797c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 807c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 817c478bd9Sstevel@tonic-gate void ehci_handle_ctrl_qtd( 827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 837c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 847c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 857c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 867c478bd9Sstevel@tonic-gate void *); 877c478bd9Sstevel@tonic-gate void ehci_handle_bulk_qtd( 887c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 897c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 907c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 917c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 927c478bd9Sstevel@tonic-gate void *); 937c478bd9Sstevel@tonic-gate void ehci_handle_intr_qtd( 947c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 957c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 967c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 977c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 987c478bd9Sstevel@tonic-gate void *); 997c478bd9Sstevel@tonic-gate static void ehci_handle_one_xfer_completion( 1007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1017c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 1027c478bd9Sstevel@tonic-gate static void ehci_sendup_qtd_message( 1037c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1047c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1057c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1067c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 1077c478bd9Sstevel@tonic-gate usb_cr_t error); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* 1117c478bd9Sstevel@tonic-gate * Interrupt Handling functions 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * ehci_handle_ue: 1167c478bd9Sstevel@tonic-gate * 1177c478bd9Sstevel@tonic-gate * Handling of Unrecoverable Error interrupt (UE). 1187c478bd9Sstevel@tonic-gate */ 1197c478bd9Sstevel@tonic-gate void 1207c478bd9Sstevel@tonic-gate ehci_handle_ue(ehci_state_t *ehcip) 1217c478bd9Sstevel@tonic-gate { 1227c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1277c478bd9Sstevel@tonic-gate "ehci_handle_ue: Handling of UE interrupt"); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * First check whether current UE error occurred due to USB or 1317c478bd9Sstevel@tonic-gate * due to some other subsystem. This can be verified by reading 1327c478bd9Sstevel@tonic-gate * usb frame numbers before & after a delay of few milliseconds. 1337c478bd9Sstevel@tonic-gate * If usb frame number read after delay is greater than the one 1347c478bd9Sstevel@tonic-gate * read before delay, then, USB subsystem is fine. In this case, 1357c478bd9Sstevel@tonic-gate * disable UE error interrupt and return without shutdowning the 1367c478bd9Sstevel@tonic-gate * USB subsystem. 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * Otherwise, if usb frame number read after delay is less than 1397c478bd9Sstevel@tonic-gate * or equal to one read before the delay, then, current UE error 1407c478bd9Sstevel@tonic-gate * occurred from USB subsystem. In this case,go ahead with actual 1417c478bd9Sstevel@tonic-gate * UE error recovery procedure. 1427c478bd9Sstevel@tonic-gate * 1437c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few 1447c478bd9Sstevel@tonic-gate * milliseconds. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 1497c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_TIMEWAIT); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 1537c478bd9Sstevel@tonic-gate * milliseconds. 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1587c478bd9Sstevel@tonic-gate "ehci_handle_ue: Before Frame Number 0x%llx " 1597c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", before_frame_number, 1607c478bd9Sstevel@tonic-gate after_frame_number); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate if (after_frame_number > before_frame_number) { 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 1657c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) & 1667c478bd9Sstevel@tonic-gate ~EHCI_INTR_HOST_SYSTEM_ERROR)); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate return; 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * This UE is due to USB hardware error. Reset ehci controller 1737c478bd9Sstevel@tonic-gate * and reprogram to bring it back to functional state. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1787c478bd9Sstevel@tonic-gate "Unrecoverable USB Hardware Error"); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 1817c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) & 1827c478bd9Sstevel@tonic-gate ~EHCI_INTR_HOST_SYSTEM_ERROR)); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* Route all Root hub ports to Classic host controller */ 1857c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 1887c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * ehci_handle_frame_list_rollover: 1957c478bd9Sstevel@tonic-gate * 1967c478bd9Sstevel@tonic-gate * Update software based usb frame number part on every frame number 1977c478bd9Sstevel@tonic-gate * overflow interrupt. 1987c478bd9Sstevel@tonic-gate * 1997c478bd9Sstevel@tonic-gate * Refer ehci spec 1.0, section 2.3.2, page 21 for more details. 2007c478bd9Sstevel@tonic-gate * 2017c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate void 2047c478bd9Sstevel@tonic-gate ehci_handle_frame_list_rollover(ehci_state_t *ehcip) 2057c478bd9Sstevel@tonic-gate { 2067c478bd9Sstevel@tonic-gate ehcip->ehci_fno += (0x4000 - 2077c478bd9Sstevel@tonic-gate (((Get_OpReg(ehci_frame_index) & 0x3FFF) ^ 2087c478bd9Sstevel@tonic-gate ehcip->ehci_fno) & 0x2000)); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 2117c478bd9Sstevel@tonic-gate "ehci_handle_frame_list_rollover:" 2127c478bd9Sstevel@tonic-gate "Frame Number Higher Part 0x%llx\n", ehcip->ehci_fno); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * ehci_handle_endpoint_reclamation: 2187c478bd9Sstevel@tonic-gate * 2197c478bd9Sstevel@tonic-gate * Reclamation of Host Controller (HC) Endpoint Descriptors (QH). 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate void 2227c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehci_state_t *ehcip) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number; 2257c478bd9Sstevel@tonic-gate usb_frame_number_t endpoint_frame_number; 2267c478bd9Sstevel@tonic-gate ehci_qh_t *reclaim_qh; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 2297c478bd9Sstevel@tonic-gate "ehci_handle_endpoint_reclamation:"); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate current_frame_number = ehci_get_current_frame_number(ehcip); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Deallocate all Endpoint Descriptors (QH) which are on the 2377c478bd9Sstevel@tonic-gate * reclamation list. These QH's are already removed from the 2387c478bd9Sstevel@tonic-gate * interrupt lattice tree. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate while (ehcip->ehci_reclaim_list) { 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate reclaim_qh = ehcip->ehci_reclaim_list; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate endpoint_frame_number = (usb_frame_number_t)(uintptr_t) 2457c478bd9Sstevel@tonic-gate (EHCI_LOOKUP_ID(Get_QH(reclaim_qh->qh_reclaim_frame))); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 2487c478bd9Sstevel@tonic-gate "ehci_handle_endpoint_reclamation:" 2497c478bd9Sstevel@tonic-gate "current frame number 0x%llx endpoint frame number 0x%llx", 2507c478bd9Sstevel@tonic-gate current_frame_number, endpoint_frame_number); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Deallocate current endpoint only if endpoint's usb frame 2547c478bd9Sstevel@tonic-gate * number is less than or equal to current usb frame number. 2557c478bd9Sstevel@tonic-gate * 2567c478bd9Sstevel@tonic-gate * If endpoint's usb frame number is greater than the current 2577c478bd9Sstevel@tonic-gate * usb frame number, ignore rest of the endpoints in the list 2587c478bd9Sstevel@tonic-gate * since rest of the endpoints are inserted into the reclaim 2597c478bd9Sstevel@tonic-gate * list later than the current reclaim endpoint. 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate if (endpoint_frame_number > current_frame_number) { 2627c478bd9Sstevel@tonic-gate break; 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* Get the next endpoint from the rec. list */ 2667c478bd9Sstevel@tonic-gate ehcip->ehci_reclaim_list = ehci_qh_iommu_to_cpu( 2677c478bd9Sstevel@tonic-gate ehcip, Get_QH(reclaim_qh->qh_reclaim_next)); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 2707c478bd9Sstevel@tonic-gate EHCI_FREE_ID((uint32_t)Get_QH(reclaim_qh->qh_reclaim_frame)); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* Deallocate the endpoint */ 2737c478bd9Sstevel@tonic-gate ehci_deallocate_qh(ehcip, reclaim_qh); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * ehci_traverse_active_qtd_list: 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate void 2827c478bd9Sstevel@tonic-gate ehci_traverse_active_qtd_list( 2837c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate uint_t state; /* QTD state */ 2867c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd = NULL; /* QTD pointers */ 2877c478bd9Sstevel@tonic-gate ehci_qtd_t *next_qtd = NULL; /* QTD pointers */ 2887c478bd9Sstevel@tonic-gate usb_cr_t error; /* Error from QTD */ 2897c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw = NULL; /* Transfer wrapper */ 2907c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = NULL; /* Pipe private field */ 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 2937c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list:"); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* Sync QH and QTD pool */ 2987c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* Create done qtd list */ 3017c478bd9Sstevel@tonic-gate curr_qtd = ehci_create_done_qtd_list(ehcip); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */ 3047c478bd9Sstevel@tonic-gate while (curr_qtd) { 3057c478bd9Sstevel@tonic-gate /* Get next qtd from the active qtd list */ 3067c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 3077c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* Check for QTD state */ 3107c478bd9Sstevel@tonic-gate state = Get_QTD(curr_qtd->qtd_state); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3137c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list:\n\t" 3147c478bd9Sstevel@tonic-gate "curr_qtd = 0x%p state = 0x%x", (void *)curr_qtd, state); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper for this QTD */ 3177c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID( 3187c478bd9Sstevel@tonic-gate (uint32_t)Get_QTD(curr_qtd->qtd_trans_wrapper)); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3257c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list: " 3267c478bd9Sstevel@tonic-gate "PP = 0x%p TW = 0x%p", pp, tw); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * A QTD that is marked as RECLAIM has already been 3307c478bd9Sstevel@tonic-gate * processed by QTD timeout handler & client driver 3317c478bd9Sstevel@tonic-gate * has been informed through exception callback. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate if (state != EHCI_QTD_RECLAIM) { 3347c478bd9Sstevel@tonic-gate /* Look at the error status */ 3357c478bd9Sstevel@tonic-gate error = ehci_parse_error(ehcip, curr_qtd); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) { 3387c478bd9Sstevel@tonic-gate ehci_handle_normal_qtd(ehcip, curr_qtd, tw); 3397c478bd9Sstevel@tonic-gate } else { 3407c478bd9Sstevel@tonic-gate /* handle the error condition */ 3417c478bd9Sstevel@tonic-gate ehci_handle_error(ehcip, curr_qtd, error); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate } else { 3447c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3457c478bd9Sstevel@tonic-gate "ehci_traverse_active_qtd_list: " 3467c478bd9Sstevel@tonic-gate "QTD State = %d", state); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 3507c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, curr_qtd); 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more 3547c478bd9Sstevel@tonic-gate * QTD's for the transfer wrapper. ehci_deallocate_tw() 3557c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic endpoint 3567c478bd9Sstevel@tonic-gate * since it will always have a QTD attached to it. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate curr_qtd = next_qtd; 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * ehci_create_done_qtd_list: 3677c478bd9Sstevel@tonic-gate * 3687c478bd9Sstevel@tonic-gate * Create done qtd list from active qtd list. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate ehci_qtd_t * 3717c478bd9Sstevel@tonic-gate ehci_create_done_qtd_list( 3727c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 3737c478bd9Sstevel@tonic-gate { 3747c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd = NULL, *next_qtd = NULL; 3757c478bd9Sstevel@tonic-gate ehci_qtd_t *done_qtd_list = NULL, *last_done_qtd = NULL; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3787c478bd9Sstevel@tonic-gate "ehci_create_done_qtd_list:"); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate curr_qtd = ehcip->ehci_active_qtd_list; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate while (curr_qtd) { 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* Get next qtd from the active qtd list */ 3877c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 3887c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* Check this QTD has been processed by Host Controller */ 3917c478bd9Sstevel@tonic-gate if (!(Get_QTD(curr_qtd->qtd_ctrl) & 3927c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_ACTIVE_XACT)) { 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* Remove this QTD from active QTD list */ 3957c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list(ehcip, curr_qtd); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate Set_QTD(curr_qtd->qtd_active_qtd_next, NULL); 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if (done_qtd_list) { 4007c478bd9Sstevel@tonic-gate Set_QTD(last_done_qtd->qtd_active_qtd_next, 4017c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, curr_qtd)); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate last_done_qtd = curr_qtd; 4047c478bd9Sstevel@tonic-gate } else { 4057c478bd9Sstevel@tonic-gate done_qtd_list = curr_qtd; 4067c478bd9Sstevel@tonic-gate last_done_qtd = curr_qtd; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate curr_qtd = next_qtd; 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate return (done_qtd_list); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * ehci_parse_error: 4197c478bd9Sstevel@tonic-gate * 4207c478bd9Sstevel@tonic-gate * Parse the result for any errors. 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate static usb_cr_t 4237c478bd9Sstevel@tonic-gate ehci_parse_error( 4247c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 4257c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 4267c478bd9Sstevel@tonic-gate { 4277c478bd9Sstevel@tonic-gate uint_t ctrl; 4287c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 4297c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 4307c478bd9Sstevel@tonic-gate uint_t flag; 4317c478bd9Sstevel@tonic-gate usb_cr_t error; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 4347c478bd9Sstevel@tonic-gate "ehci_parse_error:"); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate ASSERT(qtd != NULL); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the QTD */ 4417c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 4427c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper)); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 4477c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 4507c478bd9Sstevel@tonic-gate "ehci_parse_error: PP 0x%p TW 0x%p", pp, tw); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate ctrl = (uint_t)Get_QTD(qtd->qtd_ctrl); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Check the condition code of completed QTD and report errors 4567c478bd9Sstevel@tonic-gate * if any. This checking will be done both for the general and 4577c478bd9Sstevel@tonic-gate * the isochronous QTDs. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate if ((error = ehci_check_for_error(ehcip, pp, tw, qtd, ctrl)) != 4607c478bd9Sstevel@tonic-gate USB_CR_OK) { 4617c478bd9Sstevel@tonic-gate flag = EHCI_REMOVE_XFER_ALWAYS; 4627c478bd9Sstevel@tonic-gate } else { 4637c478bd9Sstevel@tonic-gate flag = EHCI_REMOVE_XFER_IFLAST; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* Stop the transfer timer */ 4677c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, flag); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate return (error); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* 4747c478bd9Sstevel@tonic-gate * ehci_check_for_error: 4757c478bd9Sstevel@tonic-gate * 4767c478bd9Sstevel@tonic-gate * Check for any errors. 4777c478bd9Sstevel@tonic-gate * 4787c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 4797c478bd9Sstevel@tonic-gate */ 4807c478bd9Sstevel@tonic-gate usb_cr_t 4817c478bd9Sstevel@tonic-gate ehci_check_for_error( 4827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 4837c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 4847c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 4857c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 4867c478bd9Sstevel@tonic-gate uint_t ctrl) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK; 4897c478bd9Sstevel@tonic-gate uint_t status, speed, mask; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 4927c478bd9Sstevel@tonic-gate "ehci_check_for_error: qtd = 0x%p ctrl = 0x%x", 4937c478bd9Sstevel@tonic-gate qtd, ctrl); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * Find the usb device speed and get the corresponding 4977c478bd9Sstevel@tonic-gate * error status mask. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate speed = Get_QH(pp->pp_qh->qh_ctrl) & EHCI_QH_CTRL_ED_SPEED; 5007c478bd9Sstevel@tonic-gate mask = (speed == EHCI_QH_CTRL_ED_HIGH_SPEED)? 5017c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_HS_XACT_STATUS : EHCI_QTD_CTRL_NON_HS_XACT_STATUS; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* Exclude halted transaction error condition */ 5047c478bd9Sstevel@tonic-gate status = ctrl & EHCI_QTD_CTRL_XACT_STATUS & ~EHCI_QTD_CTRL_HALTED_XACT; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate switch (status & mask) { 5077c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_NO_ERROR: 5087c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5097c478bd9Sstevel@tonic-gate "ehci_check_for_error: No Error"); 5107c478bd9Sstevel@tonic-gate error = USB_CR_OK; 5117c478bd9Sstevel@tonic-gate break; 5127c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_ACTIVE_XACT: 5137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5147c478bd9Sstevel@tonic-gate "ehci_check_for_error: Not accessed"); 5157c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED; 5167c478bd9Sstevel@tonic-gate break; 5177c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_HALTED_XACT: 5187c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5197c478bd9Sstevel@tonic-gate "ehci_check_for_error: Halted"); 5207c478bd9Sstevel@tonic-gate error = USB_CR_STALL; 5217c478bd9Sstevel@tonic-gate break; 5227c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_DATA_BUFFER_ERROR: 5237c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 5247c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5257c478bd9Sstevel@tonic-gate "ehci_check_for_error: Buffer Overrun"); 5267c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_OVERRUN; 5277c478bd9Sstevel@tonic-gate } else { 5287c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5297c478bd9Sstevel@tonic-gate "ehci_check_for_error: Buffer Underrun"); 5307c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_UNDERRUN; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate break; 5337c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_BABBLE_DETECTED: 5347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5357c478bd9Sstevel@tonic-gate "ehci_check_for_error: Babble Detected"); 5367c478bd9Sstevel@tonic-gate error = USB_CR_DATA_OVERRUN; 5377c478bd9Sstevel@tonic-gate break; 5387c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_XACT_ERROR: 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * An xacterr bit of one is not necessarily an error, 5417c478bd9Sstevel@tonic-gate * the transaction might have completed successfully 5427c478bd9Sstevel@tonic-gate * after some retries. 5437c478bd9Sstevel@tonic-gate * 5447c478bd9Sstevel@tonic-gate * Try to detect the case when the queue is halted, 5457c478bd9Sstevel@tonic-gate * because the error counter was decremented from one 5467c478bd9Sstevel@tonic-gate * down to zero after a transaction error. 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate if (ctrl & EHCI_QTD_CTRL_HALTED_XACT && (ctrl & 5497c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_ERR_COUNT_MASK) == 0) { 5507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5517c478bd9Sstevel@tonic-gate "ehci_check_for_error: Transaction Error"); 5527c478bd9Sstevel@tonic-gate error = USB_CR_DEV_NOT_RESP; 5537c478bd9Sstevel@tonic-gate } else { 5547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5557c478bd9Sstevel@tonic-gate "ehci_check_for_error: No Error"); 5567c478bd9Sstevel@tonic-gate error = USB_CR_OK; 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate break; 5597c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_MISSED_uFRAME: 5607c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5617c478bd9Sstevel@tonic-gate "ehci_check_for_error: Missed uFrame"); 5627c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED; 5637c478bd9Sstevel@tonic-gate break; 5647c478bd9Sstevel@tonic-gate case EHCI_QTD_CTRL_PRD_SPLIT_XACT_ERR: 5657c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5667c478bd9Sstevel@tonic-gate "ehci_check_for_error: Periodic split-transaction " 5677c478bd9Sstevel@tonic-gate "receives an error handshake"); 5687c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR; 5697c478bd9Sstevel@tonic-gate break; 5707c478bd9Sstevel@tonic-gate default: 5717c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5727c478bd9Sstevel@tonic-gate "ehci_check_for_error: Unspecified Error"); 5737c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR; 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * Check for halted transaction error condition. 5797c478bd9Sstevel@tonic-gate * Under short xfer conditions, EHCI HC will not return an error 5807c478bd9Sstevel@tonic-gate * or halt the QH. This is done manually later in 5817c478bd9Sstevel@tonic-gate * ehci_check_for_short_xfer. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate if ((ctrl & EHCI_QTD_CTRL_HALTED_XACT) && (error == USB_CR_OK)) { 5847c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5857c478bd9Sstevel@tonic-gate "ehci_check_for_error: Halted"); 5867c478bd9Sstevel@tonic-gate error = USB_CR_STALL; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) { 5907c478bd9Sstevel@tonic-gate error = ehci_check_for_short_xfer(ehcip, pp, tw, qtd); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate if (error) { 5947c478bd9Sstevel@tonic-gate uint_t qh_ctrl = Get_QH(pp->pp_qh->qh_ctrl); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 5977c478bd9Sstevel@tonic-gate "ehci_check_for_error: Error %d Device address %d " 5987c478bd9Sstevel@tonic-gate "Endpoint number %d", error, 5997c478bd9Sstevel@tonic-gate (qh_ctrl & EHCI_QH_CTRL_DEVICE_ADDRESS), 6007c478bd9Sstevel@tonic-gate ((qh_ctrl & EHCI_QH_CTRL_ED_NUMBER) >> 6017c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_ED_NUMBER_SHIFT)); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate return (error); 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* 6087c478bd9Sstevel@tonic-gate * ehci_check_for_short_xfer: 6097c478bd9Sstevel@tonic-gate * 6107c478bd9Sstevel@tonic-gate * Check to see if there was a short xfer condition. 6117c478bd9Sstevel@tonic-gate * 6127c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 6137c478bd9Sstevel@tonic-gate * But it doesn't do anything. 6147c478bd9Sstevel@tonic-gate */ 6157c478bd9Sstevel@tonic-gate static usb_cr_t 6167c478bd9Sstevel@tonic-gate ehci_check_for_short_xfer( 6177c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 6187c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 6197c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 6207c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK; 6237c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd; 6247c478bd9Sstevel@tonic-gate uchar_t attributes; 6257c478bd9Sstevel@tonic-gate uint32_t residue = 0; 6267c478bd9Sstevel@tonic-gate usb_req_attrs_t xfer_attrs; 6277c478bd9Sstevel@tonic-gate size_t length; 6287c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 6297c478bd9Sstevel@tonic-gate usb_opaque_t xfer_reqp; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 6327c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer:"); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate if (pp->pp_flag == EHCI_POLLED_MODE_FLAG) { 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate return (error); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * Check for short xfer error. If this is a control pipe, only check 6417c478bd9Sstevel@tonic-gate * if it is in the data phase. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate eptd = &pp->pp_pipe_handle->p_ep; 6447c478bd9Sstevel@tonic-gate attributes = eptd->bmAttributes & USB_EP_ATTR_MASK; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate switch (attributes) { 6477c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 6487c478bd9Sstevel@tonic-gate if (Get_QTD(qtd->qtd_ctrl_phase) != 6497c478bd9Sstevel@tonic-gate EHCI_CTRL_DATA_PHASE) { 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate break; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 6547c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 6557c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * If "Total bytes of xfer" in control field of 6587c478bd9Sstevel@tonic-gate * Transfer Descriptor (QTD) is not equal to zero, 6597c478bd9Sstevel@tonic-gate * then, we sent/received less data from the usb 6607c478bd9Sstevel@tonic-gate * device than requested. In that case, get the 6617c478bd9Sstevel@tonic-gate * actual received data size. 6627c478bd9Sstevel@tonic-gate */ 6637c478bd9Sstevel@tonic-gate residue = (Get_QTD(qtd->qtd_ctrl) & 6647c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_BYTES_TO_XFER) >> 6657c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate break; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if (residue) { 6747c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 6757c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer: residue=%d direction=0x%x", 6767c478bd9Sstevel@tonic-gate residue, tw->tw_direction); 6777c478bd9Sstevel@tonic-gate 678*3304303fSsl length = Get_QTD(qtd->qtd_xfer_offs) + 679*3304303fSsl Get_QTD(qtd->qtd_xfer_len) - residue; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 6827c478bd9Sstevel@tonic-gate xfer_attrs = ehci_get_xfer_attrs(ehcip, pp, tw); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) { 6857c478bd9Sstevel@tonic-gate ehci_cleanup_data_underrun(ehcip, tw, qtd); 6867c478bd9Sstevel@tonic-gate } else { 6877c478bd9Sstevel@tonic-gate /* Halt the pipe to mirror OHCI behavior */ 6887c478bd9Sstevel@tonic-gate Set_QH(pp->pp_qh->qh_status, 6897c478bd9Sstevel@tonic-gate ((Get_QH(pp->pp_qh->qh_status) & 6907c478bd9Sstevel@tonic-gate ~EHCI_QH_STS_ACTIVE) | 6917c478bd9Sstevel@tonic-gate EHCI_QH_STS_HALTED)); 6927c478bd9Sstevel@tonic-gate error = USB_CR_DATA_UNDERRUN; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 6967c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer: requested data=%lu " 6977c478bd9Sstevel@tonic-gate "received data=%lu", tw->tw_length, length); 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate switch (attributes) { 7007c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 7017c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 7027c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 7037c478bd9Sstevel@tonic-gate /* Save the actual received length */ 7047c478bd9Sstevel@tonic-gate tw->tw_length = length; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate break; 7077c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 7087c478bd9Sstevel@tonic-gate default: 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate break; 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate } else { 7137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 7147c478bd9Sstevel@tonic-gate "ehci_check_for_short_xfer: requested data=%lu " 7157c478bd9Sstevel@tonic-gate "sent data=%lu", tw->tw_length, length); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate xfer_reqp = tw->tw_curr_xfer_reqp; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate switch (attributes) { 7207c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate break; 7237c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 7247c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_bulk_req_t *) 7257c478bd9Sstevel@tonic-gate (xfer_reqp))->bulk_data; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* Increment the read pointer */ 7287c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate break; 7317c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 7327c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_intr_req_t *) 7337c478bd9Sstevel@tonic-gate (xfer_reqp))->intr_data; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* Increment the read pointer */ 7367c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate break; 7397c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 7407c478bd9Sstevel@tonic-gate default: 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate break; 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate return (error); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * ehci_handle_error: 7527c478bd9Sstevel@tonic-gate * 7537c478bd9Sstevel@tonic-gate * Inform USBA about occurred transaction errors by calling the USBA callback 7547c478bd9Sstevel@tonic-gate * routine. 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate void 7577c478bd9Sstevel@tonic-gate ehci_handle_error( 7587c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 7597c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 7607c478bd9Sstevel@tonic-gate usb_cr_t error) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 7637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph; 7647c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 7657c478bd9Sstevel@tonic-gate ehci_qtd_t *tw_qtd = qtd; 7667c478bd9Sstevel@tonic-gate uchar_t attributes; 7677c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 7707c478bd9Sstevel@tonic-gate "ehci_handle_error: error = 0x%x", error); 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate ASSERT(qtd != NULL); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* Print the values in the qtd */ 7777c478bd9Sstevel@tonic-gate ehci_print_qtd(ehcip, qtd); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the QTD */ 7807c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 7817c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper)); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 7867c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate ph = tw->tw_pipe_private->pp_pipe_handle; 7897c478bd9Sstevel@tonic-gate attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * Mark all QTDs belongs to this TW as RECLAIM 7937c478bd9Sstevel@tonic-gate * so that we don't process them by mistake. 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate while (tw_qtd) { 7967c478bd9Sstevel@tonic-gate /* Set QTD state to RECLAIM */ 7977c478bd9Sstevel@tonic-gate Set_QTD(tw_qtd->qtd_state, EHCI_QTD_RECLAIM); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* Get the next QTD from the wrapper */ 8007c478bd9Sstevel@tonic-gate tw_qtd = ehci_qtd_iommu_to_cpu(ehcip, 8017c478bd9Sstevel@tonic-gate Get_QTD(tw_qtd->qtd_tw_next_qtd)); 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate /* 8057c478bd9Sstevel@tonic-gate * Special error handling 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate switch (attributes) { 8107c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 8117c478bd9Sstevel@tonic-gate if (((ph->p_ep.bmAttributes & 8127c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == 8137c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) && 8147c478bd9Sstevel@tonic-gate (Get_QTD(qtd->qtd_ctrl_phase) == 8157c478bd9Sstevel@tonic-gate EHCI_CTRL_SETUP_PHASE)) { 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate break; 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 8207c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 8217c478bd9Sstevel@tonic-gate /* 8227c478bd9Sstevel@tonic-gate * Call ehci_sendup_qtd_message 8237c478bd9Sstevel@tonic-gate * to send message to upstream. 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, pp, tw, qtd, error); 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate return; 8287c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 8297c478bd9Sstevel@tonic-gate curr_intr_reqp = 8307c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & 8337c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion(ehcip, tw); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 8397c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 8407c478bd9Sstevel@tonic-gate break; 8417c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 8427c478bd9Sstevel@tonic-gate break; 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, error); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 8497c478bd9Sstevel@tonic-gate ehci_check_for_transfers_completion(ehcip, pp); 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * ehci_cleanup_data_underrun: 8547c478bd9Sstevel@tonic-gate * 8557c478bd9Sstevel@tonic-gate * Cleans up resources when a short xfer occurs. Will only do cleanup if 8567c478bd9Sstevel@tonic-gate * this pipe supports alternate_qtds. 8577c478bd9Sstevel@tonic-gate * 8587c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate static void 8617c478bd9Sstevel@tonic-gate ehci_cleanup_data_underrun( 8627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 8637c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 8647c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 8657c478bd9Sstevel@tonic-gate { 8667c478bd9Sstevel@tonic-gate ehci_qtd_t *next_qtd, *temp_qtd; 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 8697c478bd9Sstevel@tonic-gate "ehci_cleanup_data_underrun: qtd=0x%p, tw=0x%p", qtd, tw); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * Check if this transfer doesn't supports short_xfer or 8737c478bd9Sstevel@tonic-gate * if this QTD is the last qtd in the tw. If so there is 8747c478bd9Sstevel@tonic-gate * no need for cleanup. 8757c478bd9Sstevel@tonic-gate */ 8767c478bd9Sstevel@tonic-gate if ((tw->tw_alt_qtd == NULL) || (qtd == tw->tw_qtd_tail)) { 8777c478bd9Sstevel@tonic-gate /* There is no need for cleanup */ 8787c478bd9Sstevel@tonic-gate return; 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* Start removing all the unused QTDs from the TW */ 8827c478bd9Sstevel@tonic-gate next_qtd = (ehci_qtd_t *)ehci_qtd_iommu_to_cpu(ehcip, 8837c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_tw_next_qtd)); 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate while (next_qtd) { 8867c478bd9Sstevel@tonic-gate tw->tw_num_qtds--; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list(ehcip, next_qtd); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate temp_qtd = next_qtd; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 8937c478bd9Sstevel@tonic-gate Get_QTD(next_qtd->qtd_tw_next_qtd)); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, temp_qtd); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate ASSERT(tw->tw_num_qtds == 1); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * ehci_handle_normal_qtd: 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate static void 9057c478bd9Sstevel@tonic-gate ehci_handle_normal_qtd( 9067c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 9077c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 9087c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 9097c478bd9Sstevel@tonic-gate { 9107c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; /* Pipe private field */ 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 9137c478bd9Sstevel@tonic-gate "ehci_handle_normal_qtd:"); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 9167c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 9197c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate (*tw->tw_handle_qtd)(ehcip, pp, tw, 9227c478bd9Sstevel@tonic-gate qtd, tw->tw_handle_callback_value); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 9257c478bd9Sstevel@tonic-gate ehci_check_for_transfers_completion(ehcip, pp); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * ehci_handle_ctrl_qtd: 9317c478bd9Sstevel@tonic-gate * 9327c478bd9Sstevel@tonic-gate * Handle a control Transfer Descriptor (QTD). 9337c478bd9Sstevel@tonic-gate */ 9347c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9357c478bd9Sstevel@tonic-gate void 9367c478bd9Sstevel@tonic-gate ehci_handle_ctrl_qtd( 9377c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 9387c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 9397c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 9407c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 9417c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 9427c478bd9Sstevel@tonic-gate { 9437c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 9467c478bd9Sstevel@tonic-gate "ehci_handle_ctrl_qtd: pp = 0x%p tw = 0x%p qtd = 0x%p state = 0x%x", 9477c478bd9Sstevel@tonic-gate (void *)pp, (void *)tw, (void *)qtd, Get_QTD(qtd->qtd_ctrl_phase)); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * A control transfer consists of three phases: 9537c478bd9Sstevel@tonic-gate * 9547c478bd9Sstevel@tonic-gate * Setup 9557c478bd9Sstevel@tonic-gate * Data (optional) 9567c478bd9Sstevel@tonic-gate * Status 9577c478bd9Sstevel@tonic-gate * 9587c478bd9Sstevel@tonic-gate * There is a QTD per phase. A QTD for a given phase isn't 9597c478bd9Sstevel@tonic-gate * enqueued until the previous phase is finished. EHCI 9607c478bd9Sstevel@tonic-gate * spec allows more than one control transfer on a pipe 9617c478bd9Sstevel@tonic-gate * within a frame. However, we've found that some devices 9627c478bd9Sstevel@tonic-gate * can't handle this. 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate tw->tw_num_qtds--; 9657c478bd9Sstevel@tonic-gate switch (Get_QTD(qtd->qtd_ctrl_phase)) { 9667c478bd9Sstevel@tonic-gate case EHCI_CTRL_SETUP_PHASE: 9677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 9687c478bd9Sstevel@tonic-gate "Setup complete: pp 0x%p qtd 0x%p", 9697c478bd9Sstevel@tonic-gate (void *)pp, (void *)qtd); 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate break; 9727c478bd9Sstevel@tonic-gate case EHCI_CTRL_DATA_PHASE: 9737c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 9747c478bd9Sstevel@tonic-gate "Data complete: pp 0x%p qtd 0x%p", 9757c478bd9Sstevel@tonic-gate (void *)pp, (void *)qtd); 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate break; 9787c478bd9Sstevel@tonic-gate case EHCI_CTRL_STATUS_PHASE: 9797c478bd9Sstevel@tonic-gate if ((tw->tw_length) && 9807c478bd9Sstevel@tonic-gate (tw->tw_direction == EHCI_QTD_CTRL_IN_PID)) { 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * Call ehci_sendup_qtd_message 9837c478bd9Sstevel@tonic-gate * to send message to upstream. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, 9867c478bd9Sstevel@tonic-gate pp, tw, qtd, USB_CR_OK); 9877c478bd9Sstevel@tonic-gate } else { 9887c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, USB_CR_OK); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 9927c478bd9Sstevel@tonic-gate "Status complete: pp 0x%p qtd 0x%p", 9937c478bd9Sstevel@tonic-gate (void *)pp, (void *)qtd); 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate break; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate /* 10017c478bd9Sstevel@tonic-gate * ehci_handle_bulk_qtd: 10027c478bd9Sstevel@tonic-gate * 10037c478bd9Sstevel@tonic-gate * Handle a bulk Transfer Descriptor (QTD). 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10067c478bd9Sstevel@tonic-gate void 10077c478bd9Sstevel@tonic-gate ehci_handle_bulk_qtd( 10087c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 10097c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 10107c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 10117c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 10127c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 10137c478bd9Sstevel@tonic-gate { 10147c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 10157c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 10187c478bd9Sstevel@tonic-gate "ehci_handle_bulk_qtd:"); 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Decrement the QTDs counter and check whether all the bulk 10247c478bd9Sstevel@tonic-gate * data has been send or received. If QTDs counter reaches 10257c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 10267c478bd9Sstevel@tonic-gate * bulk request. Other wise wait for completion of other bulk 10277c478bd9Sstevel@tonic-gate * QTDs or transactions on this pipe. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate if (--tw->tw_num_qtds != 0) { 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 10327c478bd9Sstevel@tonic-gate "ehci_handle_bulk_qtd: Number of QTDs %d", tw->tw_num_qtds); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate return; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * If this is a bulk in pipe, return the data to the client. 10397c478bd9Sstevel@tonic-gate * For a bulk out pipe, there is no need to do anything. 10407c478bd9Sstevel@tonic-gate */ 10417c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & 10427c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 10457c478bd9Sstevel@tonic-gate "ehci_handle_bulk_qtd: Bulk out pipe"); 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* Do the callback */ 10487c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, USB_CR_OK); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate return; 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate /* Call ehci_sendup_qtd_message to send message to upstream */ 10547c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate /* 10597c478bd9Sstevel@tonic-gate * ehci_handle_intr_qtd: 10607c478bd9Sstevel@tonic-gate * 10617c478bd9Sstevel@tonic-gate * Handle a interrupt Transfer Descriptor (QTD). 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10647c478bd9Sstevel@tonic-gate void 10657c478bd9Sstevel@tonic-gate ehci_handle_intr_qtd( 10667c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 10677c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 10687c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 10697c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 10707c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 10737c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 10747c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 10757c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 10767c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs; 10777c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 10807c478bd9Sstevel@tonic-gate "ehci_handle_intr_qtd:"); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate /* Get the interrupt xfer attributes */ 10857c478bd9Sstevel@tonic-gate attrs = curr_intr_reqp->intr_attributes; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * For a Interrupt OUT pipe, we just callback and we are done 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 10937c478bd9Sstevel@tonic-gate "ehci_handle_intr_qtd: Intr out pipe, intr_reqp=0x%p," 10947c478bd9Sstevel@tonic-gate "data=0x%p", curr_intr_reqp, curr_intr_reqp->intr_data); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* Do the callback */ 10977c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, USB_CR_OK); 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate return; 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate /* Decrement number of interrupt request count */ 11037c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_XFER flag is set 11077c478bd9Sstevel@tonic-gate * and if so, free duplicate request. 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate if (attrs & USB_ATTRS_ONE_XFER) { 11107c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion(ehcip, tw); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate /* Call ehci_sendup_qtd_message to callback into client */ 11147c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* 11177c478bd9Sstevel@tonic-gate * If interrupt pipe state is still active, insert next Interrupt 11187c478bd9Sstevel@tonic-gate * request into the Host Controller's Interrupt list. Otherwise 11197c478bd9Sstevel@tonic-gate * you are done. 11207c478bd9Sstevel@tonic-gate */ 11217c478bd9Sstevel@tonic-gate if ((pp->pp_state != EHCI_PIPE_STATE_ACTIVE) || 11227c478bd9Sstevel@tonic-gate (ehci_state_is_operational(ehcip) != USB_SUCCESS)) { 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate return; 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_intr_in_resource(ehcip, pp, tw, 0)) == 11287c478bd9Sstevel@tonic-gate USB_SUCCESS) { 11297c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp != NULL); 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate tw->tw_num_qtds = 1; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (ehci_allocate_tds_for_tw(ehcip, pp, tw, tw->tw_num_qtds) != 11367c478bd9Sstevel@tonic-gate USB_SUCCESS) { 11377c478bd9Sstevel@tonic-gate ehci_deallocate_intr_in_resource(ehcip, pp, tw); 11387c478bd9Sstevel@tonic-gate error = USB_FAILURE; 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 11457c478bd9Sstevel@tonic-gate * resource. Don't insert any more interrupt polling 11467c478bd9Sstevel@tonic-gate * requests. 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING; 11497c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 11507c478bd9Sstevel@tonic-gate } else { 11517c478bd9Sstevel@tonic-gate ehci_insert_intr_req(ehcip, pp, tw, 0); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* Increment number of interrupt request count */ 11547c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 11577c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * ehci_handle_one_xfer_completion: 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate static void 11667c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion( 11677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 11687c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 11697c478bd9Sstevel@tonic-gate { 11707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = tw->tw_pipe_private->pp_pipe_handle; 11717c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = tw->tw_pipe_private; 11727c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 11737c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 11767c478bd9Sstevel@tonic-gate "ehci_handle_one_xfer_completion: tw = 0x%p", tw); 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 11797c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER); 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_IDLE; 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /* 11847c478bd9Sstevel@tonic-gate * For one xfer, we need to copy back data ptr 11857c478bd9Sstevel@tonic-gate * and free current request 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))-> 11887c478bd9Sstevel@tonic-gate intr_data = ((usb_intr_req_t *) 11897c478bd9Sstevel@tonic-gate (tw->tw_curr_xfer_reqp))->intr_data; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* Now free duplicate current request */ 11947c478bd9Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 11977c478bd9Sstevel@tonic-gate ph->p_req_count--; 11987c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* Make client's request the current request */ 12017c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 12027c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate /* 12077c478bd9Sstevel@tonic-gate * ehci_sendup_qtd_message: 12087c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12117c478bd9Sstevel@tonic-gate static void 12127c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message( 12137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 12147c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 12157c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 12167c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 12177c478bd9Sstevel@tonic-gate usb_cr_t error) 12187c478bd9Sstevel@tonic-gate { 12197c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 12207c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 12217c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp; 12227c478bd9Sstevel@tonic-gate size_t skip_len = 0; 12237c478bd9Sstevel@tonic-gate size_t length; 12247c478bd9Sstevel@tonic-gate uchar_t *buf; 12257c478bd9Sstevel@tonic-gate mblk_t *mp; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 12307c478bd9Sstevel@tonic-gate "ehci_sendup_qtd_message:"); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate length = tw->tw_length; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) { 12377c478bd9Sstevel@tonic-gate /* Get the correct length */ 1238*3304303fSsl if (((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_wLength) 1239*3304303fSsl length = length - EHCI_MAX_QTD_BUF_SIZE; 1240*3304303fSsl else 1241*3304303fSsl length = length - SETUP_SIZE; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* Set the length of the buffer to skip */ 1244*3304303fSsl skip_len = EHCI_MAX_QTD_BUF_SIZE; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */ 12487c478bd9Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf + skip_len; 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 12517c478bd9Sstevel@tonic-gate "ehci_sendup_qtd_message: length %ld error %d", length, error); 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate /* Get the message block */ 12547c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 12557c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 12567c478bd9Sstevel@tonic-gate mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data; 12577c478bd9Sstevel@tonic-gate break; 12587c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 12597c478bd9Sstevel@tonic-gate mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data; 12607c478bd9Sstevel@tonic-gate break; 12617c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 12627c478bd9Sstevel@tonic-gate mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data; 12637c478bd9Sstevel@tonic-gate break; 12647c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 12657c478bd9Sstevel@tonic-gate /* Isoc messages must not go through this path */ 12667c478bd9Sstevel@tonic-gate mp = NULL; 12677c478bd9Sstevel@tonic-gate break; 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate if (length) { 12737c478bd9Sstevel@tonic-gate /* 12747c478bd9Sstevel@tonic-gate * Update kstat byte counts 12757c478bd9Sstevel@tonic-gate * The control endpoints don't have direction bits so in 12767c478bd9Sstevel@tonic-gate * order for control stats to be counted correctly an in 12777c478bd9Sstevel@tonic-gate * bit must be faked on a control read. 12787c478bd9Sstevel@tonic-gate */ 12797c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 12807c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) { 12817c478bd9Sstevel@tonic-gate ehci_do_byte_stats(ehcip, length, 12827c478bd9Sstevel@tonic-gate eptd->bmAttributes, USB_EP_DIR_IN); 12837c478bd9Sstevel@tonic-gate } else { 12847c478bd9Sstevel@tonic-gate ehci_do_byte_stats(ehcip, length, 12857c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate /* Sync IO buffer */ 1289*3304303fSsl Sync_IO_Buffer(tw->tw_dmahandle, (skip_len + length)); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* since we specified NEVERSWAP, we can just use bcopy */ 12927c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_rptr, length); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* Increment the write pointer */ 12957c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length; 12967c478bd9Sstevel@tonic-gate } else { 12977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 12987c478bd9Sstevel@tonic-gate "ehci_sendup_qtd_message: Zero length packet"); 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, tw, error); 13027c478bd9Sstevel@tonic-gate } 1303