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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Open Host Controller Driver (OHCI) 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * The USB Open Host Controller driver is a software driver which interfaces 337c478bd9Sstevel@tonic-gate * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller. 347c478bd9Sstevel@tonic-gate * The interface to USB Open Host Controller is defined by the OpenHCI Host 357c478bd9Sstevel@tonic-gate * Controller Interface. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * NOTE: 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * Currently OHCI driver does not support the following features 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * - Handle request with multiple TDs under short xfer conditions except for 427c478bd9Sstevel@tonic-gate * bulk transfers. 437c478bd9Sstevel@tonic-gate */ 447c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohcid.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* Pointer to the state structure */ 477c478bd9Sstevel@tonic-gate static void *ohci_statep; 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* Number of instances */ 507c478bd9Sstevel@tonic-gate #define OHCI_INSTS 1 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 534610e4a0Sfrits int ohci_ed_pool_size = OHCI_ED_POOL_SIZE; 544610e4a0Sfrits int ohci_td_pool_size = OHCI_TD_POOL_SIZE; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers for 587c478bd9Sstevel@tonic-gate * the 32ms scheduling lists which starts from the HCCA. 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate static uchar_t ohci_index[NUM_INTR_ED_LISTS / 2] = {0x0, 0x8, 0x4, 0xc, 617c478bd9Sstevel@tonic-gate 0x2, 0xa, 0x6, 0xe, 627c478bd9Sstevel@tonic-gate 0x1, 0x9, 0x5, 0xd, 637c478bd9Sstevel@tonic-gate 0x3, 0xb, 0x7, 0xf}; 647c478bd9Sstevel@tonic-gate /* Debugging information */ 657c478bd9Sstevel@tonic-gate uint_t ohci_errmask = (uint_t)PRINT_MASK_ALL; 667c478bd9Sstevel@tonic-gate uint_t ohci_errlevel = USB_LOG_L2; 677c478bd9Sstevel@tonic-gate uint_t ohci_instance_debug = (uint_t)-1; 687c478bd9Sstevel@tonic-gate 69*9c75c6bfSgovinda /* 70*9c75c6bfSgovinda * OHCI MSI tunable: 71*9c75c6bfSgovinda * 72*9c75c6bfSgovinda * By default MSI is enabled on all supported platforms. 73*9c75c6bfSgovinda */ 74*9c75c6bfSgovinda boolean_t ohci_enable_msi = B_TRUE; 75*9c75c6bfSgovinda 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * HCDI entry points 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * The Host Controller Driver Interfaces (HCDI) are the software interfaces 807c478bd9Sstevel@tonic-gate * between the Universal Serial Bus Driver (USBA) and the Host Controller 817c478bd9Sstevel@tonic-gate * Driver (HCD). The HCDI interfaces or entry points are subject to change. 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_open( 847c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 857c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 867c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_close( 877c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 887c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 897c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_reset( 907c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 917c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 927c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_ctrl_xfer( 937c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 947c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 957c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 967c478bd9Sstevel@tonic-gate static int ohci_hcdi_bulk_transfer_size( 977c478bd9Sstevel@tonic-gate usba_device_t *usba_device, 987c478bd9Sstevel@tonic-gate size_t *size); 997c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_bulk_xfer( 1007c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1017c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 1027c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1037c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_intr_xfer( 1047c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1057c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_req, 1067c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1077c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_stop_intr_polling( 1087c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1097c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1107c478bd9Sstevel@tonic-gate static usb_frame_number_t ohci_hcdi_get_current_frame_number( 1117c478bd9Sstevel@tonic-gate usba_device_t *usba_device); 1127c478bd9Sstevel@tonic-gate static uint_t ohci_hcdi_get_max_isoc_pkts( 1137c478bd9Sstevel@tonic-gate usba_device_t *usba_device); 1147c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_isoc_xfer( 1157c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1167c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 1177c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1187c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_stop_isoc_polling( 1197c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1207c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate /* 1237c478bd9Sstevel@tonic-gate * Internal Function Prototypes 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */ 1277c478bd9Sstevel@tonic-gate static void ohci_set_dma_attributes(ohci_state_t *ohcip); 1287c478bd9Sstevel@tonic-gate static int ohci_allocate_pools(ohci_state_t *ohcip); 1297c478bd9Sstevel@tonic-gate static void ohci_decode_ddi_dma_addr_bind_handle_result( 1307c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1317c478bd9Sstevel@tonic-gate int result); 1327c478bd9Sstevel@tonic-gate static int ohci_map_regs(ohci_state_t *ohcip); 1337c478bd9Sstevel@tonic-gate static int ohci_register_intrs_and_init_mutex( 1347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 135*9c75c6bfSgovinda static int ohci_add_intrs(ohci_state_t *ohcip, 136*9c75c6bfSgovinda int intr_type); 1377c478bd9Sstevel@tonic-gate static int ohci_init_ctlr(ohci_state_t *ohcip); 1387c478bd9Sstevel@tonic-gate static int ohci_init_hcca(ohci_state_t *ohcip); 1397c478bd9Sstevel@tonic-gate static void ohci_build_interrupt_lattice( 1407c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 1417c478bd9Sstevel@tonic-gate static int ohci_take_control(ohci_state_t *ohcip); 1427c478bd9Sstevel@tonic-gate static usba_hcdi_ops_t *ohci_alloc_hcdi_ops( 1437c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */ 1467c478bd9Sstevel@tonic-gate static int ohci_cleanup(ohci_state_t *ohcip); 147*9c75c6bfSgovinda static void ohci_rem_intrs(ohci_state_t *ohcip); 1487c478bd9Sstevel@tonic-gate static int ohci_cpr_suspend(ohci_state_t *ohcip); 1497c478bd9Sstevel@tonic-gate static int ohci_cpr_resume(ohci_state_t *ohcip); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */ 1527c478bd9Sstevel@tonic-gate static int ohci_allocate_bandwidth(ohci_state_t *ohcip, 1537c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1547c478bd9Sstevel@tonic-gate uint_t *node); 1557c478bd9Sstevel@tonic-gate static void ohci_deallocate_bandwidth(ohci_state_t *ohcip, 1567c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1577c478bd9Sstevel@tonic-gate static int ohci_compute_total_bandwidth( 1587c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1597c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1607c478bd9Sstevel@tonic-gate uint_t *bandwidth); 1617c478bd9Sstevel@tonic-gate static int ohci_adjust_polling_interval( 1627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1637c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1647c478bd9Sstevel@tonic-gate usb_port_status_t port_status); 1657c478bd9Sstevel@tonic-gate static uint_t ohci_lattice_height(uint_t interval); 1667c478bd9Sstevel@tonic-gate static uint_t ohci_lattice_parent(uint_t node); 1677c478bd9Sstevel@tonic-gate static uint_t ohci_leftmost_leaf(uint_t node, 1687c478bd9Sstevel@tonic-gate uint_t height); 1697c478bd9Sstevel@tonic-gate static uint_t ohci_hcca_intr_index( 1707c478bd9Sstevel@tonic-gate uint_t node); 1717c478bd9Sstevel@tonic-gate static uint_t ohci_hcca_leaf_index( 1727c478bd9Sstevel@tonic-gate uint_t leaf); 1737c478bd9Sstevel@tonic-gate static uint_t ohci_pow_2(uint_t x); 1747c478bd9Sstevel@tonic-gate static uint_t ohci_log_2(uint_t x); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* Endpoint Descriptor (ED) related functions */ 1777c478bd9Sstevel@tonic-gate static uint_t ohci_unpack_endpoint(ohci_state_t *ohcip, 1787c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1797c478bd9Sstevel@tonic-gate static void ohci_insert_ed(ohci_state_t *ohcip, 1807c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1817c478bd9Sstevel@tonic-gate static void ohci_insert_ctrl_ed( 1827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1837c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1847c478bd9Sstevel@tonic-gate static void ohci_insert_bulk_ed( 1857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1867c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1877c478bd9Sstevel@tonic-gate static void ohci_insert_intr_ed( 1887c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1897c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1907c478bd9Sstevel@tonic-gate static void ohci_insert_isoc_ed( 1917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1927c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1937c478bd9Sstevel@tonic-gate static void ohci_modify_sKip_bit(ohci_state_t *ohcip, 1947c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 1957c478bd9Sstevel@tonic-gate skip_bit_t action, 1967c478bd9Sstevel@tonic-gate usb_flags_t flag); 1977c478bd9Sstevel@tonic-gate static void ohci_remove_ed(ohci_state_t *ohcip, 1987c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1997c478bd9Sstevel@tonic-gate static void ohci_remove_ctrl_ed( 2007c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2017c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2027c478bd9Sstevel@tonic-gate static void ohci_remove_bulk_ed( 2037c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2057c478bd9Sstevel@tonic-gate static void ohci_remove_periodic_ed( 2067c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2077c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2087c478bd9Sstevel@tonic-gate static void ohci_insert_ed_on_reclaim_list( 2097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2107c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2117c478bd9Sstevel@tonic-gate static void ohci_detach_ed_from_list( 2127c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2137c478bd9Sstevel@tonic-gate ohci_ed_t *ept, 2147c478bd9Sstevel@tonic-gate uint_t ept_type); 2157c478bd9Sstevel@tonic-gate static ohci_ed_t *ohci_ed_iommu_to_cpu( 2167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2177c478bd9Sstevel@tonic-gate uintptr_t addr); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* Transfer Descriptor (TD) related functions */ 2207c478bd9Sstevel@tonic-gate static int ohci_initialize_dummy(ohci_state_t *ohcip, 2217c478bd9Sstevel@tonic-gate ohci_ed_t *ept); 2227c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_ctrl_resources( 2237c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2247c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2257c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 2267c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2277c478bd9Sstevel@tonic-gate static void ohci_insert_ctrl_req( 2287c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2297c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2307c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 2317c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2327c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2337c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_bulk_resources( 2347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2357c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2367c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 2377c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2387c478bd9Sstevel@tonic-gate static void ohci_insert_bulk_req(ohci_state_t *ohcip, 2397c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2407c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 2417c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2427c478bd9Sstevel@tonic-gate usb_flags_t flags); 2437c478bd9Sstevel@tonic-gate static int ohci_start_pipe_polling(ohci_state_t *ohcip, 2447c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2457c478bd9Sstevel@tonic-gate usb_flags_t flags); 2467c478bd9Sstevel@tonic-gate static void ohci_set_periodic_pipe_polling( 2477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2487c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 2497c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_intr_resources( 2507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2527c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 2537c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2547c478bd9Sstevel@tonic-gate static void ohci_insert_intr_req(ohci_state_t *ohcip, 2557c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2567c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2577c478bd9Sstevel@tonic-gate usb_flags_t flags); 2587c478bd9Sstevel@tonic-gate static int ohci_stop_periodic_pipe_polling( 2597c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2617c478bd9Sstevel@tonic-gate usb_flags_t flags); 2627c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_isoc_resources( 2637c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2647c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2657c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 2667c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2677c478bd9Sstevel@tonic-gate static int ohci_insert_isoc_req(ohci_state_t *ohcip, 2687c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2697c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2707c478bd9Sstevel@tonic-gate uint_t flags); 2717c478bd9Sstevel@tonic-gate static int ohci_insert_hc_td(ohci_state_t *ohcip, 2727c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 2737c478bd9Sstevel@tonic-gate uint32_t hctd_iommu_cbp, 2747c478bd9Sstevel@tonic-gate size_t hctd_length, 2757c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 2767c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2777c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 2787c478bd9Sstevel@tonic-gate static ohci_td_t *ohci_allocate_td_from_pool( 2797c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 2807c478bd9Sstevel@tonic-gate static void ohci_fill_in_td(ohci_state_t *ohcip, 2817c478bd9Sstevel@tonic-gate ohci_td_t *td, 2827c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy, 2837c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 2847c478bd9Sstevel@tonic-gate uint32_t hctd_iommu_cbp, 2857c478bd9Sstevel@tonic-gate size_t hctd_length, 2867c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 2877c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2887c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 2897c478bd9Sstevel@tonic-gate static void ohci_init_itd( 2907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2927c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2937c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 2947c478bd9Sstevel@tonic-gate uint32_t hctd_iommu_cbp, 2957c478bd9Sstevel@tonic-gate ohci_td_t *td); 2967c478bd9Sstevel@tonic-gate static int ohci_insert_td_with_frame_number( 2977c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2987c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2997c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3007c478bd9Sstevel@tonic-gate ohci_td_t *current_td, 3017c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td); 3027c478bd9Sstevel@tonic-gate static void ohci_insert_td_on_tw(ohci_state_t *ohcip, 3037c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3047c478bd9Sstevel@tonic-gate ohci_td_t *td); 3057c478bd9Sstevel@tonic-gate static void ohci_done_list_tds(ohci_state_t *ohcip, 3067c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* Transfer Wrapper (TW) functions */ 3097c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_create_transfer_wrapper( 3107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3117c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3127c478bd9Sstevel@tonic-gate size_t length, 3137c478bd9Sstevel@tonic-gate uint_t usb_flags); 3147c478bd9Sstevel@tonic-gate static int ohci_allocate_tds_for_tw( 3157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3177c478bd9Sstevel@tonic-gate size_t td_count); 3187c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_tw_resources( 3197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3207c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3217c478bd9Sstevel@tonic-gate size_t length, 3227c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 3237c478bd9Sstevel@tonic-gate size_t td_count); 3247c478bd9Sstevel@tonic-gate static void ohci_free_tw_tds_resources( 3257c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3267c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3277c478bd9Sstevel@tonic-gate static void ohci_start_xfer_timer( 3287c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3297c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3307c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3317c478bd9Sstevel@tonic-gate static void ohci_stop_xfer_timer( 3327c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3337c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3347c478bd9Sstevel@tonic-gate uint_t flag); 3357c478bd9Sstevel@tonic-gate static void ohci_xfer_timeout_handler(void *arg); 3367c478bd9Sstevel@tonic-gate static void ohci_remove_tw_from_timeout_list( 3377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3387c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3397c478bd9Sstevel@tonic-gate static void ohci_start_timer(ohci_state_t *ohcip); 3407c478bd9Sstevel@tonic-gate static void ohci_free_dma_resources(ohci_state_t *ohcip, 3417c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 3427c478bd9Sstevel@tonic-gate static void ohci_free_tw(ohci_state_t *ohcip, 3437c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* Interrupt Handling functions */ 346*9c75c6bfSgovinda static uint_t ohci_intr(caddr_t arg1, 347*9c75c6bfSgovinda caddr_t arg2); 3487c478bd9Sstevel@tonic-gate static void ohci_handle_missed_intr( 3497c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 3507c478bd9Sstevel@tonic-gate static void ohci_handle_ue(ohci_state_t *ohcip); 3517c478bd9Sstevel@tonic-gate static void ohci_handle_endpoint_reclaimation( 3527c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 3537c478bd9Sstevel@tonic-gate static void ohci_traverse_done_list( 3547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3557c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list); 3567c478bd9Sstevel@tonic-gate static ohci_td_t *ohci_reverse_done_list( 3577c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3587c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list); 3597c478bd9Sstevel@tonic-gate static usb_cr_t ohci_parse_error(ohci_state_t *ohcip, 3607c478bd9Sstevel@tonic-gate ohci_td_t *td); 3617c478bd9Sstevel@tonic-gate static void ohci_parse_isoc_error( 3627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3637c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3647c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3657c478bd9Sstevel@tonic-gate ohci_td_t *td); 3667c478bd9Sstevel@tonic-gate static usb_cr_t ohci_check_for_error( 3677c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3687c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3697c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3707c478bd9Sstevel@tonic-gate ohci_td_t *td, 3717c478bd9Sstevel@tonic-gate uint_t ctrl); 3727c478bd9Sstevel@tonic-gate static void ohci_handle_error( 3737c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3747c478bd9Sstevel@tonic-gate ohci_td_t *td, 3757c478bd9Sstevel@tonic-gate usb_cr_t error); 3767c478bd9Sstevel@tonic-gate static int ohci_cleanup_data_underrun( 3777c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3787c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3797c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3807c478bd9Sstevel@tonic-gate ohci_td_t *td); 3817c478bd9Sstevel@tonic-gate static void ohci_handle_normal_td( 3827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3837c478bd9Sstevel@tonic-gate ohci_td_t *td, 3847c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3857c478bd9Sstevel@tonic-gate static void ohci_handle_ctrl_td(ohci_state_t *ohcip, 3867c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3877c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3887c478bd9Sstevel@tonic-gate ohci_td_t *td, 3897c478bd9Sstevel@tonic-gate void *); 3907c478bd9Sstevel@tonic-gate static void ohci_handle_bulk_td(ohci_state_t *ohcip, 3917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3927c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3937c478bd9Sstevel@tonic-gate ohci_td_t *td, 3947c478bd9Sstevel@tonic-gate void *); 3957c478bd9Sstevel@tonic-gate static void ohci_handle_intr_td(ohci_state_t *ohcip, 3967c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3977c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3987c478bd9Sstevel@tonic-gate ohci_td_t *td, 3997c478bd9Sstevel@tonic-gate void *); 4007c478bd9Sstevel@tonic-gate static void ohci_handle_one_xfer_completion( 4017c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4027c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 4037c478bd9Sstevel@tonic-gate static void ohci_handle_isoc_td(ohci_state_t *ohcip, 4047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4057c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4067c478bd9Sstevel@tonic-gate ohci_td_t *td, 4077c478bd9Sstevel@tonic-gate void *); 4087c478bd9Sstevel@tonic-gate static void ohci_sendup_td_message( 4097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4107c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4117c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4127c478bd9Sstevel@tonic-gate ohci_td_t *td, 4137c478bd9Sstevel@tonic-gate usb_cr_t error); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* Miscillaneous functions */ 4167c478bd9Sstevel@tonic-gate static void ohci_cpr_cleanup( 4177c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 4187c478bd9Sstevel@tonic-gate static usb_req_attrs_t ohci_get_xfer_attrs(ohci_state_t *ohcip, 4197c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4207c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 4217c478bd9Sstevel@tonic-gate static int ohci_allocate_periodic_in_resource( 4227c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4237c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4247c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4257c478bd9Sstevel@tonic-gate usb_flags_t flags); 4267c478bd9Sstevel@tonic-gate static int ohci_wait_for_sof( 4277c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 4287c478bd9Sstevel@tonic-gate static void ohci_pipe_cleanup( 4297c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4307c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 4317c478bd9Sstevel@tonic-gate static void ohci_wait_for_transfers_completion( 4327c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4337c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 4347c478bd9Sstevel@tonic-gate static void ohci_check_for_transfers_completion( 4357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4367c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 4377c478bd9Sstevel@tonic-gate static void ohci_save_data_toggle(ohci_state_t *ohcip, 4387c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 4397c478bd9Sstevel@tonic-gate static void ohci_restore_data_toggle(ohci_state_t *ohcip, 4407c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 4417c478bd9Sstevel@tonic-gate static void ohci_deallocate_periodic_in_resource( 4427c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4437c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4447c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 4457c478bd9Sstevel@tonic-gate static void ohci_do_client_periodic_in_req_callback( 4467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4477c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4487c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 4497c478bd9Sstevel@tonic-gate static void ohci_hcdi_callback( 4507c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 4517c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4527c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* Kstat Support */ 4557c478bd9Sstevel@tonic-gate static void ohci_create_stats(ohci_state_t *ohcip); 4567c478bd9Sstevel@tonic-gate static void ohci_destroy_stats(ohci_state_t *ohcip); 4577c478bd9Sstevel@tonic-gate static void ohci_do_byte_stats( 4587c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4597c478bd9Sstevel@tonic-gate size_t len, 4607c478bd9Sstevel@tonic-gate uint8_t attr, 4617c478bd9Sstevel@tonic-gate uint8_t addr); 4627c478bd9Sstevel@tonic-gate static void ohci_do_intrs_stats( 4637c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4647c478bd9Sstevel@tonic-gate int val); 4657c478bd9Sstevel@tonic-gate static void ohci_print_op_regs(ohci_state_t *ohcip); 4667c478bd9Sstevel@tonic-gate static void ohci_print_ed(ohci_state_t *ohcip, 4677c478bd9Sstevel@tonic-gate ohci_ed_t *ed); 4687c478bd9Sstevel@tonic-gate static void ohci_print_td(ohci_state_t *ohcip, 4697c478bd9Sstevel@tonic-gate ohci_td_t *td); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* extern */ 4727c478bd9Sstevel@tonic-gate int usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * Device operations (dev_ops) entries function prototypes. 4767c478bd9Sstevel@tonic-gate * 4777c478bd9Sstevel@tonic-gate * We use the hub cbops since all nexus ioctl operations defined so far will 4787c478bd9Sstevel@tonic-gate * be executed by the root hub. The following are the Host Controller Driver 4797c478bd9Sstevel@tonic-gate * (HCD) entry points. 4807c478bd9Sstevel@tonic-gate * 4817c478bd9Sstevel@tonic-gate * the open/close/ioctl functions call the corresponding usba_hubdi_* 4827c478bd9Sstevel@tonic-gate * calls after looking up the dip thru the dev_t. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate static int ohci_open(dev_t *devp, int flags, int otyp, cred_t *credp); 4857c478bd9Sstevel@tonic-gate static int ohci_close(dev_t dev, int flag, int otyp, cred_t *credp); 4867c478bd9Sstevel@tonic-gate static int ohci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 4877c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate static int ohci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 4907c478bd9Sstevel@tonic-gate static int ohci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 4917c478bd9Sstevel@tonic-gate static int ohci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 4927c478bd9Sstevel@tonic-gate void *arg, void **result); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate static struct cb_ops ohci_cb_ops = { 4957c478bd9Sstevel@tonic-gate ohci_open, /* Open */ 4967c478bd9Sstevel@tonic-gate ohci_close, /* Close */ 4977c478bd9Sstevel@tonic-gate nodev, /* Strategy */ 4987c478bd9Sstevel@tonic-gate nodev, /* Print */ 4997c478bd9Sstevel@tonic-gate nodev, /* Dump */ 5007c478bd9Sstevel@tonic-gate nodev, /* Read */ 5017c478bd9Sstevel@tonic-gate nodev, /* Write */ 5027c478bd9Sstevel@tonic-gate ohci_ioctl, /* Ioctl */ 5037c478bd9Sstevel@tonic-gate nodev, /* Devmap */ 5047c478bd9Sstevel@tonic-gate nodev, /* Mmap */ 5057c478bd9Sstevel@tonic-gate nodev, /* Segmap */ 5067c478bd9Sstevel@tonic-gate nochpoll, /* Poll */ 5077c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 5087c478bd9Sstevel@tonic-gate NULL, /* Streamtab */ 5097c478bd9Sstevel@tonic-gate D_MP /* Driver compatibility flag */ 5107c478bd9Sstevel@tonic-gate }; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate static struct dev_ops ohci_ops = { 5137c478bd9Sstevel@tonic-gate DEVO_REV, /* Devo_rev */ 5147c478bd9Sstevel@tonic-gate 0, /* Refcnt */ 5157c478bd9Sstevel@tonic-gate ohci_info, /* Info */ 5167c478bd9Sstevel@tonic-gate nulldev, /* Identify */ 5177c478bd9Sstevel@tonic-gate nulldev, /* Probe */ 5187c478bd9Sstevel@tonic-gate ohci_attach, /* Attach */ 5197c478bd9Sstevel@tonic-gate ohci_detach, /* Detach */ 5207c478bd9Sstevel@tonic-gate nodev, /* Reset */ 5217c478bd9Sstevel@tonic-gate &ohci_cb_ops, /* Driver operations */ 5227c478bd9Sstevel@tonic-gate &usba_hubdi_busops, /* Bus operations */ 5237c478bd9Sstevel@tonic-gate usba_hubdi_root_hub_power /* Power */ 5247c478bd9Sstevel@tonic-gate }; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * The USBA library must be loaded for this driver. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 5307c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 5317c478bd9Sstevel@tonic-gate "USB OpenHCI Driver %I%", /* Name of the module. */ 5327c478bd9Sstevel@tonic-gate &ohci_ops, /* Driver ops */ 5337c478bd9Sstevel@tonic-gate }; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 5367c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 5377c478bd9Sstevel@tonic-gate }; 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate int 5417c478bd9Sstevel@tonic-gate _init(void) 5427c478bd9Sstevel@tonic-gate { 5437c478bd9Sstevel@tonic-gate int error; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* Initialize the soft state structures */ 5467c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&ohci_statep, sizeof (ohci_state_t), 5477c478bd9Sstevel@tonic-gate OHCI_INSTS)) != 0) { 5487c478bd9Sstevel@tonic-gate return (error); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* Install the loadable module */ 5527c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 5537c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ohci_statep); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate return (error); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate int 5617c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 5627c478bd9Sstevel@tonic-gate { 5637c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate int 5687c478bd9Sstevel@tonic-gate _fini(void) 5697c478bd9Sstevel@tonic-gate { 5707c478bd9Sstevel@tonic-gate int error; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) == 0) { 5737c478bd9Sstevel@tonic-gate /* Release per module resources */ 5747c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ohci_statep); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate return (error); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) entry points 5837c478bd9Sstevel@tonic-gate */ 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * ohci_attach: 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate static int 5897c478bd9Sstevel@tonic-gate ohci_attach(dev_info_t *dip, 5907c478bd9Sstevel@tonic-gate ddi_attach_cmd_t cmd) 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate int instance; 5937c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = NULL; 5947c478bd9Sstevel@tonic-gate usba_hcdi_register_args_t hcdi_args; 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate switch (cmd) { 5977c478bd9Sstevel@tonic-gate case DDI_ATTACH: 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate case DDI_RESUME: 6007c478bd9Sstevel@tonic-gate ohcip = ohci_obtain_state(dip); 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate return (ohci_cpr_resume(ohcip)); 6037c478bd9Sstevel@tonic-gate default: 6047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* Get the instance and create soft state */ 6087c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(ohci_statep, instance) != 0) { 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate ohcip = ddi_get_soft_state(ohci_statep, instance); 6167c478bd9Sstevel@tonic-gate if (ohcip == NULL) { 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate ohcip->ohci_flags = OHCI_ATTACH; 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl = usb_alloc_log_hdl(dip, "ohci", &ohci_errlevel, 6247c478bd9Sstevel@tonic-gate &ohci_errmask, &ohci_instance_debug, 0); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_ZALLOC; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* Set host controller soft state to initilization */ 6297c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_INIT_STATE; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 6327c478bd9Sstevel@tonic-gate "ohcip = 0x%p", (void *)ohcip); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 6357c478bd9Sstevel@tonic-gate ohci_set_dma_attributes(ohcip); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* Save the dip and instance */ 6387c478bd9Sstevel@tonic-gate ohcip->ohci_dip = dip; 6397c478bd9Sstevel@tonic-gate ohcip->ohci_instance = instance; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* Initialize the kstat structures */ 6427c478bd9Sstevel@tonic-gate ohci_create_stats(ohcip); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* Create the td and ed pools */ 6457c478bd9Sstevel@tonic-gate if (ohci_allocate_pools(ohcip) != DDI_SUCCESS) { 6467c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* Map the registers */ 6527c478bd9Sstevel@tonic-gate if (ohci_map_regs(ohcip) != DDI_SUCCESS) { 6537c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* Register interrupts */ 6597c478bd9Sstevel@tonic-gate if (ohci_register_intrs_and_init_mutex(ohcip) != DDI_SUCCESS) { 6607c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* Initialize the controller */ 6687c478bd9Sstevel@tonic-gate if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) { 6697c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 6707c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate /* 6767c478bd9Sstevel@tonic-gate * At this point, the hardware wiil be okay. 6777c478bd9Sstevel@tonic-gate * Initialize the usba_hcdi structure 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate ohcip->ohci_hcdi_ops = ohci_alloc_hcdi_ops(ohcip); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * Make this HCD instance known to USBA 6857c478bd9Sstevel@tonic-gate * (dma_attr must be passed for USBA busctl's) 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION; 6887c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dip = dip; 6897c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_ops = ohcip->ohci_hcdi_ops; 6907c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dma_attr = &ohcip->ohci_dma_attr; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /* 6937c478bd9Sstevel@tonic-gate * Priority and iblock_cookie are one and the same 6947c478bd9Sstevel@tonic-gate * (However, retaining hcdi_soft_iblock_cookie for now 6957c478bd9Sstevel@tonic-gate * assigning it w/ priority. In future all iblock_cookie 6967c478bd9Sstevel@tonic-gate * could just go) 6977c478bd9Sstevel@tonic-gate */ 6987c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_iblock_cookie = 699abdbd06dSagiri (ddi_iblock_cookie_t)(uintptr_t)ohcip->ohci_intr_pri; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) { 7027c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_USBAREG; 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if ((ohci_init_root_hub(ohcip)) != USB_SUCCESS) { 7117c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 7127c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* Finally load the root hub driver */ 7207c478bd9Sstevel@tonic-gate if (ohci_load_root_hub_driver(ohcip) != USB_SUCCESS) { 7217c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_RHREG; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* Display information in the banner */ 7287c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate /* Reset the ohci initilization flag */ 7337c478bd9Sstevel@tonic-gate ohcip->ohci_flags &= ~OHCI_ATTACH; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* Print the Host Control's Operational registers */ 7367c478bd9Sstevel@tonic-gate ohci_print_op_regs(ohcip); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* For RIO we need to call pci_report_pmcap */ 7397c478bd9Sstevel@tonic-gate if (OHCI_IS_RIO(ohcip)) { 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000); 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 7477c478bd9Sstevel@tonic-gate "ohci_attach: dip = 0x%p done", (void *)dip); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * ohci_detach: 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate int 7577c478bd9Sstevel@tonic-gate ohci_detach(dev_info_t *dip, 7587c478bd9Sstevel@tonic-gate ddi_detach_cmd_t cmd) 7597c478bd9Sstevel@tonic-gate { 7607c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(dip); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_detach:"); 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate switch (cmd) { 7657c478bd9Sstevel@tonic-gate case DDI_DETACH: 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate return (ohci_cleanup(ohcip)); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate return (ohci_cpr_suspend(ohcip)); 7727c478bd9Sstevel@tonic-gate default: 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * ohci_info: 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7837c478bd9Sstevel@tonic-gate static int 7847c478bd9Sstevel@tonic-gate ohci_info(dev_info_t *dip, 7857c478bd9Sstevel@tonic-gate ddi_info_cmd_t infocmd, 7867c478bd9Sstevel@tonic-gate void *arg, 7877c478bd9Sstevel@tonic-gate void **result) 7887c478bd9Sstevel@tonic-gate { 7897c478bd9Sstevel@tonic-gate dev_t dev; 7907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip; 7917c478bd9Sstevel@tonic-gate int instance; 7927c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate switch (infocmd) { 7957c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 7967c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 7977c478bd9Sstevel@tonic-gate instance = OHCI_UNIT(dev); 7987c478bd9Sstevel@tonic-gate ohcip = ddi_get_soft_state(ohci_statep, instance); 7997c478bd9Sstevel@tonic-gate if (ohcip != NULL) { 8007c478bd9Sstevel@tonic-gate *result = (void *)ohcip->ohci_dip; 8017c478bd9Sstevel@tonic-gate if (*result != NULL) { 8027c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate } else { 8057c478bd9Sstevel@tonic-gate *result = NULL; 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate break; 8097c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 8107c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 8117c478bd9Sstevel@tonic-gate instance = OHCI_UNIT(dev); 8127c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 8137c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 8147c478bd9Sstevel@tonic-gate break; 8157c478bd9Sstevel@tonic-gate default: 8167c478bd9Sstevel@tonic-gate break; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate return (error); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * cb_ops entry points 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate static dev_info_t * 8277c478bd9Sstevel@tonic-gate ohci_get_dip(dev_t dev) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate int instance = OHCI_UNIT(dev); 8307c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ddi_get_soft_state(ohci_statep, instance); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate if (ohcip) { 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate return (ohcip->ohci_dip); 8357c478bd9Sstevel@tonic-gate } else { 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate return (NULL); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate static int 8437c478bd9Sstevel@tonic-gate ohci_open(dev_t *devp, 8447c478bd9Sstevel@tonic-gate int flags, 8457c478bd9Sstevel@tonic-gate int otyp, 8467c478bd9Sstevel@tonic-gate cred_t *credp) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(*devp); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate return (usba_hubdi_open(dip, devp, flags, otyp, credp)); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate static int 8557c478bd9Sstevel@tonic-gate ohci_close(dev_t dev, 8567c478bd9Sstevel@tonic-gate int flag, 8577c478bd9Sstevel@tonic-gate int otyp, 8587c478bd9Sstevel@tonic-gate cred_t *credp) 8597c478bd9Sstevel@tonic-gate { 8607c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(dev); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate return (usba_hubdi_close(dip, dev, flag, otyp, credp)); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate static int 8677c478bd9Sstevel@tonic-gate ohci_ioctl(dev_t dev, 8687c478bd9Sstevel@tonic-gate int cmd, 8697c478bd9Sstevel@tonic-gate intptr_t arg, 8707c478bd9Sstevel@tonic-gate int mode, 8717c478bd9Sstevel@tonic-gate cred_t *credp, 8727c478bd9Sstevel@tonic-gate int *rvalp) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(dev); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate return (usba_hubdi_ioctl(dip, 8777c478bd9Sstevel@tonic-gate dev, cmd, arg, mode, credp, rvalp)); 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * ohci_set_dma_attributes: 8877c478bd9Sstevel@tonic-gate * 8887c478bd9Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used 8897c478bd9Sstevel@tonic-gate * in the DMA limit structres are the default values as specified by the 8907c478bd9Sstevel@tonic-gate * Writing PCI device drivers document. 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate static void 8937c478bd9Sstevel@tonic-gate ohci_set_dma_attributes(ohci_state_t *ohcip) 8947c478bd9Sstevel@tonic-gate { 8957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 8967c478bd9Sstevel@tonic-gate "ohci_set_dma_attributes:"); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 8997c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_version = DMA_ATTR_V0; 9007c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_addr_lo = 0x00000000ull; 9017c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_addr_hi = 0xfffffffeull; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* 32 bit addressing */ 9047c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_count_max = OHCI_DMA_ATTR_COUNT_MAX; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* Byte alignment */ 9077c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * Since PCI specification is byte alignment, the 9117c478bd9Sstevel@tonic-gate * burstsize field should be set to 1 for PCI devices. 9127c478bd9Sstevel@tonic-gate */ 9137c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_burstsizes = 0x1; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_minxfer = 0x1; 9167c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_maxxfer = OHCI_DMA_ATTR_MAX_XFER; 9177c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_seg = 0xffffffffull; 9187c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_sgllen = 1; 9197c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_granular = OHCI_DMA_ATTR_GRANULAR; 9207c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_flags = 0; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * ohci_allocate_pools: 9267c478bd9Sstevel@tonic-gate * 9277c478bd9Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (ED) and for the 9287c478bd9Sstevel@tonic-gate * Transfer Descriptor (TD) pools. Both ED and TD structures must be aligned 9297c478bd9Sstevel@tonic-gate * to a 16 byte boundary. 9307c478bd9Sstevel@tonic-gate */ 9317c478bd9Sstevel@tonic-gate static int 9327c478bd9Sstevel@tonic-gate ohci_allocate_pools(ohci_state_t *ohcip) 9337c478bd9Sstevel@tonic-gate { 9347c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 9357c478bd9Sstevel@tonic-gate size_t real_length; 9367c478bd9Sstevel@tonic-gate int result; 9377c478bd9Sstevel@tonic-gate uint_t ccount; 9387c478bd9Sstevel@tonic-gate int i; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 9417c478bd9Sstevel@tonic-gate "ohci_allocate_pools:"); 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 9447c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9457c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 9467c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* Byte alignment to TD alignment */ 9497c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_TD_ALIGNMENT; 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* Allocate the TD pool DMA handle */ 9527c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, &ohcip->ohci_dma_attr, 9537c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, 9547c478bd9Sstevel@tonic-gate &ohcip->ohci_td_pool_dma_handle) != DDI_SUCCESS) { 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* Allocate the memory for the TD pool */ 9607c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_td_pool_dma_handle, 9617c478bd9Sstevel@tonic-gate ohci_td_pool_size * sizeof (ohci_td_t), 9627c478bd9Sstevel@tonic-gate &dev_attr, 9637c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 9647c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 9657c478bd9Sstevel@tonic-gate 0, 9667c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_td_pool_addr, 9677c478bd9Sstevel@tonic-gate &real_length, 9687c478bd9Sstevel@tonic-gate &ohcip->ohci_td_pool_mem_handle)) { 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate /* Map the TD pool into the I/O address space */ 9747c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle( 9757c478bd9Sstevel@tonic-gate ohcip->ohci_td_pool_dma_handle, 9767c478bd9Sstevel@tonic-gate NULL, 9777c478bd9Sstevel@tonic-gate (caddr_t)ohcip->ohci_td_pool_addr, 9787c478bd9Sstevel@tonic-gate real_length, 9797c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 9807c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 9817c478bd9Sstevel@tonic-gate NULL, 9827c478bd9Sstevel@tonic-gate &ohcip->ohci_td_pool_cookie, 9837c478bd9Sstevel@tonic-gate &ccount); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_td_pool_addr, 9867c478bd9Sstevel@tonic-gate ohci_td_pool_size * sizeof (ohci_td_t)); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* Process the result */ 9897c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 9907c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 9917c478bd9Sstevel@tonic-gate if (ccount != 1) { 9927c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 9937c478bd9Sstevel@tonic-gate "ohci_allocate_pools: More than 1 cookie"); 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate } else { 9987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 9997c478bd9Sstevel@tonic-gate "ohci_allocate_pools: Result = %d", result); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * DMA addresses for TD pools are bound 10087c478bd9Sstevel@tonic-gate */ 10097c478bd9Sstevel@tonic-gate ohcip->ohci_dma_addr_bind_flag |= OHCI_TD_POOL_BOUND; 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate /* Initialize the TD pool */ 10127c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) { 10137c478bd9Sstevel@tonic-gate Set_TD(ohcip->ohci_td_pool_addr[i].hctd_state, HC_TD_FREE); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* Byte alignment to ED alignment */ 10177c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ED_ALIGNMENT; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* Allocate the ED pool DMA handle */ 10207c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, 10217c478bd9Sstevel@tonic-gate &ohcip->ohci_dma_attr, 10227c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 10237c478bd9Sstevel@tonic-gate 0, 10247c478bd9Sstevel@tonic-gate &ohcip->ohci_ed_pool_dma_handle) != DDI_SUCCESS) { 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate /* Allocate the memory for the ED pool */ 10307c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_ed_pool_dma_handle, 10317c478bd9Sstevel@tonic-gate ohci_ed_pool_size * sizeof (ohci_ed_t), 10327c478bd9Sstevel@tonic-gate &dev_attr, 10337c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 10347c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 10357c478bd9Sstevel@tonic-gate 0, 10367c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_ed_pool_addr, 10377c478bd9Sstevel@tonic-gate &real_length, 10387c478bd9Sstevel@tonic-gate &ohcip->ohci_ed_pool_mem_handle) != DDI_SUCCESS) { 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ohcip->ohci_ed_pool_dma_handle, 10447c478bd9Sstevel@tonic-gate NULL, 10457c478bd9Sstevel@tonic-gate (caddr_t)ohcip->ohci_ed_pool_addr, 10467c478bd9Sstevel@tonic-gate real_length, 10477c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 10487c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 10497c478bd9Sstevel@tonic-gate NULL, 10507c478bd9Sstevel@tonic-gate &ohcip->ohci_ed_pool_cookie, 10517c478bd9Sstevel@tonic-gate &ccount); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_ed_pool_addr, 10547c478bd9Sstevel@tonic-gate ohci_ed_pool_size * sizeof (ohci_ed_t)); 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* Process the result */ 10577c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 10587c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 10597c478bd9Sstevel@tonic-gate if (ccount != 1) { 10607c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 10617c478bd9Sstevel@tonic-gate "ohci_allocate_pools: More than 1 cookie"); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate } else { 10667c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate /* 10727c478bd9Sstevel@tonic-gate * DMA addresses for ED pools are bound 10737c478bd9Sstevel@tonic-gate */ 10747c478bd9Sstevel@tonic-gate ohcip->ohci_dma_addr_bind_flag |= OHCI_ED_POOL_BOUND; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* Initialize the ED pool */ 10777c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_ed_pool_size; i ++) { 10787c478bd9Sstevel@tonic-gate Set_ED(ohcip->ohci_ed_pool_addr[i].hced_state, HC_EPT_FREE); 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * ohci_decode_ddi_dma_addr_bind_handle_result: 10877c478bd9Sstevel@tonic-gate * 10887c478bd9Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle() 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate static void 10917c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result( 10927c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 10937c478bd9Sstevel@tonic-gate int result) 10947c478bd9Sstevel@tonic-gate { 10957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 10967c478bd9Sstevel@tonic-gate "ohci_decode_ddi_dma_addr_bind_handle_result:"); 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate switch (result) { 10997c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 11007c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11017c478bd9Sstevel@tonic-gate "Partial transfers not allowed"); 11027c478bd9Sstevel@tonic-gate break; 11037c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 11047c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11057c478bd9Sstevel@tonic-gate "Handle is in use"); 11067c478bd9Sstevel@tonic-gate break; 11077c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 11087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11097c478bd9Sstevel@tonic-gate "No resources"); 11107c478bd9Sstevel@tonic-gate break; 11117c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 11127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11137c478bd9Sstevel@tonic-gate "No mapping"); 11147c478bd9Sstevel@tonic-gate break; 11157c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 11167c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11177c478bd9Sstevel@tonic-gate "Object is too big"); 11187c478bd9Sstevel@tonic-gate break; 11197c478bd9Sstevel@tonic-gate default: 11207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11217c478bd9Sstevel@tonic-gate "Unknown dma error"); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* 11277c478bd9Sstevel@tonic-gate * ohci_map_regs: 11287c478bd9Sstevel@tonic-gate * 11297c478bd9Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers 11307c478bd9Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system 11317c478bd9Sstevel@tonic-gate * addressable space. 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate static int 11347c478bd9Sstevel@tonic-gate ohci_map_regs(ohci_state_t *ohcip) 11357c478bd9Sstevel@tonic-gate { 11367c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 11377c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_map_regs:"); 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 11427c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 11437c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 11447c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* Map in operational registers */ 11477c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ohcip->ohci_dip, 1, 11487c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_regsp, 0, 11497c478bd9Sstevel@tonic-gate sizeof (ohci_regs_t), &attr, 11507c478bd9Sstevel@tonic-gate &ohcip->ohci_regs_handle) != DDI_SUCCESS) { 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11537c478bd9Sstevel@tonic-gate "ohci_map_regs: Map setup error"); 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate if (pci_config_setup(ohcip->ohci_dip, 11597c478bd9Sstevel@tonic-gate &ohcip->ohci_config_handle) != DDI_SUCCESS) { 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11627c478bd9Sstevel@tonic-gate "ohci_map_regs: Config error"); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate /* Make sure Memory Access Enable and Master Enable are set */ 11687c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ohcip->ohci_config_handle, PCI_CONF_COMM); 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) { 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11737c478bd9Sstevel@tonic-gate "ohci_map_regs: Memory base address access disabled"); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate pci_config_put16(ohcip->ohci_config_handle, PCI_CONF_COMM, cmd_reg); 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* 11877c478bd9Sstevel@tonic-gate * ohci_register_intrs_and_init_mutex: 11887c478bd9Sstevel@tonic-gate * 11897c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 11907c478bd9Sstevel@tonic-gate */ 11917c478bd9Sstevel@tonic-gate static int 11927c478bd9Sstevel@tonic-gate ohci_register_intrs_and_init_mutex(ohci_state_t *ohcip) 11937c478bd9Sstevel@tonic-gate { 1194*9c75c6bfSgovinda int intr_types; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11977c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex:"); 11987c478bd9Sstevel@tonic-gate 1199*9c75c6bfSgovinda /* Get supported interrupt types */ 1200*9c75c6bfSgovinda if (ddi_intr_get_supported_types(ohcip->ohci_dip, 1201*9c75c6bfSgovinda &intr_types) != DDI_SUCCESS) { 12027c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12037c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: " 1204*9c75c6bfSgovinda "ddi_intr_get_supported_types failed"); 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 1209*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1210*9c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: " 1211*9c75c6bfSgovinda "supported interrupt types 0x%x", intr_types); 1212*9c75c6bfSgovinda 1213*9c75c6bfSgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ohci_enable_msi) { 1214*9c75c6bfSgovinda if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_MSI) 1215*9c75c6bfSgovinda != DDI_SUCCESS) { 1216*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1217*9c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: MSI " 1218*9c75c6bfSgovinda "registration failed, trying FIXED interrupt \n"); 1219*9c75c6bfSgovinda } else { 1220*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1221*9c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: " 1222*9c75c6bfSgovinda "Using MSI interrupt type\n"); 12237c478bd9Sstevel@tonic-gate 1224*9c75c6bfSgovinda ohcip->ohci_intr_type = DDI_INTR_TYPE_MSI; 1225*9c75c6bfSgovinda ohcip->ohci_flags |= OHCI_INTR; 1226*9c75c6bfSgovinda } 1227*9c75c6bfSgovinda } 1228*9c75c6bfSgovinda 1229*9c75c6bfSgovinda if ((!(ohcip->ohci_flags & OHCI_INTR)) && 1230*9c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) { 1231*9c75c6bfSgovinda if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_FIXED) 1232*9c75c6bfSgovinda != DDI_SUCCESS) { 1233*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1234*9c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: " 1235*9c75c6bfSgovinda "FIXED interrupt registration failed\n"); 1236*9c75c6bfSgovinda 1237*9c75c6bfSgovinda return (DDI_FAILURE); 1238*9c75c6bfSgovinda } 1239*9c75c6bfSgovinda 1240*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12417c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: " 1242*9c75c6bfSgovinda "Using FIXED interrupt type\n"); 1243*9c75c6bfSgovinda 1244*9c75c6bfSgovinda ohcip->ohci_intr_type = DDI_INTR_TYPE_FIXED; 1245*9c75c6bfSgovinda ohcip->ohci_flags |= OHCI_INTR; 1246*9c75c6bfSgovinda } 1247*9c75c6bfSgovinda 1248*9c75c6bfSgovinda /* Create prototype for SOF condition variable */ 1249*9c75c6bfSgovinda cv_init(&ohcip->ohci_SOF_cv, NULL, CV_DRIVER, NULL); 1250*9c75c6bfSgovinda 1251*9c75c6bfSgovinda /* Semaphore to serialize opens and closes */ 1252*9c75c6bfSgovinda sema_init(&ohcip->ohci_ocsem, 1, NULL, SEMA_DRIVER, NULL); 1253*9c75c6bfSgovinda 1254*9c75c6bfSgovinda return (DDI_SUCCESS); 1255*9c75c6bfSgovinda } 1256*9c75c6bfSgovinda 1257*9c75c6bfSgovinda 1258*9c75c6bfSgovinda /* 1259*9c75c6bfSgovinda * ohci_add_intrs: 1260*9c75c6bfSgovinda * 1261*9c75c6bfSgovinda * Register FIXED or MSI interrupts. 1262*9c75c6bfSgovinda */ 1263*9c75c6bfSgovinda static int 1264*9c75c6bfSgovinda ohci_add_intrs(ohci_state_t *ohcip, 1265*9c75c6bfSgovinda int intr_type) 1266*9c75c6bfSgovinda { 1267*9c75c6bfSgovinda int actual, avail, intr_size, count = 0; 1268*9c75c6bfSgovinda int i, flag, ret; 1269*9c75c6bfSgovinda 1270*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1271*9c75c6bfSgovinda "ohci_add_intrs: interrupt type 0x%x", intr_type); 1272*9c75c6bfSgovinda 1273*9c75c6bfSgovinda /* Get number of interrupts */ 1274*9c75c6bfSgovinda ret = ddi_intr_get_nintrs(ohcip->ohci_dip, intr_type, &count); 1275*9c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) { 1276*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1277*9c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_nintrs() failure, " 1278*9c75c6bfSgovinda "ret: %d, count: %d", ret, count); 1279*9c75c6bfSgovinda 1280*9c75c6bfSgovinda return (DDI_FAILURE); 1281*9c75c6bfSgovinda } 1282*9c75c6bfSgovinda 1283*9c75c6bfSgovinda /* Get number of available interrupts */ 1284*9c75c6bfSgovinda ret = ddi_intr_get_navail(ohcip->ohci_dip, intr_type, &avail); 1285*9c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) { 1286*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1287*9c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_navail() failure, " 1288*9c75c6bfSgovinda "ret: %d, count: %d", ret, count); 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 1293*9c75c6bfSgovinda if (avail < count) { 1294*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1295*9c75c6bfSgovinda "ohci_add_intrs: ohci_add_intrs: nintrs () " 1296*9c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail); 1297*9c75c6bfSgovinda } 1298*9c75c6bfSgovinda 1299*9c75c6bfSgovinda /* Allocate an array of interrupt handles */ 1300*9c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t); 1301*9c75c6bfSgovinda ohcip->ohci_htable = kmem_zalloc(intr_size, KM_SLEEP); 1302*9c75c6bfSgovinda 1303*9c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ? 1304*9c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 1305*9c75c6bfSgovinda 1306*9c75c6bfSgovinda /* call ddi_intr_alloc() */ 13077c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ohcip->ohci_dip, ohcip->ohci_htable, 1308*9c75c6bfSgovinda intr_type, 0, count, &actual, flag); 13097c478bd9Sstevel@tonic-gate 1310*9c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) { 13117c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1312*9c75c6bfSgovinda "ohci_add_intrs: ddi_intr_alloc() failed %d", ret); 13137c478bd9Sstevel@tonic-gate 1314*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 1319*9c75c6bfSgovinda if (actual < count) { 1320*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1321*9c75c6bfSgovinda "ohci_add_intrs: Requested: %d, Received: %d\n", 1322*9c75c6bfSgovinda count, actual); 13237c478bd9Sstevel@tonic-gate 1324*9c75c6bfSgovinda for (i = 0; i < actual; i++) 1325*9c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 1326*9c75c6bfSgovinda 1327*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 1328*9c75c6bfSgovinda 1329*9c75c6bfSgovinda return (DDI_FAILURE); 1330*9c75c6bfSgovinda } 1331*9c75c6bfSgovinda 1332*9c75c6bfSgovinda ohcip->ohci_intr_cnt = actual; 1333*9c75c6bfSgovinda 1334*9c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ohcip->ohci_htable[0], 1335*9c75c6bfSgovinda &ohcip->ohci_intr_pri)) != DDI_SUCCESS) { 13367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1337*9c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_pri() failed %d", ret); 13387c478bd9Sstevel@tonic-gate 1339*9c75c6bfSgovinda for (i = 0; i < actual; i++) 1340*9c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 1341*9c75c6bfSgovinda 1342*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate 1347*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1348*9c75c6bfSgovinda "ohci_add_intrs: Supported Interrupt priority 0x%x", 1349*9c75c6bfSgovinda ohcip->ohci_intr_pri); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 13527c478bd9Sstevel@tonic-gate if (ohcip->ohci_intr_pri >= ddi_intr_get_hilevel_pri()) { 13537c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1354*9c75c6bfSgovinda "ohci_add_intrs: Hi level interrupt not supported"); 1355*9c75c6bfSgovinda 1356*9c75c6bfSgovinda for (i = 0; i < actual; i++) 1357*9c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 13587c478bd9Sstevel@tonic-gate 1359*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 13657c478bd9Sstevel@tonic-gate mutex_init(&ohcip->ohci_int_mutex, NULL, MUTEX_DRIVER, 1366a195726fSgovinda DDI_INTR_PRI(ohcip->ohci_intr_pri)); 13677c478bd9Sstevel@tonic-gate 1368*9c75c6bfSgovinda /* Call ddi_intr_add_handler() */ 1369*9c75c6bfSgovinda for (i = 0; i < actual; i++) { 1370*9c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ohcip->ohci_htable[i], 1371*9c75c6bfSgovinda ohci_intr, (caddr_t)ohcip, 1372*9c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 1373*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1374*9c75c6bfSgovinda "ohci_add_intrs: ddi_intr_add_handler() " 1375*9c75c6bfSgovinda "failed %d", ret); 13767c478bd9Sstevel@tonic-gate 1377*9c75c6bfSgovinda for (i = 0; i < actual; i++) 1378*9c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 13797c478bd9Sstevel@tonic-gate 1380*9c75c6bfSgovinda mutex_destroy(&ohcip->ohci_int_mutex); 1381*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 1382*9c75c6bfSgovinda 1383*9c75c6bfSgovinda return (DDI_FAILURE); 1384*9c75c6bfSgovinda } 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 1387*9c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ohcip->ohci_htable[0], 1388*9c75c6bfSgovinda &ohcip->ohci_intr_cap)) != DDI_SUCCESS) { 13897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1390*9c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_cap() failed %d", ret); 1391*9c75c6bfSgovinda 1392*9c75c6bfSgovinda for (i = 0; i < actual; i++) { 1393*9c75c6bfSgovinda (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]); 1394*9c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 1395*9c75c6bfSgovinda } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate mutex_destroy(&ohcip->ohci_int_mutex); 1398*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate 1403*9c75c6bfSgovinda /* Enable all interrupts */ 1404*9c75c6bfSgovinda if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) { 1405*9c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */ 1406*9c75c6bfSgovinda (void) ddi_intr_block_enable(ohcip->ohci_htable, 1407*9c75c6bfSgovinda ohcip->ohci_intr_cnt); 1408*9c75c6bfSgovinda } else { 1409*9c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */ 1410*9c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) 1411*9c75c6bfSgovinda (void) ddi_intr_enable(ohcip->ohci_htable[i]); 1412*9c75c6bfSgovinda } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * ohci_init_ctlr: 14207c478bd9Sstevel@tonic-gate * 14217c478bd9Sstevel@tonic-gate * Initialize the Host Controller (HC). 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate static int 14247c478bd9Sstevel@tonic-gate ohci_init_ctlr(ohci_state_t *ohcip) 14257c478bd9Sstevel@tonic-gate { 14267c478bd9Sstevel@tonic-gate int revision, curr_control, max_packet = 0; 14277c478bd9Sstevel@tonic-gate clock_t sof_time_wait; 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_ctlr:"); 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate if (ohci_take_control(ohcip) != DDI_SUCCESS) { 14327c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14337c478bd9Sstevel@tonic-gate "ohci_init_ctlr: ohci_take_control failed\n"); 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate /* 14397c478bd9Sstevel@tonic-gate * Soft reset the host controller. 14407c478bd9Sstevel@tonic-gate * 14417c478bd9Sstevel@tonic-gate * On soft reset, the ohci host controller moves to the 14427c478bd9Sstevel@tonic-gate * USB Suspend state in which most of the ohci operational 14437c478bd9Sstevel@tonic-gate * registers are reset except stated ones. The soft reset 14447c478bd9Sstevel@tonic-gate * doesn't cause a reset to the ohci root hub and even no 14457c478bd9Sstevel@tonic-gate * subsequent reset signaling should be asserterd to its 14467c478bd9Sstevel@tonic-gate * down stream. 14477c478bd9Sstevel@tonic-gate */ 14487c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET); 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 14517c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESET_TIMEWAIT); 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate /* 14547c478bd9Sstevel@tonic-gate * Do hard reset the host controller. 14557c478bd9Sstevel@tonic-gate * 14567c478bd9Sstevel@tonic-gate * Now perform USB reset in order to reset the ohci root 14577c478bd9Sstevel@tonic-gate * hub. 14587c478bd9Sstevel@tonic-gate */ 14597c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, HCR_CONTROL_RESET); 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate /* 14627c478bd9Sstevel@tonic-gate * According to Section 5.1.2.3 of the specification, the 14637c478bd9Sstevel@tonic-gate * host controller will go into suspend state immediately 14647c478bd9Sstevel@tonic-gate * after the reset. 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* Verify the version number */ 14687c478bd9Sstevel@tonic-gate revision = Get_OpReg(hcr_revision); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if ((revision & HCR_REVISION_MASK) != HCR_REVISION_1_0) { 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14767c478bd9Sstevel@tonic-gate "ohci_init_ctlr: Revision verified"); 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* hcca area need not be initialized on resume */ 14797c478bd9Sstevel@tonic-gate if (ohcip->ohci_hc_soft_state == OHCI_CTLR_INIT_STATE) { 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate /* Get the ohci chip vendor and device id */ 14827c478bd9Sstevel@tonic-gate ohcip->ohci_vendor_id = pci_config_get16( 14837c478bd9Sstevel@tonic-gate ohcip->ohci_config_handle, PCI_CONF_VENID); 14847c478bd9Sstevel@tonic-gate ohcip->ohci_device_id = pci_config_get16( 14857c478bd9Sstevel@tonic-gate ohcip->ohci_config_handle, PCI_CONF_DEVID); 14867c478bd9Sstevel@tonic-gate ohcip->ohci_rev_id = pci_config_get8( 14877c478bd9Sstevel@tonic-gate ohcip->ohci_config_handle, PCI_CONF_REVID); 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate /* Initialize the hcca area */ 14907c478bd9Sstevel@tonic-gate if (ohci_init_hcca(ohcip) != DDI_SUCCESS) { 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate 1496f806f48bShs /* 1497f806f48bShs * Workaround for ULI1575 chipset. Following OHCI Operational Memory 1498f806f48bShs * Registers are not cleared to their default value on reset. 1499f806f48bShs * Explicitly set the registers to default value. 1500f806f48bShs */ 1501f806f48bShs if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID && 1502f806f48bShs ohcip->ohci_device_id == PCI_ULI1575_DEVID) { 1503f806f48bShs Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT); 1504f806f48bShs Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT); 1505f806f48bShs Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT); 1506f806f48bShs Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT); 1507f806f48bShs Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT); 1508f806f48bShs Set_OpReg(hcr_frame_interval, HCR_FRAME_INTERVAL_DEFAULT); 1509f806f48bShs Set_OpReg(hcr_periodic_strt, HCR_PERIODIC_START_DEFAULT); 1510f806f48bShs } 1511f806f48bShs 15127c478bd9Sstevel@tonic-gate /* Set the HcHCCA to the physical address of the HCCA block */ 15137c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, (uint_t)ohcip->ohci_hcca_cookie.dmac_address); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except Root 15177c478bd9Sstevel@tonic-gate * Hub Status change and SOF interrupts. 15187c478bd9Sstevel@tonic-gate */ 15197c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SO | HCR_INTR_WDH | 15207c478bd9Sstevel@tonic-gate HCR_INTR_RD | HCR_INTR_UE | HCR_INTR_FNO | HCR_INTR_MIE); 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * For non-periodic transfers, reserve atleast for one low-speed 15247c478bd9Sstevel@tonic-gate * device transaction. According to USB Bandwidth Analysis white 15257c478bd9Sstevel@tonic-gate * paper and also as per OHCI Specification 1.0a, section 7.3.5, 15267c478bd9Sstevel@tonic-gate * page 123, one low-speed transaction takes 0x628h full speed 15277c478bd9Sstevel@tonic-gate * bits (197 bytes), which comes to around 13% of USB frame time. 15287c478bd9Sstevel@tonic-gate * 15297c478bd9Sstevel@tonic-gate * The periodic transfers will get around 87% of USB frame time. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_strt, 15327c478bd9Sstevel@tonic-gate ((PERIODIC_XFER_STARTS * BITS_PER_BYTE) - 1)); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* Save the contents of the Frame Interval Registers */ 15357c478bd9Sstevel@tonic-gate ohcip->ohci_frame_interval = Get_OpReg(hcr_frame_interval); 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate * Initialize the FSLargestDataPacket value in the frame interval 15397c478bd9Sstevel@tonic-gate * register. The controller compares the value of MaxPacketSize to 15407c478bd9Sstevel@tonic-gate * this value to see if the entire packet may be sent out before 15417c478bd9Sstevel@tonic-gate * the EOF. 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate max_packet = ((((ohcip->ohci_frame_interval - 15447c478bd9Sstevel@tonic-gate MAX_OVERHEAD) * 6) / 7) << HCR_FRME_FSMPS_SHFT); 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate Set_OpReg(hcr_frame_interval, 15477c478bd9Sstevel@tonic-gate (max_packet | ohcip->ohci_frame_interval)); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate /* Begin sending SOFs */ 15507c478bd9Sstevel@tonic-gate curr_control = Get_OpReg(hcr_control); 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 15537c478bd9Sstevel@tonic-gate "ohci_init_ctlr: curr_control=0x%x", curr_control); 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate /* Set the state to operational */ 15567c478bd9Sstevel@tonic-gate curr_control = (curr_control & 15577c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_OPERAT; 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, curr_control); 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate ASSERT((Get_OpReg(hcr_control) & 15627c478bd9Sstevel@tonic-gate HCR_CONTROL_HCFS) == HCR_CONTROL_OPERAT); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */ 15657c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_OPERATIONAL_STATE; 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 15687c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz(OHCI_MAX_SOF_TIMEWAIT * 1000000); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate /* Clear ohci_sof_flag indicating waiting for SOF interrupt */ 15717c478bd9Sstevel@tonic-gate ohcip->ohci_sof_flag = B_FALSE; 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */ 15747c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF); 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_intr_enable) & HCR_INTR_SOF); 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ohcip->ohci_SOF_cv, 15797c478bd9Sstevel@tonic-gate &ohcip->ohci_int_mutex, ddi_get_lbolt() + sof_time_wait); 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate /* Wait for the SOF or timeout event */ 15827c478bd9Sstevel@tonic-gate if (ohcip->ohci_sof_flag == B_FALSE) { 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 15857c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_ERROR_STATE; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 15887c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB OHCI host" 15897c478bd9Sstevel@tonic-gate "controller is unusable"); 15907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 15947c478bd9Sstevel@tonic-gate "ohci_init_ctlr: SOF's have started"); 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * ohci_init_hcca: 16027c478bd9Sstevel@tonic-gate * 16037c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller Communication 16047c478bd9Sstevel@tonic-gate * Area (HCCA). The HCCA structure must be aligned to a 256-byte boundary. 16057c478bd9Sstevel@tonic-gate */ 16067c478bd9Sstevel@tonic-gate static int 16077c478bd9Sstevel@tonic-gate ohci_init_hcca(ohci_state_t *ohcip) 16087c478bd9Sstevel@tonic-gate { 16097c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 16107c478bd9Sstevel@tonic-gate size_t real_length; 16117c478bd9Sstevel@tonic-gate uint_t mask, ccount; 16127c478bd9Sstevel@tonic-gate int result; 16137c478bd9Sstevel@tonic-gate uintptr_t addr; 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_hcca:"); 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 16207c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 16217c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 16227c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* Byte alignment to HCCA alignment */ 16257c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_HCCA_ALIGNMENT; 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate /* Create space for the HCCA block */ 16287c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, &ohcip->ohci_dma_attr, 16297c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 16307c478bd9Sstevel@tonic-gate 0, 16317c478bd9Sstevel@tonic-gate &ohcip->ohci_hcca_dma_handle) 16327c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_hcca_dma_handle, 16387c478bd9Sstevel@tonic-gate 2 * sizeof (ohci_hcca_t), 16397c478bd9Sstevel@tonic-gate &dev_attr, 16407c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 16417c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 16427c478bd9Sstevel@tonic-gate 0, 16437c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_hccap, 16447c478bd9Sstevel@tonic-gate &real_length, 16457c478bd9Sstevel@tonic-gate &ohcip->ohci_hcca_mem_handle)) { 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_hccap, real_length); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* Figure out the alignment requirements */ 16537c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, 0xFFFFFFFF); 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* 16567c478bd9Sstevel@tonic-gate * Read the hcr_HCCA register until 16577c478bd9Sstevel@tonic-gate * contenets are non-zero. 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate mask = Get_OpReg(hcr_HCCA); 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate while (mask == 0) { 16627c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 16637c478bd9Sstevel@tonic-gate mask = Get_OpReg(hcr_HCCA); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate ASSERT(mask != 0); 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate addr = (uintptr_t)ohcip->ohci_hccap; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16717c478bd9Sstevel@tonic-gate "ohci_init_hcca: addr=0x%lx, mask=0x%x", addr, mask); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate while (addr & (~mask)) { 16747c478bd9Sstevel@tonic-gate addr++; 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate ohcip->ohci_hccap = (ohci_hcca_t *)addr; 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16807c478bd9Sstevel@tonic-gate "ohci_init_hcca: Real length %lu", real_length); 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16837c478bd9Sstevel@tonic-gate "ohci_init_hcca: virtual hcca 0x%p", (void *)ohcip->ohci_hccap); 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* Map the whole HCCA into the I/O address space */ 16867c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ohcip->ohci_hcca_dma_handle, 16877c478bd9Sstevel@tonic-gate NULL, 16887c478bd9Sstevel@tonic-gate (caddr_t)ohcip->ohci_hccap, 16897c478bd9Sstevel@tonic-gate real_length, 16907c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 16917c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 16927c478bd9Sstevel@tonic-gate &ohcip->ohci_hcca_cookie, 16937c478bd9Sstevel@tonic-gate &ccount); 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 16967c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 16977c478bd9Sstevel@tonic-gate if (ccount != 1) { 16987c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16997c478bd9Sstevel@tonic-gate "ohci_init_hcca: More than 1 cookie"); 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate } else { 17047c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17096d9a41ffSqz /* 17106d9a41ffSqz * DMA addresses for HCCA are bound 17116d9a41ffSqz */ 17126d9a41ffSqz ohcip->ohci_dma_addr_bind_flag |= OHCI_HCCA_DMA_BOUND; 17136d9a41ffSqz 17147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17157c478bd9Sstevel@tonic-gate "ohci_init_hcca: physical 0x%p", 17167c478bd9Sstevel@tonic-gate (void *)(uintptr_t)ohcip->ohci_hcca_cookie.dmac_address); 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17197c478bd9Sstevel@tonic-gate "ohci_init_hcca: size %lu", ohcip->ohci_hcca_cookie.dmac_size); 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate /* Initialize the interrupt lists */ 17227c478bd9Sstevel@tonic-gate ohci_build_interrupt_lattice(ohcip); 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17257c478bd9Sstevel@tonic-gate "ohci_init_hcca: End"); 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate /* 17327c478bd9Sstevel@tonic-gate * ohci_build_interrupt_lattice: 17337c478bd9Sstevel@tonic-gate * 17347c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 17357c478bd9Sstevel@tonic-gate * (ED). This interrupt lattice tree will have total of 32 interrupt ED 17367c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt ED list in 17377c478bd9Sstevel@tonic-gate * every frame. The lower five bits of the current frame number indexes 17387c478bd9Sstevel@tonic-gate * into an array of 32 interrupt Endpoint Descriptor lists found in the 17397c478bd9Sstevel@tonic-gate * HCCA. 17407c478bd9Sstevel@tonic-gate */ 17417c478bd9Sstevel@tonic-gate static void 17427c478bd9Sstevel@tonic-gate ohci_build_interrupt_lattice(ohci_state_t *ohcip) 17437c478bd9Sstevel@tonic-gate { 17447c478bd9Sstevel@tonic-gate ohci_ed_t *list_array = ohcip->ohci_ed_pool_addr; 17457c478bd9Sstevel@tonic-gate int half_list = NUM_INTR_ED_LISTS / 2; 17467c478bd9Sstevel@tonic-gate ohci_hcca_t *hccap = ohcip->ohci_hccap; 17477c478bd9Sstevel@tonic-gate uintptr_t addr; 17487c478bd9Sstevel@tonic-gate int i; 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17517c478bd9Sstevel@tonic-gate "ohci_build_interrupt_lattice:"); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * Reserve the first 31 Endpoint Descriptor (ED) structures 17557c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 17567c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_STATIC_NODES; i++) { 17597c478bd9Sstevel@tonic-gate Set_ED(list_array[i].hced_ctrl, HC_EPT_sKip); 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate Set_ED(list_array[i].hced_state, HC_EPT_STATIC); 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 17657c478bd9Sstevel@tonic-gate for (i = 0; i < half_list - 1; i++) { 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate /* 17687c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 17697c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 17707c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 17717c478bd9Sstevel@tonic-gate * starting iommu address. 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate addr = ohci_ed_cpu_to_iommu(ohcip, (ohci_ed_t *)&list_array[i]); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate Set_ED(list_array[2*i + 1].hced_next, addr); 17767c478bd9Sstevel@tonic-gate Set_ED(list_array[2*i + 2].hced_next, addr); 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate /* 17807c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the HCCA so that it points 17817c478bd9Sstevel@tonic-gate * to the bottom of the tree. 17827c478bd9Sstevel@tonic-gate */ 17837c478bd9Sstevel@tonic-gate for (i = 0; i < half_list; i++) { 17847c478bd9Sstevel@tonic-gate addr = ohci_ed_cpu_to_iommu(ohcip, 17857c478bd9Sstevel@tonic-gate (ohci_ed_t *)&list_array[half_list - 1 + ohci_index[i]]); 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate ASSERT(Get_ED(list_array[half_list - 1 + 17887c478bd9Sstevel@tonic-gate ohci_index[i]].hced_ctrl)); 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate ASSERT(addr != 0); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate Set_HCCA(hccap->HccaIntTble[i], addr); 17937c478bd9Sstevel@tonic-gate Set_HCCA(hccap->HccaIntTble[i + half_list], addr); 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate /* 17997c478bd9Sstevel@tonic-gate * ohci_take_control: 18007c478bd9Sstevel@tonic-gate * 18017c478bd9Sstevel@tonic-gate * Take control of the host controller. OpenHCI allows for optional support 18027c478bd9Sstevel@tonic-gate * of legacy devices through the use of System Management Mode software and 18037c478bd9Sstevel@tonic-gate * system Management interrupt hardware. See section 5.1.1.3 of the OpenHCI 18047c478bd9Sstevel@tonic-gate * spec for more details. 18057c478bd9Sstevel@tonic-gate */ 18067c478bd9Sstevel@tonic-gate static int 18077c478bd9Sstevel@tonic-gate ohci_take_control(ohci_state_t *ohcip) 18087c478bd9Sstevel@tonic-gate { 18097c478bd9Sstevel@tonic-gate #if defined(__x86) 18107c478bd9Sstevel@tonic-gate uint32_t hcr_control_val; 18117c478bd9Sstevel@tonic-gate uint32_t hcr_cmd_status_val; 18127c478bd9Sstevel@tonic-gate int wait; 18137c478bd9Sstevel@tonic-gate #endif /* __x86 */ 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18167c478bd9Sstevel@tonic-gate "ohci_take_control:"); 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate #if defined(__x86) 18197c478bd9Sstevel@tonic-gate /* 18207c478bd9Sstevel@tonic-gate * On x86, we must tell the BIOS we want the controller, 18217c478bd9Sstevel@tonic-gate * and wait for it to respond that we can have it. 18227c478bd9Sstevel@tonic-gate */ 18237c478bd9Sstevel@tonic-gate hcr_control_val = Get_OpReg(hcr_control); 18247c478bd9Sstevel@tonic-gate if ((hcr_control_val & HCR_CONTROL_IR) == 0) { 18257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18267c478bd9Sstevel@tonic-gate "ohci_take_control: InterruptRouting off\n"); 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* attempt the OwnershipChange request */ 18327c478bd9Sstevel@tonic-gate hcr_cmd_status_val = Get_OpReg(hcr_cmd_status); 18337c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18347c478bd9Sstevel@tonic-gate "ohci_take_control: hcr_cmd_status: 0x%x\n", 18357c478bd9Sstevel@tonic-gate hcr_cmd_status_val); 18367c478bd9Sstevel@tonic-gate hcr_cmd_status_val |= HCR_STATUS_OCR; 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, hcr_cmd_status_val); 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate /* now wait for 5 seconds for InterruptRouting to go away */ 18417c478bd9Sstevel@tonic-gate for (wait = 0; wait < 5000; wait++) { 18427c478bd9Sstevel@tonic-gate if ((Get_OpReg(hcr_control) & HCR_CONTROL_IR) == 0) 18437c478bd9Sstevel@tonic-gate break; 18447c478bd9Sstevel@tonic-gate drv_usecwait(1000); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate if (wait >= 5000) { 18477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18487c478bd9Sstevel@tonic-gate "ohci_take_control: couldn't take control from BIOS\n"); 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate #else /* __x86 */ 18537c478bd9Sstevel@tonic-gate /* 18547c478bd9Sstevel@tonic-gate * On Sparc, there won't be special System Management Mode 18557c478bd9Sstevel@tonic-gate * hardware for legacy devices, while the x86 platforms may 18567c478bd9Sstevel@tonic-gate * have to deal with this. This function may be platform 18577c478bd9Sstevel@tonic-gate * specific. 18587c478bd9Sstevel@tonic-gate * 18597c478bd9Sstevel@tonic-gate * The interrupt routing bit should not be set. 18607c478bd9Sstevel@tonic-gate */ 18617c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_control) & HCR_CONTROL_IR) { 18627c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18637c478bd9Sstevel@tonic-gate "ohci_take_control: Routing bit set"); 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate #endif /* __x86 */ 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18707c478bd9Sstevel@tonic-gate "ohci_take_control: End"); 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18754610e4a0Sfrits /* 18764610e4a0Sfrits * ohci_pm_support: 18774610e4a0Sfrits * always return success since PM has been quite reliable on ohci 18784610e4a0Sfrits */ 18794610e4a0Sfrits /*ARGSUSED*/ 18804610e4a0Sfrits int 18814610e4a0Sfrits ohci_hcdi_pm_support(dev_info_t *dip) 18824610e4a0Sfrits { 18834610e4a0Sfrits return (USB_SUCCESS); 18844610e4a0Sfrits } 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate /* 18877c478bd9Sstevel@tonic-gate * ohci_alloc_hcdi_ops: 18887c478bd9Sstevel@tonic-gate * 18897c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 18907c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 18917c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 18927c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 18937c478bd9Sstevel@tonic-gate */ 18947c478bd9Sstevel@tonic-gate static usba_hcdi_ops_t * 18957c478bd9Sstevel@tonic-gate ohci_alloc_hcdi_ops(ohci_state_t *ohcip) 18967c478bd9Sstevel@tonic-gate { 18977c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19007c478bd9Sstevel@tonic-gate "ohci_alloc_hcdi_ops:"); 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 19057c478bd9Sstevel@tonic-gate 19064610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ohci_hcdi_pm_support; 19077c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ohci_hcdi_pipe_open; 19087c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ohci_hcdi_pipe_close; 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ohci_hcdi_pipe_reset; 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ohci_hcdi_pipe_ctrl_xfer; 19137c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ohci_hcdi_pipe_bulk_xfer; 19147c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ohci_hcdi_pipe_intr_xfer; 19157c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ohci_hcdi_pipe_isoc_xfer; 19167c478bd9Sstevel@tonic-gate 19177c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 19187c478bd9Sstevel@tonic-gate ohci_hcdi_bulk_transfer_size; 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 19217c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_intr_polling; 19227c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 19237c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_isoc_polling; 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 19267c478bd9Sstevel@tonic-gate ohci_hcdi_get_current_frame_number; 19277c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 19287c478bd9Sstevel@tonic-gate ohci_hcdi_get_max_isoc_pkts; 19297c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 19307c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_init; 19317c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 19327c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_enter; 19337c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = ohci_hcdi_polled_read; 19347c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 19357c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_exit; 19367c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 19377c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_fini; 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate 19437c478bd9Sstevel@tonic-gate /* 19447c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 19457c478bd9Sstevel@tonic-gate */ 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate /* 19487c478bd9Sstevel@tonic-gate * ohci_cleanup: 19497c478bd9Sstevel@tonic-gate * 19507c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 19517c478bd9Sstevel@tonic-gate */ 19527c478bd9Sstevel@tonic-gate static int 19537c478bd9Sstevel@tonic-gate ohci_cleanup(ohci_state_t *ohcip) 19547c478bd9Sstevel@tonic-gate { 19557c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 19567c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 19577c478bd9Sstevel@tonic-gate ohci_td_t *td; 19587c478bd9Sstevel@tonic-gate int i, state, rval; 19597c478bd9Sstevel@tonic-gate int flags = ohcip->ohci_flags; 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_cleanup:"); 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate if (flags & OHCI_RHREG) { 19647c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 19657c478bd9Sstevel@tonic-gate if (ohci_unload_root_hub_driver(ohcip) != USB_SUCCESS) { 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate } 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate if (flags & OHCI_USBAREG) { 19727c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 19737c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ohcip->ohci_dip); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate if (flags & OHCI_INTR) { 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate /* Disable all HC ED list processing */ 19817c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 19827c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE | 19837c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE))); 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate /* Disable all HC interrupts */ 19867c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, 19877c478bd9Sstevel@tonic-gate (HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE)); 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 19907c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip); 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate /* Disable Master and SOF interrupts */ 19937c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, (HCR_INTR_MIE | HCR_INTR_SOF)); 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate /* Set the Host Controller Functional State to Reset */ 19967c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) & 19977c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESET)); 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate /* Wait for sometime */ 20007c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 20017c478bd9Sstevel@tonic-gate 2002f806f48bShs /* 2003f806f48bShs * Workaround for ULI1575 chipset. Following OHCI Operational 2004f806f48bShs * Memory Registers are not cleared to their default value 2005f806f48bShs * on reset. Explicitly set the registers to default value. 2006f806f48bShs */ 2007f806f48bShs if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID && 2008f806f48bShs ohcip->ohci_device_id == PCI_ULI1575_DEVID) { 2009f806f48bShs Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT); 2010f806f48bShs Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT); 2011f806f48bShs Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT); 2012f806f48bShs Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT); 2013f806f48bShs Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT); 2014f806f48bShs Set_OpReg(hcr_frame_interval, 2015f806f48bShs HCR_FRAME_INTERVAL_DEFAULT); 2016f806f48bShs Set_OpReg(hcr_periodic_strt, 2017f806f48bShs HCR_PERIODIC_START_DEFAULT); 2018f806f48bShs } 2019f806f48bShs 20207c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 20217c478bd9Sstevel@tonic-gate 2022*9c75c6bfSgovinda ohci_rem_intrs(ohcip); 20237c478bd9Sstevel@tonic-gate } 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate /* Unmap the OHCI registers */ 20267c478bd9Sstevel@tonic-gate if (ohcip->ohci_regs_handle) { 20277c478bd9Sstevel@tonic-gate /* Reset the host controller */ 20287c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET); 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ohcip->ohci_regs_handle); 20317c478bd9Sstevel@tonic-gate } 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate if (ohcip->ohci_config_handle) { 20347c478bd9Sstevel@tonic-gate pci_config_teardown(&ohcip->ohci_config_handle); 20357c478bd9Sstevel@tonic-gate } 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate /* Free all the buffers */ 20387c478bd9Sstevel@tonic-gate if (ohcip->ohci_td_pool_addr && ohcip->ohci_td_pool_mem_handle) { 20397c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) { 20407c478bd9Sstevel@tonic-gate td = &ohcip->ohci_td_pool_addr[i]; 20417c478bd9Sstevel@tonic-gate state = Get_TD(ohcip->ohci_td_pool_addr[i].hctd_state); 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate if ((state != HC_TD_FREE) && (state != HC_TD_DUMMY) && 20447c478bd9Sstevel@tonic-gate (td->hctd_trans_wrapper)) { 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 20497c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t) 20507c478bd9Sstevel@tonic-gate Get_TD(td->hctd_trans_wrapper)); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 20537c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 20567c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, 20577c478bd9Sstevel@tonic-gate OHCI_REMOVE_XFER_ALWAYS); 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate /* 20667c478bd9Sstevel@tonic-gate * If OHCI_TD_POOL_BOUND flag is set, then unbind 20677c478bd9Sstevel@tonic-gate * the handle for TD pools. 20687c478bd9Sstevel@tonic-gate */ 20697c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag & 20707c478bd9Sstevel@tonic-gate OHCI_TD_POOL_BOUND) == OHCI_TD_POOL_BOUND) { 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 20737c478bd9Sstevel@tonic-gate ohcip->ohci_td_pool_dma_handle); 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_td_pool_mem_handle); 20787c478bd9Sstevel@tonic-gate } 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate /* Free the TD pool */ 20817c478bd9Sstevel@tonic-gate if (ohcip->ohci_td_pool_dma_handle) { 20827c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_td_pool_dma_handle); 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate if (ohcip->ohci_ed_pool_addr && ohcip->ohci_ed_pool_mem_handle) { 20867c478bd9Sstevel@tonic-gate /* 20877c478bd9Sstevel@tonic-gate * If OHCI_ED_POOL_BOUND flag is set, then unbind 20887c478bd9Sstevel@tonic-gate * the handle for ED pools. 20897c478bd9Sstevel@tonic-gate */ 20907c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag & 20917c478bd9Sstevel@tonic-gate OHCI_ED_POOL_BOUND) == OHCI_ED_POOL_BOUND) { 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 20947c478bd9Sstevel@tonic-gate ohcip->ohci_ed_pool_dma_handle); 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_ed_pool_mem_handle); 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate /* Free the ED pool */ 21037c478bd9Sstevel@tonic-gate if (ohcip->ohci_ed_pool_dma_handle) { 21047c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_ed_pool_dma_handle); 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate /* Free the HCCA area */ 21087c478bd9Sstevel@tonic-gate if (ohcip->ohci_hccap && ohcip->ohci_hcca_mem_handle) { 21097c478bd9Sstevel@tonic-gate /* 21107c478bd9Sstevel@tonic-gate * If OHCI_HCCA_DMA_BOUND flag is set, then unbind 21117c478bd9Sstevel@tonic-gate * the handle for HCCA. 21127c478bd9Sstevel@tonic-gate */ 21137c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag & 21147c478bd9Sstevel@tonic-gate OHCI_HCCA_DMA_BOUND) == OHCI_HCCA_DMA_BOUND) { 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 21177c478bd9Sstevel@tonic-gate ohcip->ohci_hcca_dma_handle); 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate 21227c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_hcca_mem_handle); 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate if (ohcip->ohci_hcca_dma_handle) { 21267c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_hcca_dma_handle); 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate if (flags & OHCI_INTR) { 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 21327c478bd9Sstevel@tonic-gate mutex_destroy(&ohcip->ohci_int_mutex); 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate /* Destroy the SOF condition varibale */ 21357c478bd9Sstevel@tonic-gate cv_destroy(&ohcip->ohci_SOF_cv); 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* Destroy the serialize opens and closes semaphore */ 21387c478bd9Sstevel@tonic-gate sema_destroy(&ohcip->ohci_ocsem); 21397c478bd9Sstevel@tonic-gate } 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 21427c478bd9Sstevel@tonic-gate ohci_destroy_stats(ohcip); 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate /* Free ohci hcdi ops */ 21457c478bd9Sstevel@tonic-gate if (ohcip->ohci_hcdi_ops) { 21467c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ohcip->ohci_hcdi_ops); 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate if (flags & OHCI_ZALLOC) { 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate usb_free_log_hdl(ohcip->ohci_log_hdl); 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 21547c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ohcip->ohci_dip); 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate /* Free the soft state */ 21577c478bd9Sstevel@tonic-gate ddi_soft_state_free(ohci_statep, 21587c478bd9Sstevel@tonic-gate ddi_get_instance(ohcip->ohci_dip)); 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate 2165*9c75c6bfSgovinda /* 2166*9c75c6bfSgovinda * ohci_rem_intrs: 2167*9c75c6bfSgovinda * 2168*9c75c6bfSgovinda * Unregister FIXED or MSI interrupts 2169*9c75c6bfSgovinda */ 2170*9c75c6bfSgovinda static void 2171*9c75c6bfSgovinda ohci_rem_intrs(ohci_state_t *ohcip) 2172*9c75c6bfSgovinda { 2173*9c75c6bfSgovinda int i; 2174*9c75c6bfSgovinda 2175*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 2176*9c75c6bfSgovinda "ohci_rem_intrs: interrupt type 0x%x", ohcip->ohci_intr_type); 2177*9c75c6bfSgovinda 2178*9c75c6bfSgovinda /* Disable all interrupts */ 2179*9c75c6bfSgovinda if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) { 2180*9c75c6bfSgovinda (void) ddi_intr_block_disable(ohcip->ohci_htable, 2181*9c75c6bfSgovinda ohcip->ohci_intr_cnt); 2182*9c75c6bfSgovinda } else { 2183*9c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) { 2184*9c75c6bfSgovinda (void) ddi_intr_disable(ohcip->ohci_htable[i]); 2185*9c75c6bfSgovinda } 2186*9c75c6bfSgovinda } 2187*9c75c6bfSgovinda 2188*9c75c6bfSgovinda /* Call ddi_intr_remove_handler() */ 2189*9c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) { 2190*9c75c6bfSgovinda (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]); 2191*9c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 2192*9c75c6bfSgovinda } 2193*9c75c6bfSgovinda 2194*9c75c6bfSgovinda kmem_free(ohcip->ohci_htable, 2195*9c75c6bfSgovinda ohcip->ohci_intr_cnt * sizeof (ddi_intr_handle_t)); 2196*9c75c6bfSgovinda } 2197*9c75c6bfSgovinda 2198*9c75c6bfSgovinda 21997c478bd9Sstevel@tonic-gate /* 22007c478bd9Sstevel@tonic-gate * ohci_cpr_suspend 22017c478bd9Sstevel@tonic-gate */ 22027c478bd9Sstevel@tonic-gate static int 22037c478bd9Sstevel@tonic-gate ohci_cpr_suspend(ohci_state_t *ohcip) 22047c478bd9Sstevel@tonic-gate { 22057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22067c478bd9Sstevel@tonic-gate "ohci_cpr_suspend:"); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 22097c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ohcip->ohci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 22127c478bd9Sstevel@tonic-gate } 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 22157c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_pipe_count > 1) { 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22207c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: fails as open pipe count = %d", 22217c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count); 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 22247c478bd9Sstevel@tonic-gate 22257c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 22267c478bd9Sstevel@tonic-gate } 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22297c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable HC ED list processing"); 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate /* Disable all HC ED list processing */ 22327c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE | 22337c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE))); 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22367c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable HC interrupts"); 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* Disable all HC interrupts */ 22397c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, ~(HCR_INTR_MIE|HCR_INTR_SOF)); 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22427c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Wait for the next SOF"); 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 22457c478bd9Sstevel@tonic-gate if (ohci_wait_for_sof(ohcip) != USB_SUCCESS) { 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22487c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: ohci host controller suspend failed"); 22497c478bd9Sstevel@tonic-gate 22507c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 22517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 22527c478bd9Sstevel@tonic-gate } 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22557c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable Master interrupt"); 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate /* 22587c478bd9Sstevel@tonic-gate * Disable Master interrupt so that ohci driver don't 22597c478bd9Sstevel@tonic-gate * get any ohci interrupts. 22607c478bd9Sstevel@tonic-gate */ 22617c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE); 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate /* 22647c478bd9Sstevel@tonic-gate * Suspend the ohci host controller 22657c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 22667c478bd9Sstevel@tonic-gate */ 22677c478bd9Sstevel@tonic-gate if (ohcip->ohci_polled_kbd_count == 0) { 22687c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, HCR_CONTROL_SUSPD); 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate 22717c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 22727c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_SUSPEND_STATE; 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate /* 22817c478bd9Sstevel@tonic-gate * ohci_cpr_resume 22827c478bd9Sstevel@tonic-gate */ 22837c478bd9Sstevel@tonic-gate static int 22847c478bd9Sstevel@tonic-gate ohci_cpr_resume(ohci_state_t *ohcip) 22857c478bd9Sstevel@tonic-gate { 22867c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22897c478bd9Sstevel@tonic-gate "ohci_cpr_resume: Restart the controller"); 22907c478bd9Sstevel@tonic-gate 22917c478bd9Sstevel@tonic-gate /* Cleanup ohci specific information across cpr */ 22927c478bd9Sstevel@tonic-gate ohci_cpr_cleanup(ohcip); 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate /* Restart the controller */ 22957c478bd9Sstevel@tonic-gate if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) { 22967c478bd9Sstevel@tonic-gate 22977c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22987c478bd9Sstevel@tonic-gate "ohci_cpr_resume: ohci host controller resume failed "); 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 23087c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ohcip->ohci_dip, DDI_RESUME) != DDI_SUCCESS) { 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 23147c478bd9Sstevel@tonic-gate } 23157c478bd9Sstevel@tonic-gate 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate /* 23187c478bd9Sstevel@tonic-gate * HCDI entry points 23197c478bd9Sstevel@tonic-gate * 23207c478bd9Sstevel@tonic-gate * The Host Controller Driver Interfaces (HCDI) are the software interfaces 23217c478bd9Sstevel@tonic-gate * between the Universal Serial Bus Layer (USBA) and the Host Controller 23227c478bd9Sstevel@tonic-gate * Driver (HCD). The HCDI interfaces or entry points are subject to change. 23237c478bd9Sstevel@tonic-gate */ 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate /* 23267c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_open: 23277c478bd9Sstevel@tonic-gate * 23287c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during client specific pipe open 23297c478bd9Sstevel@tonic-gate * Add the pipe to the data structure representing the device and allocate 23307c478bd9Sstevel@tonic-gate * bandwidth for the pipe if it is a interrupt or isochronous endpoint. 23317c478bd9Sstevel@tonic-gate */ 23327c478bd9Sstevel@tonic-gate static int 23337c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_open( 23347c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 23357c478bd9Sstevel@tonic-gate usb_flags_t flags) 23367c478bd9Sstevel@tonic-gate { 23377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 23387c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 23397c478bd9Sstevel@tonic-gate usb_ep_descr_t *epdt = &ph->p_ep; 23407c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS; 23417c478bd9Sstevel@tonic-gate int kmflag = (flags & USB_FLAGS_SLEEP) ? 23427c478bd9Sstevel@tonic-gate KM_SLEEP : KM_NOSLEEP; 23437c478bd9Sstevel@tonic-gate uint_t node = 0; 23447c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 23477c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: addr = 0x%x, ep%d", 23487c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_addr, 23497c478bd9Sstevel@tonic-gate epdt->bEndpointAddress & USB_EP_NUM_MASK); 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate sema_p(&ohcip->ohci_ocsem); 23527c478bd9Sstevel@tonic-gate 23537c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 23547c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 23557c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 23587c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate return (rval); 23617c478bd9Sstevel@tonic-gate } 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate /* 23647c478bd9Sstevel@tonic-gate * Check and handle root hub pipe open. 23657c478bd9Sstevel@tonic-gate */ 23667c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 23697c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_open(ph, flags); 23707c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23717c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate return (error); 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate /* 23777c478bd9Sstevel@tonic-gate * Opening of other pipes excluding root hub pipe are 23787c478bd9Sstevel@tonic-gate * handled below. Check whether pipe is already opened. 23797c478bd9Sstevel@tonic-gate */ 23807c478bd9Sstevel@tonic-gate if (ph->p_hcd_private) { 23817c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 23827c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: Pipe is already opened"); 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate return (USB_FAILURE); 23877c478bd9Sstevel@tonic-gate } 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate /* 23907c478bd9Sstevel@tonic-gate * A portion of the bandwidth is reserved for the non-periodic 23917c478bd9Sstevel@tonic-gate * transfers, i.e control and bulk transfers in each of one 23927c478bd9Sstevel@tonic-gate * millisecond frame period & usually it will be 10% of frame 23937c478bd9Sstevel@tonic-gate * period. Hence there is no need to check for the available 23947c478bd9Sstevel@tonic-gate * bandwidth before adding the control or bulk endpoints. 23957c478bd9Sstevel@tonic-gate * 23967c478bd9Sstevel@tonic-gate * There is a need to check for the available bandwidth before 23977c478bd9Sstevel@tonic-gate * adding the periodic transfers, i.e interrupt & isochronous, 23987c478bd9Sstevel@tonic-gate * since all these periodic transfers are guaranteed transfers. 23997c478bd9Sstevel@tonic-gate * Usually 90% of the total frame time is reserved for periodic 24007c478bd9Sstevel@tonic-gate * transfers. 24017c478bd9Sstevel@tonic-gate */ 24027c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) { 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 24057c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate error = ohci_allocate_bandwidth(ohcip, ph, &node); 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 24127c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: Bandwidth allocation failed"); 24137c478bd9Sstevel@tonic-gate 24147c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 24157c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24167c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate return (error); 24197c478bd9Sstevel@tonic-gate } 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 24227c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24237c478bd9Sstevel@tonic-gate } 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate /* Create the HCD pipe private structure */ 24267c478bd9Sstevel@tonic-gate pp = kmem_zalloc(sizeof (ohci_pipe_private_t), kmflag); 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate /* 24297c478bd9Sstevel@tonic-gate * Return failure if ohci pipe private 24307c478bd9Sstevel@tonic-gate * structure allocation fails. 24317c478bd9Sstevel@tonic-gate */ 24327c478bd9Sstevel@tonic-gate if (pp == NULL) { 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 24377c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) { 24387c478bd9Sstevel@tonic-gate 24397c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 24407c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph); 24417c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 24427c478bd9Sstevel@tonic-gate } 24437c478bd9Sstevel@tonic-gate 24447c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24457c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 24467c478bd9Sstevel@tonic-gate 24477c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 24487c478bd9Sstevel@tonic-gate } 24497c478bd9Sstevel@tonic-gate 24507c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate /* Store the node in the interrupt lattice */ 24537c478bd9Sstevel@tonic-gate pp->pp_node = node; 24547c478bd9Sstevel@tonic-gate 24557c478bd9Sstevel@tonic-gate /* Create prototype for xfer completion condition variable */ 24567c478bd9Sstevel@tonic-gate cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL); 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate /* Set the state of pipe as idle */ 24597c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate /* Store a pointer to the pipe handle */ 24627c478bd9Sstevel@tonic-gate pp->pp_pipe_handle = ph; 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate /* Store the pointer in the pipe handle */ 24677c478bd9Sstevel@tonic-gate ph->p_hcd_private = (usb_opaque_t)pp; 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate /* Store a copy of the pipe policy */ 24707c478bd9Sstevel@tonic-gate bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t)); 24717c478bd9Sstevel@tonic-gate 24727c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate /* Allocate the host controller endpoint descriptor */ 24757c478bd9Sstevel@tonic-gate pp->pp_ept = ohci_alloc_hc_ed(ohcip, ph); 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate if (pp->pp_ept == NULL) { 24787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 24797c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: ED allocation failed"); 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 24847c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) { 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph); 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate /* Destroy the xfer completion condition varibale */ 24907c478bd9Sstevel@tonic-gate cv_destroy(&pp->pp_xfer_cmpl_cv); 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate /* 24937c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion 24947c478bd9Sstevel@tonic-gate * of the pipe handle. 24957c478bd9Sstevel@tonic-gate */ 24967c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (ohci_pipe_private_t)); 24977c478bd9Sstevel@tonic-gate 24987c478bd9Sstevel@tonic-gate /* 24997c478bd9Sstevel@tonic-gate * Set the private structure in the 25007c478bd9Sstevel@tonic-gate * pipe handle equal to NULL. 25017c478bd9Sstevel@tonic-gate */ 25027c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL; 25037c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 25067c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate /* Restore the data toggle information */ 25127c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(ohcip, ph); 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate /* 25157c478bd9Sstevel@tonic-gate * Insert the endpoint onto the host controller's 25167c478bd9Sstevel@tonic-gate * appropriate endpoint list. The host controller 25177c478bd9Sstevel@tonic-gate * will not schedule this endpoint and will not have 25187c478bd9Sstevel@tonic-gate * any TD's to process. 25197c478bd9Sstevel@tonic-gate */ 25207c478bd9Sstevel@tonic-gate ohci_insert_ed(ohcip, ph); 25217c478bd9Sstevel@tonic-gate 25227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 25237c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: ph = 0x%p", (void *)ph); 25247c478bd9Sstevel@tonic-gate 25257c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count++; 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 25307c478bd9Sstevel@tonic-gate 25317c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 25327c478bd9Sstevel@tonic-gate } 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate /* 25367c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_close: 25377c478bd9Sstevel@tonic-gate * 25387c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during the client specific pipe 25397c478bd9Sstevel@tonic-gate * close. Remove the pipe and the data structure representing the device. 25407c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the pipe if it is a interrupt or isochronous 25417c478bd9Sstevel@tonic-gate * endpoint. 25427c478bd9Sstevel@tonic-gate */ 25437c478bd9Sstevel@tonic-gate /* ARGSUSED */ 25447c478bd9Sstevel@tonic-gate static int 25457c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_close( 25467c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 25477c478bd9Sstevel@tonic-gate usb_flags_t flags) 25487c478bd9Sstevel@tonic-gate { 25497c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 25507c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 25517c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 25527c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 25537c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 25567c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_close: addr = 0x%x, ep%d", 25577c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_addr, 25587c478bd9Sstevel@tonic-gate eptd->bEndpointAddress & USB_EP_NUM_MASK); 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate sema_p(&ohcip->ohci_ocsem); 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate /* Check and handle root hub pipe close */ 25637c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 25647c478bd9Sstevel@tonic-gate 25657c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 25667c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_close(ph); 25677c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 25687c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate return (error); 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate ASSERT(ph->p_hcd_private != NULL); 25747c478bd9Sstevel@tonic-gate 25757c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate /* Set pipe state to pipe close */ 25787c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_CLOSE; 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph); 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate /* 25837c478bd9Sstevel@tonic-gate * Remove the endoint descriptor from Host 25847c478bd9Sstevel@tonic-gate * Controller's appropriate endpoint list. 25857c478bd9Sstevel@tonic-gate */ 25867c478bd9Sstevel@tonic-gate ohci_remove_ed(ohcip, pp); 25877c478bd9Sstevel@tonic-gate 25887c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 25897c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(eptd)) { 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 25927c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph); 25937c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 25947c478bd9Sstevel@tonic-gate } 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate /* Destroy the xfer completion condition varibale */ 25997c478bd9Sstevel@tonic-gate cv_destroy(&pp->pp_xfer_cmpl_cv); 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate /* 26027c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion 26037c478bd9Sstevel@tonic-gate * of the pipe handle. 26047c478bd9Sstevel@tonic-gate */ 26057c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (ohci_pipe_private_t)); 26067c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL; 26077c478bd9Sstevel@tonic-gate 26087c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 26117c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_close: ph = 0x%p", (void *)ph); 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count--; 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 26167c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate return (error); 26197c478bd9Sstevel@tonic-gate } 26207c478bd9Sstevel@tonic-gate 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate /* 26237c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_reset: 26247c478bd9Sstevel@tonic-gate */ 26257c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26267c478bd9Sstevel@tonic-gate static int 26277c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_reset( 26287c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 26297c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 26307c478bd9Sstevel@tonic-gate { 26317c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 26327c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 26337c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 26347c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 26357c478bd9Sstevel@tonic-gate 26367c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 26377c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_reset: ph = 0x%p ", (void *)ph); 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * Check and handle root hub pipe reset. 26417c478bd9Sstevel@tonic-gate */ 26427c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_reset(ph, usb_flags); 26457c478bd9Sstevel@tonic-gate return (error); 26467c478bd9Sstevel@tonic-gate } 26477c478bd9Sstevel@tonic-gate 26487c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 26497c478bd9Sstevel@tonic-gate 26507c478bd9Sstevel@tonic-gate /* Set pipe state to pipe reset */ 26517c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_RESET; 26527c478bd9Sstevel@tonic-gate 26537c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph); 26547c478bd9Sstevel@tonic-gate 26557c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate return (error); 26587c478bd9Sstevel@tonic-gate } 26597c478bd9Sstevel@tonic-gate 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate /* 26627c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_ctrl_xfer: 26637c478bd9Sstevel@tonic-gate */ 26647c478bd9Sstevel@tonic-gate static int 26657c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_ctrl_xfer( 26667c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 26677c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 26687c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 26697c478bd9Sstevel@tonic-gate { 26707c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 26717c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 26727c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 26737c478bd9Sstevel@tonic-gate int rval; 26747c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 26757c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 26787c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_ctrl_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 26797c478bd9Sstevel@tonic-gate (void *)ph, ctrl_reqp, usb_flags); 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 26827c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 26837c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate return (rval); 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate /* 26917c478bd9Sstevel@tonic-gate * Check and handle root hub control request. 26927c478bd9Sstevel@tonic-gate */ 26937c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_request(ohcip, ph, ctrl_reqp); 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate return (error); 26987c478bd9Sstevel@tonic-gate } 26997c478bd9Sstevel@tonic-gate 27007c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate /* 27037c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 27047c478bd9Sstevel@tonic-gate */ 27057c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) { 27067c478bd9Sstevel@tonic-gate 27077c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 27087c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_ctrl_xfer:" 27097c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate return (USB_FAILURE); 27147c478bd9Sstevel@tonic-gate } 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate /* Allocate a transfer wrapper */ 27177c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_ctrl_resources(ohcip, pp, ctrl_reqp, 27187c478bd9Sstevel@tonic-gate usb_flags)) == NULL) { 27197c478bd9Sstevel@tonic-gate 27207c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 27217c478bd9Sstevel@tonic-gate } else { 27227c478bd9Sstevel@tonic-gate /* Insert the td's on the endpoint */ 27237c478bd9Sstevel@tonic-gate ohci_insert_ctrl_req(ohcip, ph, ctrl_reqp, tw, usb_flags); 27247c478bd9Sstevel@tonic-gate } 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate return (error); 27297c478bd9Sstevel@tonic-gate } 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate /* 27337c478bd9Sstevel@tonic-gate * ohci_hcdi_bulk_transfer_size: 27347c478bd9Sstevel@tonic-gate * 27357c478bd9Sstevel@tonic-gate * Return maximum bulk transfer size 27367c478bd9Sstevel@tonic-gate */ 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27397c478bd9Sstevel@tonic-gate static int 27407c478bd9Sstevel@tonic-gate ohci_hcdi_bulk_transfer_size( 27417c478bd9Sstevel@tonic-gate usba_device_t *usba_device, 27427c478bd9Sstevel@tonic-gate size_t *size) 27437c478bd9Sstevel@tonic-gate { 27447c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 27457c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip); 27467c478bd9Sstevel@tonic-gate int rval; 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 27497c478bd9Sstevel@tonic-gate "ohci_hcdi_bulk_transfer_size:"); 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 27527c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 27537c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate return (rval); 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate 27607c478bd9Sstevel@tonic-gate *size = OHCI_MAX_BULK_XFER_SIZE; 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 27637c478bd9Sstevel@tonic-gate } 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate 27667c478bd9Sstevel@tonic-gate /* 27677c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_bulk_xfer: 27687c478bd9Sstevel@tonic-gate */ 27697c478bd9Sstevel@tonic-gate static int 27707c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_bulk_xfer( 27717c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 27727c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 27737c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 27747c478bd9Sstevel@tonic-gate { 27757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 27767c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 27777c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 27787c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS; 27797c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 27827c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 27837c478bd9Sstevel@tonic-gate (void *)ph, bulk_reqp, usb_flags); 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 27867c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 27897c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate return (rval); 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate /* 27957c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 27967c478bd9Sstevel@tonic-gate */ 27977c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) { 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 28007c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_bulk_xfer:" 28017c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28067c478bd9Sstevel@tonic-gate } 28077c478bd9Sstevel@tonic-gate 28087c478bd9Sstevel@tonic-gate /* Allocate a transfer wrapper */ 28097c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_bulk_resources(ohcip, pp, bulk_reqp, 28107c478bd9Sstevel@tonic-gate usb_flags)) == NULL) { 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 28137c478bd9Sstevel@tonic-gate } else { 28147c478bd9Sstevel@tonic-gate /* Add the TD into the Host Controller's bulk list */ 28157c478bd9Sstevel@tonic-gate ohci_insert_bulk_req(ohcip, ph, bulk_reqp, tw, usb_flags); 28167c478bd9Sstevel@tonic-gate } 28177c478bd9Sstevel@tonic-gate 28187c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28197c478bd9Sstevel@tonic-gate 28207c478bd9Sstevel@tonic-gate return (error); 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate /* 28257c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_intr_xfer: 28267c478bd9Sstevel@tonic-gate */ 28277c478bd9Sstevel@tonic-gate static int 28287c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_intr_xfer( 28297c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 28307c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 28317c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 28327c478bd9Sstevel@tonic-gate { 28337c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 28347c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 28357c478bd9Sstevel@tonic-gate int pipe_dir, rval, error = USB_SUCCESS; 28367c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 28377c478bd9Sstevel@tonic-gate 28387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 28397c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_intr_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 28407c478bd9Sstevel@tonic-gate (void *)ph, intr_reqp, usb_flags); 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 28437c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 28447c478bd9Sstevel@tonic-gate 28457c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 28467c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate return (rval); 28497c478bd9Sstevel@tonic-gate } 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate /* Get the pipe direction */ 28527c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 28537c478bd9Sstevel@tonic-gate 28547c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 28557c478bd9Sstevel@tonic-gate error = ohci_start_periodic_pipe_polling(ohcip, ph, 28567c478bd9Sstevel@tonic-gate (usb_opaque_t)intr_reqp, usb_flags); 28577c478bd9Sstevel@tonic-gate } else { 28587c478bd9Sstevel@tonic-gate /* Allocate transaction resources */ 28597c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_intr_resources(ohcip, ph, 28607c478bd9Sstevel@tonic-gate intr_reqp, usb_flags)) == NULL) { 28617c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 28627c478bd9Sstevel@tonic-gate } else { 28637c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, 28647c478bd9Sstevel@tonic-gate (ohci_pipe_private_t *)ph->p_hcd_private, 28657c478bd9Sstevel@tonic-gate tw, usb_flags); 28667c478bd9Sstevel@tonic-gate } 28677c478bd9Sstevel@tonic-gate } 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate return (error); 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate 28747c478bd9Sstevel@tonic-gate 28757c478bd9Sstevel@tonic-gate /* 28767c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_stop_intr_polling() 28777c478bd9Sstevel@tonic-gate */ 28787c478bd9Sstevel@tonic-gate static int 28797c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_intr_polling( 28807c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 28817c478bd9Sstevel@tonic-gate usb_flags_t flags) 28827c478bd9Sstevel@tonic-gate { 28837c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 28847c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 28857c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 28887c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x", 28897c478bd9Sstevel@tonic-gate ph, flags); 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate error = ohci_stop_periodic_pipe_polling(ohcip, ph, flags); 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate return (error); 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate /* 29027c478bd9Sstevel@tonic-gate * ohci_hcdi_get_current_frame_number: 29037c478bd9Sstevel@tonic-gate * 29047c478bd9Sstevel@tonic-gate * Return the current usb frame number 29057c478bd9Sstevel@tonic-gate */ 29067c478bd9Sstevel@tonic-gate static usb_frame_number_t 29077c478bd9Sstevel@tonic-gate ohci_hcdi_get_current_frame_number(usba_device_t *usba_device) 29087c478bd9Sstevel@tonic-gate { 29097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 29107c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip); 29117c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number; 29127c478bd9Sstevel@tonic-gate int rval; 29137c478bd9Sstevel@tonic-gate 29147c478bd9Sstevel@tonic-gate ohcip = ohci_obtain_state(usba_device->usb_root_hub_dip); 29157c478bd9Sstevel@tonic-gate 29167c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 29177c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 29187c478bd9Sstevel@tonic-gate 29197c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 29207c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate return (rval); 29237c478bd9Sstevel@tonic-gate } 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate frame_number = ohci_get_current_frame_number(ohcip); 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29287c478bd9Sstevel@tonic-gate 29297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 29307c478bd9Sstevel@tonic-gate "ohci_hcdi_get_current_frame_number:" 29317c478bd9Sstevel@tonic-gate "Current frame number 0x%llx", frame_number); 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate return (frame_number); 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate /* 29387c478bd9Sstevel@tonic-gate * ohci_hcdi_get_max_isoc_pkts: 29397c478bd9Sstevel@tonic-gate * 29407c478bd9Sstevel@tonic-gate * Return maximum isochronous packets per usb isochronous request 29417c478bd9Sstevel@tonic-gate */ 29427c478bd9Sstevel@tonic-gate static uint_t 29437c478bd9Sstevel@tonic-gate ohci_hcdi_get_max_isoc_pkts(usba_device_t *usba_device) 29447c478bd9Sstevel@tonic-gate { 29457c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 29467c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip); 29477c478bd9Sstevel@tonic-gate uint_t max_isoc_pkts_per_request; 29487c478bd9Sstevel@tonic-gate int rval; 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 29517c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 29527c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate return (rval); 29577c478bd9Sstevel@tonic-gate } 29587c478bd9Sstevel@tonic-gate 29597c478bd9Sstevel@tonic-gate max_isoc_pkts_per_request = OHCI_MAX_ISOC_PKTS_PER_XFER; 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 29627c478bd9Sstevel@tonic-gate "ohci_hcdi_get_max_isoc_pkts: maximum isochronous" 29637c478bd9Sstevel@tonic-gate "packets per usb isochronous request = 0x%x", 29647c478bd9Sstevel@tonic-gate max_isoc_pkts_per_request); 29657c478bd9Sstevel@tonic-gate 29667c478bd9Sstevel@tonic-gate return (max_isoc_pkts_per_request); 29677c478bd9Sstevel@tonic-gate } 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate /* 29717c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_isoc_xfer: 29727c478bd9Sstevel@tonic-gate */ 29737c478bd9Sstevel@tonic-gate static int 29747c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_isoc_xfer( 29757c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 29767c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 29777c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 29787c478bd9Sstevel@tonic-gate { 29797c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 29807c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 29817c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 29827c478bd9Sstevel@tonic-gate int pipe_dir, rval; 29837c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 29847c478bd9Sstevel@tonic-gate 29857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 29867c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_isoc_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 29877c478bd9Sstevel@tonic-gate (void *)ph, isoc_reqp, usb_flags); 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 29907c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 29917c478bd9Sstevel@tonic-gate 29927c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 29937c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29947c478bd9Sstevel@tonic-gate 29957c478bd9Sstevel@tonic-gate return (rval); 29967c478bd9Sstevel@tonic-gate } 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate /* Get the isochronous pipe direction */ 29997c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 30027c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_isoc_xfer: isoc_reqp = 0x%p, uf = 0x%x", 30037c478bd9Sstevel@tonic-gate isoc_reqp, usb_flags); 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 30067c478bd9Sstevel@tonic-gate error = ohci_start_periodic_pipe_polling(ohcip, ph, 30077c478bd9Sstevel@tonic-gate (usb_opaque_t)isoc_reqp, usb_flags); 30087c478bd9Sstevel@tonic-gate } else { 30097c478bd9Sstevel@tonic-gate /* Allocate transaction resources */ 30107c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_isoc_resources(ohcip, ph, 30117c478bd9Sstevel@tonic-gate isoc_reqp, usb_flags)) == NULL) { 30127c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 30137c478bd9Sstevel@tonic-gate } else { 30147c478bd9Sstevel@tonic-gate error = ohci_insert_isoc_req(ohcip, 30157c478bd9Sstevel@tonic-gate (ohci_pipe_private_t *)ph->p_hcd_private, 30167c478bd9Sstevel@tonic-gate tw, usb_flags); 30177c478bd9Sstevel@tonic-gate } 30187c478bd9Sstevel@tonic-gate } 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate return (error); 30237c478bd9Sstevel@tonic-gate } 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate /* 30277c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_stop_isoc_polling() 30287c478bd9Sstevel@tonic-gate */ 30297c478bd9Sstevel@tonic-gate static int 30307c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_isoc_polling( 30317c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 30327c478bd9Sstevel@tonic-gate usb_flags_t flags) 30337c478bd9Sstevel@tonic-gate { 30347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 30357c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 30367c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS; 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 30397c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", 30407c478bd9Sstevel@tonic-gate (void *)ph, flags); 30417c478bd9Sstevel@tonic-gate 30427c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 30437c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 30447c478bd9Sstevel@tonic-gate 30457c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 30467c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30477c478bd9Sstevel@tonic-gate return (rval); 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate error = ohci_stop_periodic_pipe_polling(ohcip, ph, flags); 30517c478bd9Sstevel@tonic-gate 30527c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30537c478bd9Sstevel@tonic-gate return (error); 30547c478bd9Sstevel@tonic-gate } 30557c478bd9Sstevel@tonic-gate 30567c478bd9Sstevel@tonic-gate 30577c478bd9Sstevel@tonic-gate /* 30587c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 30597c478bd9Sstevel@tonic-gate */ 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate /* 30627c478bd9Sstevel@tonic-gate * ohci_allocate_bandwidth: 30637c478bd9Sstevel@tonic-gate * 30647c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 30657c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 30667c478bd9Sstevel@tonic-gate * can not be supported. 30677c478bd9Sstevel@tonic-gate * 30687c478bd9Sstevel@tonic-gate * The lattice structure looks like this with the bottom leaf actually 30697c478bd9Sstevel@tonic-gate * being an array. There is a total of 63 nodes in this tree. The lattice tree 30707c478bd9Sstevel@tonic-gate * itself is 0 based, while the bottom leaf array is 0 based. The 0 bucket in 30717c478bd9Sstevel@tonic-gate * the bottom leaf array is used to store the smalled allocated bandwidth of all 30727c478bd9Sstevel@tonic-gate * the leaves. 30737c478bd9Sstevel@tonic-gate * 30747c478bd9Sstevel@tonic-gate * 0 30757c478bd9Sstevel@tonic-gate * 1 2 30767c478bd9Sstevel@tonic-gate * 3 4 5 6 30777c478bd9Sstevel@tonic-gate * ... 30787c478bd9Sstevel@tonic-gate * (32 33 ... 62 63) <-- last row does not exist in lattice, but an array 30797c478bd9Sstevel@tonic-gate * 0 1 2 3 ... 30 31 30807c478bd9Sstevel@tonic-gate * 30817c478bd9Sstevel@tonic-gate * We keep track of the bandwidth that each leaf uses. First we search for the 30827c478bd9Sstevel@tonic-gate * first leaf with the smallest used bandwidth. Based on that leaf we find the 30837c478bd9Sstevel@tonic-gate * parent node of that leaf based on the interval time. 30847c478bd9Sstevel@tonic-gate * 30857c478bd9Sstevel@tonic-gate * From the parent node, we find all the leafs of that subtree and update the 30867c478bd9Sstevel@tonic-gate * additional bandwidth needed. In order to balance the load the leaves are not 30877c478bd9Sstevel@tonic-gate * executed directly from left to right, but scattered. For a better picture 30887c478bd9Sstevel@tonic-gate * refer to Section 3.3.2 in the OpenHCI 1.0 spec, there should be a figure 30897c478bd9Sstevel@tonic-gate * showing the Interrupt ED Structure. 30907c478bd9Sstevel@tonic-gate */ 30917c478bd9Sstevel@tonic-gate static int 30927c478bd9Sstevel@tonic-gate ohci_allocate_bandwidth( 30937c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 30947c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 30957c478bd9Sstevel@tonic-gate uint_t *node) 30967c478bd9Sstevel@tonic-gate { 30977c478bd9Sstevel@tonic-gate int interval, error, i; 30987c478bd9Sstevel@tonic-gate uint_t min, min_index, height; 30997c478bd9Sstevel@tonic-gate uint_t leftmost, list, bandwidth; 31007c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate /* This routine is protected by the ohci_int_mutex */ 31037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate /* 31067c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 31077c478bd9Sstevel@tonic-gate * periodic endpoint. 31087c478bd9Sstevel@tonic-gate */ 31097c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 31107c478bd9Sstevel@tonic-gate error = ohci_compute_total_bandwidth( 31117c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status, &bandwidth); 31127c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 31137c478bd9Sstevel@tonic-gate 31147c478bd9Sstevel@tonic-gate /* 31157c478bd9Sstevel@tonic-gate * If length is zero, then, it means endpoint maximum packet 31167c478bd9Sstevel@tonic-gate * supported is zero. In that case, return failure without 31177c478bd9Sstevel@tonic-gate * allocating any bandwidth. 31187c478bd9Sstevel@tonic-gate */ 31197c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 31207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 31217c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Periodic endpoint with " 31227c478bd9Sstevel@tonic-gate "zero endpoint maximum packet size is not supported"); 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 31257c478bd9Sstevel@tonic-gate } 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate /* 31287c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 31297c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 31307c478bd9Sstevel@tonic-gate */ 31317c478bd9Sstevel@tonic-gate if ((ohcip->ohci_periodic_minimum_bandwidth + bandwidth) > 31327c478bd9Sstevel@tonic-gate (MAX_PERIODIC_BANDWIDTH)) { 31337c478bd9Sstevel@tonic-gate 31347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 31357c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Reached maximum " 31367c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth " 31377c478bd9Sstevel@tonic-gate "for a given periodic endpoint"); 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 31407c478bd9Sstevel@tonic-gate } 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 31437c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 31447c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, 31457c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status); 31467c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 31477c478bd9Sstevel@tonic-gate 31487c478bd9Sstevel@tonic-gate /* 31497c478bd9Sstevel@tonic-gate * If this interval can't be supported, 31507c478bd9Sstevel@tonic-gate * return allocation failure. 31517c478bd9Sstevel@tonic-gate */ 31527c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 31537c478bd9Sstevel@tonic-gate 31547c478bd9Sstevel@tonic-gate return (USB_FAILURE); 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate 31577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 31587c478bd9Sstevel@tonic-gate "The new interval is %d", interval); 31597c478bd9Sstevel@tonic-gate 31607c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 31617c478bd9Sstevel@tonic-gate min_index = 0; 31627c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0]; 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) { 31657c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) { 31667c478bd9Sstevel@tonic-gate min_index = i; 31677c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i]; 31687c478bd9Sstevel@tonic-gate } 31697c478bd9Sstevel@tonic-gate } 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 31727c478bd9Sstevel@tonic-gate "The leaf %d for minimal bandwidth %d", min_index, min); 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate /* Adjust min for the lattice */ 31757c478bd9Sstevel@tonic-gate min_index = min_index + NUM_INTR_ED_LISTS - 1; 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate /* 31787c478bd9Sstevel@tonic-gate * Find the index into the lattice given the 31797c478bd9Sstevel@tonic-gate * leaf with the smallest allocated bandwidth. 31807c478bd9Sstevel@tonic-gate */ 31817c478bd9Sstevel@tonic-gate height = ohci_lattice_height(interval); 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 31847c478bd9Sstevel@tonic-gate "The height is %d", height); 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate *node = min_index; 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 31897c478bd9Sstevel@tonic-gate *node = ohci_lattice_parent(*node); 31907c478bd9Sstevel@tonic-gate } 31917c478bd9Sstevel@tonic-gate 31927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 31937c478bd9Sstevel@tonic-gate "Real node is %d", *node); 31947c478bd9Sstevel@tonic-gate 31957c478bd9Sstevel@tonic-gate /* 31967c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree 31977c478bd9Sstevel@tonic-gate * specified by the node. 31987c478bd9Sstevel@tonic-gate */ 31997c478bd9Sstevel@tonic-gate leftmost = ohci_leftmost_leaf(*node, height); 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32027c478bd9Sstevel@tonic-gate "Leftmost %d", leftmost); 32037c478bd9Sstevel@tonic-gate 32047c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) { 32057c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i); 32067c478bd9Sstevel@tonic-gate if ((ohcip->ohci_periodic_bandwidth[list] + 32077c478bd9Sstevel@tonic-gate bandwidth) > MAX_PERIODIC_BANDWIDTH) { 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32107c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Reached maximum " 32117c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth " 32127c478bd9Sstevel@tonic-gate "for periodic endpoint"); 32137c478bd9Sstevel@tonic-gate 32147c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 32157c478bd9Sstevel@tonic-gate } 32167c478bd9Sstevel@tonic-gate } 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate /* 32197c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 32207c478bd9Sstevel@tonic-gate */ 32217c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) { 32227c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i); 32237c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_bandwidth[list] += bandwidth; 32247c478bd9Sstevel@tonic-gate } 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 32277c478bd9Sstevel@tonic-gate min_index = 0; 32287c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0]; 32297c478bd9Sstevel@tonic-gate 32307c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) { 32317c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) { 32327c478bd9Sstevel@tonic-gate min_index = i; 32337c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i]; 32347c478bd9Sstevel@tonic-gate } 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 32387c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_minimum_bandwidth = min; 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 32417c478bd9Sstevel@tonic-gate } 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate 32447c478bd9Sstevel@tonic-gate /* 32457c478bd9Sstevel@tonic-gate * ohci_deallocate_bandwidth: 32467c478bd9Sstevel@tonic-gate * 32477c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 32487c478bd9Sstevel@tonic-gate * of transfer. 32497c478bd9Sstevel@tonic-gate */ 32507c478bd9Sstevel@tonic-gate static void 32517c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth( 32527c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 32537c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 32547c478bd9Sstevel@tonic-gate { 32557c478bd9Sstevel@tonic-gate uint_t min, node, bandwidth; 32567c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 32577c478bd9Sstevel@tonic-gate int i, interval; 32587c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 32597c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate /* This routine is protected by the ohci_int_mutex */ 32627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 32637c478bd9Sstevel@tonic-gate 32647c478bd9Sstevel@tonic-gate /* Obtain the length */ 32657c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 32667c478bd9Sstevel@tonic-gate (void) ohci_compute_total_bandwidth( 32677c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status, &bandwidth); 32687c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 32697c478bd9Sstevel@tonic-gate 32707c478bd9Sstevel@tonic-gate /* Obtain the node */ 32717c478bd9Sstevel@tonic-gate node = pp->pp_node; 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 32747c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 32757c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, 32767c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status); 32777c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 32807c478bd9Sstevel@tonic-gate height = ohci_lattice_height(interval); 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate /* 32837c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 32847c478bd9Sstevel@tonic-gate */ 32857c478bd9Sstevel@tonic-gate leftmost = ohci_leftmost_leaf(node, height); 32867c478bd9Sstevel@tonic-gate 32877c478bd9Sstevel@tonic-gate /* Delete the bandwith from the appropriate lists */ 32887c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) { 32897c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i); 32907c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_bandwidth[list] -= bandwidth; 32917c478bd9Sstevel@tonic-gate } 32927c478bd9Sstevel@tonic-gate 32937c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0]; 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate /* Recompute the minimum */ 32967c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) { 32977c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) { 32987c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i]; 32997c478bd9Sstevel@tonic-gate } 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 33037c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_minimum_bandwidth = min; 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate /* 33087c478bd9Sstevel@tonic-gate * ohci_compute_total_bandwidth: 33097c478bd9Sstevel@tonic-gate * 33107c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 33117c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The OpenHCI host controller traverses the 33127c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 33137c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 33147c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 33157c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 33167c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 33177c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 33187c478bd9Sstevel@tonic-gate * 33197c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 33207c478bd9Sstevel@tonic-gate * bytes and it is for the single USB full speed and low speed transaction 33217c478bd9Sstevel@tonic-gate * respectively. The protocol overheads will be different for each of type 33227c478bd9Sstevel@tonic-gate * of USB transfer and all these formulas & protocol overheads are derived 33237c478bd9Sstevel@tonic-gate * from the 5.9.3 section of USB Specification & with the help of Bandwidth 33247c478bd9Sstevel@tonic-gate * Analysis white paper which is posted on the USB developer forum. 33257c478bd9Sstevel@tonic-gate * 33267c478bd9Sstevel@tonic-gate * Full-Speed: 33277c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPacketSize * 7)/6 ) + Host_Delay 33287c478bd9Sstevel@tonic-gate * 33297c478bd9Sstevel@tonic-gate * Low-Speed: 33307c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 33317c478bd9Sstevel@tonic-gate * (Low-Speed clock * ((MaxPacketSize * 7)/6 )) + Host_Delay 33327c478bd9Sstevel@tonic-gate */ 33337c478bd9Sstevel@tonic-gate static int 33347c478bd9Sstevel@tonic-gate ohci_compute_total_bandwidth( 33357c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 33367c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 33377c478bd9Sstevel@tonic-gate uint_t *bandwidth) 33387c478bd9Sstevel@tonic-gate { 33397c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate /* 33427c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 33437c478bd9Sstevel@tonic-gate */ 33447c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 33477c478bd9Sstevel@tonic-gate } 33487c478bd9Sstevel@tonic-gate 33497c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 33507c478bd9Sstevel@tonic-gate *bandwidth = HOST_CONTROLLER_DELAY; 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 33537c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate /* Low Speed interrupt transaction */ 33567c478bd9Sstevel@tonic-gate if (port_status == USBA_LOW_SPEED_DEV) { 33577c478bd9Sstevel@tonic-gate /* Low Speed interrupt transaction */ 33587c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 33597c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 33607c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 33617c478bd9Sstevel@tonic-gate } else { 33627c478bd9Sstevel@tonic-gate /* Full Speed transaction */ 33637c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 33647c478bd9Sstevel@tonic-gate 33657c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 33667c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 33677c478bd9Sstevel@tonic-gate /* Full Speed interrupt transaction */ 33687c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 33697c478bd9Sstevel@tonic-gate } else { 33707c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 33717c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 33727c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 33737c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 33747c478bd9Sstevel@tonic-gate } else { 33757c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 33767c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate } 33797c478bd9Sstevel@tonic-gate } 33807c478bd9Sstevel@tonic-gate 33817c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 33827c478bd9Sstevel@tonic-gate } 33837c478bd9Sstevel@tonic-gate 33847c478bd9Sstevel@tonic-gate 33857c478bd9Sstevel@tonic-gate /* 33867c478bd9Sstevel@tonic-gate * ohci_adjust_polling_interval: 33877c478bd9Sstevel@tonic-gate */ 33887c478bd9Sstevel@tonic-gate static int 33897c478bd9Sstevel@tonic-gate ohci_adjust_polling_interval( 33907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 33917c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 33927c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 33937c478bd9Sstevel@tonic-gate { 33947c478bd9Sstevel@tonic-gate uint_t interval; 33957c478bd9Sstevel@tonic-gate int i = 0; 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate /* 33987c478bd9Sstevel@tonic-gate * Get the polling interval from the endpoint descriptor 33997c478bd9Sstevel@tonic-gate */ 34007c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 34017c478bd9Sstevel@tonic-gate 34027c478bd9Sstevel@tonic-gate /* 34037c478bd9Sstevel@tonic-gate * The bInterval value in the endpoint descriptor can range 34047c478bd9Sstevel@tonic-gate * from 1 to 255ms. The interrupt lattice has 32 leaf nodes, 34057c478bd9Sstevel@tonic-gate * and the host controller cycles through these nodes every 34067c478bd9Sstevel@tonic-gate * 32ms. The longest polling interval that the controller 34077c478bd9Sstevel@tonic-gate * supports is 32ms. 34087c478bd9Sstevel@tonic-gate */ 34097c478bd9Sstevel@tonic-gate 34107c478bd9Sstevel@tonic-gate /* 34117c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less than 1ms 34127c478bd9Sstevel@tonic-gate * and greater than 255ms 34137c478bd9Sstevel@tonic-gate */ 34147c478bd9Sstevel@tonic-gate if ((interval < MIN_POLL_INTERVAL) || 34157c478bd9Sstevel@tonic-gate (interval > MAX_POLL_INTERVAL)) { 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 34187c478bd9Sstevel@tonic-gate "ohci_adjust_polling_interval: " 34197c478bd9Sstevel@tonic-gate "Endpoint's poll interval must be between %d and %d ms", 34207c478bd9Sstevel@tonic-gate MIN_POLL_INTERVAL, MAX_POLL_INTERVAL); 34217c478bd9Sstevel@tonic-gate 34227c478bd9Sstevel@tonic-gate return (USB_FAILURE); 34237c478bd9Sstevel@tonic-gate } 34247c478bd9Sstevel@tonic-gate 34257c478bd9Sstevel@tonic-gate /* 34267c478bd9Sstevel@tonic-gate * According USB Specifications, a full-speed endpoint can 34277c478bd9Sstevel@tonic-gate * specify a desired polling interval 1ms to 255ms and a low 34287c478bd9Sstevel@tonic-gate * speed endpoints are limited to specifying only 10ms to 34297c478bd9Sstevel@tonic-gate * 255ms. But some old keyboards & mice uses polling interval 34307c478bd9Sstevel@tonic-gate * of 8ms. For compatibility purpose, we are using polling 34317c478bd9Sstevel@tonic-gate * interval between 8ms & 255ms for low speed endpoints. But 34327c478bd9Sstevel@tonic-gate * ohci driver will reject the any low speed endpoints which 34337c478bd9Sstevel@tonic-gate * request polling interval less than 8ms. 34347c478bd9Sstevel@tonic-gate */ 34357c478bd9Sstevel@tonic-gate if ((port_status == USBA_LOW_SPEED_DEV) && 34367c478bd9Sstevel@tonic-gate (interval < MIN_LOW_SPEED_POLL_INTERVAL)) { 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ohcip->ohci_log_hdl, 34397c478bd9Sstevel@tonic-gate "ohci_adjust_polling_interval: " 34407c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 34417c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 34427c478bd9Sstevel@tonic-gate interval, MIN_LOW_SPEED_POLL_INTERVAL); 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate interval = MIN_LOW_SPEED_POLL_INTERVAL; 34457c478bd9Sstevel@tonic-gate } 34467c478bd9Sstevel@tonic-gate 34477c478bd9Sstevel@tonic-gate /* 34487c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 34497c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 34507c478bd9Sstevel@tonic-gate */ 34517c478bd9Sstevel@tonic-gate if (interval > NUM_INTR_ED_LISTS) { 34527c478bd9Sstevel@tonic-gate interval = NUM_INTR_ED_LISTS; 34537c478bd9Sstevel@tonic-gate } 34547c478bd9Sstevel@tonic-gate 34557c478bd9Sstevel@tonic-gate /* 34567c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that'sless 34577c478bd9Sstevel@tonic-gate * than interval. 34587c478bd9Sstevel@tonic-gate */ 34597c478bd9Sstevel@tonic-gate while ((ohci_pow_2(i)) <= interval) { 34607c478bd9Sstevel@tonic-gate i++; 34617c478bd9Sstevel@tonic-gate } 34627c478bd9Sstevel@tonic-gate 34637c478bd9Sstevel@tonic-gate return (ohci_pow_2((i - 1))); 34647c478bd9Sstevel@tonic-gate } 34657c478bd9Sstevel@tonic-gate 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate /* 34687c478bd9Sstevel@tonic-gate * ohci_lattice_height: 34697c478bd9Sstevel@tonic-gate * 34707c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 34717c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 34727c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 34737c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate static uint_t 34767c478bd9Sstevel@tonic-gate ohci_lattice_height(uint_t interval) 34777c478bd9Sstevel@tonic-gate { 34787c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ohci_log_2(interval))); 34797c478bd9Sstevel@tonic-gate } 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate 34827c478bd9Sstevel@tonic-gate /* 34837c478bd9Sstevel@tonic-gate * ohci_lattice_parent: 34847c478bd9Sstevel@tonic-gate */ 34857c478bd9Sstevel@tonic-gate static uint_t 34867c478bd9Sstevel@tonic-gate ohci_lattice_parent(uint_t node) 34877c478bd9Sstevel@tonic-gate { 34887c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 34897c478bd9Sstevel@tonic-gate return ((node/2) - 1); 34907c478bd9Sstevel@tonic-gate } else { 34917c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 34927c478bd9Sstevel@tonic-gate } 34937c478bd9Sstevel@tonic-gate } 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gate 34967c478bd9Sstevel@tonic-gate /* 34977c478bd9Sstevel@tonic-gate * ohci_leftmost_leaf: 34987c478bd9Sstevel@tonic-gate * 34997c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 35007c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 35017c478bd9Sstevel@tonic-gate * node. 35027c478bd9Sstevel@tonic-gate * 35037c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 35047c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 35057c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 35067c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 35077c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (NUM_INTR_ED_LIST - 1) = 35087c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - NUM_INTR_ED_LIST = 35097c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - NUM_INTR_ED_LIST 35107c478bd9Sstevel@tonic-gate * 0 35117c478bd9Sstevel@tonic-gate * 1 2 35127c478bd9Sstevel@tonic-gate * 0 1 2 3 35137c478bd9Sstevel@tonic-gate */ 35147c478bd9Sstevel@tonic-gate static uint_t 35157c478bd9Sstevel@tonic-gate ohci_leftmost_leaf( 35167c478bd9Sstevel@tonic-gate uint_t node, 35177c478bd9Sstevel@tonic-gate uint_t height) 35187c478bd9Sstevel@tonic-gate { 35197c478bd9Sstevel@tonic-gate return ((ohci_pow_2(height) * (node + 1)) - NUM_INTR_ED_LISTS); 35207c478bd9Sstevel@tonic-gate } 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate /* 35237c478bd9Sstevel@tonic-gate * ohci_hcca_intr_index: 35247c478bd9Sstevel@tonic-gate * 35257c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index for the hcca interrupt table 35267c478bd9Sstevel@tonic-gate */ 35277c478bd9Sstevel@tonic-gate static uint_t 35287c478bd9Sstevel@tonic-gate ohci_hcca_intr_index(uint_t node) 35297c478bd9Sstevel@tonic-gate { 35307c478bd9Sstevel@tonic-gate /* 35317c478bd9Sstevel@tonic-gate * Adjust the node to the array representing 35327c478bd9Sstevel@tonic-gate * the bottom of the tree. 35337c478bd9Sstevel@tonic-gate */ 35347c478bd9Sstevel@tonic-gate node = node - NUM_STATIC_NODES; 35357c478bd9Sstevel@tonic-gate 35367c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 35377c478bd9Sstevel@tonic-gate return (ohci_index[node / 2]); 35387c478bd9Sstevel@tonic-gate } else { 35397c478bd9Sstevel@tonic-gate return (ohci_index[node / 2] + (NUM_INTR_ED_LISTS / 2)); 35407c478bd9Sstevel@tonic-gate } 35417c478bd9Sstevel@tonic-gate } 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate /* 35447c478bd9Sstevel@tonic-gate * ohci_hcca_leaf_index: 35457c478bd9Sstevel@tonic-gate * 35467c478bd9Sstevel@tonic-gate * Given a node in the bottom leaf array of the lattice, find the index 35477c478bd9Sstevel@tonic-gate * for the hcca interrupt table 35487c478bd9Sstevel@tonic-gate */ 35497c478bd9Sstevel@tonic-gate static uint_t 35507c478bd9Sstevel@tonic-gate ohci_hcca_leaf_index(uint_t leaf) 35517c478bd9Sstevel@tonic-gate { 35527c478bd9Sstevel@tonic-gate if ((leaf % 2) == 0) { 35537c478bd9Sstevel@tonic-gate return (ohci_index[leaf / 2]); 35547c478bd9Sstevel@tonic-gate } else { 35557c478bd9Sstevel@tonic-gate return (ohci_index[leaf / 2] + (NUM_INTR_ED_LISTS / 2)); 35567c478bd9Sstevel@tonic-gate } 35577c478bd9Sstevel@tonic-gate } 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate /* 35607c478bd9Sstevel@tonic-gate * ohci_pow_2: 35617c478bd9Sstevel@tonic-gate * 35627c478bd9Sstevel@tonic-gate * Compute 2 to the power 35637c478bd9Sstevel@tonic-gate */ 35647c478bd9Sstevel@tonic-gate static uint_t 35657c478bd9Sstevel@tonic-gate ohci_pow_2(uint_t x) 35667c478bd9Sstevel@tonic-gate { 35677c478bd9Sstevel@tonic-gate if (x == 0) { 35687c478bd9Sstevel@tonic-gate return (1); 35697c478bd9Sstevel@tonic-gate } else { 35707c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 35717c478bd9Sstevel@tonic-gate } 35727c478bd9Sstevel@tonic-gate } 35737c478bd9Sstevel@tonic-gate 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate /* 35767c478bd9Sstevel@tonic-gate * ohci_log_2: 35777c478bd9Sstevel@tonic-gate * 35787c478bd9Sstevel@tonic-gate * Compute log base 2 of x 35797c478bd9Sstevel@tonic-gate */ 35807c478bd9Sstevel@tonic-gate static uint_t 35817c478bd9Sstevel@tonic-gate ohci_log_2(uint_t x) 35827c478bd9Sstevel@tonic-gate { 35837c478bd9Sstevel@tonic-gate int i = 0; 35847c478bd9Sstevel@tonic-gate 35857c478bd9Sstevel@tonic-gate while (x != 1) { 35867c478bd9Sstevel@tonic-gate x = x >> 1; 35877c478bd9Sstevel@tonic-gate i++; 35887c478bd9Sstevel@tonic-gate } 35897c478bd9Sstevel@tonic-gate 35907c478bd9Sstevel@tonic-gate return (i); 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate 35937c478bd9Sstevel@tonic-gate 35947c478bd9Sstevel@tonic-gate /* 35957c478bd9Sstevel@tonic-gate * Endpoint Descriptor (ED) manipulations functions 35967c478bd9Sstevel@tonic-gate */ 35977c478bd9Sstevel@tonic-gate 35987c478bd9Sstevel@tonic-gate /* 35997c478bd9Sstevel@tonic-gate * ohci_alloc_hc_ed: 36007c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 36017c478bd9Sstevel@tonic-gate * 36027c478bd9Sstevel@tonic-gate * Allocate an endpoint descriptor (ED) 36037c478bd9Sstevel@tonic-gate */ 36047c478bd9Sstevel@tonic-gate ohci_ed_t * 36057c478bd9Sstevel@tonic-gate ohci_alloc_hc_ed( 36067c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 36077c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 36087c478bd9Sstevel@tonic-gate { 36097c478bd9Sstevel@tonic-gate int i, state; 36107c478bd9Sstevel@tonic-gate ohci_ed_t *hc_ed; 36117c478bd9Sstevel@tonic-gate 36127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 36137c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: ph = 0x%p", (void *)ph); 36147c478bd9Sstevel@tonic-gate 36157c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate /* 36187c478bd9Sstevel@tonic-gate * The first 31 endpoints in the Endpoint Descriptor (ED) 36197c478bd9Sstevel@tonic-gate * buffer pool are reserved for building interrupt lattice 36207c478bd9Sstevel@tonic-gate * tree. Search for a blank endpoint descriptor in the ED 36217c478bd9Sstevel@tonic-gate * buffer pool. 36227c478bd9Sstevel@tonic-gate */ 36237c478bd9Sstevel@tonic-gate for (i = NUM_STATIC_NODES; i < ohci_ed_pool_size; i ++) { 36247c478bd9Sstevel@tonic-gate state = Get_ED(ohcip->ohci_ed_pool_addr[i].hced_state); 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate if (state == HC_EPT_FREE) { 36277c478bd9Sstevel@tonic-gate break; 36287c478bd9Sstevel@tonic-gate } 36297c478bd9Sstevel@tonic-gate } 36307c478bd9Sstevel@tonic-gate 36317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 36327c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: Allocated %d", i); 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate if (i == ohci_ed_pool_size) { 36357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 36367c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: ED exhausted"); 36377c478bd9Sstevel@tonic-gate 36387c478bd9Sstevel@tonic-gate return (NULL); 36397c478bd9Sstevel@tonic-gate } else { 36407c478bd9Sstevel@tonic-gate 36417c478bd9Sstevel@tonic-gate hc_ed = &ohcip->ohci_ed_pool_addr[i]; 36427c478bd9Sstevel@tonic-gate 36437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 36447c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: Allocated address 0x%p", (void *)hc_ed); 36457c478bd9Sstevel@tonic-gate 36467c478bd9Sstevel@tonic-gate ohci_print_ed(ohcip, hc_ed); 36477c478bd9Sstevel@tonic-gate 36487c478bd9Sstevel@tonic-gate /* Unpack the endpoint descriptor into a control field */ 36497c478bd9Sstevel@tonic-gate if (ph) { 36507c478bd9Sstevel@tonic-gate if ((ohci_initialize_dummy(ohcip, 36517c478bd9Sstevel@tonic-gate hc_ed)) == USB_NO_RESOURCES) { 36527c478bd9Sstevel@tonic-gate bzero((void *)hc_ed, sizeof (ohci_ed_t)); 36537c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_FREE); 36547c478bd9Sstevel@tonic-gate return (NULL); 36557c478bd9Sstevel@tonic-gate } 36567c478bd9Sstevel@tonic-gate 36577c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_prev, NULL); 36587c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_next, NULL); 36597c478bd9Sstevel@tonic-gate 36607c478bd9Sstevel@tonic-gate /* Change ED's state Active */ 36617c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_ACTIVE); 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_ctrl, 36647c478bd9Sstevel@tonic-gate ohci_unpack_endpoint(ohcip, ph)); 36657c478bd9Sstevel@tonic-gate } else { 36667c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_ctrl, HC_EPT_sKip); 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate /* Change ED's state Static */ 36697c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_STATIC); 36707c478bd9Sstevel@tonic-gate } 36717c478bd9Sstevel@tonic-gate 36727c478bd9Sstevel@tonic-gate return (hc_ed); 36737c478bd9Sstevel@tonic-gate } 36747c478bd9Sstevel@tonic-gate } 36757c478bd9Sstevel@tonic-gate 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate /* 36787c478bd9Sstevel@tonic-gate * ohci_unpack_endpoint: 36797c478bd9Sstevel@tonic-gate * 36807c478bd9Sstevel@tonic-gate * Unpack the information in the pipe handle and create the first byte 36817c478bd9Sstevel@tonic-gate * of the Host Controller's (HC) Endpoint Descriptor (ED). 36827c478bd9Sstevel@tonic-gate */ 36837c478bd9Sstevel@tonic-gate static uint_t 36847c478bd9Sstevel@tonic-gate ohci_unpack_endpoint( 36857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 36867c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 36877c478bd9Sstevel@tonic-gate { 36887c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 36897c478bd9Sstevel@tonic-gate uint_t maxpacketsize, addr, ctrl = 0; 36907c478bd9Sstevel@tonic-gate 36917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 36927c478bd9Sstevel@tonic-gate "ohci_unpack_endpoint:"); 36937c478bd9Sstevel@tonic-gate 36947c478bd9Sstevel@tonic-gate ctrl = ph->p_usba_device->usb_addr; 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate addr = endpoint->bEndpointAddress; 36977c478bd9Sstevel@tonic-gate 36987c478bd9Sstevel@tonic-gate /* Assign the endpoint's address */ 36997c478bd9Sstevel@tonic-gate ctrl = ctrl | ((addr & USB_EP_NUM_MASK) << HC_EPT_EP_SHFT); 37007c478bd9Sstevel@tonic-gate 37017c478bd9Sstevel@tonic-gate /* 37027c478bd9Sstevel@tonic-gate * Assign the direction. If the endpoint is a control endpoint, 37037c478bd9Sstevel@tonic-gate * the direction is assigned by the Transfer Descriptor (TD). 37047c478bd9Sstevel@tonic-gate */ 37057c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 37067c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) != USB_EP_ATTR_CONTROL) { 37077c478bd9Sstevel@tonic-gate if (addr & USB_EP_DIR_MASK) { 37087c478bd9Sstevel@tonic-gate /* The direction is IN */ 37097c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_DF_IN; 37107c478bd9Sstevel@tonic-gate } else { 37117c478bd9Sstevel@tonic-gate /* The direction is OUT */ 37127c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_DF_OUT; 37137c478bd9Sstevel@tonic-gate } 37147c478bd9Sstevel@tonic-gate } 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate /* Assign the speed */ 37177c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 37187c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status == USBA_LOW_SPEED_DEV) { 37197c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_Speed; 37207c478bd9Sstevel@tonic-gate } 37217c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 37227c478bd9Sstevel@tonic-gate 37237c478bd9Sstevel@tonic-gate /* Assign the format */ 37247c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 37257c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 37267c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_Format; 37277c478bd9Sstevel@tonic-gate } 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate maxpacketsize = endpoint->wMaxPacketSize; 37307c478bd9Sstevel@tonic-gate maxpacketsize = maxpacketsize << HC_EPT_MAXPKTSZ; 37317c478bd9Sstevel@tonic-gate ctrl = ctrl | (maxpacketsize & HC_EPT_MPS); 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate return (ctrl); 37347c478bd9Sstevel@tonic-gate } 37357c478bd9Sstevel@tonic-gate 37367c478bd9Sstevel@tonic-gate 37377c478bd9Sstevel@tonic-gate /* 37387c478bd9Sstevel@tonic-gate * ohci_insert_ed: 37397c478bd9Sstevel@tonic-gate * 37407c478bd9Sstevel@tonic-gate * Add the Endpoint Descriptor (ED) into the Host Controller's 37417c478bd9Sstevel@tonic-gate * (HC) appropriate endpoint list. 37427c478bd9Sstevel@tonic-gate */ 37437c478bd9Sstevel@tonic-gate static void 37447c478bd9Sstevel@tonic-gate ohci_insert_ed( 37457c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 37467c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 37477c478bd9Sstevel@tonic-gate { 37487c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 37497c478bd9Sstevel@tonic-gate 37507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 37517c478bd9Sstevel@tonic-gate "ohci_insert_ed:"); 37527c478bd9Sstevel@tonic-gate 37537c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 37547c478bd9Sstevel@tonic-gate 37557c478bd9Sstevel@tonic-gate switch (ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) { 37567c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 37577c478bd9Sstevel@tonic-gate ohci_insert_ctrl_ed(ohcip, pp); 37587c478bd9Sstevel@tonic-gate break; 37597c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 37607c478bd9Sstevel@tonic-gate ohci_insert_bulk_ed(ohcip, pp); 37617c478bd9Sstevel@tonic-gate break; 37627c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 37637c478bd9Sstevel@tonic-gate ohci_insert_intr_ed(ohcip, pp); 37647c478bd9Sstevel@tonic-gate break; 37657c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 37667c478bd9Sstevel@tonic-gate ohci_insert_isoc_ed(ohcip, pp); 37677c478bd9Sstevel@tonic-gate break; 37687c478bd9Sstevel@tonic-gate } 37697c478bd9Sstevel@tonic-gate } 37707c478bd9Sstevel@tonic-gate 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate /* 37737c478bd9Sstevel@tonic-gate * ohci_insert_ctrl_ed: 37747c478bd9Sstevel@tonic-gate * 37757c478bd9Sstevel@tonic-gate * Insert a control endpoint into the Host Controller's (HC) 37767c478bd9Sstevel@tonic-gate * control endpoint list. 37777c478bd9Sstevel@tonic-gate */ 37787c478bd9Sstevel@tonic-gate static void 37797c478bd9Sstevel@tonic-gate ohci_insert_ctrl_ed( 37807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 37817c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 37827c478bd9Sstevel@tonic-gate { 37837c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 37847c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 37877c478bd9Sstevel@tonic-gate "ohci_insert_ctrl_ed:"); 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 37907c478bd9Sstevel@tonic-gate 37917c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the list */ 37927c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_ctrl_head)) { 37937c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, 37947c478bd9Sstevel@tonic-gate Get_OpReg(hcr_ctrl_head)); 37957c478bd9Sstevel@tonic-gate 37967c478bd9Sstevel@tonic-gate /* Set up the backwards pointer */ 37977c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, ept)); 37987c478bd9Sstevel@tonic-gate } 37997c478bd9Sstevel@tonic-gate 38007c478bd9Sstevel@tonic-gate /* The new endpoint points to the head of the list */ 38017c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_OpReg(hcr_ctrl_head)); 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate /* Set the head ptr to the new endpoint */ 38047c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, ohci_ed_cpu_to_iommu(ohcip, ept)); 38057c478bd9Sstevel@tonic-gate 38067c478bd9Sstevel@tonic-gate /* 38077c478bd9Sstevel@tonic-gate * Enable Control list processing if control open 38087c478bd9Sstevel@tonic-gate * pipe count is zero. 38097c478bd9Sstevel@tonic-gate */ 38107c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_ctrl_pipe_count) { 38117c478bd9Sstevel@tonic-gate /* Start Control list processing */ 38127c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 38137c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_CLE)); 38147c478bd9Sstevel@tonic-gate } 38157c478bd9Sstevel@tonic-gate 38167c478bd9Sstevel@tonic-gate ohcip->ohci_open_ctrl_pipe_count++; 38177c478bd9Sstevel@tonic-gate } 38187c478bd9Sstevel@tonic-gate 38197c478bd9Sstevel@tonic-gate 38207c478bd9Sstevel@tonic-gate /* 38217c478bd9Sstevel@tonic-gate * ohci_insert_bulk_ed: 38227c478bd9Sstevel@tonic-gate * 38237c478bd9Sstevel@tonic-gate * Insert a bulk endpoint into the Host Controller's (HC) bulk endpoint list. 38247c478bd9Sstevel@tonic-gate */ 38257c478bd9Sstevel@tonic-gate static void 38267c478bd9Sstevel@tonic-gate ohci_insert_bulk_ed( 38277c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 38287c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 38297c478bd9Sstevel@tonic-gate { 38307c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 38317c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; 38327c478bd9Sstevel@tonic-gate 38337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 38347c478bd9Sstevel@tonic-gate "ohci_insert_bulk_ed:"); 38357c478bd9Sstevel@tonic-gate 38367c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 38377c478bd9Sstevel@tonic-gate 38387c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the Bulk list */ 38397c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_bulk_head)) { 38407c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, 38417c478bd9Sstevel@tonic-gate Get_OpReg(hcr_bulk_head)); 38427c478bd9Sstevel@tonic-gate 38437c478bd9Sstevel@tonic-gate /* Set up the backwards pointer */ 38447c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, ept)); 38457c478bd9Sstevel@tonic-gate } 38467c478bd9Sstevel@tonic-gate 38477c478bd9Sstevel@tonic-gate /* The new endpoint points to the head of the Bulk list */ 38487c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_OpReg(hcr_bulk_head)); 38497c478bd9Sstevel@tonic-gate 38507c478bd9Sstevel@tonic-gate /* Set the Bulk head ptr to the new endpoint */ 38517c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, ohci_ed_cpu_to_iommu(ohcip, ept)); 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate /* 38547c478bd9Sstevel@tonic-gate * Enable Bulk list processing if bulk open pipe 38557c478bd9Sstevel@tonic-gate * count is zero. 38567c478bd9Sstevel@tonic-gate */ 38577c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_bulk_pipe_count) { 38587c478bd9Sstevel@tonic-gate /* Start Bulk list processing */ 38597c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 38607c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_BLE)); 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate ohcip->ohci_open_bulk_pipe_count++; 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate 38677c478bd9Sstevel@tonic-gate /* 38687c478bd9Sstevel@tonic-gate * ohci_insert_intr_ed: 38697c478bd9Sstevel@tonic-gate * 38707c478bd9Sstevel@tonic-gate * Insert a interrupt endpoint into the Host Controller's (HC) interrupt 38717c478bd9Sstevel@tonic-gate * lattice tree. 38727c478bd9Sstevel@tonic-gate */ 38737c478bd9Sstevel@tonic-gate static void 38747c478bd9Sstevel@tonic-gate ohci_insert_intr_ed( 38757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 38767c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 38777c478bd9Sstevel@tonic-gate { 38787c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 38797c478bd9Sstevel@tonic-gate ohci_ed_t *next_lattice_ept, *lattice_ept; 38807c478bd9Sstevel@tonic-gate uint_t node; 38817c478bd9Sstevel@tonic-gate 38827c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 38837c478bd9Sstevel@tonic-gate 38847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 38857c478bd9Sstevel@tonic-gate "ohci_insert_intr_ed:"); 38867c478bd9Sstevel@tonic-gate 38877c478bd9Sstevel@tonic-gate /* 38887c478bd9Sstevel@tonic-gate * The appropriate node was found 38897c478bd9Sstevel@tonic-gate * during the opening of the pipe. 38907c478bd9Sstevel@tonic-gate */ 38917c478bd9Sstevel@tonic-gate node = pp->pp_node; 38927c478bd9Sstevel@tonic-gate 38937c478bd9Sstevel@tonic-gate if (node >= NUM_STATIC_NODES) { 38947c478bd9Sstevel@tonic-gate /* Get the hcca interrupt table index */ 38957c478bd9Sstevel@tonic-gate node = ohci_hcca_intr_index(node); 38967c478bd9Sstevel@tonic-gate 38977c478bd9Sstevel@tonic-gate /* Get the first endpoint on the list */ 38987c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu(ohcip, 38997c478bd9Sstevel@tonic-gate Get_HCCA(ohcip->ohci_hccap->HccaIntTble[node])); 39007c478bd9Sstevel@tonic-gate 39017c478bd9Sstevel@tonic-gate /* Update this endpoint to point to it */ 39027c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, 39037c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, next_lattice_ept)); 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate /* Put this endpoint at the head of the list */ 39067c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaIntTble[node], 39077c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 39087c478bd9Sstevel@tonic-gate 39097c478bd9Sstevel@tonic-gate /* The previous pointer is NULL */ 39107c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, NULL); 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate /* Update the previous pointer of ept->hced_next */ 39137c478bd9Sstevel@tonic-gate if (Get_ED(next_lattice_ept->hced_state) != HC_EPT_STATIC) { 39147c478bd9Sstevel@tonic-gate Set_ED(next_lattice_ept->hced_prev, 39157c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 39167c478bd9Sstevel@tonic-gate } 39177c478bd9Sstevel@tonic-gate } else { 39187c478bd9Sstevel@tonic-gate /* Find the lattice endpoint */ 39197c478bd9Sstevel@tonic-gate lattice_ept = &ohcip->ohci_ed_pool_addr[node]; 39207c478bd9Sstevel@tonic-gate 39217c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 39227c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu( 39237c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next)); 39247c478bd9Sstevel@tonic-gate 39257c478bd9Sstevel@tonic-gate /* 39267c478bd9Sstevel@tonic-gate * Update this endpoint to point to the next one in the 39277c478bd9Sstevel@tonic-gate * lattice. 39287c478bd9Sstevel@tonic-gate */ 39297c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_ED(lattice_ept->hced_next)); 39307c478bd9Sstevel@tonic-gate 39317c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */ 39327c478bd9Sstevel@tonic-gate Set_ED(lattice_ept->hced_next, 39337c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate /* Update the previous pointer */ 39367c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, 39377c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, lattice_ept)); 39387c478bd9Sstevel@tonic-gate 39397c478bd9Sstevel@tonic-gate /* Update the previous pointer of ept->hced_next */ 39407c478bd9Sstevel@tonic-gate if ((next_lattice_ept) && 39417c478bd9Sstevel@tonic-gate (Get_ED(next_lattice_ept->hced_state) != HC_EPT_STATIC)) { 39427c478bd9Sstevel@tonic-gate 39437c478bd9Sstevel@tonic-gate Set_ED(next_lattice_ept->hced_prev, 39447c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 39457c478bd9Sstevel@tonic-gate } 39467c478bd9Sstevel@tonic-gate } 39477c478bd9Sstevel@tonic-gate 39487c478bd9Sstevel@tonic-gate /* 39497c478bd9Sstevel@tonic-gate * Enable periodic list processing if periodic (interrupt 39507c478bd9Sstevel@tonic-gate * and isochronous) open pipe count is zero. 39517c478bd9Sstevel@tonic-gate */ 39527c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_periodic_pipe_count) { 39537c478bd9Sstevel@tonic-gate ASSERT(!ohcip->ohci_open_isoch_pipe_count); 39547c478bd9Sstevel@tonic-gate 39557c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 39567c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_PLE)); 39577c478bd9Sstevel@tonic-gate } 39587c478bd9Sstevel@tonic-gate 39597c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count++; 39607c478bd9Sstevel@tonic-gate } 39617c478bd9Sstevel@tonic-gate 39627c478bd9Sstevel@tonic-gate 39637c478bd9Sstevel@tonic-gate /* 39647c478bd9Sstevel@tonic-gate * ohci_insert_isoc_ed: 39657c478bd9Sstevel@tonic-gate * 39667c478bd9Sstevel@tonic-gate * Insert a isochronous endpoint into the Host Controller's (HC) interrupt 39677c478bd9Sstevel@tonic-gate * lattice tree. A isochronous endpoint will be inserted at the end of the 39687c478bd9Sstevel@tonic-gate * 1ms interrupt endpoint list. 39697c478bd9Sstevel@tonic-gate */ 39707c478bd9Sstevel@tonic-gate static void 39717c478bd9Sstevel@tonic-gate ohci_insert_isoc_ed( 39727c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 39737c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 39747c478bd9Sstevel@tonic-gate { 39757c478bd9Sstevel@tonic-gate ohci_ed_t *next_lattice_ept, *lattice_ept; 39767c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 39777c478bd9Sstevel@tonic-gate uint_t node; 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 39807c478bd9Sstevel@tonic-gate 39817c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 39827c478bd9Sstevel@tonic-gate "ohci_insert_isoc_ed:"); 39837c478bd9Sstevel@tonic-gate 39847c478bd9Sstevel@tonic-gate /* 39857c478bd9Sstevel@tonic-gate * The appropriate node was found during the opening of the pipe. 39867c478bd9Sstevel@tonic-gate * This node must be root of the interrupt lattice tree. 39877c478bd9Sstevel@tonic-gate */ 39887c478bd9Sstevel@tonic-gate node = pp->pp_node; 39897c478bd9Sstevel@tonic-gate 39907c478bd9Sstevel@tonic-gate ASSERT(node == 0); 39917c478bd9Sstevel@tonic-gate 39927c478bd9Sstevel@tonic-gate /* Find the 1ms interrupt lattice endpoint */ 39937c478bd9Sstevel@tonic-gate lattice_ept = &ohcip->ohci_ed_pool_addr[node]; 39947c478bd9Sstevel@tonic-gate 39957c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 39967c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu( 39977c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next)); 39987c478bd9Sstevel@tonic-gate 39997c478bd9Sstevel@tonic-gate while (next_lattice_ept) { 40007c478bd9Sstevel@tonic-gate lattice_ept = next_lattice_ept; 40017c478bd9Sstevel@tonic-gate 40027c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 40037c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu( 40047c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next)); 40057c478bd9Sstevel@tonic-gate } 40067c478bd9Sstevel@tonic-gate 40077c478bd9Sstevel@tonic-gate /* The next pointer is NULL */ 40087c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, NULL); 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate /* Update the previous pointer */ 40117c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, lattice_ept)); 40127c478bd9Sstevel@tonic-gate 40137c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */ 40147c478bd9Sstevel@tonic-gate Set_ED(lattice_ept->hced_next, ohci_ed_cpu_to_iommu(ohcip, ept)); 40157c478bd9Sstevel@tonic-gate 40167c478bd9Sstevel@tonic-gate /* 40177c478bd9Sstevel@tonic-gate * Enable periodic and isoch lists processing if isoch 40187c478bd9Sstevel@tonic-gate * open pipe count is zero. 40197c478bd9Sstevel@tonic-gate */ 40207c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_isoch_pipe_count) { 40217c478bd9Sstevel@tonic-gate 40227c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) | 40237c478bd9Sstevel@tonic-gate HCR_CONTROL_PLE | HCR_CONTROL_IE)); 40247c478bd9Sstevel@tonic-gate } 40257c478bd9Sstevel@tonic-gate 40267c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count++; 40277c478bd9Sstevel@tonic-gate ohcip->ohci_open_isoch_pipe_count++; 40287c478bd9Sstevel@tonic-gate } 40297c478bd9Sstevel@tonic-gate 40307c478bd9Sstevel@tonic-gate 40317c478bd9Sstevel@tonic-gate /* 40327c478bd9Sstevel@tonic-gate * ohci_modify_sKip_bit: 40337c478bd9Sstevel@tonic-gate * 40347c478bd9Sstevel@tonic-gate * Modify the sKip bit on the Host Controller (HC) Endpoint Descriptor (ED). 40357c478bd9Sstevel@tonic-gate */ 40367c478bd9Sstevel@tonic-gate static void 40377c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit( 40387c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 40397c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 40407c478bd9Sstevel@tonic-gate skip_bit_t action, 40417c478bd9Sstevel@tonic-gate usb_flags_t flag) 40427c478bd9Sstevel@tonic-gate { 40437c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 40447c478bd9Sstevel@tonic-gate 40457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 40467c478bd9Sstevel@tonic-gate "ohci_modify_sKip_bit: action = 0x%x flag = 0x%x", 40477c478bd9Sstevel@tonic-gate action, flag); 40487c478bd9Sstevel@tonic-gate 40497c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 40507c478bd9Sstevel@tonic-gate 40517c478bd9Sstevel@tonic-gate if (action == CLEAR_sKip) { 40527c478bd9Sstevel@tonic-gate /* 40537c478bd9Sstevel@tonic-gate * If the skip bit is to be cleared, just clear it. 40547c478bd9Sstevel@tonic-gate * there shouldn't be any race condition problems. 40557c478bd9Sstevel@tonic-gate * If the host controller reads the bit before the 40567c478bd9Sstevel@tonic-gate * driver has a chance to set the bit, the bit will 40577c478bd9Sstevel@tonic-gate * be reread on the next frame. 40587c478bd9Sstevel@tonic-gate */ 40597c478bd9Sstevel@tonic-gate Set_ED(ept->hced_ctrl, (Get_ED(ept->hced_ctrl) & ~HC_EPT_sKip)); 40607c478bd9Sstevel@tonic-gate } else { 40617c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 40627c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_DMA_SYNC) { 40637c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 40647c478bd9Sstevel@tonic-gate } 40657c478bd9Sstevel@tonic-gate 40667c478bd9Sstevel@tonic-gate /* Check Halt or Skip bit is already set */ 40677c478bd9Sstevel@tonic-gate if ((Get_ED(ept->hced_headp) & HC_EPT_Halt) || 40687c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_ctrl) & HC_EPT_sKip)) { 40697c478bd9Sstevel@tonic-gate 40707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 40717c478bd9Sstevel@tonic-gate "ohci_modify_sKip_bit: " 40727c478bd9Sstevel@tonic-gate "Halt or Skip bit is already set"); 40737c478bd9Sstevel@tonic-gate } else { 40747c478bd9Sstevel@tonic-gate /* 40757c478bd9Sstevel@tonic-gate * The action is to set the skip bit. In order to 40767c478bd9Sstevel@tonic-gate * be sure that the HCD has seen the sKip bit, wait 40777c478bd9Sstevel@tonic-gate * for the next start of frame. 40787c478bd9Sstevel@tonic-gate */ 40797c478bd9Sstevel@tonic-gate Set_ED(ept->hced_ctrl, 40807c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_ctrl) | HC_EPT_sKip)); 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_SLEEP) { 40837c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 40847c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip); 40857c478bd9Sstevel@tonic-gate 40867c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 40877c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_DMA_SYNC) { 40887c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 40897c478bd9Sstevel@tonic-gate } 40907c478bd9Sstevel@tonic-gate } 40917c478bd9Sstevel@tonic-gate } 40927c478bd9Sstevel@tonic-gate } 40937c478bd9Sstevel@tonic-gate } 40947c478bd9Sstevel@tonic-gate 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate /* 40977c478bd9Sstevel@tonic-gate * ohci_remove_ed: 40987c478bd9Sstevel@tonic-gate * 40997c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (ED) from the Host Controller's appropriate 41007c478bd9Sstevel@tonic-gate * endpoint list. 41017c478bd9Sstevel@tonic-gate */ 41027c478bd9Sstevel@tonic-gate static void 41037c478bd9Sstevel@tonic-gate ohci_remove_ed( 41047c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 41057c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 41067c478bd9Sstevel@tonic-gate { 41077c478bd9Sstevel@tonic-gate uchar_t attributes; 41087c478bd9Sstevel@tonic-gate 41097c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 41107c478bd9Sstevel@tonic-gate 41117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 41127c478bd9Sstevel@tonic-gate "ohci_remove_ed:"); 41137c478bd9Sstevel@tonic-gate 41147c478bd9Sstevel@tonic-gate attributes = pp->pp_pipe_handle->p_ep.bmAttributes & USB_EP_ATTR_MASK; 41157c478bd9Sstevel@tonic-gate 41167c478bd9Sstevel@tonic-gate switch (attributes) { 41177c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 41187c478bd9Sstevel@tonic-gate ohci_remove_ctrl_ed(ohcip, pp); 41197c478bd9Sstevel@tonic-gate break; 41207c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 41217c478bd9Sstevel@tonic-gate ohci_remove_bulk_ed(ohcip, pp); 41227c478bd9Sstevel@tonic-gate break; 41237c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 41247c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 41257c478bd9Sstevel@tonic-gate ohci_remove_periodic_ed(ohcip, pp); 41267c478bd9Sstevel@tonic-gate break; 41277c478bd9Sstevel@tonic-gate } 41287c478bd9Sstevel@tonic-gate } 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate /* 41327c478bd9Sstevel@tonic-gate * ohci_remove_ctrl_ed: 41337c478bd9Sstevel@tonic-gate * 41347c478bd9Sstevel@tonic-gate * Remove a control Endpoint Descriptor (ED) from the Host Controller's (HC) 41357c478bd9Sstevel@tonic-gate * control endpoint list. 41367c478bd9Sstevel@tonic-gate */ 41377c478bd9Sstevel@tonic-gate static void 41387c478bd9Sstevel@tonic-gate ohci_remove_ctrl_ed( 41397c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 41407c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 41417c478bd9Sstevel@tonic-gate { 41427c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 41437c478bd9Sstevel@tonic-gate 41447c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 41457c478bd9Sstevel@tonic-gate "ohci_remove_ctrl_ed:"); 41467c478bd9Sstevel@tonic-gate 41477c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate /* The control list should already be stopped */ 41507c478bd9Sstevel@tonic-gate ASSERT(!(Get_OpReg(hcr_control) & HCR_CONTROL_CLE)); 41517c478bd9Sstevel@tonic-gate 41527c478bd9Sstevel@tonic-gate ohcip->ohci_open_ctrl_pipe_count--; 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate /* Detach the endpoint from the list that it's on */ 41557c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, USB_EP_ATTR_CONTROL); 41567c478bd9Sstevel@tonic-gate 41577c478bd9Sstevel@tonic-gate /* 41587c478bd9Sstevel@tonic-gate * If next endpoint pointed by endpoint to be removed is not NULL 41597c478bd9Sstevel@tonic-gate * then set current control pointer to the next endpoint pointed by 41607c478bd9Sstevel@tonic-gate * endpoint to be removed. Otherwise set current control pointer to 41617c478bd9Sstevel@tonic-gate * the beginning of the control list. 41627c478bd9Sstevel@tonic-gate */ 41637c478bd9Sstevel@tonic-gate if (Get_ED(ept->hced_next)) { 41647c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, Get_ED(ept->hced_next)); 41657c478bd9Sstevel@tonic-gate } else { 41667c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, Get_OpReg(hcr_ctrl_head)); 41677c478bd9Sstevel@tonic-gate } 41687c478bd9Sstevel@tonic-gate 41697c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_ctrl_pipe_count) { 41707c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_ctrl_head)); 41717c478bd9Sstevel@tonic-gate 41727c478bd9Sstevel@tonic-gate /* Reenable the control list */ 41737c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 41747c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_CLE)); 41757c478bd9Sstevel@tonic-gate } 41767c478bd9Sstevel@tonic-gate 41777c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp); 41787c478bd9Sstevel@tonic-gate } 41797c478bd9Sstevel@tonic-gate 41807c478bd9Sstevel@tonic-gate 41817c478bd9Sstevel@tonic-gate /* 41827c478bd9Sstevel@tonic-gate * ohci_remove_bulk_ed: 41837c478bd9Sstevel@tonic-gate * 41847c478bd9Sstevel@tonic-gate * Remove free the bulk Endpoint Descriptor (ED) from the Host Controller's 41857c478bd9Sstevel@tonic-gate * (HC) bulk endpoint list. 41867c478bd9Sstevel@tonic-gate */ 41877c478bd9Sstevel@tonic-gate static void 41887c478bd9Sstevel@tonic-gate ohci_remove_bulk_ed( 41897c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 41907c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 41917c478bd9Sstevel@tonic-gate { 41927c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 41937c478bd9Sstevel@tonic-gate 41947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 41957c478bd9Sstevel@tonic-gate "ohci_remove_bulk_ed:"); 41967c478bd9Sstevel@tonic-gate 41977c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 41987c478bd9Sstevel@tonic-gate 41997c478bd9Sstevel@tonic-gate /* The bulk list should already be stopped */ 42007c478bd9Sstevel@tonic-gate ASSERT(!(Get_OpReg(hcr_control) & HCR_CONTROL_BLE)); 42017c478bd9Sstevel@tonic-gate 42027c478bd9Sstevel@tonic-gate ohcip->ohci_open_bulk_pipe_count--; 42037c478bd9Sstevel@tonic-gate 42047c478bd9Sstevel@tonic-gate /* Detach the endpoint from the bulk list */ 42057c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, USB_EP_ATTR_BULK); 42067c478bd9Sstevel@tonic-gate 42077c478bd9Sstevel@tonic-gate /* 42087c478bd9Sstevel@tonic-gate * If next endpoint pointed by endpoint to be removed is not NULL 42097c478bd9Sstevel@tonic-gate * then set current bulk pointer to the next endpoint pointed by 42107c478bd9Sstevel@tonic-gate * endpoint to be removed. Otherwise set current bulk pointer to 42117c478bd9Sstevel@tonic-gate * the beginning of the bulk list. 42127c478bd9Sstevel@tonic-gate */ 42137c478bd9Sstevel@tonic-gate if (Get_ED(ept->hced_next)) { 42147c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, Get_ED(ept->hced_next)); 42157c478bd9Sstevel@tonic-gate } else { 42167c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, Get_OpReg(hcr_bulk_head)); 42177c478bd9Sstevel@tonic-gate } 42187c478bd9Sstevel@tonic-gate 42197c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_bulk_pipe_count) { 42207c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_bulk_head)); 42217c478bd9Sstevel@tonic-gate 42227c478bd9Sstevel@tonic-gate /* Re-enable the bulk list */ 42237c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 42247c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_BLE)); 42257c478bd9Sstevel@tonic-gate } 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp); 42287c478bd9Sstevel@tonic-gate } 42297c478bd9Sstevel@tonic-gate 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate /* 42327c478bd9Sstevel@tonic-gate * ohci_remove_periodic_ed: 42337c478bd9Sstevel@tonic-gate * 42347c478bd9Sstevel@tonic-gate * Set up an periodic endpoint to be removed from the Host Controller's (HC) 42357c478bd9Sstevel@tonic-gate * interrupt lattice tree. The Endpoint Descriptor (ED) will be freed in the 42367c478bd9Sstevel@tonic-gate * interrupt handler. 42377c478bd9Sstevel@tonic-gate */ 42387c478bd9Sstevel@tonic-gate static void 42397c478bd9Sstevel@tonic-gate ohci_remove_periodic_ed( 42407c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 42417c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 42427c478bd9Sstevel@tonic-gate { 42437c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 42447c478bd9Sstevel@tonic-gate uint_t ept_type; 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 42477c478bd9Sstevel@tonic-gate "ohci_remove_periodic_ed:"); 42487c478bd9Sstevel@tonic-gate 42497c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 42507c478bd9Sstevel@tonic-gate 42517c478bd9Sstevel@tonic-gate ASSERT((Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL) == 42527c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD)); 42537c478bd9Sstevel@tonic-gate 42547c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count--; 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate ept_type = pp->pp_pipe_handle-> 42577c478bd9Sstevel@tonic-gate p_ep.bmAttributes & USB_EP_ATTR_MASK; 42587c478bd9Sstevel@tonic-gate 42597c478bd9Sstevel@tonic-gate if (ept_type == USB_EP_ATTR_ISOCH) { 42607c478bd9Sstevel@tonic-gate ohcip->ohci_open_isoch_pipe_count--; 42617c478bd9Sstevel@tonic-gate } 42627c478bd9Sstevel@tonic-gate 42637c478bd9Sstevel@tonic-gate /* Store the node number */ 42647c478bd9Sstevel@tonic-gate Set_ED(ept->hced_node, pp->pp_node); 42657c478bd9Sstevel@tonic-gate 42667c478bd9Sstevel@tonic-gate /* Remove the endpoint from interrupt lattice tree */ 42677c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, ept_type); 42687c478bd9Sstevel@tonic-gate 42697c478bd9Sstevel@tonic-gate /* 42707c478bd9Sstevel@tonic-gate * Disable isoch list processing if isoch open pipe count 42717c478bd9Sstevel@tonic-gate * is zero. 42727c478bd9Sstevel@tonic-gate */ 42737c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_isoch_pipe_count) { 42747c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 42757c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_IE))); 42767c478bd9Sstevel@tonic-gate } 42777c478bd9Sstevel@tonic-gate 42787c478bd9Sstevel@tonic-gate /* 42797c478bd9Sstevel@tonic-gate * Disable periodic list processing if periodic (interrupt 42807c478bd9Sstevel@tonic-gate * and isochrous) open pipe count is zero. 42817c478bd9Sstevel@tonic-gate */ 42827c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_periodic_pipe_count) { 42837c478bd9Sstevel@tonic-gate ASSERT(!ohcip->ohci_open_isoch_pipe_count); 42847c478bd9Sstevel@tonic-gate 42857c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 42867c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_PLE))); 42877c478bd9Sstevel@tonic-gate } 42887c478bd9Sstevel@tonic-gate 42897c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp); 42907c478bd9Sstevel@tonic-gate } 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate 42937c478bd9Sstevel@tonic-gate /* 42947c478bd9Sstevel@tonic-gate * ohci_detach_ed_from_list: 42957c478bd9Sstevel@tonic-gate * 42967c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (ED) from the appropriate Host Controller's 42977c478bd9Sstevel@tonic-gate * (HC) endpoint list. 42987c478bd9Sstevel@tonic-gate */ 42997c478bd9Sstevel@tonic-gate static void 43007c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list( 43017c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 43027c478bd9Sstevel@tonic-gate ohci_ed_t *ept, 43037c478bd9Sstevel@tonic-gate uint_t ept_type) 43047c478bd9Sstevel@tonic-gate { 43057c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; /* Previous endpoint */ 43067c478bd9Sstevel@tonic-gate ohci_ed_t *next_ept; /* Endpoint after one to be removed */ 43077c478bd9Sstevel@tonic-gate uint_t node; 43087c478bd9Sstevel@tonic-gate 43097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 43107c478bd9Sstevel@tonic-gate "ohci_detach_ed_from_list:"); 43117c478bd9Sstevel@tonic-gate 43127c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 43137c478bd9Sstevel@tonic-gate 43147c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, Get_ED(ept->hced_prev)); 43157c478bd9Sstevel@tonic-gate next_ept = ohci_ed_iommu_to_cpu(ohcip, Get_ED(ept->hced_next)); 43167c478bd9Sstevel@tonic-gate 43177c478bd9Sstevel@tonic-gate /* 43187c478bd9Sstevel@tonic-gate * If there is no previous endpoint, then this 43197c478bd9Sstevel@tonic-gate * endpoint is at the head of the endpoint list. 43207c478bd9Sstevel@tonic-gate */ 43217c478bd9Sstevel@tonic-gate if (prev_ept == NULL) { 43227c478bd9Sstevel@tonic-gate if (next_ept) { 43237c478bd9Sstevel@tonic-gate /* 43247c478bd9Sstevel@tonic-gate * If this endpoint is the first element of the 43257c478bd9Sstevel@tonic-gate * list and there is more than one endpoint on 43267c478bd9Sstevel@tonic-gate * the list then perform specific actions based 43277c478bd9Sstevel@tonic-gate * on the type of endpoint list. 43287c478bd9Sstevel@tonic-gate */ 43297c478bd9Sstevel@tonic-gate switch (ept_type) { 43307c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 43317c478bd9Sstevel@tonic-gate /* Set the head of list to next ept */ 43327c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, 43337c478bd9Sstevel@tonic-gate Get_ED(ept->hced_next)); 43347c478bd9Sstevel@tonic-gate 43357c478bd9Sstevel@tonic-gate /* Clear prev ptr of next endpoint */ 43367c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, NULL); 43377c478bd9Sstevel@tonic-gate break; 43387c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 43397c478bd9Sstevel@tonic-gate /* Set the head of list to next ept */ 43407c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, 43417c478bd9Sstevel@tonic-gate Get_ED(ept->hced_next)); 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate /* Clear prev ptr of next endpoint */ 43447c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, NULL); 43457c478bd9Sstevel@tonic-gate break; 43467c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 43477c478bd9Sstevel@tonic-gate /* 43487c478bd9Sstevel@tonic-gate * HCCA area should point 43497c478bd9Sstevel@tonic-gate * directly to this ept. 43507c478bd9Sstevel@tonic-gate */ 43517c478bd9Sstevel@tonic-gate ASSERT(Get_ED(ept->hced_node) >= 43527c478bd9Sstevel@tonic-gate NUM_STATIC_NODES); 43537c478bd9Sstevel@tonic-gate 43547c478bd9Sstevel@tonic-gate /* Get the hcca interrupt table index */ 43557c478bd9Sstevel@tonic-gate node = ohci_hcca_intr_index( 43567c478bd9Sstevel@tonic-gate Get_ED(ept->hced_node)); 43577c478bd9Sstevel@tonic-gate 43587c478bd9Sstevel@tonic-gate /* 43597c478bd9Sstevel@tonic-gate * Delete the ept from the 43607c478bd9Sstevel@tonic-gate * bottom of the tree. 43617c478bd9Sstevel@tonic-gate */ 43627c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap-> 43637c478bd9Sstevel@tonic-gate HccaIntTble[node], Get_ED(ept->hced_next)); 43647c478bd9Sstevel@tonic-gate 43657c478bd9Sstevel@tonic-gate /* 43667c478bd9Sstevel@tonic-gate * Update the previous pointer 43677c478bd9Sstevel@tonic-gate * of ept->hced_next 43687c478bd9Sstevel@tonic-gate */ 43697c478bd9Sstevel@tonic-gate if (Get_ED(next_ept->hced_state) != 43707c478bd9Sstevel@tonic-gate HC_EPT_STATIC) { 43717c478bd9Sstevel@tonic-gate 43727c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, NULL); 43737c478bd9Sstevel@tonic-gate } 43747c478bd9Sstevel@tonic-gate 43757c478bd9Sstevel@tonic-gate break; 43767c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 43777c478bd9Sstevel@tonic-gate default: 43787c478bd9Sstevel@tonic-gate break; 43797c478bd9Sstevel@tonic-gate } 43807c478bd9Sstevel@tonic-gate } else { 43817c478bd9Sstevel@tonic-gate /* 43827c478bd9Sstevel@tonic-gate * If there was only one element on the list 43837c478bd9Sstevel@tonic-gate * perform specific actions based on the type 43847c478bd9Sstevel@tonic-gate * of the list. 43857c478bd9Sstevel@tonic-gate */ 43867c478bd9Sstevel@tonic-gate switch (ept_type) { 43877c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 43887c478bd9Sstevel@tonic-gate /* Set the head to NULL */ 43897c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, NULL); 43907c478bd9Sstevel@tonic-gate break; 43917c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 43927c478bd9Sstevel@tonic-gate /* Set the head to NULL */ 43937c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, NULL); 43947c478bd9Sstevel@tonic-gate break; 43957c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 43967c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 43977c478bd9Sstevel@tonic-gate default: 43987c478bd9Sstevel@tonic-gate break; 43997c478bd9Sstevel@tonic-gate } 44007c478bd9Sstevel@tonic-gate } 44017c478bd9Sstevel@tonic-gate } else { 44027c478bd9Sstevel@tonic-gate /* The previous ept points to the next one */ 44037c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_next, Get_ED(ept->hced_next)); 44047c478bd9Sstevel@tonic-gate 44057c478bd9Sstevel@tonic-gate /* 44067c478bd9Sstevel@tonic-gate * Set the previous ptr of the next_ept to prev_ept 44077c478bd9Sstevel@tonic-gate * if this isn't the last endpoint on the list 44087c478bd9Sstevel@tonic-gate */ 44097c478bd9Sstevel@tonic-gate if ((next_ept) && 44107c478bd9Sstevel@tonic-gate (Get_ED(next_ept->hced_state) != HC_EPT_STATIC)) { 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate /* Set the previous ptr of the next one */ 44137c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, Get_ED(ept->hced_prev)); 44147c478bd9Sstevel@tonic-gate } 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate } 44177c478bd9Sstevel@tonic-gate 44187c478bd9Sstevel@tonic-gate 44197c478bd9Sstevel@tonic-gate /* 44207c478bd9Sstevel@tonic-gate * ohci_insert_ed_on_reclaim_list: 44217c478bd9Sstevel@tonic-gate * 44227c478bd9Sstevel@tonic-gate * Insert Endpoint onto the reclaim list 44237c478bd9Sstevel@tonic-gate */ 44247c478bd9Sstevel@tonic-gate static void 44257c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list( 44267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 44277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 44287c478bd9Sstevel@tonic-gate { 44297c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 44307c478bd9Sstevel@tonic-gate ohci_ed_t *next_ept, *prev_ept; 44317c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number; 44327c478bd9Sstevel@tonic-gate 44337c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 44347c478bd9Sstevel@tonic-gate 44357c478bd9Sstevel@tonic-gate /* 44367c478bd9Sstevel@tonic-gate * Read current usb frame number and add appropriate number of 44377c478bd9Sstevel@tonic-gate * usb frames needs to wait before reclaiming current endpoint. 44387c478bd9Sstevel@tonic-gate */ 44397c478bd9Sstevel@tonic-gate frame_number = 44407c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohcip) + MAX_SOF_WAIT_COUNT; 44417c478bd9Sstevel@tonic-gate 44427c478bd9Sstevel@tonic-gate /* Store 32bit ID */ 44437c478bd9Sstevel@tonic-gate Set_ED(ept->hced_reclaim_frame, 44447c478bd9Sstevel@tonic-gate ((uint32_t)(OHCI_GET_ID((void *)(uintptr_t)frame_number)))); 44457c478bd9Sstevel@tonic-gate 44467c478bd9Sstevel@tonic-gate /* Insert the endpoint onto the reclaimation list */ 44477c478bd9Sstevel@tonic-gate if (ohcip->ohci_reclaim_list) { 44487c478bd9Sstevel@tonic-gate next_ept = ohcip->ohci_reclaim_list; 44497c478bd9Sstevel@tonic-gate 44507c478bd9Sstevel@tonic-gate while (next_ept) { 44517c478bd9Sstevel@tonic-gate prev_ept = next_ept; 44527c478bd9Sstevel@tonic-gate next_ept = ohci_ed_iommu_to_cpu(ohcip, 44537c478bd9Sstevel@tonic-gate Get_ED(next_ept->hced_reclaim_next)); 44547c478bd9Sstevel@tonic-gate } 44557c478bd9Sstevel@tonic-gate 44567c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_reclaim_next, 44577c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 44587c478bd9Sstevel@tonic-gate } else { 44597c478bd9Sstevel@tonic-gate ohcip->ohci_reclaim_list = ept; 44607c478bd9Sstevel@tonic-gate } 44617c478bd9Sstevel@tonic-gate 44627c478bd9Sstevel@tonic-gate ASSERT(Get_ED(ept->hced_reclaim_next) == NULL); 44637c478bd9Sstevel@tonic-gate 44647c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */ 44657c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF); 44667c478bd9Sstevel@tonic-gate } 44677c478bd9Sstevel@tonic-gate 44687c478bd9Sstevel@tonic-gate 44697c478bd9Sstevel@tonic-gate /* 44707c478bd9Sstevel@tonic-gate * ohci_deallocate_ed: 44717c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 44727c478bd9Sstevel@tonic-gate * 44737c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Endpoint Descriptor (ED). 44747c478bd9Sstevel@tonic-gate */ 44757c478bd9Sstevel@tonic-gate void 44767c478bd9Sstevel@tonic-gate ohci_deallocate_ed( 44777c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 44787c478bd9Sstevel@tonic-gate ohci_ed_t *old_ed) 44797c478bd9Sstevel@tonic-gate { 44807c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td; 44817c478bd9Sstevel@tonic-gate 44827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 44837c478bd9Sstevel@tonic-gate "ohci_deallocate_ed:"); 44847c478bd9Sstevel@tonic-gate 44857c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 44867c478bd9Sstevel@tonic-gate 44877c478bd9Sstevel@tonic-gate dummy_td = ohci_td_iommu_to_cpu(ohcip, Get_ED(old_ed->hced_headp)); 44887c478bd9Sstevel@tonic-gate 44897c478bd9Sstevel@tonic-gate if (dummy_td) { 44907c478bd9Sstevel@tonic-gate 44917c478bd9Sstevel@tonic-gate ASSERT(Get_TD(dummy_td->hctd_state) == HC_TD_DUMMY); 44927c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, dummy_td); 44937c478bd9Sstevel@tonic-gate } 44947c478bd9Sstevel@tonic-gate 44957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 44967c478bd9Sstevel@tonic-gate "ohci_deallocate_ed: Deallocated 0x%p", (void *)old_ed); 44977c478bd9Sstevel@tonic-gate 44987c478bd9Sstevel@tonic-gate bzero((void *)old_ed, sizeof (ohci_ed_t)); 44997c478bd9Sstevel@tonic-gate Set_ED(old_ed->hced_state, HC_EPT_FREE); 45007c478bd9Sstevel@tonic-gate } 45017c478bd9Sstevel@tonic-gate 45027c478bd9Sstevel@tonic-gate 45037c478bd9Sstevel@tonic-gate /* 45047c478bd9Sstevel@tonic-gate * ohci_ed_cpu_to_iommu: 45057c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 45067c478bd9Sstevel@tonic-gate * 45077c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (ED) CPU address 45087c478bd9Sstevel@tonic-gate * to IO address. 45097c478bd9Sstevel@tonic-gate */ 45107c478bd9Sstevel@tonic-gate uint32_t 45117c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu( 45127c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 45137c478bd9Sstevel@tonic-gate ohci_ed_t *addr) 45147c478bd9Sstevel@tonic-gate { 45157c478bd9Sstevel@tonic-gate uint32_t ed; 45167c478bd9Sstevel@tonic-gate 45177c478bd9Sstevel@tonic-gate ed = (uint32_t)ohcip->ohci_ed_pool_cookie.dmac_address + 45187c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ohcip->ohci_ed_pool_addr)); 45197c478bd9Sstevel@tonic-gate 45207c478bd9Sstevel@tonic-gate ASSERT(ed >= ohcip->ohci_ed_pool_cookie.dmac_address); 45217c478bd9Sstevel@tonic-gate ASSERT(ed <= ohcip->ohci_ed_pool_cookie.dmac_address + 45227c478bd9Sstevel@tonic-gate sizeof (ohci_ed_t) * ohci_ed_pool_size); 45237c478bd9Sstevel@tonic-gate 45247c478bd9Sstevel@tonic-gate return (ed); 45257c478bd9Sstevel@tonic-gate } 45267c478bd9Sstevel@tonic-gate 45277c478bd9Sstevel@tonic-gate 45287c478bd9Sstevel@tonic-gate /* 45297c478bd9Sstevel@tonic-gate * ohci_ed_iommu_to_cpu: 45307c478bd9Sstevel@tonic-gate * 45317c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (ED) IO address 45327c478bd9Sstevel@tonic-gate * to CPU address. 45337c478bd9Sstevel@tonic-gate */ 45347c478bd9Sstevel@tonic-gate static ohci_ed_t * 45357c478bd9Sstevel@tonic-gate ohci_ed_iommu_to_cpu( 45367c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 45377c478bd9Sstevel@tonic-gate uintptr_t addr) 45387c478bd9Sstevel@tonic-gate { 45397c478bd9Sstevel@tonic-gate ohci_ed_t *ed; 45407c478bd9Sstevel@tonic-gate 45417c478bd9Sstevel@tonic-gate if (addr == NULL) { 45427c478bd9Sstevel@tonic-gate 45437c478bd9Sstevel@tonic-gate return (NULL); 45447c478bd9Sstevel@tonic-gate } 45457c478bd9Sstevel@tonic-gate 45467c478bd9Sstevel@tonic-gate ed = (ohci_ed_t *)((uintptr_t) 45477c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_ed_pool_cookie.dmac_address) + 45487c478bd9Sstevel@tonic-gate (uintptr_t)ohcip->ohci_ed_pool_addr); 45497c478bd9Sstevel@tonic-gate 45507c478bd9Sstevel@tonic-gate ASSERT(ed >= ohcip->ohci_ed_pool_addr); 45517c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)ed <= (uintptr_t)ohcip->ohci_ed_pool_addr + 45527c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ohci_ed_t) * ohci_ed_pool_size)); 45537c478bd9Sstevel@tonic-gate 45547c478bd9Sstevel@tonic-gate return (ed); 45557c478bd9Sstevel@tonic-gate } 45567c478bd9Sstevel@tonic-gate 45577c478bd9Sstevel@tonic-gate 45587c478bd9Sstevel@tonic-gate /* 45597c478bd9Sstevel@tonic-gate * Transfer Descriptor manipulations functions 45607c478bd9Sstevel@tonic-gate */ 45617c478bd9Sstevel@tonic-gate 45627c478bd9Sstevel@tonic-gate /* 45637c478bd9Sstevel@tonic-gate * ohci_initialize_dummy: 45647c478bd9Sstevel@tonic-gate * 45657c478bd9Sstevel@tonic-gate * An Endpoint Descriptor (ED) has a dummy Transfer Descriptor (TD) on the 45667c478bd9Sstevel@tonic-gate * end of its TD list. Initially, both the head and tail pointers of the ED 45677c478bd9Sstevel@tonic-gate * point to the dummy TD. 45687c478bd9Sstevel@tonic-gate */ 45697c478bd9Sstevel@tonic-gate static int 45707c478bd9Sstevel@tonic-gate ohci_initialize_dummy( 45717c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 45727c478bd9Sstevel@tonic-gate ohci_ed_t *ept) 45737c478bd9Sstevel@tonic-gate { 45747c478bd9Sstevel@tonic-gate ohci_td_t *dummy; 45757c478bd9Sstevel@tonic-gate 45767c478bd9Sstevel@tonic-gate /* Obtain a dummy TD */ 45777c478bd9Sstevel@tonic-gate dummy = ohci_allocate_td_from_pool(ohcip); 45787c478bd9Sstevel@tonic-gate 45797c478bd9Sstevel@tonic-gate if (dummy == NULL) { 45807c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate 45837c478bd9Sstevel@tonic-gate /* 45847c478bd9Sstevel@tonic-gate * Both the head and tail pointers of an ED point 45857c478bd9Sstevel@tonic-gate * to this new dummy TD. 45867c478bd9Sstevel@tonic-gate */ 45877c478bd9Sstevel@tonic-gate Set_ED(ept->hced_headp, (ohci_td_cpu_to_iommu(ohcip, dummy))); 45887c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, dummy))); 45897c478bd9Sstevel@tonic-gate 45907c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 45917c478bd9Sstevel@tonic-gate } 45927c478bd9Sstevel@tonic-gate 45937c478bd9Sstevel@tonic-gate /* 45947c478bd9Sstevel@tonic-gate * ohci_allocate_ctrl_resources: 45957c478bd9Sstevel@tonic-gate * 45967c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates 45977c478bd9Sstevel@tonic-gate * all the resources necessary. 45987c478bd9Sstevel@tonic-gate * 45997c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 46007c478bd9Sstevel@tonic-gate */ 46017c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 46027c478bd9Sstevel@tonic-gate ohci_allocate_ctrl_resources( 46037c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 46047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 46057c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 46067c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 46077c478bd9Sstevel@tonic-gate { 46087c478bd9Sstevel@tonic-gate size_t td_count = 2; 46097c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 46107c478bd9Sstevel@tonic-gate 46117c478bd9Sstevel@tonic-gate /* Add one more td for data phase */ 46127c478bd9Sstevel@tonic-gate if (ctrl_reqp->ctrl_wLength) { 46137c478bd9Sstevel@tonic-gate td_count++; 46147c478bd9Sstevel@tonic-gate } 46157c478bd9Sstevel@tonic-gate 46167c478bd9Sstevel@tonic-gate tw = ohci_allocate_tw_resources(ohcip, pp, 46177c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_wLength + SETUP_SIZE, 46187c478bd9Sstevel@tonic-gate usb_flags, td_count); 46197c478bd9Sstevel@tonic-gate 46207c478bd9Sstevel@tonic-gate return (tw); 46217c478bd9Sstevel@tonic-gate } 46227c478bd9Sstevel@tonic-gate 46237c478bd9Sstevel@tonic-gate /* 46247c478bd9Sstevel@tonic-gate * ohci_insert_ctrl_req: 46257c478bd9Sstevel@tonic-gate * 46267c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (TD) and a data buffer for a control endpoint. 46277c478bd9Sstevel@tonic-gate */ 46287c478bd9Sstevel@tonic-gate /* ARGSUSED */ 46297c478bd9Sstevel@tonic-gate static void 46307c478bd9Sstevel@tonic-gate ohci_insert_ctrl_req( 46317c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 46327c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 46337c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 46347c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 46357c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 46367c478bd9Sstevel@tonic-gate { 46377c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 46387c478bd9Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType; 46397c478bd9Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest; 46407c478bd9Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue; 46417c478bd9Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex; 46427c478bd9Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength; 46437c478bd9Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data; 46447c478bd9Sstevel@tonic-gate uint32_t ctrl = 0; 46457c478bd9Sstevel@tonic-gate int sdata; 46467c478bd9Sstevel@tonic-gate 46477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 46487c478bd9Sstevel@tonic-gate "ohci_insert_ctrl_req:"); 46497c478bd9Sstevel@tonic-gate 46507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 46517c478bd9Sstevel@tonic-gate 46527c478bd9Sstevel@tonic-gate /* 46537c478bd9Sstevel@tonic-gate * Save current control request pointer and timeout values 46547c478bd9Sstevel@tonic-gate * in transfer wrapper. 46557c478bd9Sstevel@tonic-gate */ 46567c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)ctrl_reqp; 46577c478bd9Sstevel@tonic-gate tw->tw_timeout = ctrl_reqp->ctrl_timeout ? 46587c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_timeout : OHCI_DEFAULT_XFER_TIMEOUT; 46597c478bd9Sstevel@tonic-gate 46607c478bd9Sstevel@tonic-gate /* 46617c478bd9Sstevel@tonic-gate * Initialize the callback and any callback data for when 46627c478bd9Sstevel@tonic-gate * the td completes. 46637c478bd9Sstevel@tonic-gate */ 46647c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_ctrl_td; 46657c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 46667c478bd9Sstevel@tonic-gate 46677c478bd9Sstevel@tonic-gate /* Create the first four bytes of the setup packet */ 46687c478bd9Sstevel@tonic-gate sdata = (bmRequestType << 24) | (bRequest << 16) | 46697c478bd9Sstevel@tonic-gate (((wValue >> 8) | (wValue << 8)) & 0x0000FFFF); 46707c478bd9Sstevel@tonic-gate 46717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 46727c478bd9Sstevel@tonic-gate "ohci_create_setup_pkt: sdata = 0x%x", sdata); 46737c478bd9Sstevel@tonic-gate 46747c478bd9Sstevel@tonic-gate ddi_put32(tw->tw_accesshandle, (uint_t *)tw->tw_buf, sdata); 46757c478bd9Sstevel@tonic-gate 46767c478bd9Sstevel@tonic-gate /* Create the second four bytes */ 46777c478bd9Sstevel@tonic-gate sdata = (uint32_t)(((((wIndex >> 8) | 46787c478bd9Sstevel@tonic-gate (wIndex << 8)) << 16) & 0xFFFF0000) | 46797c478bd9Sstevel@tonic-gate (((wLength >> 8) | (wLength << 8)) & 0x0000FFFF)); 46807c478bd9Sstevel@tonic-gate 46817c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 46827c478bd9Sstevel@tonic-gate "ohci_create_setup_pkt: sdata = 0x%x", sdata); 46837c478bd9Sstevel@tonic-gate 46847c478bd9Sstevel@tonic-gate ddi_put32(tw->tw_accesshandle, 46857c478bd9Sstevel@tonic-gate (uint_t *)(tw->tw_buf + sizeof (uint_t)), sdata); 46867c478bd9Sstevel@tonic-gate 46877c478bd9Sstevel@tonic-gate ctrl = HC_TD_SETUP|HC_TD_MS_DT|HC_TD_DT_0|HC_TD_6I; 46887c478bd9Sstevel@tonic-gate 46897c478bd9Sstevel@tonic-gate /* 46907c478bd9Sstevel@tonic-gate * The TD's are placed on the ED one at a time. 46917c478bd9Sstevel@tonic-gate * Once this TD is placed on the done list, the 46927c478bd9Sstevel@tonic-gate * data or status phase TD will be enqueued. 46937c478bd9Sstevel@tonic-gate */ 46947c478bd9Sstevel@tonic-gate (void) ohci_insert_hc_td(ohcip, ctrl, 46957c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address, SETUP_SIZE, 46967c478bd9Sstevel@tonic-gate OHCI_CTRL_SETUP_PHASE, pp, tw); 46977c478bd9Sstevel@tonic-gate 46987c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 46997c478bd9Sstevel@tonic-gate "Create_setup: pp 0x%p", (void *)pp); 47007c478bd9Sstevel@tonic-gate 47017c478bd9Sstevel@tonic-gate /* 47027c478bd9Sstevel@tonic-gate * If this control transfer has a data phase, record the 47037c478bd9Sstevel@tonic-gate * direction. If the data phase is an OUT transaction, 47047c478bd9Sstevel@tonic-gate * copy the data into the buffer of the transfer wrapper. 47057c478bd9Sstevel@tonic-gate */ 47067c478bd9Sstevel@tonic-gate if (wLength != 0) { 47077c478bd9Sstevel@tonic-gate /* There is a data stage. Find the direction */ 47087c478bd9Sstevel@tonic-gate if (bmRequestType & USB_DEV_REQ_DEV_TO_HOST) { 47097c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN; 47107c478bd9Sstevel@tonic-gate } else { 47117c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT; 47127c478bd9Sstevel@tonic-gate 47137c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 47147c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, data->b_rptr, 47157c478bd9Sstevel@tonic-gate (uint8_t *)(tw->tw_buf + SETUP_SIZE), 47167c478bd9Sstevel@tonic-gate wLength, DDI_DEV_AUTOINCR); 47177c478bd9Sstevel@tonic-gate 47187c478bd9Sstevel@tonic-gate } 47197c478bd9Sstevel@tonic-gate 47207c478bd9Sstevel@tonic-gate ctrl = (ctrl_reqp->ctrl_attributes & USB_ATTRS_SHORT_XFER_OK) ? 47217c478bd9Sstevel@tonic-gate HC_TD_R : 0; 47227c478bd9Sstevel@tonic-gate 47237c478bd9Sstevel@tonic-gate /* 47247c478bd9Sstevel@tonic-gate * There is a data stage. 47257c478bd9Sstevel@tonic-gate * Find the direction. 47267c478bd9Sstevel@tonic-gate */ 47277c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) { 47287c478bd9Sstevel@tonic-gate ctrl = ctrl|HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_6I; 47297c478bd9Sstevel@tonic-gate } else { 47307c478bd9Sstevel@tonic-gate ctrl = ctrl|HC_TD_OUT|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_6I; 47317c478bd9Sstevel@tonic-gate } 47327c478bd9Sstevel@tonic-gate 47337c478bd9Sstevel@tonic-gate /* 47347c478bd9Sstevel@tonic-gate * Create the TD. If this is an OUT transaction, 47357c478bd9Sstevel@tonic-gate * the data is already in the buffer of the TW. 47367c478bd9Sstevel@tonic-gate */ 47377c478bd9Sstevel@tonic-gate (void) ohci_insert_hc_td(ohcip, ctrl, 47387c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address + SETUP_SIZE, 47397c478bd9Sstevel@tonic-gate tw->tw_length - SETUP_SIZE, OHCI_CTRL_DATA_PHASE, 47407c478bd9Sstevel@tonic-gate pp, tw); 47417c478bd9Sstevel@tonic-gate 47427c478bd9Sstevel@tonic-gate /* 47437c478bd9Sstevel@tonic-gate * The direction of the STATUS TD depends on 47447c478bd9Sstevel@tonic-gate * the direction of the transfer. 47457c478bd9Sstevel@tonic-gate */ 47467c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) { 47477c478bd9Sstevel@tonic-gate ctrl = HC_TD_OUT|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I; 47487c478bd9Sstevel@tonic-gate } else { 47497c478bd9Sstevel@tonic-gate ctrl = HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I; 47507c478bd9Sstevel@tonic-gate } 47517c478bd9Sstevel@tonic-gate } else { 47527c478bd9Sstevel@tonic-gate ctrl = HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I; 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate 47557c478bd9Sstevel@tonic-gate /* Status stage */ 47567c478bd9Sstevel@tonic-gate (void) ohci_insert_hc_td(ohcip, ctrl, NULL, 47577c478bd9Sstevel@tonic-gate 0, OHCI_CTRL_STATUS_PHASE, pp, tw); 47587c478bd9Sstevel@tonic-gate 47597c478bd9Sstevel@tonic-gate /* Indicate that the control list is filled */ 47607c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_CLF); 47617c478bd9Sstevel@tonic-gate 47627c478bd9Sstevel@tonic-gate /* Start the timer for this control transfer */ 47637c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw); 47647c478bd9Sstevel@tonic-gate } 47657c478bd9Sstevel@tonic-gate 47667c478bd9Sstevel@tonic-gate /* 47677c478bd9Sstevel@tonic-gate * ohci_allocate_bulk_resources: 47687c478bd9Sstevel@tonic-gate * 47697c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates 47707c478bd9Sstevel@tonic-gate * all the resources necessary. 47717c478bd9Sstevel@tonic-gate * 47727c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 47737c478bd9Sstevel@tonic-gate */ 47747c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 47757c478bd9Sstevel@tonic-gate ohci_allocate_bulk_resources( 47767c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 47777c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 47787c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 47797c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 47807c478bd9Sstevel@tonic-gate { 47817c478bd9Sstevel@tonic-gate size_t td_count = 0; 47827c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 47837c478bd9Sstevel@tonic-gate 47847c478bd9Sstevel@tonic-gate /* Check the size of bulk request */ 47857c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_len > OHCI_MAX_BULK_XFER_SIZE) { 47867c478bd9Sstevel@tonic-gate 47877c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 47887c478bd9Sstevel@tonic-gate "ohci_allocate_bulk_resources: Bulk request size 0x%x is " 47897c478bd9Sstevel@tonic-gate "more than 0x%x", bulk_reqp->bulk_len, 47907c478bd9Sstevel@tonic-gate OHCI_MAX_BULK_XFER_SIZE); 47917c478bd9Sstevel@tonic-gate 47927c478bd9Sstevel@tonic-gate return (NULL); 47937c478bd9Sstevel@tonic-gate } 47947c478bd9Sstevel@tonic-gate 47957c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */ 47967c478bd9Sstevel@tonic-gate td_count = bulk_reqp->bulk_len / OHCI_MAX_TD_XFER_SIZE; 47977c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_len % OHCI_MAX_TD_XFER_SIZE) { 47987c478bd9Sstevel@tonic-gate td_count++; 47997c478bd9Sstevel@tonic-gate } 48007c478bd9Sstevel@tonic-gate 48017c478bd9Sstevel@tonic-gate tw = ohci_allocate_tw_resources(ohcip, pp, bulk_reqp->bulk_len, 48027c478bd9Sstevel@tonic-gate usb_flags, td_count); 48037c478bd9Sstevel@tonic-gate 48047c478bd9Sstevel@tonic-gate return (tw); 48057c478bd9Sstevel@tonic-gate } 48067c478bd9Sstevel@tonic-gate 48077c478bd9Sstevel@tonic-gate /* 48087c478bd9Sstevel@tonic-gate * ohci_insert_bulk_req: 48097c478bd9Sstevel@tonic-gate * 48107c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (TD) and a data buffer for a bulk 48117c478bd9Sstevel@tonic-gate * endpoint. 48127c478bd9Sstevel@tonic-gate */ 48137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 48147c478bd9Sstevel@tonic-gate static void 48157c478bd9Sstevel@tonic-gate ohci_insert_bulk_req( 48167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 48177c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 48187c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 48197c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 48207c478bd9Sstevel@tonic-gate usb_flags_t flags) 48217c478bd9Sstevel@tonic-gate { 48227c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 48237c478bd9Sstevel@tonic-gate uint_t bulk_pkt_size, count; 48247c478bd9Sstevel@tonic-gate size_t residue = 0, len = 0; 48257c478bd9Sstevel@tonic-gate uint32_t ctrl = 0; 48267c478bd9Sstevel@tonic-gate int pipe_dir; 48277c478bd9Sstevel@tonic-gate 48287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 48297c478bd9Sstevel@tonic-gate "ohci_insert_bulk_req: bulk_reqp = 0x%p flags = 0x%x", 48307c478bd9Sstevel@tonic-gate bulk_reqp, flags); 48317c478bd9Sstevel@tonic-gate 48327c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 48337c478bd9Sstevel@tonic-gate 48347c478bd9Sstevel@tonic-gate /* Get the bulk pipe direction */ 48357c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 48367c478bd9Sstevel@tonic-gate 48377c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */ 48387c478bd9Sstevel@tonic-gate bulk_pkt_size = min(bulk_reqp->bulk_len, OHCI_MAX_TD_XFER_SIZE); 48397c478bd9Sstevel@tonic-gate 48407c478bd9Sstevel@tonic-gate residue = tw->tw_length % bulk_pkt_size; 48417c478bd9Sstevel@tonic-gate 48427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 48437c478bd9Sstevel@tonic-gate "ohci_insert_bulk_req: bulk_pkt_size = %d", bulk_pkt_size); 48447c478bd9Sstevel@tonic-gate 48457c478bd9Sstevel@tonic-gate /* 48467c478bd9Sstevel@tonic-gate * Save current bulk request pointer and timeout values 48477c478bd9Sstevel@tonic-gate * in transfer wrapper. 48487c478bd9Sstevel@tonic-gate */ 48497c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)bulk_reqp; 48507c478bd9Sstevel@tonic-gate tw->tw_timeout = bulk_reqp->bulk_timeout; 48517c478bd9Sstevel@tonic-gate 48527c478bd9Sstevel@tonic-gate /* 48537c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 48547c478bd9Sstevel@tonic-gate * data required when the td completes. 48557c478bd9Sstevel@tonic-gate */ 48567c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_bulk_td; 48577c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 48587c478bd9Sstevel@tonic-gate 48597c478bd9Sstevel@tonic-gate tw->tw_direction = 48607c478bd9Sstevel@tonic-gate (pipe_dir == USB_EP_DIR_OUT) ? HC_TD_OUT : HC_TD_IN; 48617c478bd9Sstevel@tonic-gate 48627c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_OUT) { 48637c478bd9Sstevel@tonic-gate 48647c478bd9Sstevel@tonic-gate ASSERT(bulk_reqp->bulk_data != NULL); 48657c478bd9Sstevel@tonic-gate 48667c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 48677c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, 48687c478bd9Sstevel@tonic-gate bulk_reqp->bulk_data->b_rptr, (uint8_t *)tw->tw_buf, 48697c478bd9Sstevel@tonic-gate bulk_reqp->bulk_len, DDI_DEV_AUTOINCR); 48707c478bd9Sstevel@tonic-gate } 48717c478bd9Sstevel@tonic-gate 48727c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction|HC_TD_DT_0|HC_TD_6I; 48737c478bd9Sstevel@tonic-gate 48747c478bd9Sstevel@tonic-gate /* Insert all the bulk TDs */ 48757c478bd9Sstevel@tonic-gate for (count = 0; count < tw->tw_num_tds; count++) { 48767c478bd9Sstevel@tonic-gate 48777c478bd9Sstevel@tonic-gate /* Check for last td */ 48787c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_tds - 1)) { 48797c478bd9Sstevel@tonic-gate 48807c478bd9Sstevel@tonic-gate ctrl = ((ctrl & ~HC_TD_DI) | HC_TD_1I); 48817c478bd9Sstevel@tonic-gate 48827c478bd9Sstevel@tonic-gate /* Check for inserting residue data */ 48837c478bd9Sstevel@tonic-gate if (residue) { 48847c478bd9Sstevel@tonic-gate bulk_pkt_size = residue; 48857c478bd9Sstevel@tonic-gate } 48867c478bd9Sstevel@tonic-gate 48877c478bd9Sstevel@tonic-gate /* 48887c478bd9Sstevel@tonic-gate * Only set the round bit on the last TD, to ensure 48897c478bd9Sstevel@tonic-gate * the controller will always HALT the ED in case of 48907c478bd9Sstevel@tonic-gate * a short transfer. 48917c478bd9Sstevel@tonic-gate */ 48927c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_attributes & 48937c478bd9Sstevel@tonic-gate USB_ATTRS_SHORT_XFER_OK) { 48947c478bd9Sstevel@tonic-gate ctrl |= HC_TD_R; 48957c478bd9Sstevel@tonic-gate } 48967c478bd9Sstevel@tonic-gate } 48977c478bd9Sstevel@tonic-gate 48987c478bd9Sstevel@tonic-gate /* Insert the TD onto the endpoint */ 48997c478bd9Sstevel@tonic-gate (void) ohci_insert_hc_td(ohcip, ctrl, 49007c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address + len, 49017c478bd9Sstevel@tonic-gate bulk_pkt_size, 0, pp, tw); 49027c478bd9Sstevel@tonic-gate 49037c478bd9Sstevel@tonic-gate len = len + bulk_pkt_size; 49047c478bd9Sstevel@tonic-gate } 49057c478bd9Sstevel@tonic-gate 49067c478bd9Sstevel@tonic-gate /* Indicate that the bulk list is filled */ 49077c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_BLF); 49087c478bd9Sstevel@tonic-gate 49097c478bd9Sstevel@tonic-gate /* Start the timer for this bulk transfer */ 49107c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw); 49117c478bd9Sstevel@tonic-gate } 49127c478bd9Sstevel@tonic-gate 49137c478bd9Sstevel@tonic-gate 49147c478bd9Sstevel@tonic-gate /* 49157c478bd9Sstevel@tonic-gate * ohci_start_periodic_pipe_polling: 49167c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 49177c478bd9Sstevel@tonic-gate */ 49187c478bd9Sstevel@tonic-gate int 49197c478bd9Sstevel@tonic-gate ohci_start_periodic_pipe_polling( 49207c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 49217c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 49227c478bd9Sstevel@tonic-gate usb_opaque_t periodic_in_reqp, 49237c478bd9Sstevel@tonic-gate usb_flags_t flags) 49247c478bd9Sstevel@tonic-gate { 49257c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 49267c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 49277c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 49287c478bd9Sstevel@tonic-gate 49297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49307c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: ep%d", 49317c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK); 49327c478bd9Sstevel@tonic-gate 49337c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 49347c478bd9Sstevel@tonic-gate 49357c478bd9Sstevel@tonic-gate /* 49367c478bd9Sstevel@tonic-gate * Check and handle start polling on root hub interrupt pipe. 49377c478bd9Sstevel@tonic-gate */ 49387c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) && 49397c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 49407c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) { 49417c478bd9Sstevel@tonic-gate 49427c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_start_intr_polling(ph, 49437c478bd9Sstevel@tonic-gate (usb_intr_req_t *)periodic_in_reqp, flags); 49447c478bd9Sstevel@tonic-gate 49457c478bd9Sstevel@tonic-gate return (error); 49467c478bd9Sstevel@tonic-gate } 49477c478bd9Sstevel@tonic-gate 49487c478bd9Sstevel@tonic-gate switch (pp->pp_state) { 49497c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_IDLE: 49507c478bd9Sstevel@tonic-gate /* Save the Original client's Periodic IN request */ 49517c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = periodic_in_reqp; 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate /* 49547c478bd9Sstevel@tonic-gate * This pipe is uninitialized or if a valid TD is 49557c478bd9Sstevel@tonic-gate * not found then insert a TD on the interrupt or 49567c478bd9Sstevel@tonic-gate * isochronous IN endpoint. 49577c478bd9Sstevel@tonic-gate */ 49587c478bd9Sstevel@tonic-gate error = ohci_start_pipe_polling(ohcip, ph, flags); 49597c478bd9Sstevel@tonic-gate 49607c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 49617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49627c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: " 49637c478bd9Sstevel@tonic-gate "Start polling failed"); 49647c478bd9Sstevel@tonic-gate 49657c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 49667c478bd9Sstevel@tonic-gate 49677c478bd9Sstevel@tonic-gate return (error); 49687c478bd9Sstevel@tonic-gate } 49697c478bd9Sstevel@tonic-gate 49707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 49717c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: PP = 0x%p", pp); 49727c478bd9Sstevel@tonic-gate 49737c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head != NULL) && (pp->pp_tw_tail != NULL)); 49747c478bd9Sstevel@tonic-gate 49757c478bd9Sstevel@tonic-gate break; 49767c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_ACTIVE: 49777c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49787c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: " 49797c478bd9Sstevel@tonic-gate "Polling is already in progress"); 49807c478bd9Sstevel@tonic-gate 49817c478bd9Sstevel@tonic-gate error = USB_FAILURE; 49827c478bd9Sstevel@tonic-gate break; 49837c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_ERROR: 49847c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49857c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: " 49867c478bd9Sstevel@tonic-gate "Pipe is halted and perform reset before restart polling"); 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate error = USB_FAILURE; 49897c478bd9Sstevel@tonic-gate break; 49907c478bd9Sstevel@tonic-gate default: 49917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49927c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: Undefined state"); 49937c478bd9Sstevel@tonic-gate 49947c478bd9Sstevel@tonic-gate error = USB_FAILURE; 49957c478bd9Sstevel@tonic-gate break; 49967c478bd9Sstevel@tonic-gate } 49977c478bd9Sstevel@tonic-gate 49987c478bd9Sstevel@tonic-gate return (error); 49997c478bd9Sstevel@tonic-gate } 50007c478bd9Sstevel@tonic-gate 50017c478bd9Sstevel@tonic-gate 50027c478bd9Sstevel@tonic-gate /* 50037c478bd9Sstevel@tonic-gate * ohci_start_pipe_polling: 50047c478bd9Sstevel@tonic-gate * 50057c478bd9Sstevel@tonic-gate * Insert the number of periodic requests corresponding to polling 50067c478bd9Sstevel@tonic-gate * interval as calculated during pipe open. 50077c478bd9Sstevel@tonic-gate */ 50087c478bd9Sstevel@tonic-gate static int 50097c478bd9Sstevel@tonic-gate ohci_start_pipe_polling( 50107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 50117c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 50127c478bd9Sstevel@tonic-gate usb_flags_t flags) 50137c478bd9Sstevel@tonic-gate { 50147c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 50157c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 50167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw_list, *tw; 50177c478bd9Sstevel@tonic-gate int i, total_tws; 50187c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 50197c478bd9Sstevel@tonic-gate 50207c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 50217c478bd9Sstevel@tonic-gate "ohci_start_pipe_polling:"); 50227c478bd9Sstevel@tonic-gate 50237c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 50247c478bd9Sstevel@tonic-gate 50257c478bd9Sstevel@tonic-gate /* 50267c478bd9Sstevel@tonic-gate * For the start polling, pp_max_periodic_req_cnt will be zero 50277c478bd9Sstevel@tonic-gate * and for the restart polling request, it will be non zero. 50287c478bd9Sstevel@tonic-gate * 50297c478bd9Sstevel@tonic-gate * In case of start polling request, find out number of requests 50307c478bd9Sstevel@tonic-gate * required for the Interrupt IN endpoints corresponding to the 50317c478bd9Sstevel@tonic-gate * endpoint polling interval. For Isochronous IN endpoints, it is 50327c478bd9Sstevel@tonic-gate * always fixed since its polling interval will be one ms. 50337c478bd9Sstevel@tonic-gate */ 50347c478bd9Sstevel@tonic-gate if (pp->pp_max_periodic_req_cnt == 0) { 50357c478bd9Sstevel@tonic-gate 50367c478bd9Sstevel@tonic-gate ohci_set_periodic_pipe_polling(ohcip, ph); 50377c478bd9Sstevel@tonic-gate } 50387c478bd9Sstevel@tonic-gate 50397c478bd9Sstevel@tonic-gate ASSERT(pp->pp_max_periodic_req_cnt != 0); 50407c478bd9Sstevel@tonic-gate 50417c478bd9Sstevel@tonic-gate /* Allocate all the necessary resources for the IN transfer */ 50427c478bd9Sstevel@tonic-gate tw_list = NULL; 50437c478bd9Sstevel@tonic-gate total_tws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt; 50447c478bd9Sstevel@tonic-gate for (i = 0; i < total_tws; i++) { 50457c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 50467c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 50477c478bd9Sstevel@tonic-gate tw = ohci_allocate_intr_resources( 50487c478bd9Sstevel@tonic-gate ohcip, ph, NULL, flags); 50497c478bd9Sstevel@tonic-gate break; 50507c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 50517c478bd9Sstevel@tonic-gate tw = ohci_allocate_isoc_resources( 50527c478bd9Sstevel@tonic-gate ohcip, ph, NULL, flags); 50537c478bd9Sstevel@tonic-gate break; 50547c478bd9Sstevel@tonic-gate } 50557c478bd9Sstevel@tonic-gate if (tw == NULL) { 50567c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 50577c478bd9Sstevel@tonic-gate /* There are not enough resources, deallocate the TWs */ 50587c478bd9Sstevel@tonic-gate tw = tw_list; 50597c478bd9Sstevel@tonic-gate while (tw != NULL) { 50607c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 50617c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 50627c478bd9Sstevel@tonic-gate ohcip, pp, tw); 50637c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 50647c478bd9Sstevel@tonic-gate tw = tw_list; 50657c478bd9Sstevel@tonic-gate } 50667c478bd9Sstevel@tonic-gate return (error); 50677c478bd9Sstevel@tonic-gate } else { 50687c478bd9Sstevel@tonic-gate if (tw_list == NULL) { 50697c478bd9Sstevel@tonic-gate tw_list = tw; 50707c478bd9Sstevel@tonic-gate } 50717c478bd9Sstevel@tonic-gate } 50727c478bd9Sstevel@tonic-gate } 50737c478bd9Sstevel@tonic-gate 50747c478bd9Sstevel@tonic-gate i = 0; 50757c478bd9Sstevel@tonic-gate while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) { 50767c478bd9Sstevel@tonic-gate 50777c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 50787c478bd9Sstevel@tonic-gate "ohci_start_pipe_polling: max = %d curr = %d tw = %p:", 50797c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt, 50807c478bd9Sstevel@tonic-gate tw_list); 50817c478bd9Sstevel@tonic-gate 50827c478bd9Sstevel@tonic-gate tw = tw_list; 50837c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 50847c478bd9Sstevel@tonic-gate 50857c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 50867c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 50877c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, pp, tw, flags); 50887c478bd9Sstevel@tonic-gate break; 50897c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 50907c478bd9Sstevel@tonic-gate error = ohci_insert_isoc_req(ohcip, pp, tw, flags); 50917c478bd9Sstevel@tonic-gate break; 50927c478bd9Sstevel@tonic-gate } 50937c478bd9Sstevel@tonic-gate if (error == USB_SUCCESS) { 50947c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 50957c478bd9Sstevel@tonic-gate } else { 50967c478bd9Sstevel@tonic-gate /* 50977c478bd9Sstevel@tonic-gate * Deallocate the remaining tw 50987c478bd9Sstevel@tonic-gate * The current tw should have already been deallocated 50997c478bd9Sstevel@tonic-gate */ 51007c478bd9Sstevel@tonic-gate tw = tw_list; 51017c478bd9Sstevel@tonic-gate while (tw != NULL) { 51027c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 51037c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 51047c478bd9Sstevel@tonic-gate ohcip, pp, tw); 51057c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 51067c478bd9Sstevel@tonic-gate tw = tw_list; 51077c478bd9Sstevel@tonic-gate } 51087c478bd9Sstevel@tonic-gate /* 51097c478bd9Sstevel@tonic-gate * If this is the first req return an error. 51107c478bd9Sstevel@tonic-gate * Otherwise return success. 51117c478bd9Sstevel@tonic-gate */ 51127c478bd9Sstevel@tonic-gate if (i != 0) { 51137c478bd9Sstevel@tonic-gate error = USB_SUCCESS; 51147c478bd9Sstevel@tonic-gate } 51157c478bd9Sstevel@tonic-gate 51167c478bd9Sstevel@tonic-gate break; 51177c478bd9Sstevel@tonic-gate } 51187c478bd9Sstevel@tonic-gate i++; 51197c478bd9Sstevel@tonic-gate } 51207c478bd9Sstevel@tonic-gate 51217c478bd9Sstevel@tonic-gate return (error); 51227c478bd9Sstevel@tonic-gate } 51237c478bd9Sstevel@tonic-gate 51247c478bd9Sstevel@tonic-gate 51257c478bd9Sstevel@tonic-gate /* 51267c478bd9Sstevel@tonic-gate * ohci_set_periodic_pipe_polling: 51277c478bd9Sstevel@tonic-gate * 51287c478bd9Sstevel@tonic-gate * Calculate the number of periodic requests needed corresponding to the 51297c478bd9Sstevel@tonic-gate * interrupt/isochronous IN endpoints polling interval. Table below gives 51307c478bd9Sstevel@tonic-gate * the number of periodic requests needed for the interrupt/isochronous 51317c478bd9Sstevel@tonic-gate * IN endpoints according to endpoint polling interval. 51327c478bd9Sstevel@tonic-gate * 51337c478bd9Sstevel@tonic-gate * Polling interval Number of periodic requests 51347c478bd9Sstevel@tonic-gate * 51357c478bd9Sstevel@tonic-gate * 1ms 4 51367c478bd9Sstevel@tonic-gate * 2ms 2 51377c478bd9Sstevel@tonic-gate * 4ms to 32ms 1 51387c478bd9Sstevel@tonic-gate */ 51397c478bd9Sstevel@tonic-gate static void 51407c478bd9Sstevel@tonic-gate ohci_set_periodic_pipe_polling( 51417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 51427c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 51437c478bd9Sstevel@tonic-gate { 51447c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 51457c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 51467c478bd9Sstevel@tonic-gate uchar_t ep_attr = endpoint->bmAttributes; 51477c478bd9Sstevel@tonic-gate uint_t interval; 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 51507c478bd9Sstevel@tonic-gate "ohci_set_periodic_pipe_polling:"); 51517c478bd9Sstevel@tonic-gate 51527c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 51537c478bd9Sstevel@tonic-gate 51547c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt = 0; 51557c478bd9Sstevel@tonic-gate 51567c478bd9Sstevel@tonic-gate /* 51577c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_TIME_POLL flag is 51587c478bd9Sstevel@tonic-gate * set and if so, set pp->pp_max_periodic_req_cnt to one. 51597c478bd9Sstevel@tonic-gate */ 51607c478bd9Sstevel@tonic-gate if (((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) && 51617c478bd9Sstevel@tonic-gate (pp->pp_client_periodic_in_reqp)) { 51627c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp = 51637c478bd9Sstevel@tonic-gate (usb_intr_req_t *)pp->pp_client_periodic_in_reqp; 51647c478bd9Sstevel@tonic-gate 51657c478bd9Sstevel@tonic-gate if (intr_reqp->intr_attributes & 51667c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 51677c478bd9Sstevel@tonic-gate 51687c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_XMS_REQS; 51697c478bd9Sstevel@tonic-gate 51707c478bd9Sstevel@tonic-gate return; 51717c478bd9Sstevel@tonic-gate } 51727c478bd9Sstevel@tonic-gate } 51737c478bd9Sstevel@tonic-gate 51747c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 51757c478bd9Sstevel@tonic-gate 51767c478bd9Sstevel@tonic-gate /* 51777c478bd9Sstevel@tonic-gate * The ohci_adjust_polling_interval function will not fail 51787c478bd9Sstevel@tonic-gate * at this instance since bandwidth allocation is already 51797c478bd9Sstevel@tonic-gate * done. Here we are getting only the periodic interval. 51807c478bd9Sstevel@tonic-gate */ 51817c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, endpoint, 51827c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_port_status); 51837c478bd9Sstevel@tonic-gate 51847c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 51857c478bd9Sstevel@tonic-gate 51867c478bd9Sstevel@tonic-gate switch (interval) { 51877c478bd9Sstevel@tonic-gate case INTR_1MS_POLL: 51887c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_1MS_REQS; 51897c478bd9Sstevel@tonic-gate break; 51907c478bd9Sstevel@tonic-gate case INTR_2MS_POLL: 51917c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_2MS_REQS; 51927c478bd9Sstevel@tonic-gate break; 51937c478bd9Sstevel@tonic-gate default: 51947c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_XMS_REQS; 51957c478bd9Sstevel@tonic-gate break; 51967c478bd9Sstevel@tonic-gate } 51977c478bd9Sstevel@tonic-gate 51987c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 51997c478bd9Sstevel@tonic-gate "ohci_set_periodic_pipe_polling: Max periodic requests = %d", 52007c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 52017c478bd9Sstevel@tonic-gate } 52027c478bd9Sstevel@tonic-gate 52037c478bd9Sstevel@tonic-gate /* 52047c478bd9Sstevel@tonic-gate * ohci_allocate_intr_resources: 52057c478bd9Sstevel@tonic-gate * 52067c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates 52077c478bd9Sstevel@tonic-gate * all the necessary resources. 52087c478bd9Sstevel@tonic-gate * 52097c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 52107c478bd9Sstevel@tonic-gate */ 52117c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 52127c478bd9Sstevel@tonic-gate ohci_allocate_intr_resources( 52137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 52147c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 52157c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 52167c478bd9Sstevel@tonic-gate usb_flags_t flags) 52177c478bd9Sstevel@tonic-gate { 52187c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 52197c478bd9Sstevel@tonic-gate int pipe_dir; 52207c478bd9Sstevel@tonic-gate size_t td_count = 1; 52217c478bd9Sstevel@tonic-gate size_t tw_length; 52227c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 52237c478bd9Sstevel@tonic-gate 52247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 52257c478bd9Sstevel@tonic-gate "ohci_allocate_intr_resources:"); 52267c478bd9Sstevel@tonic-gate 52277c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 52287c478bd9Sstevel@tonic-gate 52297c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 52307c478bd9Sstevel@tonic-gate 52317c478bd9Sstevel@tonic-gate /* Get the length of interrupt transfer & alloc data */ 52327c478bd9Sstevel@tonic-gate if (intr_reqp) { 52337c478bd9Sstevel@tonic-gate tw_length = intr_reqp->intr_len; 52347c478bd9Sstevel@tonic-gate } else { 52357c478bd9Sstevel@tonic-gate ASSERT(pipe_dir == USB_EP_DIR_IN); 52367c478bd9Sstevel@tonic-gate tw_length = (pp->pp_client_periodic_in_reqp) ? 52377c478bd9Sstevel@tonic-gate (((usb_intr_req_t *)pp-> 52387c478bd9Sstevel@tonic-gate pp_client_periodic_in_reqp)->intr_len) : 52397c478bd9Sstevel@tonic-gate ph->p_ep.wMaxPacketSize; 52407c478bd9Sstevel@tonic-gate } 52417c478bd9Sstevel@tonic-gate 52427c478bd9Sstevel@tonic-gate /* Check the size of interrupt request */ 52437c478bd9Sstevel@tonic-gate if (tw_length > OHCI_MAX_TD_XFER_SIZE) { 52447c478bd9Sstevel@tonic-gate 52457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 52467c478bd9Sstevel@tonic-gate "ohci_allocate_intr_resources: Intr request size 0x%lx is " 52477c478bd9Sstevel@tonic-gate "more than 0x%x", tw_length, OHCI_MAX_TD_XFER_SIZE); 52487c478bd9Sstevel@tonic-gate 52497c478bd9Sstevel@tonic-gate return (NULL); 52507c478bd9Sstevel@tonic-gate } 52517c478bd9Sstevel@tonic-gate 52527c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_tw_resources(ohcip, pp, tw_length, 52537c478bd9Sstevel@tonic-gate flags, td_count)) == NULL) { 52547c478bd9Sstevel@tonic-gate 52557c478bd9Sstevel@tonic-gate return (NULL); 52567c478bd9Sstevel@tonic-gate } 52577c478bd9Sstevel@tonic-gate 52587c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 52597c478bd9Sstevel@tonic-gate if (ohci_allocate_periodic_in_resource(ohcip, pp, tw, flags) != 52607c478bd9Sstevel@tonic-gate USB_SUCCESS) { 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 52637c478bd9Sstevel@tonic-gate return (NULL); 52647c478bd9Sstevel@tonic-gate } 52657c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN; 52667c478bd9Sstevel@tonic-gate } else { 52677c478bd9Sstevel@tonic-gate ASSERT(intr_reqp->intr_data != NULL); 52687c478bd9Sstevel@tonic-gate 52697c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 52707c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, 52717c478bd9Sstevel@tonic-gate intr_reqp->intr_data->b_rptr, (uint8_t *)tw->tw_buf, 52727c478bd9Sstevel@tonic-gate intr_reqp->intr_len, DDI_DEV_AUTOINCR); 52737c478bd9Sstevel@tonic-gate 52747c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)intr_reqp; 52757c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT; 52767c478bd9Sstevel@tonic-gate } 52777c478bd9Sstevel@tonic-gate 52787c478bd9Sstevel@tonic-gate if (intr_reqp) { 52797c478bd9Sstevel@tonic-gate tw->tw_timeout = intr_reqp->intr_timeout; 52807c478bd9Sstevel@tonic-gate } 52817c478bd9Sstevel@tonic-gate 52827c478bd9Sstevel@tonic-gate /* 52837c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 52847c478bd9Sstevel@tonic-gate * data required when the td completes. 52857c478bd9Sstevel@tonic-gate */ 52867c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_intr_td; 52877c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 52887c478bd9Sstevel@tonic-gate 52897c478bd9Sstevel@tonic-gate return (tw); 52907c478bd9Sstevel@tonic-gate } 52917c478bd9Sstevel@tonic-gate 52927c478bd9Sstevel@tonic-gate /* 52937c478bd9Sstevel@tonic-gate * ohci_insert_intr_req: 52947c478bd9Sstevel@tonic-gate * 52957c478bd9Sstevel@tonic-gate * Insert an Interrupt request into the Host Controller's periodic list. 52967c478bd9Sstevel@tonic-gate */ 52977c478bd9Sstevel@tonic-gate /* ARGSUSED */ 52987c478bd9Sstevel@tonic-gate static void 52997c478bd9Sstevel@tonic-gate ohci_insert_intr_req( 53007c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 53017c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 53027c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 53037c478bd9Sstevel@tonic-gate usb_flags_t flags) 53047c478bd9Sstevel@tonic-gate { 53057c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = NULL; 53067c478bd9Sstevel@tonic-gate uint_t ctrl = 0; 53077c478bd9Sstevel@tonic-gate 53087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 53097c478bd9Sstevel@tonic-gate 53107c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp != NULL); 53117c478bd9Sstevel@tonic-gate 53127c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */ 53137c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 53147c478bd9Sstevel@tonic-gate 53157c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction | HC_TD_DT_0 | HC_TD_1I; 53167c478bd9Sstevel@tonic-gate 53177c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & USB_ATTRS_SHORT_XFER_OK) { 53187c478bd9Sstevel@tonic-gate ctrl |= HC_TD_R; 53197c478bd9Sstevel@tonic-gate } 53207c478bd9Sstevel@tonic-gate 53217c478bd9Sstevel@tonic-gate /* Insert another interrupt TD */ 53227c478bd9Sstevel@tonic-gate (void) ohci_insert_hc_td(ohcip, ctrl, 53237c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address, tw->tw_length, 0, pp, tw); 53247c478bd9Sstevel@tonic-gate 53257c478bd9Sstevel@tonic-gate /* Start the timer for this Interrupt transfer */ 53267c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw); 53277c478bd9Sstevel@tonic-gate } 53287c478bd9Sstevel@tonic-gate 53297c478bd9Sstevel@tonic-gate 53307c478bd9Sstevel@tonic-gate /* 53317c478bd9Sstevel@tonic-gate * ohci_stop_periodic_pipe_polling: 53327c478bd9Sstevel@tonic-gate */ 53337c478bd9Sstevel@tonic-gate /* ARGSUSED */ 53347c478bd9Sstevel@tonic-gate static int 53357c478bd9Sstevel@tonic-gate ohci_stop_periodic_pipe_polling( 53367c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 53377c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 53387c478bd9Sstevel@tonic-gate usb_flags_t flags) 53397c478bd9Sstevel@tonic-gate { 53407c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 53417c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 53427c478bd9Sstevel@tonic-gate 53437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 53447c478bd9Sstevel@tonic-gate "ohci_stop_periodic_pipe_polling: Flags = 0x%x", flags); 53457c478bd9Sstevel@tonic-gate 53467c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 53477c478bd9Sstevel@tonic-gate 53487c478bd9Sstevel@tonic-gate /* 53497c478bd9Sstevel@tonic-gate * Check and handle stop polling on root hub interrupt pipe. 53507c478bd9Sstevel@tonic-gate */ 53517c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) && 53527c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 53537c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) { 53547c478bd9Sstevel@tonic-gate 53557c478bd9Sstevel@tonic-gate ohci_handle_root_hub_pipe_stop_intr_polling( 53567c478bd9Sstevel@tonic-gate ph, flags); 53577c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 53587c478bd9Sstevel@tonic-gate } 53597c478bd9Sstevel@tonic-gate 53607c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) { 53617c478bd9Sstevel@tonic-gate 53627c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 53637c478bd9Sstevel@tonic-gate "ohci_stop_periodic_pipe_polling: Polling already stopped"); 53647c478bd9Sstevel@tonic-gate 53657c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 53667c478bd9Sstevel@tonic-gate } 53677c478bd9Sstevel@tonic-gate 53687c478bd9Sstevel@tonic-gate /* Set pipe state to pipe stop polling */ 53697c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 53707c478bd9Sstevel@tonic-gate 53717c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph); 53727c478bd9Sstevel@tonic-gate 53737c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 53747c478bd9Sstevel@tonic-gate } 53757c478bd9Sstevel@tonic-gate 53767c478bd9Sstevel@tonic-gate /* 53777c478bd9Sstevel@tonic-gate * ohci_allocate_isoc_resources: 53787c478bd9Sstevel@tonic-gate * 53797c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates 53807c478bd9Sstevel@tonic-gate * all the necessary resources. 53817c478bd9Sstevel@tonic-gate * 53827c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 53837c478bd9Sstevel@tonic-gate */ 53847c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 53857c478bd9Sstevel@tonic-gate ohci_allocate_isoc_resources( 53867c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 53877c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 53887c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 53897c478bd9Sstevel@tonic-gate usb_flags_t flags) 53907c478bd9Sstevel@tonic-gate { 53917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 53927c478bd9Sstevel@tonic-gate int pipe_dir; 53937c478bd9Sstevel@tonic-gate uint_t max_pkt_size = ph->p_ep.wMaxPacketSize; 53947c478bd9Sstevel@tonic-gate uint_t max_isoc_xfer_size; 53957c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *isoc_pkt_descr; 53967c478bd9Sstevel@tonic-gate ushort_t isoc_pkt_count; 53977c478bd9Sstevel@tonic-gate size_t count, td_count; 53987c478bd9Sstevel@tonic-gate size_t tw_length; 53997c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 54007c478bd9Sstevel@tonic-gate 54017c478bd9Sstevel@tonic-gate 54027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 54037c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: flags = ox%x", flags); 54047c478bd9Sstevel@tonic-gate 54057c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 54067c478bd9Sstevel@tonic-gate 54077c478bd9Sstevel@tonic-gate /* 54087c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 54097c478bd9Sstevel@tonic-gate */ 54107c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) { 54117c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 54127c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources:" 54137c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 54147c478bd9Sstevel@tonic-gate 54157c478bd9Sstevel@tonic-gate return (NULL); 54167c478bd9Sstevel@tonic-gate } 54177c478bd9Sstevel@tonic-gate 54187c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 54197c478bd9Sstevel@tonic-gate 54207c478bd9Sstevel@tonic-gate /* Calculate the maximum isochronous transfer size */ 54217c478bd9Sstevel@tonic-gate max_isoc_xfer_size = OHCI_MAX_ISOC_PKTS_PER_XFER * max_pkt_size; 54227c478bd9Sstevel@tonic-gate 54237c478bd9Sstevel@tonic-gate if (isoc_reqp) { 54247c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr; 54257c478bd9Sstevel@tonic-gate isoc_pkt_count = isoc_reqp->isoc_pkts_count; 54267c478bd9Sstevel@tonic-gate } else { 54277c478bd9Sstevel@tonic-gate isoc_pkt_descr = ((usb_isoc_req_t *) 54287c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkt_descr; 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate isoc_pkt_count = ((usb_isoc_req_t *) 54317c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_count; 54327c478bd9Sstevel@tonic-gate } 54337c478bd9Sstevel@tonic-gate 54347c478bd9Sstevel@tonic-gate /* 54357c478bd9Sstevel@tonic-gate * For isochronous IN pipe, get value of number of isochronous 54367c478bd9Sstevel@tonic-gate * packets per usb isochronous request 54377c478bd9Sstevel@tonic-gate */ 54387c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 54397c478bd9Sstevel@tonic-gate for (count = 0, tw_length = 0; 54407c478bd9Sstevel@tonic-gate count < isoc_pkt_count; count++) { 54417c478bd9Sstevel@tonic-gate tw_length += isoc_pkt_descr->isoc_pkt_length; 54427c478bd9Sstevel@tonic-gate isoc_pkt_descr++; 54437c478bd9Sstevel@tonic-gate } 54447c478bd9Sstevel@tonic-gate } else { 54457c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp != NULL); 54467c478bd9Sstevel@tonic-gate tw_length = isoc_reqp->isoc_data->b_wptr - 54477c478bd9Sstevel@tonic-gate isoc_reqp->isoc_data->b_rptr; 54487c478bd9Sstevel@tonic-gate } 54497c478bd9Sstevel@tonic-gate 54507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 54517c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: length = 0x%lx", tw_length); 54527c478bd9Sstevel@tonic-gate 54537c478bd9Sstevel@tonic-gate /* Check the size of isochronous request */ 54547c478bd9Sstevel@tonic-gate if (tw_length > max_isoc_xfer_size) { 54557c478bd9Sstevel@tonic-gate 54567c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 54577c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: Maximum isoc request" 54587c478bd9Sstevel@tonic-gate "size 0x%x Given isoc request size 0x%lx", 54597c478bd9Sstevel@tonic-gate max_isoc_xfer_size, tw_length); 54607c478bd9Sstevel@tonic-gate 54617c478bd9Sstevel@tonic-gate return (NULL); 54627c478bd9Sstevel@tonic-gate } 54637c478bd9Sstevel@tonic-gate 54647c478bd9Sstevel@tonic-gate /* 54657c478bd9Sstevel@tonic-gate * Each isochronous TD can hold data upto eight isochronous 54667c478bd9Sstevel@tonic-gate * data packets. Calculate the number of isochronous TDs needs 54677c478bd9Sstevel@tonic-gate * to be insert to complete current isochronous request. 54687c478bd9Sstevel@tonic-gate */ 54697c478bd9Sstevel@tonic-gate td_count = isoc_pkt_count / OHCI_ISOC_PKTS_PER_TD; 54707c478bd9Sstevel@tonic-gate 54717c478bd9Sstevel@tonic-gate if (isoc_pkt_count % OHCI_ISOC_PKTS_PER_TD) { 54727c478bd9Sstevel@tonic-gate td_count++; 54737c478bd9Sstevel@tonic-gate } 54747c478bd9Sstevel@tonic-gate 54757c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_tw_resources(ohcip, pp, tw_length, 54767c478bd9Sstevel@tonic-gate flags, td_count)) == NULL) { 54777c478bd9Sstevel@tonic-gate return (NULL); 54787c478bd9Sstevel@tonic-gate } 54797c478bd9Sstevel@tonic-gate 54807c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 54817c478bd9Sstevel@tonic-gate if (ohci_allocate_periodic_in_resource(ohcip, pp, tw, flags) != 54827c478bd9Sstevel@tonic-gate USB_SUCCESS) { 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 54857c478bd9Sstevel@tonic-gate return (NULL); 54867c478bd9Sstevel@tonic-gate } 54877c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN; 54887c478bd9Sstevel@tonic-gate } else { 54897c478bd9Sstevel@tonic-gate if (tw->tw_length) { 54907c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp->isoc_data != NULL); 54917c478bd9Sstevel@tonic-gate 54927c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 54937c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, 54947c478bd9Sstevel@tonic-gate isoc_reqp->isoc_data->b_rptr, 54957c478bd9Sstevel@tonic-gate (uint8_t *)tw->tw_buf, tw->tw_length, 54967c478bd9Sstevel@tonic-gate DDI_DEV_AUTOINCR); 54977c478bd9Sstevel@tonic-gate } 54987c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)isoc_reqp; 54997c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT; 55007c478bd9Sstevel@tonic-gate } 55017c478bd9Sstevel@tonic-gate 55027c478bd9Sstevel@tonic-gate /* 55037c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 55047c478bd9Sstevel@tonic-gate * data required when the td completes. 55057c478bd9Sstevel@tonic-gate */ 55067c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_isoc_td; 55077c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 55087c478bd9Sstevel@tonic-gate 55097c478bd9Sstevel@tonic-gate return (tw); 55107c478bd9Sstevel@tonic-gate } 55117c478bd9Sstevel@tonic-gate 55127c478bd9Sstevel@tonic-gate /* 55137c478bd9Sstevel@tonic-gate * ohci_insert_isoc_req: 55147c478bd9Sstevel@tonic-gate * 55157c478bd9Sstevel@tonic-gate * Insert an isochronous request into the Host Controller's 55167c478bd9Sstevel@tonic-gate * isochronous list. If there is an error is will appropriately 55177c478bd9Sstevel@tonic-gate * deallocate the unused resources. 55187c478bd9Sstevel@tonic-gate */ 55197c478bd9Sstevel@tonic-gate static int 55207c478bd9Sstevel@tonic-gate ohci_insert_isoc_req( 55217c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 55227c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 55237c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 55247c478bd9Sstevel@tonic-gate uint_t flags) 55257c478bd9Sstevel@tonic-gate { 55267c478bd9Sstevel@tonic-gate size_t curr_isoc_xfer_offset, curr_isoc_xfer_len; 55277c478bd9Sstevel@tonic-gate uint_t isoc_pkts, residue, count; 55287c478bd9Sstevel@tonic-gate uint_t i, ctrl, frame_count; 55297c478bd9Sstevel@tonic-gate uint_t error = USB_SUCCESS; 55307c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp; 55317c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *curr_isoc_pkt_descr; 55327c478bd9Sstevel@tonic-gate 55337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 55347c478bd9Sstevel@tonic-gate "ohci_insert_isoc_req: flags = 0x%x", flags); 55357c478bd9Sstevel@tonic-gate 55367c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 55377c478bd9Sstevel@tonic-gate 55387c478bd9Sstevel@tonic-gate /* 55397c478bd9Sstevel@tonic-gate * Get the current isochronous request and packet 55407c478bd9Sstevel@tonic-gate * descriptor pointers. 55417c478bd9Sstevel@tonic-gate */ 55427c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 55437c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = curr_isoc_reqp->isoc_pkt_descr; 55447c478bd9Sstevel@tonic-gate 55457c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL); 55467c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp->isoc_pkt_descr != NULL); 55477c478bd9Sstevel@tonic-gate 55487c478bd9Sstevel@tonic-gate /* 55497c478bd9Sstevel@tonic-gate * Save address of first usb isochronous packet descriptor. 55507c478bd9Sstevel@tonic-gate */ 55517c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr; 55527c478bd9Sstevel@tonic-gate 55537c478bd9Sstevel@tonic-gate /* Insert all the isochronous TDs */ 55547c478bd9Sstevel@tonic-gate for (count = 0, curr_isoc_xfer_offset = 0, 55557c478bd9Sstevel@tonic-gate isoc_pkts = 0; count < tw->tw_num_tds; count++) { 55567c478bd9Sstevel@tonic-gate 55577c478bd9Sstevel@tonic-gate residue = curr_isoc_reqp->isoc_pkts_count - isoc_pkts; 55587c478bd9Sstevel@tonic-gate 55597c478bd9Sstevel@tonic-gate /* Check for inserting residue data */ 55607c478bd9Sstevel@tonic-gate if ((count == (tw->tw_num_tds - 1)) && 55617c478bd9Sstevel@tonic-gate (residue < OHCI_ISOC_PKTS_PER_TD)) { 55627c478bd9Sstevel@tonic-gate frame_count = residue; 55637c478bd9Sstevel@tonic-gate } else { 55647c478bd9Sstevel@tonic-gate frame_count = OHCI_ISOC_PKTS_PER_TD; 55657c478bd9Sstevel@tonic-gate } 55667c478bd9Sstevel@tonic-gate 55677c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = tw->tw_curr_isoc_pktp; 55687c478bd9Sstevel@tonic-gate 55697c478bd9Sstevel@tonic-gate /* 55707c478bd9Sstevel@tonic-gate * Calculate length of isochronous transfer 55717c478bd9Sstevel@tonic-gate * for the current TD. 55727c478bd9Sstevel@tonic-gate */ 55737c478bd9Sstevel@tonic-gate for (i = 0, curr_isoc_xfer_len = 0; 55747c478bd9Sstevel@tonic-gate i < frame_count; i++, curr_isoc_pkt_descr++) { 55757c478bd9Sstevel@tonic-gate curr_isoc_xfer_len += 55767c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr->isoc_pkt_length; 55777c478bd9Sstevel@tonic-gate } 55787c478bd9Sstevel@tonic-gate 55797c478bd9Sstevel@tonic-gate /* 55807c478bd9Sstevel@tonic-gate * Programm td control field by checking whether this 55817c478bd9Sstevel@tonic-gate * is last td. 55827c478bd9Sstevel@tonic-gate */ 55837c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_tds - 1)) { 55847c478bd9Sstevel@tonic-gate ctrl = ((((frame_count - 1) << HC_ITD_FC_SHIFT) & 55857c478bd9Sstevel@tonic-gate HC_ITD_FC) | HC_TD_DT_0 | HC_TD_0I); 55867c478bd9Sstevel@tonic-gate } else { 55877c478bd9Sstevel@tonic-gate ctrl = ((((frame_count - 1) << HC_ITD_FC_SHIFT) & 55887c478bd9Sstevel@tonic-gate HC_ITD_FC) | HC_TD_DT_0 | HC_TD_6I); 55897c478bd9Sstevel@tonic-gate } 55907c478bd9Sstevel@tonic-gate 55917c478bd9Sstevel@tonic-gate /* Insert the TD into the endpoint */ 55927c478bd9Sstevel@tonic-gate if ((error = ohci_insert_hc_td(ohcip, ctrl, 55937c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address + curr_isoc_xfer_offset, 55947c478bd9Sstevel@tonic-gate curr_isoc_xfer_len, 0, pp, tw)) != 55957c478bd9Sstevel@tonic-gate USB_SUCCESS) { 55967c478bd9Sstevel@tonic-gate tw->tw_num_tds = count; 55977c478bd9Sstevel@tonic-gate tw->tw_length = curr_isoc_xfer_offset; 55987c478bd9Sstevel@tonic-gate break; 55997c478bd9Sstevel@tonic-gate } 56007c478bd9Sstevel@tonic-gate 56017c478bd9Sstevel@tonic-gate isoc_pkts += frame_count; 56027c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp += frame_count; 56037c478bd9Sstevel@tonic-gate curr_isoc_xfer_offset += curr_isoc_xfer_len; 56047c478bd9Sstevel@tonic-gate } 56057c478bd9Sstevel@tonic-gate 56067c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 56077c478bd9Sstevel@tonic-gate /* Free periodic in resources */ 56087c478bd9Sstevel@tonic-gate if (tw->tw_direction == USB_EP_DIR_IN) { 56097c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 56107c478bd9Sstevel@tonic-gate } 56117c478bd9Sstevel@tonic-gate 56127c478bd9Sstevel@tonic-gate /* Free all resources if IN or if count == 0(for both IN/OUT) */ 56137c478bd9Sstevel@tonic-gate if (tw->tw_direction == USB_EP_DIR_IN || count == 0) { 56147c478bd9Sstevel@tonic-gate 56157c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 56167c478bd9Sstevel@tonic-gate 56177c478bd9Sstevel@tonic-gate if (pp->pp_cur_periodic_req_cnt) { 56187c478bd9Sstevel@tonic-gate /* 56197c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and 56207c478bd9Sstevel@tonic-gate * error to no resource. Don't insert 56217c478bd9Sstevel@tonic-gate * any more isochronous polling requests. 56227c478bd9Sstevel@tonic-gate */ 56237c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 56247c478bd9Sstevel@tonic-gate pp->pp_error = error; 56257c478bd9Sstevel@tonic-gate } else { 56267c478bd9Sstevel@tonic-gate /* Set periodic in pipe state to idle */ 56277c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 56287c478bd9Sstevel@tonic-gate } 56297c478bd9Sstevel@tonic-gate } 56307c478bd9Sstevel@tonic-gate } else { 56317c478bd9Sstevel@tonic-gate 56327c478bd9Sstevel@tonic-gate /* 56337c478bd9Sstevel@tonic-gate * Reset back to the address of first usb isochronous 56347c478bd9Sstevel@tonic-gate * packet descriptor. 56357c478bd9Sstevel@tonic-gate */ 56367c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr; 56377c478bd9Sstevel@tonic-gate 56387c478bd9Sstevel@tonic-gate /* Reset the CONTINUE flag */ 56397c478bd9Sstevel@tonic-gate pp->pp_flag &= ~OHCI_ISOC_XFER_CONTINUE; 56407c478bd9Sstevel@tonic-gate } 56417c478bd9Sstevel@tonic-gate 56427c478bd9Sstevel@tonic-gate return (error); 56437c478bd9Sstevel@tonic-gate } 56447c478bd9Sstevel@tonic-gate 56457c478bd9Sstevel@tonic-gate 56467c478bd9Sstevel@tonic-gate /* 56477c478bd9Sstevel@tonic-gate * ohci_insert_hc_td: 56487c478bd9Sstevel@tonic-gate * 56497c478bd9Sstevel@tonic-gate * Insert a Transfer Descriptor (TD) on an Endpoint Descriptor (ED). 56507c478bd9Sstevel@tonic-gate * Always returns USB_SUCCESS, except for ISOCH. 56517c478bd9Sstevel@tonic-gate */ 56527c478bd9Sstevel@tonic-gate static int 56537c478bd9Sstevel@tonic-gate ohci_insert_hc_td( 56547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 56557c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 56567c478bd9Sstevel@tonic-gate uint32_t hctd_iommu_cbp, 56577c478bd9Sstevel@tonic-gate size_t hctd_length, 56587c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 56597c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 56607c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 56617c478bd9Sstevel@tonic-gate { 56627c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy; 56637c478bd9Sstevel@tonic-gate ohci_td_t *cpu_current_dummy; 56647c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 56657c478bd9Sstevel@tonic-gate int error; 56667c478bd9Sstevel@tonic-gate 56677c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 56687c478bd9Sstevel@tonic-gate 56697c478bd9Sstevel@tonic-gate /* Retrieve preallocated td from the TW */ 56707c478bd9Sstevel@tonic-gate new_dummy = tw->tw_hctd_free_list; 56717c478bd9Sstevel@tonic-gate 56727c478bd9Sstevel@tonic-gate ASSERT(new_dummy != NULL); 56737c478bd9Sstevel@tonic-gate 56747c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = ohci_td_iommu_to_cpu(ohcip, 56757c478bd9Sstevel@tonic-gate Get_TD(new_dummy->hctd_tw_next_td)); 56767c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_tw_next_td, NULL); 56777c478bd9Sstevel@tonic-gate 56787c478bd9Sstevel@tonic-gate /* Fill in the current dummy */ 56797c478bd9Sstevel@tonic-gate cpu_current_dummy = (ohci_td_t *) 56807c478bd9Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip, Get_ED(ept->hced_tailp))); 56817c478bd9Sstevel@tonic-gate 56827c478bd9Sstevel@tonic-gate /* 56837c478bd9Sstevel@tonic-gate * Fill in the current dummy td and 56847c478bd9Sstevel@tonic-gate * add the new dummy to the end. 56857c478bd9Sstevel@tonic-gate */ 56867c478bd9Sstevel@tonic-gate ohci_fill_in_td(ohcip, cpu_current_dummy, new_dummy, 56877c478bd9Sstevel@tonic-gate hctd_ctrl, hctd_iommu_cbp, hctd_length, hctd_ctrl_phase, pp, tw); 56887c478bd9Sstevel@tonic-gate 56897c478bd9Sstevel@tonic-gate /* 56907c478bd9Sstevel@tonic-gate * If this is an isochronous TD, first write proper 56917c478bd9Sstevel@tonic-gate * starting usb frame number in which this TD must 56927c478bd9Sstevel@tonic-gate * can be processed. After writing the frame number 56937c478bd9Sstevel@tonic-gate * insert this TD into the ED's list. 56947c478bd9Sstevel@tonic-gate */ 56957c478bd9Sstevel@tonic-gate if ((pp->pp_pipe_handle->p_ep.bmAttributes & 56967c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 56977c478bd9Sstevel@tonic-gate 56987c478bd9Sstevel@tonic-gate error = ohci_insert_td_with_frame_number( 56997c478bd9Sstevel@tonic-gate ohcip, pp, tw, cpu_current_dummy, new_dummy); 57007c478bd9Sstevel@tonic-gate 57017c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 57027c478bd9Sstevel@tonic-gate /* Reset the current dummy back to a dummy */ 57037c478bd9Sstevel@tonic-gate bzero((char *)cpu_current_dummy, sizeof (ohci_td_t)); 57047c478bd9Sstevel@tonic-gate Set_TD(cpu_current_dummy->hctd_state, HC_TD_DUMMY); 57057c478bd9Sstevel@tonic-gate 57067c478bd9Sstevel@tonic-gate /* return the new dummy back to the free list */ 57077c478bd9Sstevel@tonic-gate bzero((char *)new_dummy, sizeof (ohci_td_t)); 57087c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_state, HC_TD_DUMMY); 57097c478bd9Sstevel@tonic-gate if (tw->tw_hctd_free_list != NULL) { 57107c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_tw_next_td, 57117c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, 57127c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list)); 57137c478bd9Sstevel@tonic-gate } 57147c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = new_dummy; 57157c478bd9Sstevel@tonic-gate 57167c478bd9Sstevel@tonic-gate return (error); 57177c478bd9Sstevel@tonic-gate } 57187c478bd9Sstevel@tonic-gate } else { 57197c478bd9Sstevel@tonic-gate /* 57207c478bd9Sstevel@tonic-gate * For control, bulk and interrupt TD, just 57217c478bd9Sstevel@tonic-gate * add the new dummy to the ED's list. When 57227c478bd9Sstevel@tonic-gate * this occurs, the Host Controller ill see 57237c478bd9Sstevel@tonic-gate * the newly filled in dummy TD. 57247c478bd9Sstevel@tonic-gate */ 57257c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, 57267c478bd9Sstevel@tonic-gate (ohci_td_cpu_to_iommu(ohcip, new_dummy))); 57277c478bd9Sstevel@tonic-gate } 57287c478bd9Sstevel@tonic-gate 57297c478bd9Sstevel@tonic-gate /* Insert this td onto the tw */ 57307c478bd9Sstevel@tonic-gate ohci_insert_td_on_tw(ohcip, tw, cpu_current_dummy); 57317c478bd9Sstevel@tonic-gate 57327c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 57337c478bd9Sstevel@tonic-gate } 57347c478bd9Sstevel@tonic-gate 57357c478bd9Sstevel@tonic-gate 57367c478bd9Sstevel@tonic-gate /* 57377c478bd9Sstevel@tonic-gate * ohci_allocate_td_from_pool: 57387c478bd9Sstevel@tonic-gate * 57397c478bd9Sstevel@tonic-gate * Allocate a Transfer Descriptor (TD) from the TD buffer pool. 57407c478bd9Sstevel@tonic-gate */ 57417c478bd9Sstevel@tonic-gate static ohci_td_t * 57427c478bd9Sstevel@tonic-gate ohci_allocate_td_from_pool(ohci_state_t *ohcip) 57437c478bd9Sstevel@tonic-gate { 57447c478bd9Sstevel@tonic-gate int i, state; 57457c478bd9Sstevel@tonic-gate ohci_td_t *td; 57467c478bd9Sstevel@tonic-gate 57477c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 57487c478bd9Sstevel@tonic-gate 57497c478bd9Sstevel@tonic-gate /* 57507c478bd9Sstevel@tonic-gate * Search for a blank Transfer Descriptor (TD) 57517c478bd9Sstevel@tonic-gate * in the TD buffer pool. 57527c478bd9Sstevel@tonic-gate */ 57537c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) { 57547c478bd9Sstevel@tonic-gate state = Get_TD(ohcip->ohci_td_pool_addr[i].hctd_state); 57557c478bd9Sstevel@tonic-gate if (state == HC_TD_FREE) { 57567c478bd9Sstevel@tonic-gate break; 57577c478bd9Sstevel@tonic-gate } 57587c478bd9Sstevel@tonic-gate } 57597c478bd9Sstevel@tonic-gate 57607c478bd9Sstevel@tonic-gate if (i >= ohci_td_pool_size) { 57617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 57627c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: TD exhausted"); 57637c478bd9Sstevel@tonic-gate 57647c478bd9Sstevel@tonic-gate return (NULL); 57657c478bd9Sstevel@tonic-gate } 57667c478bd9Sstevel@tonic-gate 57677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 57687c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: Allocated %d", i); 57697c478bd9Sstevel@tonic-gate 57707c478bd9Sstevel@tonic-gate /* Create a new dummy for the end of the TD list */ 57717c478bd9Sstevel@tonic-gate td = &ohcip->ohci_td_pool_addr[i]; 57727c478bd9Sstevel@tonic-gate 57737c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 57747c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: td 0x%p", (void *)td); 57757c478bd9Sstevel@tonic-gate 57767c478bd9Sstevel@tonic-gate /* Mark the newly allocated TD as a dummy */ 57777c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_DUMMY); 57787c478bd9Sstevel@tonic-gate 57797c478bd9Sstevel@tonic-gate return (td); 57807c478bd9Sstevel@tonic-gate } 57817c478bd9Sstevel@tonic-gate 57827c478bd9Sstevel@tonic-gate /* 57837c478bd9Sstevel@tonic-gate * ohci_fill_in_td: 57847c478bd9Sstevel@tonic-gate * 57857c478bd9Sstevel@tonic-gate * Fill in the fields of a Transfer Descriptor (TD). 57867c478bd9Sstevel@tonic-gate */ 57877c478bd9Sstevel@tonic-gate static void 57887c478bd9Sstevel@tonic-gate ohci_fill_in_td( 57897c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 57907c478bd9Sstevel@tonic-gate ohci_td_t *td, 57917c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy, 57927c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 57937c478bd9Sstevel@tonic-gate uint32_t hctd_iommu_cbp, 57947c478bd9Sstevel@tonic-gate size_t hctd_length, 57957c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 57967c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 57977c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 57987c478bd9Sstevel@tonic-gate { 57997c478bd9Sstevel@tonic-gate /* Assert that the td to be filled in is a dummy */ 58007c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) == HC_TD_DUMMY); 58017c478bd9Sstevel@tonic-gate 58027c478bd9Sstevel@tonic-gate /* Change TD's state Active */ 58037c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_ACTIVE); 58047c478bd9Sstevel@tonic-gate 58057c478bd9Sstevel@tonic-gate /* 58067c478bd9Sstevel@tonic-gate * If this is an isochronous TD, update the special itd 58077c478bd9Sstevel@tonic-gate * portions. Otherwise, just update the control field. 58087c478bd9Sstevel@tonic-gate */ 58097c478bd9Sstevel@tonic-gate if ((pp->pp_pipe_handle->p_ep.bmAttributes & 58107c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 58117c478bd9Sstevel@tonic-gate ohci_init_itd(ohcip, pp, tw, hctd_ctrl, hctd_iommu_cbp, td); 58127c478bd9Sstevel@tonic-gate } else { 58137c478bd9Sstevel@tonic-gate /* Update the dummy with control information */ 58147c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA)); 58157c478bd9Sstevel@tonic-gate 58167c478bd9Sstevel@tonic-gate /* Update the beginning of the buffer */ 58177c478bd9Sstevel@tonic-gate Set_TD(td->hctd_cbp, hctd_iommu_cbp); 58187c478bd9Sstevel@tonic-gate } 58197c478bd9Sstevel@tonic-gate 58207c478bd9Sstevel@tonic-gate /* The current dummy now points to the new dummy */ 58217c478bd9Sstevel@tonic-gate Set_TD(td->hctd_next_td, (ohci_td_cpu_to_iommu(ohcip, new_dummy))); 58227c478bd9Sstevel@tonic-gate 58237c478bd9Sstevel@tonic-gate /* Fill in the end of the buffer */ 58247c478bd9Sstevel@tonic-gate if (hctd_length == 0) { 58257c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_cbp) == 0); 58267c478bd9Sstevel@tonic-gate ASSERT(hctd_iommu_cbp == 0); 58277c478bd9Sstevel@tonic-gate Set_TD(td->hctd_buf_end, 0); 58287c478bd9Sstevel@tonic-gate } else { 58297c478bd9Sstevel@tonic-gate Set_TD(td->hctd_buf_end, 58307c478bd9Sstevel@tonic-gate hctd_iommu_cbp + hctd_length - 1); 58317c478bd9Sstevel@tonic-gate } 58327c478bd9Sstevel@tonic-gate 58337c478bd9Sstevel@tonic-gate /* 58347c478bd9Sstevel@tonic-gate * For Control transfer, hctd_ctrl_phase is a valid field. 58357c478bd9Sstevel@tonic-gate */ 58367c478bd9Sstevel@tonic-gate if (hctd_ctrl_phase) { 58377c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl_phase, hctd_ctrl_phase); 58387c478bd9Sstevel@tonic-gate } 58397c478bd9Sstevel@tonic-gate 58407c478bd9Sstevel@tonic-gate /* Print the td */ 58417c478bd9Sstevel@tonic-gate ohci_print_td(ohcip, td); 58427c478bd9Sstevel@tonic-gate 58437c478bd9Sstevel@tonic-gate /* Fill in the wrapper portion of the TD */ 58447c478bd9Sstevel@tonic-gate 58457c478bd9Sstevel@tonic-gate /* Set the transfer wrapper */ 58467c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 58477c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 58487c478bd9Sstevel@tonic-gate 58497c478bd9Sstevel@tonic-gate Set_TD(td->hctd_trans_wrapper, (uint32_t)tw->tw_id); 58507c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL); 58517c478bd9Sstevel@tonic-gate } 58527c478bd9Sstevel@tonic-gate 58537c478bd9Sstevel@tonic-gate 58547c478bd9Sstevel@tonic-gate /* 58557c478bd9Sstevel@tonic-gate * ohci_init_itd: 58567c478bd9Sstevel@tonic-gate * 58577c478bd9Sstevel@tonic-gate * Initialize the Isochronous portion of the Transfer Descriptor (TD). 58587c478bd9Sstevel@tonic-gate */ 58597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 58607c478bd9Sstevel@tonic-gate static void 58617c478bd9Sstevel@tonic-gate ohci_init_itd( 58627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 58637c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 58647c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 58657c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 58667c478bd9Sstevel@tonic-gate uint32_t hctd_iommu_cbp, 58677c478bd9Sstevel@tonic-gate ohci_td_t *td) 58687c478bd9Sstevel@tonic-gate { 58697c478bd9Sstevel@tonic-gate uint32_t offset, offset_addr; 58707c478bd9Sstevel@tonic-gate uint_t buf, fc, toggle, flag; 58717c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *temp_pkt_descr; 58727c478bd9Sstevel@tonic-gate int i; 58737c478bd9Sstevel@tonic-gate 58747c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 58757c478bd9Sstevel@tonic-gate 58767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 58777c478bd9Sstevel@tonic-gate "ohci_init_itd: ctrl = 0x%x", hctd_ctrl); 58787c478bd9Sstevel@tonic-gate 58797c478bd9Sstevel@tonic-gate /* 58807c478bd9Sstevel@tonic-gate * Write control information except starting 58817c478bd9Sstevel@tonic-gate * usb frame number. 58827c478bd9Sstevel@tonic-gate */ 58837c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA)); 58847c478bd9Sstevel@tonic-gate 58857c478bd9Sstevel@tonic-gate /* 58867c478bd9Sstevel@tonic-gate * For an isochronous transfer, the hctd_cbp contains, 58877c478bd9Sstevel@tonic-gate * the 4k page, and not the actual start of the buffer. 58887c478bd9Sstevel@tonic-gate */ 58897c478bd9Sstevel@tonic-gate Set_TD(td->hctd_cbp, ((uint32_t)hctd_iommu_cbp & HC_ITD_PAGE_MASK)); 58907c478bd9Sstevel@tonic-gate 58917c478bd9Sstevel@tonic-gate fc = (hctd_ctrl & HC_ITD_FC) >> HC_ITD_FC_SHIFT; 58927c478bd9Sstevel@tonic-gate toggle = 0; 58937c478bd9Sstevel@tonic-gate buf = hctd_iommu_cbp; 58947c478bd9Sstevel@tonic-gate 58957c478bd9Sstevel@tonic-gate /* 58967c478bd9Sstevel@tonic-gate * Get the address of first isochronous data packet 58977c478bd9Sstevel@tonic-gate * for the current isochronous TD. 58987c478bd9Sstevel@tonic-gate */ 58997c478bd9Sstevel@tonic-gate temp_pkt_descr = tw->tw_curr_isoc_pktp; 59007c478bd9Sstevel@tonic-gate 59017c478bd9Sstevel@tonic-gate /* The offsets are actually offsets into the page */ 59027c478bd9Sstevel@tonic-gate for (i = 0; i <= fc; i++) { 59037c478bd9Sstevel@tonic-gate offset_addr = (uint32_t)((buf & 59047c478bd9Sstevel@tonic-gate HC_ITD_OFFSET_ADDR) | (HC_TD_CC_NA >> HC_ITD_CC_SHIFT)); 59057c478bd9Sstevel@tonic-gate 59067c478bd9Sstevel@tonic-gate flag = ((hctd_iommu_cbp & 59077c478bd9Sstevel@tonic-gate HC_ITD_PAGE_MASK) ^ (buf & HC_ITD_PAGE_MASK)); 59087c478bd9Sstevel@tonic-gate 59097c478bd9Sstevel@tonic-gate if (flag) { 59107c478bd9Sstevel@tonic-gate offset_addr |= HC_ITD_4KBOUNDARY_CROSS; 59117c478bd9Sstevel@tonic-gate } 59127c478bd9Sstevel@tonic-gate 59137c478bd9Sstevel@tonic-gate if (toggle) { 59147c478bd9Sstevel@tonic-gate offset = (uint32_t)((offset_addr << 59157c478bd9Sstevel@tonic-gate HC_ITD_OFFSET_SHIFT) & HC_ITD_ODD_OFFSET); 59167c478bd9Sstevel@tonic-gate 59177c478bd9Sstevel@tonic-gate Set_TD(td->hctd_offsets[i / 2], 59187c478bd9Sstevel@tonic-gate Get_TD(td->hctd_offsets[i / 2]) | offset); 59197c478bd9Sstevel@tonic-gate toggle = 0; 59207c478bd9Sstevel@tonic-gate } else { 59217c478bd9Sstevel@tonic-gate offset = (uint32_t)(offset_addr & HC_ITD_EVEN_OFFSET); 59227c478bd9Sstevel@tonic-gate 59237c478bd9Sstevel@tonic-gate Set_TD(td->hctd_offsets[i / 2], 59247c478bd9Sstevel@tonic-gate Get_TD(td->hctd_offsets[i / 2]) | offset); 59257c478bd9Sstevel@tonic-gate toggle = 1; 59267c478bd9Sstevel@tonic-gate } 59277c478bd9Sstevel@tonic-gate 59287c478bd9Sstevel@tonic-gate buf = (uint32_t)(buf + temp_pkt_descr->isoc_pkt_length); 59297c478bd9Sstevel@tonic-gate temp_pkt_descr++; 59307c478bd9Sstevel@tonic-gate } 59317c478bd9Sstevel@tonic-gate } 59327c478bd9Sstevel@tonic-gate 59337c478bd9Sstevel@tonic-gate 59347c478bd9Sstevel@tonic-gate /* 59357c478bd9Sstevel@tonic-gate * ohci_insert_td_with_frame_number: 59367c478bd9Sstevel@tonic-gate * 59377c478bd9Sstevel@tonic-gate * Insert current isochronous TD into the ED's list. with proper 59387c478bd9Sstevel@tonic-gate * usb frame number in which this TD can be processed. 59397c478bd9Sstevel@tonic-gate */ 59407c478bd9Sstevel@tonic-gate static int 59417c478bd9Sstevel@tonic-gate ohci_insert_td_with_frame_number( 59427c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 59437c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 59447c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 59457c478bd9Sstevel@tonic-gate ohci_td_t *current_td, 59467c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td) 59477c478bd9Sstevel@tonic-gate { 59487c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp = 59497c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 59507c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number, start_frame_number; 59517c478bd9Sstevel@tonic-gate uint_t ddic, ctrl, isoc_pkts; 59527c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 59537c478bd9Sstevel@tonic-gate 59547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 59557c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:" 59567c478bd9Sstevel@tonic-gate "isoc flags 0x%x", isoc_reqp->isoc_attributes); 59577c478bd9Sstevel@tonic-gate 59587c478bd9Sstevel@tonic-gate /* Get the TD ctrl information */ 59597c478bd9Sstevel@tonic-gate isoc_pkts = ((Get_TD(current_td->hctd_ctrl) & 59607c478bd9Sstevel@tonic-gate HC_ITD_FC) >> HC_ITD_FC_SHIFT) + 1; 59617c478bd9Sstevel@tonic-gate 59627c478bd9Sstevel@tonic-gate /* 59637c478bd9Sstevel@tonic-gate * Enter critical, while programming the usb frame number 59647c478bd9Sstevel@tonic-gate * and inserting current isochronous TD into the ED's list. 59657c478bd9Sstevel@tonic-gate */ 59667c478bd9Sstevel@tonic-gate ddic = ddi_enter_critical(); 59677c478bd9Sstevel@tonic-gate 59687c478bd9Sstevel@tonic-gate /* Get the current frame number */ 59697c478bd9Sstevel@tonic-gate current_frame_number = ohci_get_current_frame_number(ohcip); 59707c478bd9Sstevel@tonic-gate 59717c478bd9Sstevel@tonic-gate /* Check the given isochronous flags */ 59727c478bd9Sstevel@tonic-gate switch (isoc_reqp->isoc_attributes & 59737c478bd9Sstevel@tonic-gate (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) { 59747c478bd9Sstevel@tonic-gate case USB_ATTRS_ISOC_START_FRAME: 59757c478bd9Sstevel@tonic-gate /* Starting frame number is specified */ 59767c478bd9Sstevel@tonic-gate if (pp->pp_flag & OHCI_ISOC_XFER_CONTINUE) { 59777c478bd9Sstevel@tonic-gate /* Get the starting usb frame number */ 59787c478bd9Sstevel@tonic-gate start_frame_number = pp->pp_next_frame_number; 59797c478bd9Sstevel@tonic-gate } else { 59807c478bd9Sstevel@tonic-gate /* Check for the Starting usb frame number */ 59817c478bd9Sstevel@tonic-gate if ((isoc_reqp->isoc_frame_no == 0) || 59827c478bd9Sstevel@tonic-gate ((isoc_reqp->isoc_frame_no + 59837c478bd9Sstevel@tonic-gate isoc_reqp->isoc_pkts_count) < 59847c478bd9Sstevel@tonic-gate current_frame_number)) { 59857c478bd9Sstevel@tonic-gate 59867c478bd9Sstevel@tonic-gate /* Exit the critical */ 59877c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 59887c478bd9Sstevel@tonic-gate 59897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, 59907c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, 59917c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:" 59927c478bd9Sstevel@tonic-gate "Invalid starting frame number"); 59937c478bd9Sstevel@tonic-gate 59947c478bd9Sstevel@tonic-gate return (USB_INVALID_START_FRAME); 59957c478bd9Sstevel@tonic-gate } 59967c478bd9Sstevel@tonic-gate 59977c478bd9Sstevel@tonic-gate /* Get the starting usb frame number */ 59987c478bd9Sstevel@tonic-gate start_frame_number = isoc_reqp->isoc_frame_no; 59997c478bd9Sstevel@tonic-gate 60007c478bd9Sstevel@tonic-gate pp->pp_next_frame_number = 0; 60017c478bd9Sstevel@tonic-gate } 60027c478bd9Sstevel@tonic-gate break; 60037c478bd9Sstevel@tonic-gate case USB_ATTRS_ISOC_XFER_ASAP: 60047c478bd9Sstevel@tonic-gate /* ohci has to specify starting frame number */ 60057c478bd9Sstevel@tonic-gate if ((pp->pp_next_frame_number) && 60067c478bd9Sstevel@tonic-gate (pp->pp_next_frame_number > current_frame_number)) { 60077c478bd9Sstevel@tonic-gate /* 60087c478bd9Sstevel@tonic-gate * Get the next usb frame number. 60097c478bd9Sstevel@tonic-gate */ 60107c478bd9Sstevel@tonic-gate start_frame_number = pp->pp_next_frame_number; 60117c478bd9Sstevel@tonic-gate } else { 60127c478bd9Sstevel@tonic-gate /* 60137c478bd9Sstevel@tonic-gate * Add appropriate offset to the current usb 60147c478bd9Sstevel@tonic-gate * frame number and use it as a starting frame 60157c478bd9Sstevel@tonic-gate * number. 60167c478bd9Sstevel@tonic-gate */ 60177c478bd9Sstevel@tonic-gate start_frame_number = 60187c478bd9Sstevel@tonic-gate current_frame_number + OHCI_FRAME_OFFSET; 60197c478bd9Sstevel@tonic-gate } 60207c478bd9Sstevel@tonic-gate 60217c478bd9Sstevel@tonic-gate if (!(pp->pp_flag & OHCI_ISOC_XFER_CONTINUE)) { 60227c478bd9Sstevel@tonic-gate isoc_reqp->isoc_frame_no = start_frame_number; 60237c478bd9Sstevel@tonic-gate } 60247c478bd9Sstevel@tonic-gate break; 60257c478bd9Sstevel@tonic-gate default: 60267c478bd9Sstevel@tonic-gate /* Exit the critical */ 60277c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 60287c478bd9Sstevel@tonic-gate 60297c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 60307c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number: Either starting " 60317c478bd9Sstevel@tonic-gate "frame number or ASAP flags are not set, attrs = 0x%x", 60327c478bd9Sstevel@tonic-gate isoc_reqp->isoc_attributes); 60337c478bd9Sstevel@tonic-gate 60347c478bd9Sstevel@tonic-gate return (USB_NO_FRAME_NUMBER); 60357c478bd9Sstevel@tonic-gate } 60367c478bd9Sstevel@tonic-gate 60377c478bd9Sstevel@tonic-gate /* Get the TD ctrl information */ 60387c478bd9Sstevel@tonic-gate ctrl = Get_TD(current_td->hctd_ctrl) & (~(HC_ITD_SF)); 60397c478bd9Sstevel@tonic-gate 60407c478bd9Sstevel@tonic-gate /* Set the frame number field */ 60417c478bd9Sstevel@tonic-gate Set_TD(current_td->hctd_ctrl, ctrl | (start_frame_number & HC_ITD_SF)); 60427c478bd9Sstevel@tonic-gate 60437c478bd9Sstevel@tonic-gate /* 60447c478bd9Sstevel@tonic-gate * Add the new dummy to the ED's list. When this occurs, 60457c478bd9Sstevel@tonic-gate * the Host Controller will see newly filled in dummy TD. 60467c478bd9Sstevel@tonic-gate */ 60477c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, dummy_td))); 60487c478bd9Sstevel@tonic-gate 60497c478bd9Sstevel@tonic-gate /* Exit the critical */ 60507c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 60517c478bd9Sstevel@tonic-gate 60527c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 60537c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:" 60547c478bd9Sstevel@tonic-gate "current frame number 0x%llx start frame number 0x%llx", 60557c478bd9Sstevel@tonic-gate current_frame_number, start_frame_number); 60567c478bd9Sstevel@tonic-gate 60577c478bd9Sstevel@tonic-gate /* 60587c478bd9Sstevel@tonic-gate * Increment this saved frame number by current number 60597c478bd9Sstevel@tonic-gate * of data packets needs to be transfer. 60607c478bd9Sstevel@tonic-gate */ 60617c478bd9Sstevel@tonic-gate pp->pp_next_frame_number = start_frame_number + isoc_pkts; 60627c478bd9Sstevel@tonic-gate 60637c478bd9Sstevel@tonic-gate /* 60647c478bd9Sstevel@tonic-gate * Set OHCI_ISOC_XFER_CONTINUE flag in order to send other 60657c478bd9Sstevel@tonic-gate * isochronous packets, part of the current isoch request 60667c478bd9Sstevel@tonic-gate * in the subsequent frames. 60677c478bd9Sstevel@tonic-gate */ 60687c478bd9Sstevel@tonic-gate pp->pp_flag |= OHCI_ISOC_XFER_CONTINUE; 60697c478bd9Sstevel@tonic-gate 60707c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 60717c478bd9Sstevel@tonic-gate } 60727c478bd9Sstevel@tonic-gate 60737c478bd9Sstevel@tonic-gate 60747c478bd9Sstevel@tonic-gate /* 60757c478bd9Sstevel@tonic-gate * ohci_insert_td_on_tw: 60767c478bd9Sstevel@tonic-gate * 60777c478bd9Sstevel@tonic-gate * The transfer wrapper keeps a list of all Transfer Descriptors (TD) that 60787c478bd9Sstevel@tonic-gate * are allocated for this transfer. Insert a TD onto this list. The list 60797c478bd9Sstevel@tonic-gate * of TD's does not include the dummy TD that is at the end of the list of 60807c478bd9Sstevel@tonic-gate * TD's for the endpoint. 60817c478bd9Sstevel@tonic-gate */ 60827c478bd9Sstevel@tonic-gate static void 60837c478bd9Sstevel@tonic-gate ohci_insert_td_on_tw( 60847c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 60857c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 60867c478bd9Sstevel@tonic-gate ohci_td_t *td) 60877c478bd9Sstevel@tonic-gate { 60887c478bd9Sstevel@tonic-gate /* 60897c478bd9Sstevel@tonic-gate * Set the next pointer to NULL because 60907c478bd9Sstevel@tonic-gate * this is the last TD on list. 60917c478bd9Sstevel@tonic-gate */ 60927c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL); 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head == NULL) { 60957c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL); 60967c478bd9Sstevel@tonic-gate tw->tw_hctd_head = td; 60977c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td; 60987c478bd9Sstevel@tonic-gate } else { 60997c478bd9Sstevel@tonic-gate ohci_td_t *dummy = (ohci_td_t *)tw->tw_hctd_tail; 61007c478bd9Sstevel@tonic-gate 61017c478bd9Sstevel@tonic-gate ASSERT(dummy != NULL); 61027c478bd9Sstevel@tonic-gate ASSERT(dummy != td); 61037c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) != HC_TD_DUMMY); 61047c478bd9Sstevel@tonic-gate 61057c478bd9Sstevel@tonic-gate /* Add the td to the end of the list */ 61067c478bd9Sstevel@tonic-gate Set_TD(dummy->hctd_tw_next_td, 61077c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, td)); 61087c478bd9Sstevel@tonic-gate 61097c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td; 61107c478bd9Sstevel@tonic-gate 61117c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_tw_next_td) == NULL); 61127c478bd9Sstevel@tonic-gate } 61137c478bd9Sstevel@tonic-gate } 61147c478bd9Sstevel@tonic-gate 61157c478bd9Sstevel@tonic-gate 61167c478bd9Sstevel@tonic-gate /* 61177c478bd9Sstevel@tonic-gate * ohci_traverse_tds: 61187c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 61197c478bd9Sstevel@tonic-gate * 61207c478bd9Sstevel@tonic-gate * Traverse the list of TD's for an endpoint. Since the endpoint is marked 61217c478bd9Sstevel@tonic-gate * as sKipped, the Host Controller (HC) is no longer accessing these TD's. 61227c478bd9Sstevel@tonic-gate * Remove all the TD's that are attached to the endpoint. 61237c478bd9Sstevel@tonic-gate */ 61247c478bd9Sstevel@tonic-gate void 61257c478bd9Sstevel@tonic-gate ohci_traverse_tds( 61267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 61277c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 61287c478bd9Sstevel@tonic-gate { 61297c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 61307c478bd9Sstevel@tonic-gate ohci_ed_t *ept; 61317c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 61327c478bd9Sstevel@tonic-gate uint32_t addr; 61337c478bd9Sstevel@tonic-gate ohci_td_t *tailp, *headp, *next; 61347c478bd9Sstevel@tonic-gate 61357c478bd9Sstevel@tonic-gate pp = (ohci_pipe_private_t *)ph->p_hcd_private; 61367c478bd9Sstevel@tonic-gate ept = pp->pp_ept; 61377c478bd9Sstevel@tonic-gate 61387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61397c478bd9Sstevel@tonic-gate "ohci_traverse_tds: ph = 0x%p ept = 0x%p", 61407c478bd9Sstevel@tonic-gate (void *)ph, (void *)ept); 61417c478bd9Sstevel@tonic-gate 61427c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 61437c478bd9Sstevel@tonic-gate 61447c478bd9Sstevel@tonic-gate addr = Get_ED(ept->hced_headp) & (uint32_t)HC_EPT_TD_HEAD; 61457c478bd9Sstevel@tonic-gate 61467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61477c478bd9Sstevel@tonic-gate "ohci_traverse_tds: addr (head) = 0x%x", addr); 61487c478bd9Sstevel@tonic-gate 61497c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, addr)); 61507c478bd9Sstevel@tonic-gate 61517c478bd9Sstevel@tonic-gate addr = Get_ED(ept->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL; 61527c478bd9Sstevel@tonic-gate 61537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61547c478bd9Sstevel@tonic-gate "ohci_traverse_tds: addr (tail) = 0x%x", addr); 61557c478bd9Sstevel@tonic-gate 61567c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, addr)); 61577c478bd9Sstevel@tonic-gate 61587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61597c478bd9Sstevel@tonic-gate "ohci_traverse_tds: cpu head = 0x%p cpu tail = 0x%p", 61607c478bd9Sstevel@tonic-gate (void *)headp, (void *)tailp); 61617c478bd9Sstevel@tonic-gate 61627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61637c478bd9Sstevel@tonic-gate "ohci_traverse_tds: iommu head = 0x%x iommu tail = 0x%x", 61647c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, headp), 61657c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, tailp)); 61667c478bd9Sstevel@tonic-gate 61677c478bd9Sstevel@tonic-gate /* 61687c478bd9Sstevel@tonic-gate * Traverse the list of TD's that are currently on the endpoint. 61697c478bd9Sstevel@tonic-gate * These TD's have not been processed and will not be processed 61707c478bd9Sstevel@tonic-gate * because the endpoint processing is stopped. 61717c478bd9Sstevel@tonic-gate */ 61727c478bd9Sstevel@tonic-gate while (headp != tailp) { 61737c478bd9Sstevel@tonic-gate next = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 61747c478bd9Sstevel@tonic-gate (Get_TD(headp->hctd_next_td) & HC_EPT_TD_TAIL))); 61757c478bd9Sstevel@tonic-gate 61767c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID( 61777c478bd9Sstevel@tonic-gate (uint32_t)Get_TD(headp->hctd_trans_wrapper)); 61787c478bd9Sstevel@tonic-gate 61797c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 61807c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, OHCI_REMOVE_XFER_ALWAYS); 61817c478bd9Sstevel@tonic-gate 61827c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, headp); 61837c478bd9Sstevel@tonic-gate headp = next; 61847c478bd9Sstevel@tonic-gate } 61857c478bd9Sstevel@tonic-gate 61867c478bd9Sstevel@tonic-gate /* Both head and tail pointers must be same */ 61877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61887c478bd9Sstevel@tonic-gate "ohci_traverse_tds: head = 0x%p tail = 0x%p", 61897c478bd9Sstevel@tonic-gate (void *)headp, (void *)tailp); 61907c478bd9Sstevel@tonic-gate 61917c478bd9Sstevel@tonic-gate /* Update the pointer in the endpoint descriptor */ 61927c478bd9Sstevel@tonic-gate Set_ED(ept->hced_headp, (ohci_td_cpu_to_iommu(ohcip, headp))); 61937c478bd9Sstevel@tonic-gate 61947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61957c478bd9Sstevel@tonic-gate "ohci_traverse_tds: new head = 0x%x", 61967c478bd9Sstevel@tonic-gate (ohci_td_cpu_to_iommu(ohcip, headp))); 61977c478bd9Sstevel@tonic-gate 61987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61997c478bd9Sstevel@tonic-gate "ohci_traverse_tds: tailp = 0x%x headp = 0x%x", 62007c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL), 62017c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD)); 62027c478bd9Sstevel@tonic-gate 62037c478bd9Sstevel@tonic-gate ASSERT((Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL) == 62047c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD)); 62057c478bd9Sstevel@tonic-gate } 62067c478bd9Sstevel@tonic-gate 62077c478bd9Sstevel@tonic-gate 62087c478bd9Sstevel@tonic-gate /* 62097c478bd9Sstevel@tonic-gate * ohci_done_list_tds: 62107c478bd9Sstevel@tonic-gate * 62117c478bd9Sstevel@tonic-gate * There may be TD's on the done list that have not been processed yet. Walk 62127c478bd9Sstevel@tonic-gate * through these TD's and mark them as RECLAIM. All the mappings for the TD 62137c478bd9Sstevel@tonic-gate * will be torn down, so the interrupt handle is alerted of this fact through 62147c478bd9Sstevel@tonic-gate * the RECLAIM flag. 62157c478bd9Sstevel@tonic-gate */ 62167c478bd9Sstevel@tonic-gate static void 62177c478bd9Sstevel@tonic-gate ohci_done_list_tds( 62187c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 62197c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 62207c478bd9Sstevel@tonic-gate { 62217c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 62227c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head; 62237c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw; 62247c478bd9Sstevel@tonic-gate ohci_td_t *head_td, *next_td; 62257c478bd9Sstevel@tonic-gate 62267c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 62277c478bd9Sstevel@tonic-gate 62287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 62297c478bd9Sstevel@tonic-gate "ohci_done_list_tds:"); 62307c478bd9Sstevel@tonic-gate 62317c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */ 62327c478bd9Sstevel@tonic-gate next_tw = head_tw; 62337c478bd9Sstevel@tonic-gate while (next_tw) { 62347c478bd9Sstevel@tonic-gate head_td = (ohci_td_t *)next_tw->tw_hctd_head; 62357c478bd9Sstevel@tonic-gate next_td = head_td; 62367c478bd9Sstevel@tonic-gate 62377c478bd9Sstevel@tonic-gate if (head_td) { 62387c478bd9Sstevel@tonic-gate /* 62397c478bd9Sstevel@tonic-gate * Walk through each TD for this transfer 62407c478bd9Sstevel@tonic-gate * wrapper. If a TD still exists, then it 62417c478bd9Sstevel@tonic-gate * is currently on the done list. 62427c478bd9Sstevel@tonic-gate */ 62437c478bd9Sstevel@tonic-gate while (next_td) { 62447c478bd9Sstevel@tonic-gate 62457c478bd9Sstevel@tonic-gate /* To free TD, set TD state to RECLAIM */ 62467c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_state, HC_TD_RECLAIM); 62477c478bd9Sstevel@tonic-gate 62487c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_trans_wrapper, NULL); 62497c478bd9Sstevel@tonic-gate 62507c478bd9Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip, 62517c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td)); 62527c478bd9Sstevel@tonic-gate } 62537c478bd9Sstevel@tonic-gate } 62547c478bd9Sstevel@tonic-gate 62557c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 62567c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, next_tw, OHCI_REMOVE_XFER_ALWAYS); 62577c478bd9Sstevel@tonic-gate 62587c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next; 62597c478bd9Sstevel@tonic-gate } 62607c478bd9Sstevel@tonic-gate } 62617c478bd9Sstevel@tonic-gate 62627c478bd9Sstevel@tonic-gate 62637c478bd9Sstevel@tonic-gate /* 62647c478bd9Sstevel@tonic-gate * ohci_deallocate_td: 62657c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 62667c478bd9Sstevel@tonic-gate * 62677c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Transfer Descriptor (TD). 62687c478bd9Sstevel@tonic-gate */ 62697c478bd9Sstevel@tonic-gate void 62707c478bd9Sstevel@tonic-gate ohci_deallocate_td( 62717c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 62727c478bd9Sstevel@tonic-gate ohci_td_t *old_td) 62737c478bd9Sstevel@tonic-gate { 62747c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 62757c478bd9Sstevel@tonic-gate 62767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 62777c478bd9Sstevel@tonic-gate "ohci_deallocate_td: old_td = 0x%p", (void *)old_td); 62787c478bd9Sstevel@tonic-gate 62797c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 62807c478bd9Sstevel@tonic-gate 62817c478bd9Sstevel@tonic-gate /* 62827c478bd9Sstevel@tonic-gate * Obtain the transaction wrapper and tw will be 62837c478bd9Sstevel@tonic-gate * NULL for the dummy and for the reclaim TD's. 62847c478bd9Sstevel@tonic-gate */ 62857c478bd9Sstevel@tonic-gate if ((Get_TD(old_td->hctd_state) == HC_TD_DUMMY) || 62867c478bd9Sstevel@tonic-gate (Get_TD(old_td->hctd_state) == HC_TD_RECLAIM)) { 62877c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)((uintptr_t) 62887c478bd9Sstevel@tonic-gate Get_TD(old_td->hctd_trans_wrapper)); 62897c478bd9Sstevel@tonic-gate ASSERT(tw == NULL); 62907c478bd9Sstevel@tonic-gate } else { 62917c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 62927c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t) 62937c478bd9Sstevel@tonic-gate Get_TD(old_td->hctd_trans_wrapper)); 62947c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 62957c478bd9Sstevel@tonic-gate } 62967c478bd9Sstevel@tonic-gate 62977c478bd9Sstevel@tonic-gate /* 62987c478bd9Sstevel@tonic-gate * If this TD should be reclaimed, don't try to access its 62997c478bd9Sstevel@tonic-gate * transfer wrapper. 63007c478bd9Sstevel@tonic-gate */ 63017c478bd9Sstevel@tonic-gate if ((Get_TD(old_td->hctd_state) != HC_TD_RECLAIM) && tw) { 63027c478bd9Sstevel@tonic-gate ohci_td_t *td = (ohci_td_t *)tw->tw_hctd_head; 63037c478bd9Sstevel@tonic-gate ohci_td_t *test; 63047c478bd9Sstevel@tonic-gate 63057c478bd9Sstevel@tonic-gate /* 63067c478bd9Sstevel@tonic-gate * Take this TD off the transfer wrapper's list since 63077c478bd9Sstevel@tonic-gate * the pipe is FIFO, this must be the first TD on the 63087c478bd9Sstevel@tonic-gate * list. 63097c478bd9Sstevel@tonic-gate */ 63107c478bd9Sstevel@tonic-gate ASSERT((ohci_td_t *)tw->tw_hctd_head == old_td); 63117c478bd9Sstevel@tonic-gate 63127c478bd9Sstevel@tonic-gate tw->tw_hctd_head = 63137c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_tw_next_td)); 63147c478bd9Sstevel@tonic-gate 63157c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head) { 63167c478bd9Sstevel@tonic-gate test = (ohci_td_t *)tw->tw_hctd_head; 63177c478bd9Sstevel@tonic-gate ASSERT(Get_TD(test->hctd_state) != HC_TD_DUMMY); 63187c478bd9Sstevel@tonic-gate } 63197c478bd9Sstevel@tonic-gate 63207c478bd9Sstevel@tonic-gate /* 63217c478bd9Sstevel@tonic-gate * If the head becomes NULL, then there are no more 63227c478bd9Sstevel@tonic-gate * active TD's for this transfer wrapper. Also set 63237c478bd9Sstevel@tonic-gate * the tail to NULL. 63247c478bd9Sstevel@tonic-gate */ 63257c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head == NULL) { 63267c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = NULL; 63277c478bd9Sstevel@tonic-gate } else { 63287c478bd9Sstevel@tonic-gate /* 63297c478bd9Sstevel@tonic-gate * If this is the last td on the list, make 63307c478bd9Sstevel@tonic-gate * sure it doesn't point to yet another td. 63317c478bd9Sstevel@tonic-gate */ 63327c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head == tw->tw_hctd_tail) { 63337c478bd9Sstevel@tonic-gate td = (ohci_td_t *)tw->tw_hctd_head; 63347c478bd9Sstevel@tonic-gate 63357c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_tw_next_td) == NULL); 63367c478bd9Sstevel@tonic-gate } 63377c478bd9Sstevel@tonic-gate } 63387c478bd9Sstevel@tonic-gate } 63397c478bd9Sstevel@tonic-gate 63407c478bd9Sstevel@tonic-gate bzero((void *)old_td, sizeof (ohci_td_t)); 63417c478bd9Sstevel@tonic-gate Set_TD(old_td->hctd_state, HC_TD_FREE); 63427c478bd9Sstevel@tonic-gate 63437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 63447c478bd9Sstevel@tonic-gate "ohci_deallocate_td: td 0x%p", (void *)old_td); 63457c478bd9Sstevel@tonic-gate } 63467c478bd9Sstevel@tonic-gate 63477c478bd9Sstevel@tonic-gate 63487c478bd9Sstevel@tonic-gate /* 63497c478bd9Sstevel@tonic-gate * ohci_td_cpu_to_iommu: 63507c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 63517c478bd9Sstevel@tonic-gate * 63527c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (TD) CPU address 63537c478bd9Sstevel@tonic-gate * to IO address. 63547c478bd9Sstevel@tonic-gate */ 63557c478bd9Sstevel@tonic-gate uint32_t 63567c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu( 63577c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 63587c478bd9Sstevel@tonic-gate ohci_td_t *addr) 63597c478bd9Sstevel@tonic-gate { 63607c478bd9Sstevel@tonic-gate uint32_t td; 63617c478bd9Sstevel@tonic-gate 63627c478bd9Sstevel@tonic-gate td = (uint32_t)ohcip->ohci_td_pool_cookie.dmac_address + 63637c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ohcip->ohci_td_pool_addr)); 63647c478bd9Sstevel@tonic-gate 63657c478bd9Sstevel@tonic-gate ASSERT((ohcip->ohci_td_pool_cookie.dmac_address + 63667c478bd9Sstevel@tonic-gate (uint32_t) (sizeof (ohci_td_t) * 63677c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_td_pool_addr))) == 63687c478bd9Sstevel@tonic-gate (ohcip->ohci_td_pool_cookie.dmac_address + 63697c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t) 63707c478bd9Sstevel@tonic-gate (ohcip->ohci_td_pool_addr)))); 63717c478bd9Sstevel@tonic-gate 63727c478bd9Sstevel@tonic-gate ASSERT(td >= ohcip->ohci_td_pool_cookie.dmac_address); 63737c478bd9Sstevel@tonic-gate ASSERT(td <= ohcip->ohci_td_pool_cookie.dmac_address + 63747c478bd9Sstevel@tonic-gate sizeof (ohci_td_t) * ohci_td_pool_size); 63757c478bd9Sstevel@tonic-gate 63767c478bd9Sstevel@tonic-gate return (td); 63777c478bd9Sstevel@tonic-gate } 63787c478bd9Sstevel@tonic-gate 63797c478bd9Sstevel@tonic-gate 63807c478bd9Sstevel@tonic-gate /* 63817c478bd9Sstevel@tonic-gate * ohci_td_iommu_to_cpu: 63827c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 63837c478bd9Sstevel@tonic-gate * 63847c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (TD) IO address 63857c478bd9Sstevel@tonic-gate * to CPU address. 63867c478bd9Sstevel@tonic-gate */ 63877c478bd9Sstevel@tonic-gate ohci_td_t * 63887c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu( 63897c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 63907c478bd9Sstevel@tonic-gate uintptr_t addr) 63917c478bd9Sstevel@tonic-gate { 63927c478bd9Sstevel@tonic-gate ohci_td_t *td; 63937c478bd9Sstevel@tonic-gate 63947c478bd9Sstevel@tonic-gate if (addr == NULL) { 63957c478bd9Sstevel@tonic-gate 63967c478bd9Sstevel@tonic-gate return (NULL); 63977c478bd9Sstevel@tonic-gate } 63987c478bd9Sstevel@tonic-gate 63997c478bd9Sstevel@tonic-gate td = (ohci_td_t *)((uintptr_t) 64007c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_td_pool_cookie.dmac_address) + 64017c478bd9Sstevel@tonic-gate (uintptr_t)ohcip->ohci_td_pool_addr); 64027c478bd9Sstevel@tonic-gate 64037c478bd9Sstevel@tonic-gate ASSERT(td >= ohcip->ohci_td_pool_addr); 64047c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)td <= (uintptr_t)ohcip->ohci_td_pool_addr + 64057c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ohci_td_t) * ohci_td_pool_size)); 64067c478bd9Sstevel@tonic-gate 64077c478bd9Sstevel@tonic-gate return (td); 64087c478bd9Sstevel@tonic-gate } 64097c478bd9Sstevel@tonic-gate 64107c478bd9Sstevel@tonic-gate /* 64117c478bd9Sstevel@tonic-gate * ohci_allocate_tds_for_tw: 64127c478bd9Sstevel@tonic-gate * 64137c478bd9Sstevel@tonic-gate * Allocate n Transfer Descriptors (TD) from the TD buffer pool and places it 64147c478bd9Sstevel@tonic-gate * into the TW. 64157c478bd9Sstevel@tonic-gate * 64167c478bd9Sstevel@tonic-gate * Returns USB_NO_RESOURCES if it was not able to allocate all the requested TD 64177c478bd9Sstevel@tonic-gate * otherwise USB_SUCCESS. 64187c478bd9Sstevel@tonic-gate */ 64197c478bd9Sstevel@tonic-gate static int 64207c478bd9Sstevel@tonic-gate ohci_allocate_tds_for_tw( 64217c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 64227c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 64237c478bd9Sstevel@tonic-gate size_t td_count) 64247c478bd9Sstevel@tonic-gate { 64257c478bd9Sstevel@tonic-gate ohci_td_t *td; 64267c478bd9Sstevel@tonic-gate uint32_t td_addr; 64277c478bd9Sstevel@tonic-gate int i; 64287c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 64297c478bd9Sstevel@tonic-gate 64307c478bd9Sstevel@tonic-gate for (i = 0; i < td_count; i++) { 64317c478bd9Sstevel@tonic-gate td = ohci_allocate_td_from_pool(ohcip); 64327c478bd9Sstevel@tonic-gate if (td == NULL) { 64337c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 64347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64357c478bd9Sstevel@tonic-gate "ohci_allocate_tds_for_tw: " 64367c478bd9Sstevel@tonic-gate "Unable to allocate %lu TDs", 64377c478bd9Sstevel@tonic-gate td_count); 64387c478bd9Sstevel@tonic-gate break; 64397c478bd9Sstevel@tonic-gate } 64407c478bd9Sstevel@tonic-gate if (tw->tw_hctd_free_list != NULL) { 64417c478bd9Sstevel@tonic-gate td_addr = ohci_td_cpu_to_iommu(ohcip, 64427c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list); 64437c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, td_addr); 64447c478bd9Sstevel@tonic-gate } 64457c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = td; 64467c478bd9Sstevel@tonic-gate } 64477c478bd9Sstevel@tonic-gate 64487c478bd9Sstevel@tonic-gate return (error); 64497c478bd9Sstevel@tonic-gate } 64507c478bd9Sstevel@tonic-gate 64517c478bd9Sstevel@tonic-gate /* 64527c478bd9Sstevel@tonic-gate * ohci_allocate_tw_resources: 64537c478bd9Sstevel@tonic-gate * 64547c478bd9Sstevel@tonic-gate * Allocate a Transaction Wrapper (TW) and n Transfer Descriptors (TD) 64557c478bd9Sstevel@tonic-gate * from the TD buffer pool and places it into the TW. It does an all 64567c478bd9Sstevel@tonic-gate * or nothing transaction. 64577c478bd9Sstevel@tonic-gate * 64587c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 64597c478bd9Sstevel@tonic-gate */ 64607c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 64617c478bd9Sstevel@tonic-gate ohci_allocate_tw_resources( 64627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 64637c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 64647c478bd9Sstevel@tonic-gate size_t tw_length, 64657c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 64667c478bd9Sstevel@tonic-gate size_t td_count) 64677c478bd9Sstevel@tonic-gate { 64687c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 64697c478bd9Sstevel@tonic-gate 64707c478bd9Sstevel@tonic-gate tw = ohci_create_transfer_wrapper(ohcip, pp, tw_length, usb_flags); 64717c478bd9Sstevel@tonic-gate 64727c478bd9Sstevel@tonic-gate if (tw == NULL) { 64737c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64747c478bd9Sstevel@tonic-gate "ohci_allocate_tw_resources: Unable to allocate TW"); 64757c478bd9Sstevel@tonic-gate } else { 64767c478bd9Sstevel@tonic-gate if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) == 64777c478bd9Sstevel@tonic-gate USB_SUCCESS) { 64787c478bd9Sstevel@tonic-gate tw->tw_num_tds = td_count; 64797c478bd9Sstevel@tonic-gate } else { 64807c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 64817c478bd9Sstevel@tonic-gate tw = NULL; 64827c478bd9Sstevel@tonic-gate } 64837c478bd9Sstevel@tonic-gate } 64847c478bd9Sstevel@tonic-gate 64857c478bd9Sstevel@tonic-gate return (tw); 64867c478bd9Sstevel@tonic-gate } 64877c478bd9Sstevel@tonic-gate 64887c478bd9Sstevel@tonic-gate /* 64897c478bd9Sstevel@tonic-gate * ohci_free_tw_tds_resources: 64907c478bd9Sstevel@tonic-gate * 64917c478bd9Sstevel@tonic-gate * Free all allocated resources for Transaction Wrapper (TW). 64927c478bd9Sstevel@tonic-gate * Does not free the TW itself. 64937c478bd9Sstevel@tonic-gate */ 64947c478bd9Sstevel@tonic-gate static void 64957c478bd9Sstevel@tonic-gate ohci_free_tw_tds_resources( 64967c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 64977c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 64987c478bd9Sstevel@tonic-gate { 64997c478bd9Sstevel@tonic-gate ohci_td_t *td; 65007c478bd9Sstevel@tonic-gate ohci_td_t *temp_td; 65017c478bd9Sstevel@tonic-gate 65027c478bd9Sstevel@tonic-gate td = tw->tw_hctd_free_list; 65037c478bd9Sstevel@tonic-gate while (td != NULL) { 65047c478bd9Sstevel@tonic-gate /* Save the pointer to the next td before destroying it */ 65057c478bd9Sstevel@tonic-gate temp_td = ohci_td_iommu_to_cpu(ohcip, 65067c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td)); 65077c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, td); 65087c478bd9Sstevel@tonic-gate td = temp_td; 65097c478bd9Sstevel@tonic-gate } 65107c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = NULL; 65117c478bd9Sstevel@tonic-gate } 65127c478bd9Sstevel@tonic-gate 65137c478bd9Sstevel@tonic-gate 65147c478bd9Sstevel@tonic-gate /* 65157c478bd9Sstevel@tonic-gate * Transfer Wrapper functions 65167c478bd9Sstevel@tonic-gate * 65177c478bd9Sstevel@tonic-gate * ohci_create_transfer_wrapper: 65187c478bd9Sstevel@tonic-gate * 65197c478bd9Sstevel@tonic-gate * Create a Transaction Wrapper (TW) and this involves the allocating of DMA 65207c478bd9Sstevel@tonic-gate * resources. 65217c478bd9Sstevel@tonic-gate */ 65227c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 65237c478bd9Sstevel@tonic-gate ohci_create_transfer_wrapper( 65247c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 65257c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 65267c478bd9Sstevel@tonic-gate size_t length, 65277c478bd9Sstevel@tonic-gate uint_t usb_flags) 65287c478bd9Sstevel@tonic-gate { 65297c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 65307c478bd9Sstevel@tonic-gate int result; 65317c478bd9Sstevel@tonic-gate size_t real_length; 65327c478bd9Sstevel@tonic-gate uint_t ccount; /* Cookie count */ 65337c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 65347c478bd9Sstevel@tonic-gate 65357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 65367c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: length = 0x%lx flags = 0x%x", 65377c478bd9Sstevel@tonic-gate length, usb_flags); 65387c478bd9Sstevel@tonic-gate 65397c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 65407c478bd9Sstevel@tonic-gate 65417c478bd9Sstevel@tonic-gate /* Allocate space for the transfer wrapper */ 65427c478bd9Sstevel@tonic-gate tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t), KM_NOSLEEP); 65437c478bd9Sstevel@tonic-gate 65447c478bd9Sstevel@tonic-gate if (tw == NULL) { 65457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 65467c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: kmem_zalloc failed"); 65477c478bd9Sstevel@tonic-gate 65487c478bd9Sstevel@tonic-gate return (NULL); 65497c478bd9Sstevel@tonic-gate } 65507c478bd9Sstevel@tonic-gate 65517c478bd9Sstevel@tonic-gate /* Force the required 4K restrictive alignment */ 65527c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT; 65537c478bd9Sstevel@tonic-gate 65547c478bd9Sstevel@tonic-gate /* Allocate the DMA handle */ 65557c478bd9Sstevel@tonic-gate result = ddi_dma_alloc_handle(ohcip->ohci_dip, 65567c478bd9Sstevel@tonic-gate &ohcip->ohci_dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle); 65577c478bd9Sstevel@tonic-gate 65587c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 65597c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 65607c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: Alloc handle failed"); 65617c478bd9Sstevel@tonic-gate 65627c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 65637c478bd9Sstevel@tonic-gate 65647c478bd9Sstevel@tonic-gate return (NULL); 65657c478bd9Sstevel@tonic-gate } 65667c478bd9Sstevel@tonic-gate 65677c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 65687c478bd9Sstevel@tonic-gate 65697c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 65707c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 65717c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 65727c478bd9Sstevel@tonic-gate 65737c478bd9Sstevel@tonic-gate /* Allocate the memory */ 65747c478bd9Sstevel@tonic-gate result = ddi_dma_mem_alloc(tw->tw_dmahandle, length, 65757c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 65767c478bd9Sstevel@tonic-gate (caddr_t *)&tw->tw_buf, &real_length, &tw->tw_accesshandle); 65777c478bd9Sstevel@tonic-gate 65787c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 65797c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 65807c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: dma_mem_alloc fail"); 65817c478bd9Sstevel@tonic-gate 65827c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 65837c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 65847c478bd9Sstevel@tonic-gate 65857c478bd9Sstevel@tonic-gate return (NULL); 65867c478bd9Sstevel@tonic-gate } 65877c478bd9Sstevel@tonic-gate 65887c478bd9Sstevel@tonic-gate ASSERT(real_length >= length); 65897c478bd9Sstevel@tonic-gate 65907c478bd9Sstevel@tonic-gate /* Bind the handle */ 65917c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL, 65927c478bd9Sstevel@tonic-gate (caddr_t)tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT, 65937c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount); 65947c478bd9Sstevel@tonic-gate 65957c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 65967c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 65977c478bd9Sstevel@tonic-gate if (ccount != 1) { 65987c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 65997c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: More than 1 cookie"); 66007c478bd9Sstevel@tonic-gate 66017c478bd9Sstevel@tonic-gate result = ddi_dma_unbind_handle(tw->tw_dmahandle); 66027c478bd9Sstevel@tonic-gate ASSERT(result == DDI_SUCCESS); 66037c478bd9Sstevel@tonic-gate 66047c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&tw->tw_accesshandle); 66057c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 66067c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 66077c478bd9Sstevel@tonic-gate 66087c478bd9Sstevel@tonic-gate return (NULL); 66097c478bd9Sstevel@tonic-gate } 66107c478bd9Sstevel@tonic-gate } else { 66117c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 66127c478bd9Sstevel@tonic-gate 66137c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&tw->tw_accesshandle); 66147c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 66157c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 66167c478bd9Sstevel@tonic-gate 66177c478bd9Sstevel@tonic-gate return (NULL); 66187c478bd9Sstevel@tonic-gate } 66197c478bd9Sstevel@tonic-gate 66207c478bd9Sstevel@tonic-gate /* 66217c478bd9Sstevel@tonic-gate * Only allow one wrapper to be added at a time. Insert the 66227c478bd9Sstevel@tonic-gate * new transaction wrapper into the list for this pipe. 66237c478bd9Sstevel@tonic-gate */ 66247c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == NULL) { 66257c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw; 66267c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw; 66277c478bd9Sstevel@tonic-gate } else { 66287c478bd9Sstevel@tonic-gate pp->pp_tw_tail->tw_next = tw; 66297c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw; 66307c478bd9Sstevel@tonic-gate } 66317c478bd9Sstevel@tonic-gate 66327c478bd9Sstevel@tonic-gate /* Store the transfer length */ 66337c478bd9Sstevel@tonic-gate tw->tw_length = length; 66347c478bd9Sstevel@tonic-gate 66357c478bd9Sstevel@tonic-gate /* Store a back pointer to the pipe private structure */ 66367c478bd9Sstevel@tonic-gate tw->tw_pipe_private = pp; 66377c478bd9Sstevel@tonic-gate 66387c478bd9Sstevel@tonic-gate /* Store the transfer type - synchronous or asynchronous */ 66397c478bd9Sstevel@tonic-gate tw->tw_flags = usb_flags; 66407c478bd9Sstevel@tonic-gate 66417c478bd9Sstevel@tonic-gate /* Get and Store 32bit ID */ 66427c478bd9Sstevel@tonic-gate tw->tw_id = OHCI_GET_ID((void *)tw); 66437c478bd9Sstevel@tonic-gate 66447c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 66457c478bd9Sstevel@tonic-gate 66467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 66477c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: tw = 0x%p", tw); 66487c478bd9Sstevel@tonic-gate 66497c478bd9Sstevel@tonic-gate return (tw); 66507c478bd9Sstevel@tonic-gate } 66517c478bd9Sstevel@tonic-gate 66527c478bd9Sstevel@tonic-gate 66537c478bd9Sstevel@tonic-gate /* 66547c478bd9Sstevel@tonic-gate * ohci_start_xfer_timer: 66557c478bd9Sstevel@tonic-gate * 66567c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt 66577c478bd9Sstevel@tonic-gate * transfers. 66587c478bd9Sstevel@tonic-gate */ 66597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 66607c478bd9Sstevel@tonic-gate static void 66617c478bd9Sstevel@tonic-gate ohci_start_xfer_timer( 66627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 66637c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 66647c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 66657c478bd9Sstevel@tonic-gate { 66667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 66677c478bd9Sstevel@tonic-gate "ohci_start_xfer_timer: tw = 0x%p", tw); 66687c478bd9Sstevel@tonic-gate 66697c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 66707c478bd9Sstevel@tonic-gate 66717c478bd9Sstevel@tonic-gate /* 66727c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk and for 66737c478bd9Sstevel@tonic-gate * one time Interrupt transfers. 66747c478bd9Sstevel@tonic-gate * 66757c478bd9Sstevel@tonic-gate * NOTE: If timeout is zero; Assume infinite timeout and don't 66767c478bd9Sstevel@tonic-gate * insert this transfer on the timeout list. 66777c478bd9Sstevel@tonic-gate */ 66787c478bd9Sstevel@tonic-gate if (tw->tw_timeout) { 66797c478bd9Sstevel@tonic-gate /* 66807c478bd9Sstevel@tonic-gate * Increase timeout value by one second and this extra one 66817c478bd9Sstevel@tonic-gate * second is used to halt the endpoint if given transfer 66827c478bd9Sstevel@tonic-gate * times out. 66837c478bd9Sstevel@tonic-gate */ 66847c478bd9Sstevel@tonic-gate tw->tw_timeout++; 66857c478bd9Sstevel@tonic-gate 66867c478bd9Sstevel@tonic-gate /* 66877c478bd9Sstevel@tonic-gate * Add this transfer wrapper into the transfer timeout list. 66887c478bd9Sstevel@tonic-gate */ 66897c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list) { 66907c478bd9Sstevel@tonic-gate tw->tw_timeout_next = ohcip->ohci_timeout_list; 66917c478bd9Sstevel@tonic-gate } 66927c478bd9Sstevel@tonic-gate 66937c478bd9Sstevel@tonic-gate ohcip->ohci_timeout_list = tw; 66947c478bd9Sstevel@tonic-gate ohci_start_timer(ohcip); 66957c478bd9Sstevel@tonic-gate } 66967c478bd9Sstevel@tonic-gate } 66977c478bd9Sstevel@tonic-gate 66987c478bd9Sstevel@tonic-gate 66997c478bd9Sstevel@tonic-gate /* 67007c478bd9Sstevel@tonic-gate * ohci_stop_xfer_timer: 67017c478bd9Sstevel@tonic-gate * 67027c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt 67037c478bd9Sstevel@tonic-gate * transfers. 67047c478bd9Sstevel@tonic-gate */ 67057c478bd9Sstevel@tonic-gate void 67067c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer( 67077c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 67087c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 67097c478bd9Sstevel@tonic-gate uint_t flag) 67107c478bd9Sstevel@tonic-gate { 67117c478bd9Sstevel@tonic-gate timeout_id_t timer_id; 67127c478bd9Sstevel@tonic-gate 67137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 67147c478bd9Sstevel@tonic-gate "ohci_stop_xfer_timer: tw = 0x%p", tw); 67157c478bd9Sstevel@tonic-gate 67167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 67177c478bd9Sstevel@tonic-gate 67187c478bd9Sstevel@tonic-gate /* 67197c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk 67207c478bd9Sstevel@tonic-gate * and for one time Interrupt transfers. 67217c478bd9Sstevel@tonic-gate */ 67227c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list == NULL) { 67237c478bd9Sstevel@tonic-gate return; 67247c478bd9Sstevel@tonic-gate } 67257c478bd9Sstevel@tonic-gate 67267c478bd9Sstevel@tonic-gate switch (flag) { 67277c478bd9Sstevel@tonic-gate case OHCI_REMOVE_XFER_IFLAST: 67287c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head != tw->tw_hctd_tail) { 67297c478bd9Sstevel@tonic-gate break; 67307c478bd9Sstevel@tonic-gate } 67317c478bd9Sstevel@tonic-gate /* FALLTHRU */ 67327c478bd9Sstevel@tonic-gate case OHCI_REMOVE_XFER_ALWAYS: 67337c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(ohcip, tw); 67347c478bd9Sstevel@tonic-gate 67357c478bd9Sstevel@tonic-gate if ((ohcip->ohci_timeout_list == NULL) && 67367c478bd9Sstevel@tonic-gate (ohcip->ohci_timer_id)) { 67377c478bd9Sstevel@tonic-gate 67387c478bd9Sstevel@tonic-gate timer_id = ohcip->ohci_timer_id; 67397c478bd9Sstevel@tonic-gate 67407c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */ 67417c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0; 67427c478bd9Sstevel@tonic-gate 67437c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 67447c478bd9Sstevel@tonic-gate 67457c478bd9Sstevel@tonic-gate (void) untimeout(timer_id); 67467c478bd9Sstevel@tonic-gate 67477c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 67487c478bd9Sstevel@tonic-gate } 67497c478bd9Sstevel@tonic-gate break; 67507c478bd9Sstevel@tonic-gate default: 67517c478bd9Sstevel@tonic-gate break; 67527c478bd9Sstevel@tonic-gate } 67537c478bd9Sstevel@tonic-gate } 67547c478bd9Sstevel@tonic-gate 67557c478bd9Sstevel@tonic-gate 67567c478bd9Sstevel@tonic-gate /* 67577c478bd9Sstevel@tonic-gate * ohci_xfer_timeout_handler: 67587c478bd9Sstevel@tonic-gate * 67597c478bd9Sstevel@tonic-gate * Control or bulk transfer timeout handler. 67607c478bd9Sstevel@tonic-gate */ 67617c478bd9Sstevel@tonic-gate static void 67627c478bd9Sstevel@tonic-gate ohci_xfer_timeout_handler(void *arg) 67637c478bd9Sstevel@tonic-gate { 67647c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = (ohci_state_t *)arg; 67657c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *exp_xfer_list_head = NULL; 67667c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *exp_xfer_list_tail = NULL; 67677c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, *next; 67687c478bd9Sstevel@tonic-gate ohci_td_t *td; 67697c478bd9Sstevel@tonic-gate usb_flags_t flags; 67707c478bd9Sstevel@tonic-gate 67717c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 67727c478bd9Sstevel@tonic-gate "ohci_xfer_timeout_handler: ohcip = 0x%p", ohcip); 67737c478bd9Sstevel@tonic-gate 67747c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 67757c478bd9Sstevel@tonic-gate 67767c478bd9Sstevel@tonic-gate /* Set the required flags */ 67777c478bd9Sstevel@tonic-gate flags = OHCI_FLAGS_NOSLEEP | OHCI_FLAGS_DMA_SYNC; 67787c478bd9Sstevel@tonic-gate 67797c478bd9Sstevel@tonic-gate /* 67807c478bd9Sstevel@tonic-gate * Check whether still timeout handler is valid. 67817c478bd9Sstevel@tonic-gate */ 67827c478bd9Sstevel@tonic-gate if (ohcip->ohci_timer_id) { 67837c478bd9Sstevel@tonic-gate 67847c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */ 67857c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0; 67867c478bd9Sstevel@tonic-gate } else { 67877c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 67887c478bd9Sstevel@tonic-gate 67897c478bd9Sstevel@tonic-gate return; 67907c478bd9Sstevel@tonic-gate } 67917c478bd9Sstevel@tonic-gate 67927c478bd9Sstevel@tonic-gate /* Get the transfer timeout list head */ 67937c478bd9Sstevel@tonic-gate tw = ohcip->ohci_timeout_list; 67947c478bd9Sstevel@tonic-gate 67957c478bd9Sstevel@tonic-gate /* 67967c478bd9Sstevel@tonic-gate * Process ohci timeout list and look whether the timer 67977c478bd9Sstevel@tonic-gate * has expired for any transfers. Create a temporary list 67987c478bd9Sstevel@tonic-gate * of expired transfers and process them later. 67997c478bd9Sstevel@tonic-gate */ 68007c478bd9Sstevel@tonic-gate while (tw) { 68017c478bd9Sstevel@tonic-gate /* Get the transfer on the timeout list */ 68027c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next; 68037c478bd9Sstevel@tonic-gate 68047c478bd9Sstevel@tonic-gate tw->tw_timeout--; 68057c478bd9Sstevel@tonic-gate 68067c478bd9Sstevel@tonic-gate /* 68077c478bd9Sstevel@tonic-gate * Set the sKip bit to stop all transactions on 68087c478bd9Sstevel@tonic-gate * this pipe 68097c478bd9Sstevel@tonic-gate */ 68107c478bd9Sstevel@tonic-gate if (tw->tw_timeout == 1) { 68117c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, 68127c478bd9Sstevel@tonic-gate tw->tw_pipe_private, SET_sKip, flags); 68137c478bd9Sstevel@tonic-gate 68147c478bd9Sstevel@tonic-gate /* Reset dma sync flag */ 68157c478bd9Sstevel@tonic-gate flags &= ~OHCI_FLAGS_DMA_SYNC; 68167c478bd9Sstevel@tonic-gate } 68177c478bd9Sstevel@tonic-gate 68187c478bd9Sstevel@tonic-gate /* Remove tw from the timeout list */ 68197c478bd9Sstevel@tonic-gate if (tw->tw_timeout <= 0) { 68207c478bd9Sstevel@tonic-gate 68217c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(ohcip, tw); 68227c478bd9Sstevel@tonic-gate 68237c478bd9Sstevel@tonic-gate /* Add tw to the end of expire list */ 68247c478bd9Sstevel@tonic-gate if (exp_xfer_list_head) { 68257c478bd9Sstevel@tonic-gate exp_xfer_list_tail->tw_timeout_next = tw; 68267c478bd9Sstevel@tonic-gate } else { 68277c478bd9Sstevel@tonic-gate exp_xfer_list_head = tw; 68287c478bd9Sstevel@tonic-gate } 68297c478bd9Sstevel@tonic-gate exp_xfer_list_tail = tw; 68307c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL; 68317c478bd9Sstevel@tonic-gate } 68327c478bd9Sstevel@tonic-gate 68337c478bd9Sstevel@tonic-gate tw = next; 68347c478bd9Sstevel@tonic-gate } 68357c478bd9Sstevel@tonic-gate 68367c478bd9Sstevel@tonic-gate /* Get the expired transfer timeout list head */ 68377c478bd9Sstevel@tonic-gate tw = exp_xfer_list_head; 68387c478bd9Sstevel@tonic-gate 68397c478bd9Sstevel@tonic-gate if (tw && (flags & OHCI_FLAGS_DMA_SYNC)) { 68407c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 68417c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 68427c478bd9Sstevel@tonic-gate } 68437c478bd9Sstevel@tonic-gate 68447c478bd9Sstevel@tonic-gate /* 68457c478bd9Sstevel@tonic-gate * Process the expired transfers by notifing the corrsponding 68467c478bd9Sstevel@tonic-gate * client driver through the exception callback. 68477c478bd9Sstevel@tonic-gate */ 68487c478bd9Sstevel@tonic-gate while (tw) { 68497c478bd9Sstevel@tonic-gate /* Get the transfer on the expired transfer timeout list */ 68507c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next; 68517c478bd9Sstevel@tonic-gate 68527c478bd9Sstevel@tonic-gate td = tw->tw_hctd_head; 68537c478bd9Sstevel@tonic-gate 68547c478bd9Sstevel@tonic-gate while (td) { 68557c478bd9Sstevel@tonic-gate /* Set TD state to TIMEOUT */ 68567c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_TIMEOUT); 68577c478bd9Sstevel@tonic-gate 68587c478bd9Sstevel@tonic-gate /* Get the next TD from the wrapper */ 68597c478bd9Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip, 68607c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td)); 68617c478bd9Sstevel@tonic-gate } 68627c478bd9Sstevel@tonic-gate 68637c478bd9Sstevel@tonic-gate ohci_handle_error(ohcip, tw->tw_hctd_head, USB_CR_TIMEOUT); 68647c478bd9Sstevel@tonic-gate 68657c478bd9Sstevel@tonic-gate tw = next; 68667c478bd9Sstevel@tonic-gate } 68677c478bd9Sstevel@tonic-gate 68687c478bd9Sstevel@tonic-gate ohci_start_timer(ohcip); 68697c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 68707c478bd9Sstevel@tonic-gate } 68717c478bd9Sstevel@tonic-gate 68727c478bd9Sstevel@tonic-gate 68737c478bd9Sstevel@tonic-gate /* 68747c478bd9Sstevel@tonic-gate * ohci_remove_tw_from_timeout_list: 68757c478bd9Sstevel@tonic-gate * 68767c478bd9Sstevel@tonic-gate * Remove Control or bulk transfer from the timeout list. 68777c478bd9Sstevel@tonic-gate */ 68787c478bd9Sstevel@tonic-gate static void 68797c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list( 68807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 68817c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 68827c478bd9Sstevel@tonic-gate { 68837c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *prev, *next; 68847c478bd9Sstevel@tonic-gate 68857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 68867c478bd9Sstevel@tonic-gate "ohci_remove_tw_from_timeout_list: tw = 0x%p", tw); 68877c478bd9Sstevel@tonic-gate 68887c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 68897c478bd9Sstevel@tonic-gate 68907c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list == tw) { 68917c478bd9Sstevel@tonic-gate ohcip->ohci_timeout_list = tw->tw_timeout_next; 68927c478bd9Sstevel@tonic-gate } else { 68937c478bd9Sstevel@tonic-gate prev = ohcip->ohci_timeout_list; 68947c478bd9Sstevel@tonic-gate next = prev->tw_timeout_next; 68957c478bd9Sstevel@tonic-gate 68967c478bd9Sstevel@tonic-gate while (next && (next != tw)) { 68977c478bd9Sstevel@tonic-gate prev = next; 68987c478bd9Sstevel@tonic-gate next = next->tw_timeout_next; 68997c478bd9Sstevel@tonic-gate } 69007c478bd9Sstevel@tonic-gate 69017c478bd9Sstevel@tonic-gate if (next == tw) { 69027c478bd9Sstevel@tonic-gate prev->tw_timeout_next = next->tw_timeout_next; 69037c478bd9Sstevel@tonic-gate } 69047c478bd9Sstevel@tonic-gate } 69057c478bd9Sstevel@tonic-gate 69067c478bd9Sstevel@tonic-gate /* Reset the xfer timeout */ 69077c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL; 69087c478bd9Sstevel@tonic-gate } 69097c478bd9Sstevel@tonic-gate 69107c478bd9Sstevel@tonic-gate 69117c478bd9Sstevel@tonic-gate /* 69127c478bd9Sstevel@tonic-gate * ohci_start_timer: 69137c478bd9Sstevel@tonic-gate * 69147c478bd9Sstevel@tonic-gate * Start the ohci timer 69157c478bd9Sstevel@tonic-gate */ 69167c478bd9Sstevel@tonic-gate static void 69177c478bd9Sstevel@tonic-gate ohci_start_timer(ohci_state_t *ohcip) 69187c478bd9Sstevel@tonic-gate { 69197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 69207c478bd9Sstevel@tonic-gate "ohci_start_timer: ohcip = 0x%p", ohcip); 69217c478bd9Sstevel@tonic-gate 69227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 69237c478bd9Sstevel@tonic-gate 69247c478bd9Sstevel@tonic-gate /* 69257c478bd9Sstevel@tonic-gate * Start the global timer only if currently timer is not 69267c478bd9Sstevel@tonic-gate * running and if there are any transfers on the timeout 69277c478bd9Sstevel@tonic-gate * list. This timer will be per USB Host Controller. 69287c478bd9Sstevel@tonic-gate */ 69297c478bd9Sstevel@tonic-gate if ((!ohcip->ohci_timer_id) && (ohcip->ohci_timeout_list)) { 69307c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = timeout(ohci_xfer_timeout_handler, 69317c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(1000000)); 69327c478bd9Sstevel@tonic-gate } 69337c478bd9Sstevel@tonic-gate } 69347c478bd9Sstevel@tonic-gate 69357c478bd9Sstevel@tonic-gate 69367c478bd9Sstevel@tonic-gate /* 69377c478bd9Sstevel@tonic-gate * ohci_deallocate_tw_resources: 69387c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 69397c478bd9Sstevel@tonic-gate * 69407c478bd9Sstevel@tonic-gate * Deallocate of a Transaction Wrapper (TW) and this involves the freeing of 69417c478bd9Sstevel@tonic-gate * of DMA resources. 69427c478bd9Sstevel@tonic-gate */ 69437c478bd9Sstevel@tonic-gate void 69447c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources( 69457c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 69467c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 69477c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 69487c478bd9Sstevel@tonic-gate { 69497c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *prev, *next; 69507c478bd9Sstevel@tonic-gate 69517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 69527c478bd9Sstevel@tonic-gate "ohci_deallocate_tw_resources: tw = 0x%p", tw); 69537c478bd9Sstevel@tonic-gate 69547c478bd9Sstevel@tonic-gate /* 69557c478bd9Sstevel@tonic-gate * If the transfer wrapper has no Host Controller (HC) 69567c478bd9Sstevel@tonic-gate * Transfer Descriptors (TD) associated with it, then 69577c478bd9Sstevel@tonic-gate * remove the transfer wrapper. 69587c478bd9Sstevel@tonic-gate */ 69597c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head) { 69607c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail != NULL); 69617c478bd9Sstevel@tonic-gate 69627c478bd9Sstevel@tonic-gate return; 69637c478bd9Sstevel@tonic-gate } 69647c478bd9Sstevel@tonic-gate 69657c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL); 69667c478bd9Sstevel@tonic-gate 69677c478bd9Sstevel@tonic-gate /* Make sure we return all the unused td's to the pool as well */ 69687c478bd9Sstevel@tonic-gate ohci_free_tw_tds_resources(ohcip, tw); 69697c478bd9Sstevel@tonic-gate 69707c478bd9Sstevel@tonic-gate /* 69717c478bd9Sstevel@tonic-gate * If pp->pp_tw_head and pp->pp_tw_tail are pointing to 69727c478bd9Sstevel@tonic-gate * given TW then set the head and tail equal to NULL. 69737c478bd9Sstevel@tonic-gate * Otherwise search for this TW in the linked TW's list 69747c478bd9Sstevel@tonic-gate * and then remove this TW from the list. 69757c478bd9Sstevel@tonic-gate */ 69767c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == tw) { 69777c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) { 69787c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL; 69797c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL; 69807c478bd9Sstevel@tonic-gate } else { 69817c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw->tw_next; 69827c478bd9Sstevel@tonic-gate } 69837c478bd9Sstevel@tonic-gate } else { 69847c478bd9Sstevel@tonic-gate prev = pp->pp_tw_head; 69857c478bd9Sstevel@tonic-gate next = prev->tw_next; 69867c478bd9Sstevel@tonic-gate 69877c478bd9Sstevel@tonic-gate while (next && (next != tw)) { 69887c478bd9Sstevel@tonic-gate prev = next; 69897c478bd9Sstevel@tonic-gate next = next->tw_next; 69907c478bd9Sstevel@tonic-gate } 69917c478bd9Sstevel@tonic-gate 69927c478bd9Sstevel@tonic-gate if (next == tw) { 69937c478bd9Sstevel@tonic-gate prev->tw_next = next->tw_next; 69947c478bd9Sstevel@tonic-gate 69957c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) { 69967c478bd9Sstevel@tonic-gate pp->pp_tw_tail = prev; 69977c478bd9Sstevel@tonic-gate } 69987c478bd9Sstevel@tonic-gate } 69997c478bd9Sstevel@tonic-gate } 70007c478bd9Sstevel@tonic-gate 70017c478bd9Sstevel@tonic-gate ohci_free_tw(ohcip, tw); 70027c478bd9Sstevel@tonic-gate } 70037c478bd9Sstevel@tonic-gate 70047c478bd9Sstevel@tonic-gate 70057c478bd9Sstevel@tonic-gate /* 70067c478bd9Sstevel@tonic-gate * ohci_free_dma_resources: 70077c478bd9Sstevel@tonic-gate * 70087c478bd9Sstevel@tonic-gate * Free dma resources of a Transfer Wrapper (TW) and also free the TW. 70097c478bd9Sstevel@tonic-gate */ 70107c478bd9Sstevel@tonic-gate static void 70117c478bd9Sstevel@tonic-gate ohci_free_dma_resources( 70127c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 70137c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 70147c478bd9Sstevel@tonic-gate { 70157c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 70167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head; 70177c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw, *tw; 70187c478bd9Sstevel@tonic-gate 70197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 70207c478bd9Sstevel@tonic-gate "ohci_free_dma_resources: ph = 0x%p", (void *)ph); 70217c478bd9Sstevel@tonic-gate 70227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 70237c478bd9Sstevel@tonic-gate 70247c478bd9Sstevel@tonic-gate /* Process the Transfer Wrappers */ 70257c478bd9Sstevel@tonic-gate next_tw = head_tw; 70267c478bd9Sstevel@tonic-gate while (next_tw) { 70277c478bd9Sstevel@tonic-gate tw = next_tw; 70287c478bd9Sstevel@tonic-gate next_tw = tw->tw_next; 70297c478bd9Sstevel@tonic-gate 70307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 70317c478bd9Sstevel@tonic-gate "ohci_free_dma_resources: Free TW = 0x%p", (void *)tw); 70327c478bd9Sstevel@tonic-gate 70337c478bd9Sstevel@tonic-gate ohci_free_tw(ohcip, tw); 70347c478bd9Sstevel@tonic-gate } 70357c478bd9Sstevel@tonic-gate 70367c478bd9Sstevel@tonic-gate /* Adjust the head and tail pointers */ 70377c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL; 70387c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL; 70397c478bd9Sstevel@tonic-gate } 70407c478bd9Sstevel@tonic-gate 70417c478bd9Sstevel@tonic-gate 70427c478bd9Sstevel@tonic-gate /* 70437c478bd9Sstevel@tonic-gate * ohci_free_tw: 70447c478bd9Sstevel@tonic-gate * 70457c478bd9Sstevel@tonic-gate * Free the Transfer Wrapper (TW). 70467c478bd9Sstevel@tonic-gate */ 70477c478bd9Sstevel@tonic-gate static void 70487c478bd9Sstevel@tonic-gate ohci_free_tw( 70497c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 70507c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 70517c478bd9Sstevel@tonic-gate { 70527c478bd9Sstevel@tonic-gate int rval; 70537c478bd9Sstevel@tonic-gate 70547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 70557c478bd9Sstevel@tonic-gate "ohci_free_tw: tw = 0x%p", tw); 70567c478bd9Sstevel@tonic-gate 70577c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 70587c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 70597c478bd9Sstevel@tonic-gate 70607c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 70617c478bd9Sstevel@tonic-gate OHCI_FREE_ID((uint32_t)tw->tw_id); 70627c478bd9Sstevel@tonic-gate 70637c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle(tw->tw_dmahandle); 70647c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 70657c478bd9Sstevel@tonic-gate 70667c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&tw->tw_accesshandle); 70677c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 70687c478bd9Sstevel@tonic-gate 70697c478bd9Sstevel@tonic-gate /* Free transfer wrapper */ 70707c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 70717c478bd9Sstevel@tonic-gate } 70727c478bd9Sstevel@tonic-gate 70737c478bd9Sstevel@tonic-gate 70747c478bd9Sstevel@tonic-gate /* 70757c478bd9Sstevel@tonic-gate * Interrupt Handling functions 70767c478bd9Sstevel@tonic-gate */ 70777c478bd9Sstevel@tonic-gate 70787c478bd9Sstevel@tonic-gate /* 70797c478bd9Sstevel@tonic-gate * ohci_intr: 70807c478bd9Sstevel@tonic-gate * 70817c478bd9Sstevel@tonic-gate * OpenHCI (OHCI) interrupt handling routine. 70827c478bd9Sstevel@tonic-gate */ 70837c478bd9Sstevel@tonic-gate static uint_t 7084*9c75c6bfSgovinda ohci_intr(caddr_t arg1, caddr_t arg2) 70857c478bd9Sstevel@tonic-gate { 7086*9c75c6bfSgovinda ohci_state_t *ohcip = (ohci_state_t *)arg1; 70877c478bd9Sstevel@tonic-gate uint_t intr; 70887c478bd9Sstevel@tonic-gate ohci_td_t *done_head = NULL; 70897c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = &ohcip->ohci_save_intr_sts; 70907c478bd9Sstevel@tonic-gate 70917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 7092*9c75c6bfSgovinda "ohci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2); 70937c478bd9Sstevel@tonic-gate 70947c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 70957c478bd9Sstevel@tonic-gate 70967c478bd9Sstevel@tonic-gate /* 70977c478bd9Sstevel@tonic-gate * Suppose if we switched to the polled mode from the normal 70987c478bd9Sstevel@tonic-gate * mode when interrupt handler is executing then we need to 70997c478bd9Sstevel@tonic-gate * save the interrupt status information in the polled mode 71007c478bd9Sstevel@tonic-gate * to avoid race conditions. The following flag will be set 71017c478bd9Sstevel@tonic-gate * and reset on entering & exiting of ohci interrupt handler 71027c478bd9Sstevel@tonic-gate * respectively. This flag will be used in the polled mode 71037c478bd9Sstevel@tonic-gate * to check whether the interrupt handler was running when we 71047c478bd9Sstevel@tonic-gate * switched to the polled mode from the normal mode. 71057c478bd9Sstevel@tonic-gate */ 71067c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag = OHCI_INTR_HANDLING; 71077c478bd9Sstevel@tonic-gate 71087c478bd9Sstevel@tonic-gate /* Temporarily turn off interrupts */ 71097c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE); 71107c478bd9Sstevel@tonic-gate 71117c478bd9Sstevel@tonic-gate /* 71127c478bd9Sstevel@tonic-gate * Handle any missed ohci interrupt especially WriteDoneHead 71137c478bd9Sstevel@tonic-gate * and SOF interrupts because of previous polled mode switch. 71147c478bd9Sstevel@tonic-gate */ 71157c478bd9Sstevel@tonic-gate ohci_handle_missed_intr(ohcip); 71167c478bd9Sstevel@tonic-gate 71177c478bd9Sstevel@tonic-gate /* 71187c478bd9Sstevel@tonic-gate * Now process the actual ohci interrupt events that caused 71197c478bd9Sstevel@tonic-gate * invocation of this ohci interrupt handler. 71207c478bd9Sstevel@tonic-gate */ 71217c478bd9Sstevel@tonic-gate 71227c478bd9Sstevel@tonic-gate /* 71237c478bd9Sstevel@tonic-gate * Updating the WriteDoneHead interrupt: 71247c478bd9Sstevel@tonic-gate * 71257c478bd9Sstevel@tonic-gate * (a) Host Controller 71267c478bd9Sstevel@tonic-gate * 71277c478bd9Sstevel@tonic-gate * - First Host controller (HC) checks whether WDH bit 71287c478bd9Sstevel@tonic-gate * in the interrupt status register is cleared. 71297c478bd9Sstevel@tonic-gate * 71307c478bd9Sstevel@tonic-gate * - If WDH bit is cleared then HC writes new done head 71317c478bd9Sstevel@tonic-gate * list information into the HCCA done head field. 71327c478bd9Sstevel@tonic-gate * 71337c478bd9Sstevel@tonic-gate * - Set WDH bit in the interrupt status register. 71347c478bd9Sstevel@tonic-gate * 71357c478bd9Sstevel@tonic-gate * (b) Host Controller Driver (HCD) 71367c478bd9Sstevel@tonic-gate * 71377c478bd9Sstevel@tonic-gate * - First read the interrupt status register. The HCCA 71387c478bd9Sstevel@tonic-gate * done head and WDH bit may be set or may not be set 71397c478bd9Sstevel@tonic-gate * while reading the interrupt status register. 71407c478bd9Sstevel@tonic-gate * 71417c478bd9Sstevel@tonic-gate * - Read the HCCA done head list. By this time may be 71427c478bd9Sstevel@tonic-gate * HC has updated HCCA done head and WDH bit in ohci 71437c478bd9Sstevel@tonic-gate * interrupt status register. 71447c478bd9Sstevel@tonic-gate * 71457c478bd9Sstevel@tonic-gate * - If done head is non-null and if WDH bit is not set 71467c478bd9Sstevel@tonic-gate * then Host Controller has updated HCCA done head & 71477c478bd9Sstevel@tonic-gate * WDH bit in the interrupt stats register in between 71487c478bd9Sstevel@tonic-gate * reading the interrupt status register & HCCA done 71497c478bd9Sstevel@tonic-gate * head. In that case, definitely WDH bit will be set 71507c478bd9Sstevel@tonic-gate * in the interrupt status register & driver can take 71517c478bd9Sstevel@tonic-gate * it for granted. 71527c478bd9Sstevel@tonic-gate * 71537c478bd9Sstevel@tonic-gate * Now read the Interrupt Status & Interrupt enable register 71547c478bd9Sstevel@tonic-gate * to determine the exact interrupt events. 71557c478bd9Sstevel@tonic-gate */ 71567c478bd9Sstevel@tonic-gate intr = ohci_intr_sts->ohci_curr_intr_sts = 71577c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_intr_status) & Get_OpReg(hcr_intr_enable)); 71587c478bd9Sstevel@tonic-gate 71597c478bd9Sstevel@tonic-gate if (ohcip->ohci_hccap) { 71607c478bd9Sstevel@tonic-gate /* Sync HCCA area */ 71617c478bd9Sstevel@tonic-gate Sync_HCCA(ohcip); 71627c478bd9Sstevel@tonic-gate 71637c478bd9Sstevel@tonic-gate /* Read and Save the HCCA DoneHead value */ 71647c478bd9Sstevel@tonic-gate done_head = ohci_intr_sts->ohci_curr_done_lst = 71657c478bd9Sstevel@tonic-gate (ohci_td_t *)(uintptr_t) 71667c478bd9Sstevel@tonic-gate (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & 71677c478bd9Sstevel@tonic-gate HCCA_DONE_HEAD_MASK); 71687c478bd9Sstevel@tonic-gate 71697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 71707c478bd9Sstevel@tonic-gate "ohci_intr: Done head! 0x%p", (void *)done_head); 71717c478bd9Sstevel@tonic-gate } 71727c478bd9Sstevel@tonic-gate 71737c478bd9Sstevel@tonic-gate /* Update kstat values */ 71747c478bd9Sstevel@tonic-gate ohci_do_intrs_stats(ohcip, intr); 71757c478bd9Sstevel@tonic-gate 71767c478bd9Sstevel@tonic-gate /* 71777c478bd9Sstevel@tonic-gate * Look at the HccaDoneHead & if it is non-zero, then a done 71787c478bd9Sstevel@tonic-gate * list update interrupt is indicated. 71797c478bd9Sstevel@tonic-gate */ 71807c478bd9Sstevel@tonic-gate if (done_head) { 71817c478bd9Sstevel@tonic-gate 71827c478bd9Sstevel@tonic-gate /* 71837c478bd9Sstevel@tonic-gate * Check for the WriteDoneHead interrupt bit in the 71847c478bd9Sstevel@tonic-gate * interrupt condition and set the WriteDoneHead bit 71857c478bd9Sstevel@tonic-gate * in the interrupt events if it is not set. 71867c478bd9Sstevel@tonic-gate */ 71877c478bd9Sstevel@tonic-gate if (!(intr & HCR_INTR_WDH)) { 71887c478bd9Sstevel@tonic-gate intr |= HCR_INTR_WDH; 71897c478bd9Sstevel@tonic-gate } 71907c478bd9Sstevel@tonic-gate } 71917c478bd9Sstevel@tonic-gate 71927c478bd9Sstevel@tonic-gate /* 71937c478bd9Sstevel@tonic-gate * We could have gotten a spurious interrupts. If so, do not 71947c478bd9Sstevel@tonic-gate * claim it. This is quite possible on some architectures 71957c478bd9Sstevel@tonic-gate * where more than one PCI slots share the IRQs. If so, the 71967c478bd9Sstevel@tonic-gate * associated driver's interrupt routine may get called even 71977c478bd9Sstevel@tonic-gate * if the interrupt is not meant for them. 71987c478bd9Sstevel@tonic-gate * 71997c478bd9Sstevel@tonic-gate * By unclaiming the interrupt, the other driver gets chance 72007c478bd9Sstevel@tonic-gate * to service its interrupt. 72017c478bd9Sstevel@tonic-gate */ 72027c478bd9Sstevel@tonic-gate if (!intr) { 72037c478bd9Sstevel@tonic-gate 72047c478bd9Sstevel@tonic-gate /* Reset the interrupt handler flag */ 72057c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_HANDLING; 72067c478bd9Sstevel@tonic-gate 72077c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_MIE); 72087c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 72097c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 72107c478bd9Sstevel@tonic-gate } 72117c478bd9Sstevel@tonic-gate 72127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72137c478bd9Sstevel@tonic-gate "Interrupt status 0x%x", intr); 72147c478bd9Sstevel@tonic-gate 72157c478bd9Sstevel@tonic-gate /* 72167c478bd9Sstevel@tonic-gate * Check for Frame Number Overflow. 72177c478bd9Sstevel@tonic-gate */ 72187c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_FNO) { 72197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72207c478bd9Sstevel@tonic-gate "ohci_intr: Frame Number Overflow"); 72217c478bd9Sstevel@tonic-gate 72227c478bd9Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohcip); 72237c478bd9Sstevel@tonic-gate } 72247c478bd9Sstevel@tonic-gate 72257c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SOF) { 72267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72277c478bd9Sstevel@tonic-gate "ohci_intr: Start of Frame"); 72287c478bd9Sstevel@tonic-gate 72297c478bd9Sstevel@tonic-gate /* Set ohci_sof_flag indicating SOF interrupt occurred */ 72307c478bd9Sstevel@tonic-gate ohcip->ohci_sof_flag = B_TRUE; 72317c478bd9Sstevel@tonic-gate 72327c478bd9Sstevel@tonic-gate /* Disabel SOF interrupt */ 72337c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SOF); 72347c478bd9Sstevel@tonic-gate 72357c478bd9Sstevel@tonic-gate /* 72367c478bd9Sstevel@tonic-gate * Call cv_broadcast on every SOF interrupt to wakeup 72377c478bd9Sstevel@tonic-gate * all the threads that are waiting the SOF. Calling 72387c478bd9Sstevel@tonic-gate * cv_broadcast on every SOF has no effect even if no 72397c478bd9Sstevel@tonic-gate * threads are waiting for the SOF. 72407c478bd9Sstevel@tonic-gate */ 72417c478bd9Sstevel@tonic-gate cv_broadcast(&ohcip->ohci_SOF_cv); 72427c478bd9Sstevel@tonic-gate } 72437c478bd9Sstevel@tonic-gate 72447c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SO) { 72457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72467c478bd9Sstevel@tonic-gate "ohci_intr: Schedule overrun"); 72477c478bd9Sstevel@tonic-gate 72487c478bd9Sstevel@tonic-gate ohcip->ohci_so_error++; 72497c478bd9Sstevel@tonic-gate } 72507c478bd9Sstevel@tonic-gate 72517c478bd9Sstevel@tonic-gate if ((intr & HCR_INTR_WDH) && (done_head)) { 72527c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72537c478bd9Sstevel@tonic-gate "ohci_intr: Done Head"); 72547c478bd9Sstevel@tonic-gate 72557c478bd9Sstevel@tonic-gate /* 72567c478bd9Sstevel@tonic-gate * Currently if we are processing one WriteDoneHead 72577c478bd9Sstevel@tonic-gate * interrupt and also if we switched to the polled 72587c478bd9Sstevel@tonic-gate * mode at least once during this time, then there 72597c478bd9Sstevel@tonic-gate * may be chance that Host Controller generates one 72607c478bd9Sstevel@tonic-gate * more Write DoneHead or Start of Frame interrupts 72617c478bd9Sstevel@tonic-gate * for the normal since the polled code clears WDH & 72627c478bd9Sstevel@tonic-gate * SOF interrupt bits before returning to the normal 72637c478bd9Sstevel@tonic-gate * mode. Under this condition, we must not clear the 72647c478bd9Sstevel@tonic-gate * HCCA done head field & also we must not clear WDH 72657c478bd9Sstevel@tonic-gate * interrupt bit in the interrupt status register. 72667c478bd9Sstevel@tonic-gate */ 72677c478bd9Sstevel@tonic-gate if (done_head == (ohci_td_t *)(uintptr_t) 72687c478bd9Sstevel@tonic-gate (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & 72697c478bd9Sstevel@tonic-gate HCCA_DONE_HEAD_MASK)) { 72707c478bd9Sstevel@tonic-gate 72717c478bd9Sstevel@tonic-gate /* Reset the done head to NULL */ 72727c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL); 72737c478bd9Sstevel@tonic-gate } else { 72747c478bd9Sstevel@tonic-gate intr &= ~HCR_INTR_WDH; 72757c478bd9Sstevel@tonic-gate } 72767c478bd9Sstevel@tonic-gate 72777c478bd9Sstevel@tonic-gate /* Clear the current done head field */ 72787c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_curr_done_lst = NULL; 72797c478bd9Sstevel@tonic-gate 72807c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head); 72817c478bd9Sstevel@tonic-gate } 72827c478bd9Sstevel@tonic-gate 72837c478bd9Sstevel@tonic-gate /* Process endpoint reclaimation list */ 72847c478bd9Sstevel@tonic-gate if (ohcip->ohci_reclaim_list) { 72857c478bd9Sstevel@tonic-gate ohci_handle_endpoint_reclaimation(ohcip); 72867c478bd9Sstevel@tonic-gate } 72877c478bd9Sstevel@tonic-gate 72887c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_RD) { 72897c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72907c478bd9Sstevel@tonic-gate "ohci_intr: Resume Detected"); 72917c478bd9Sstevel@tonic-gate } 72927c478bd9Sstevel@tonic-gate 72937c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_RHSC) { 72947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 72957c478bd9Sstevel@tonic-gate "ohci_intr: Root hub status change"); 72967c478bd9Sstevel@tonic-gate } 72977c478bd9Sstevel@tonic-gate 72987c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_OC) { 72997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 73007c478bd9Sstevel@tonic-gate "ohci_intr: Change ownership"); 73017c478bd9Sstevel@tonic-gate 73027c478bd9Sstevel@tonic-gate } 73037c478bd9Sstevel@tonic-gate 73047c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_UE) { 73057c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 73067c478bd9Sstevel@tonic-gate "ohci_intr: Unrecoverable error"); 73077c478bd9Sstevel@tonic-gate 73087c478bd9Sstevel@tonic-gate ohci_handle_ue(ohcip); 73097c478bd9Sstevel@tonic-gate } 73107c478bd9Sstevel@tonic-gate 73117c478bd9Sstevel@tonic-gate /* Acknowledge the interrupt */ 73127c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_status, intr); 73137c478bd9Sstevel@tonic-gate 73147c478bd9Sstevel@tonic-gate /* Clear the current interrupt event field */ 73157c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_curr_intr_sts = 0; 73167c478bd9Sstevel@tonic-gate 73177c478bd9Sstevel@tonic-gate /* 73187c478bd9Sstevel@tonic-gate * Reset the following flag indicating exiting the interrupt 73197c478bd9Sstevel@tonic-gate * handler and this flag will be used in the polled mode to 73207c478bd9Sstevel@tonic-gate * do some extra processing. 73217c478bd9Sstevel@tonic-gate */ 73227c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_HANDLING; 73237c478bd9Sstevel@tonic-gate 73247c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_MIE); 73257c478bd9Sstevel@tonic-gate 73267c478bd9Sstevel@tonic-gate /* 73277c478bd9Sstevel@tonic-gate * Read interrupt status register to make sure that any PIO 73287c478bd9Sstevel@tonic-gate * store to clear the ISR has made it on the PCI bus before 73297c478bd9Sstevel@tonic-gate * returning from its interrupt handler. 73307c478bd9Sstevel@tonic-gate */ 73317c478bd9Sstevel@tonic-gate (void) Get_OpReg(hcr_intr_status); 73327c478bd9Sstevel@tonic-gate 73337c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 73347c478bd9Sstevel@tonic-gate 73357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 73367c478bd9Sstevel@tonic-gate "Interrupt handling completed"); 73377c478bd9Sstevel@tonic-gate 73387c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 73397c478bd9Sstevel@tonic-gate } 73407c478bd9Sstevel@tonic-gate 73417c478bd9Sstevel@tonic-gate 73427c478bd9Sstevel@tonic-gate /* 73437c478bd9Sstevel@tonic-gate * ohci_handle_missed_intr: 73447c478bd9Sstevel@tonic-gate * 73457c478bd9Sstevel@tonic-gate * Handle any ohci missed interrupts because of polled mode switch. 73467c478bd9Sstevel@tonic-gate */ 73477c478bd9Sstevel@tonic-gate static void 73487c478bd9Sstevel@tonic-gate ohci_handle_missed_intr(ohci_state_t *ohcip) 73497c478bd9Sstevel@tonic-gate { 73507c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = 73517c478bd9Sstevel@tonic-gate &ohcip->ohci_save_intr_sts; 73527c478bd9Sstevel@tonic-gate ohci_td_t *done_head; 73537c478bd9Sstevel@tonic-gate uint_t intr; 73547c478bd9Sstevel@tonic-gate 73557c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 73567c478bd9Sstevel@tonic-gate 73577c478bd9Sstevel@tonic-gate /* 73587c478bd9Sstevel@tonic-gate * Check whether we have missed any ohci interrupts because 73597c478bd9Sstevel@tonic-gate * of the polled mode switch during previous ohci interrupt 73607c478bd9Sstevel@tonic-gate * handler execution. Only Write Done Head & SOF interrupts 73617c478bd9Sstevel@tonic-gate * saved in the polled mode. First process these interrupts 73627c478bd9Sstevel@tonic-gate * before processing actual interrupts that caused invocation 73637c478bd9Sstevel@tonic-gate * of ohci interrupt handler. 73647c478bd9Sstevel@tonic-gate */ 73657c478bd9Sstevel@tonic-gate if (!ohci_intr_sts->ohci_missed_intr_sts) { 73667c478bd9Sstevel@tonic-gate /* No interrupts are missed, simply return */ 73677c478bd9Sstevel@tonic-gate 73687c478bd9Sstevel@tonic-gate return; 73697c478bd9Sstevel@tonic-gate } 73707c478bd9Sstevel@tonic-gate 73717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 73727c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Handle ohci missed interrupts"); 73737c478bd9Sstevel@tonic-gate 73747c478bd9Sstevel@tonic-gate /* 73757c478bd9Sstevel@tonic-gate * The functionality and importance of critical code section 73767c478bd9Sstevel@tonic-gate * in the normal mode ohci interrupt handler & its usage in 73777c478bd9Sstevel@tonic-gate * the polled mode is explained below. 73787c478bd9Sstevel@tonic-gate * 73797c478bd9Sstevel@tonic-gate * (a) Normal mode: 73807c478bd9Sstevel@tonic-gate * 73817c478bd9Sstevel@tonic-gate * - Set the flag indicating that processing critical 73827c478bd9Sstevel@tonic-gate * code in ohci interrupt handler. 73837c478bd9Sstevel@tonic-gate * 73847c478bd9Sstevel@tonic-gate * - Process the missed ohci interrupts by copying the 73857c478bd9Sstevel@tonic-gate * miised interrupt events and done head list fields 73867c478bd9Sstevel@tonic-gate * information to the critical interrupt event & done 73877c478bd9Sstevel@tonic-gate * list fields. 73887c478bd9Sstevel@tonic-gate * 73897c478bd9Sstevel@tonic-gate * - Reset the missed ohci interrupt events & done head 73907c478bd9Sstevel@tonic-gate * list fields so that the new missed interrupt event 73917c478bd9Sstevel@tonic-gate * and done head list information can be saved. 73927c478bd9Sstevel@tonic-gate * 73937c478bd9Sstevel@tonic-gate * - All above steps will be executed with in critical 73947c478bd9Sstevel@tonic-gate * section of the interrupt handler.Then ohci missed 73957c478bd9Sstevel@tonic-gate * interrupt handler will be called to service missed 73967c478bd9Sstevel@tonic-gate * ohci interrupts. 73977c478bd9Sstevel@tonic-gate * 73987c478bd9Sstevel@tonic-gate * (b) Polled mode: 73997c478bd9Sstevel@tonic-gate * 74007c478bd9Sstevel@tonic-gate * - On entering the polled code,it checks for critical 74017c478bd9Sstevel@tonic-gate * section code execution within the normal mode ohci 74027c478bd9Sstevel@tonic-gate * interrupt handler. 74037c478bd9Sstevel@tonic-gate * 74047c478bd9Sstevel@tonic-gate * - If the critical section code is executing in normal 74057c478bd9Sstevel@tonic-gate * mode ohci interrupt handler and if copying of ohci 74067c478bd9Sstevel@tonic-gate * missed interrupt events & done head list fields to 74077c478bd9Sstevel@tonic-gate * the critical fields is finished then save the "any 74087c478bd9Sstevel@tonic-gate * missed interrupt events & done head list" because 74097c478bd9Sstevel@tonic-gate * of current polled mode switch into "critical missed 74107c478bd9Sstevel@tonic-gate * interrupt events & done list fields" instead actual 74117c478bd9Sstevel@tonic-gate * missed events and done list fields. 74127c478bd9Sstevel@tonic-gate * 74137c478bd9Sstevel@tonic-gate * - Otherwise save "any missed interrupt events & done 74147c478bd9Sstevel@tonic-gate * list" because of this current polled mode switch 74157c478bd9Sstevel@tonic-gate * in the actual missed interrupt events & done head 74167c478bd9Sstevel@tonic-gate * list fields. 74177c478bd9Sstevel@tonic-gate */ 74187c478bd9Sstevel@tonic-gate 74197c478bd9Sstevel@tonic-gate /* 74207c478bd9Sstevel@tonic-gate * Set flag indicating that interrupt handler is processing 74217c478bd9Sstevel@tonic-gate * critical interrupt code, so that polled mode code checks 74227c478bd9Sstevel@tonic-gate * for this condition & will do extra processing as explained 74237c478bd9Sstevel@tonic-gate * above in order to aviod the race conditions. 74247c478bd9Sstevel@tonic-gate */ 74257c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag |= OHCI_INTR_CRITICAL; 74267c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts |= 74277c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts; 74287c478bd9Sstevel@tonic-gate 74297c478bd9Sstevel@tonic-gate if (ohci_intr_sts->ohci_missed_done_lst) { 74307c478bd9Sstevel@tonic-gate 74317c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_done_lst = 74327c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_done_lst; 74337c478bd9Sstevel@tonic-gate } 74347c478bd9Sstevel@tonic-gate 74357c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts = 0; 74367c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_done_lst = NULL; 74377c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_CRITICAL; 74387c478bd9Sstevel@tonic-gate 74397c478bd9Sstevel@tonic-gate intr = ohci_intr_sts->ohci_critical_intr_sts; 74407c478bd9Sstevel@tonic-gate done_head = ohci_intr_sts->ohci_critical_done_lst; 74417c478bd9Sstevel@tonic-gate 74427c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SOF) { 74437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 74447c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Start of Frame"); 74457c478bd9Sstevel@tonic-gate 74467c478bd9Sstevel@tonic-gate /* 74477c478bd9Sstevel@tonic-gate * Call cv_broadcast on every SOF interrupt to wakeup 74487c478bd9Sstevel@tonic-gate * all the threads that are waiting the SOF. Calling 74497c478bd9Sstevel@tonic-gate * cv_broadcast on every SOF has no effect even if no 74507c478bd9Sstevel@tonic-gate * threads are waiting for the SOF. 74517c478bd9Sstevel@tonic-gate */ 74527c478bd9Sstevel@tonic-gate cv_broadcast(&ohcip->ohci_SOF_cv); 74537c478bd9Sstevel@tonic-gate } 74547c478bd9Sstevel@tonic-gate 74557c478bd9Sstevel@tonic-gate if ((intr & HCR_INTR_WDH) && (done_head)) { 74567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 74577c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Done Head"); 74587c478bd9Sstevel@tonic-gate 74597c478bd9Sstevel@tonic-gate /* Clear the critical done head field */ 74607c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_done_lst = NULL; 74617c478bd9Sstevel@tonic-gate 74627c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head); 74637c478bd9Sstevel@tonic-gate } 74647c478bd9Sstevel@tonic-gate 74657c478bd9Sstevel@tonic-gate /* Clear the critical interrupt event field */ 74667c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts = 0; 74677c478bd9Sstevel@tonic-gate } 74687c478bd9Sstevel@tonic-gate 74697c478bd9Sstevel@tonic-gate 74707c478bd9Sstevel@tonic-gate /* 74717c478bd9Sstevel@tonic-gate * ohci_handle_ue: 74727c478bd9Sstevel@tonic-gate * 74737c478bd9Sstevel@tonic-gate * Handling of Unrecoverable Error interrupt (UE). 74747c478bd9Sstevel@tonic-gate */ 74757c478bd9Sstevel@tonic-gate static void 74767c478bd9Sstevel@tonic-gate ohci_handle_ue(ohci_state_t *ohcip) 74777c478bd9Sstevel@tonic-gate { 74787c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 74797c478bd9Sstevel@tonic-gate 74807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 74817c478bd9Sstevel@tonic-gate 74827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 74837c478bd9Sstevel@tonic-gate "ohci_handle_ue: Handling of UE interrupt"); 74847c478bd9Sstevel@tonic-gate 74857c478bd9Sstevel@tonic-gate /* 74867c478bd9Sstevel@tonic-gate * First check whether current UE error occured due to USB or 74877c478bd9Sstevel@tonic-gate * due to some other subsystem. This can be verified by reading 74887c478bd9Sstevel@tonic-gate * usb frame numbers before & after a delay of few milliseconds. 74897c478bd9Sstevel@tonic-gate * If usb frame number read after delay is greater than the one 74907c478bd9Sstevel@tonic-gate * read before delay, then, USB subsystem is fine. In this case, 74917c478bd9Sstevel@tonic-gate * disable UE error interrupt and return without shutdowning the 74927c478bd9Sstevel@tonic-gate * USB subsystem. 74937c478bd9Sstevel@tonic-gate * 74947c478bd9Sstevel@tonic-gate * Otherwise, if usb frame number read after delay is less than 74957c478bd9Sstevel@tonic-gate * or equal to one read before the delay, then, current UE error 74967c478bd9Sstevel@tonic-gate * occured from USB susbsystem. In this case,go ahead with actual 74977c478bd9Sstevel@tonic-gate * UE error recovery procedure. 74987c478bd9Sstevel@tonic-gate * 74997c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few 75007c478bd9Sstevel@tonic-gate * milliseconds. 75017c478bd9Sstevel@tonic-gate */ 75027c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip); 75037c478bd9Sstevel@tonic-gate 75047c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 75057c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 75067c478bd9Sstevel@tonic-gate 75077c478bd9Sstevel@tonic-gate /* 75087c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 75097c478bd9Sstevel@tonic-gate * milliseconds. 75107c478bd9Sstevel@tonic-gate */ 75117c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip); 75127c478bd9Sstevel@tonic-gate 75137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 75147c478bd9Sstevel@tonic-gate "ohci_handle_ue: Before Frm No 0x%llx After Frm No 0x%llx", 75157c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 75167c478bd9Sstevel@tonic-gate 75177c478bd9Sstevel@tonic-gate if (after_frame_number > before_frame_number) { 75187c478bd9Sstevel@tonic-gate 75197c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 75207c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_UE); 75217c478bd9Sstevel@tonic-gate 75227c478bd9Sstevel@tonic-gate return; 75237c478bd9Sstevel@tonic-gate } 75247c478bd9Sstevel@tonic-gate 75257c478bd9Sstevel@tonic-gate /* 75267c478bd9Sstevel@tonic-gate * This UE is due to USB hardware error. Reset ohci controller 75277c478bd9Sstevel@tonic-gate * and reprogram to bring it back to functional state. 75287c478bd9Sstevel@tonic-gate */ 75297c478bd9Sstevel@tonic-gate if ((ohci_do_soft_reset(ohcip)) != USB_SUCCESS) { 75307c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 75317c478bd9Sstevel@tonic-gate "Unrecoverable USB Hardware Error"); 75327c478bd9Sstevel@tonic-gate 75337c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 75347c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_UE); 75357c478bd9Sstevel@tonic-gate 75367c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 75377c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_ERROR_STATE; 75387c478bd9Sstevel@tonic-gate } 75397c478bd9Sstevel@tonic-gate } 75407c478bd9Sstevel@tonic-gate 75417c478bd9Sstevel@tonic-gate 75427c478bd9Sstevel@tonic-gate /* 75437c478bd9Sstevel@tonic-gate * ohci_handle_frame_number_overflow: 75447c478bd9Sstevel@tonic-gate * 75457c478bd9Sstevel@tonic-gate * Update software based usb frame number part on every frame number 75467c478bd9Sstevel@tonic-gate * overflow interrupt. 75477c478bd9Sstevel@tonic-gate * 75487c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 75497c478bd9Sstevel@tonic-gate * 75507c478bd9Sstevel@tonic-gate * Refer ohci spec 1.0a, section 5.3, page 81 for more details. 75517c478bd9Sstevel@tonic-gate */ 75527c478bd9Sstevel@tonic-gate void 75537c478bd9Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohci_state_t *ohcip) 75547c478bd9Sstevel@tonic-gate { 75557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 75567c478bd9Sstevel@tonic-gate "ohci_handle_frame_number_overflow:"); 75577c478bd9Sstevel@tonic-gate 75587c478bd9Sstevel@tonic-gate ohcip->ohci_fno += (0x10000 - 75597c478bd9Sstevel@tonic-gate (((Get_HCCA(ohcip->ohci_hccap->HccaFrameNo) & 75607c478bd9Sstevel@tonic-gate 0xFFFF) ^ ohcip->ohci_fno) & 0x8000)); 75617c478bd9Sstevel@tonic-gate 75627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 75637c478bd9Sstevel@tonic-gate "ohci_handle_frame_number_overflow:" 75647c478bd9Sstevel@tonic-gate "Frame Number Higher Part 0x%llx\n", ohcip->ohci_fno); 75657c478bd9Sstevel@tonic-gate } 75667c478bd9Sstevel@tonic-gate 75677c478bd9Sstevel@tonic-gate 75687c478bd9Sstevel@tonic-gate /* 75697c478bd9Sstevel@tonic-gate * ohci_handle_endpoint_reclaimation: 75707c478bd9Sstevel@tonic-gate * 75717c478bd9Sstevel@tonic-gate * Reclamation of Host Controller (HC) Endpoint Descriptors (ED). 75727c478bd9Sstevel@tonic-gate */ 75737c478bd9Sstevel@tonic-gate static void 75747c478bd9Sstevel@tonic-gate ohci_handle_endpoint_reclaimation(ohci_state_t *ohcip) 75757c478bd9Sstevel@tonic-gate { 75767c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number; 75777c478bd9Sstevel@tonic-gate usb_frame_number_t endpoint_frame_number; 75787c478bd9Sstevel@tonic-gate ohci_ed_t *reclaim_ed; 75797c478bd9Sstevel@tonic-gate 75807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 75817c478bd9Sstevel@tonic-gate "ohci_handle_endpoint_reclaimation:"); 75827c478bd9Sstevel@tonic-gate 75837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 75847c478bd9Sstevel@tonic-gate 75857c478bd9Sstevel@tonic-gate current_frame_number = ohci_get_current_frame_number(ohcip); 75867c478bd9Sstevel@tonic-gate 75877c478bd9Sstevel@tonic-gate /* 75887c478bd9Sstevel@tonic-gate * Deallocate all Endpoint Descriptors (ED) which are on the 75897c478bd9Sstevel@tonic-gate * reclaimation list. These ED's are already removed from the 75907c478bd9Sstevel@tonic-gate * interrupt lattice tree. 75917c478bd9Sstevel@tonic-gate */ 75927c478bd9Sstevel@tonic-gate while (ohcip->ohci_reclaim_list) { 75937c478bd9Sstevel@tonic-gate reclaim_ed = ohcip->ohci_reclaim_list; 75947c478bd9Sstevel@tonic-gate 75957c478bd9Sstevel@tonic-gate endpoint_frame_number = (usb_frame_number_t)(uintptr_t) 75967c478bd9Sstevel@tonic-gate (OHCI_LOOKUP_ID(Get_ED(reclaim_ed->hced_reclaim_frame))); 75977c478bd9Sstevel@tonic-gate 75987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 75997c478bd9Sstevel@tonic-gate "ohci_handle_endpoint_reclaimation:" 76007c478bd9Sstevel@tonic-gate "current frame number 0x%llx endpoint frame number 0x%llx", 76017c478bd9Sstevel@tonic-gate current_frame_number, endpoint_frame_number); 76027c478bd9Sstevel@tonic-gate 76037c478bd9Sstevel@tonic-gate /* 76047c478bd9Sstevel@tonic-gate * Deallocate current endpoint only if endpoint's usb frame 76057c478bd9Sstevel@tonic-gate * number is less than or equal to current usb frame number. 76067c478bd9Sstevel@tonic-gate * 76077c478bd9Sstevel@tonic-gate * If endpoint's usb frame number is greater than the current 76087c478bd9Sstevel@tonic-gate * usb frame number, ignore rest of the endpoints in the list 76097c478bd9Sstevel@tonic-gate * since rest of the endpoints are inserted into the reclaim 76107c478bd9Sstevel@tonic-gate * list later than the current reclaim endpoint. 76117c478bd9Sstevel@tonic-gate */ 76127c478bd9Sstevel@tonic-gate if (endpoint_frame_number > current_frame_number) { 76137c478bd9Sstevel@tonic-gate break; 76147c478bd9Sstevel@tonic-gate } 76157c478bd9Sstevel@tonic-gate 76167c478bd9Sstevel@tonic-gate /* Get the next endpoint from the rec. list */ 76177c478bd9Sstevel@tonic-gate ohcip->ohci_reclaim_list = ohci_ed_iommu_to_cpu(ohcip, 76187c478bd9Sstevel@tonic-gate Get_ED(reclaim_ed->hced_reclaim_next)); 76197c478bd9Sstevel@tonic-gate 76207c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 76217c478bd9Sstevel@tonic-gate OHCI_FREE_ID((uint32_t)Get_ED(reclaim_ed->hced_reclaim_frame)); 76227c478bd9Sstevel@tonic-gate 76237c478bd9Sstevel@tonic-gate /* Deallocate the endpoint */ 76247c478bd9Sstevel@tonic-gate ohci_deallocate_ed(ohcip, reclaim_ed); 76257c478bd9Sstevel@tonic-gate } 76267c478bd9Sstevel@tonic-gate } 76277c478bd9Sstevel@tonic-gate 76287c478bd9Sstevel@tonic-gate 76297c478bd9Sstevel@tonic-gate /* 76307c478bd9Sstevel@tonic-gate * ohci_traverse_done_list: 76317c478bd9Sstevel@tonic-gate */ 76327c478bd9Sstevel@tonic-gate static void 76337c478bd9Sstevel@tonic-gate ohci_traverse_done_list( 76347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 76357c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list) 76367c478bd9Sstevel@tonic-gate { 76377c478bd9Sstevel@tonic-gate uint_t state; /* TD state */ 76387c478bd9Sstevel@tonic-gate ohci_td_t *td, *old_td; /* TD pointers */ 76397c478bd9Sstevel@tonic-gate usb_cr_t error; /* Error from TD */ 76407c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw = NULL; /* Transfer wrapper */ 76417c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = NULL; /* Pipe private field */ 76427c478bd9Sstevel@tonic-gate 76437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 76447c478bd9Sstevel@tonic-gate "ohci_traverse_done_list:"); 76457c478bd9Sstevel@tonic-gate 76467c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 76477c478bd9Sstevel@tonic-gate 76487c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 76497c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 76507c478bd9Sstevel@tonic-gate 76517c478bd9Sstevel@tonic-gate /* Reverse the done list */ 76527c478bd9Sstevel@tonic-gate td = ohci_reverse_done_list(ohcip, head_done_list); 76537c478bd9Sstevel@tonic-gate 76547c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */ 76557c478bd9Sstevel@tonic-gate while (td) { 76567c478bd9Sstevel@tonic-gate /* Check for TD state */ 76577c478bd9Sstevel@tonic-gate state = Get_TD(td->hctd_state); 76587c478bd9Sstevel@tonic-gate 76597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 76607c478bd9Sstevel@tonic-gate "ohci_traverse_done_list:\n\t" 76617c478bd9Sstevel@tonic-gate "td = 0x%p state = 0x%x", (void *)td, state); 76627c478bd9Sstevel@tonic-gate 76637c478bd9Sstevel@tonic-gate /* 76647c478bd9Sstevel@tonic-gate * Obtain the transfer wrapper only if the TD is 76657c478bd9Sstevel@tonic-gate * not marked as RECLAIM. 76667c478bd9Sstevel@tonic-gate * 76677c478bd9Sstevel@tonic-gate * A TD that is marked as RECLAIM has had its DMA 76687c478bd9Sstevel@tonic-gate * mappings, ED, TD and pipe private structure are 76697c478bd9Sstevel@tonic-gate * ripped down. Just deallocate this TD. 76707c478bd9Sstevel@tonic-gate */ 76717c478bd9Sstevel@tonic-gate if (state != HC_TD_RECLAIM) { 76727c478bd9Sstevel@tonic-gate 76737c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID( 76747c478bd9Sstevel@tonic-gate (uint32_t)Get_TD(td->hctd_trans_wrapper)); 76757c478bd9Sstevel@tonic-gate 76767c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 76777c478bd9Sstevel@tonic-gate 76787c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 76797c478bd9Sstevel@tonic-gate 76807c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 76817c478bd9Sstevel@tonic-gate "ohci_traverse_done_list: PP = 0x%p TW = 0x%p", 76827c478bd9Sstevel@tonic-gate pp, tw); 76837c478bd9Sstevel@tonic-gate } 76847c478bd9Sstevel@tonic-gate 76857c478bd9Sstevel@tonic-gate /* 76867c478bd9Sstevel@tonic-gate * Don't process the TD if its state is marked as 76877c478bd9Sstevel@tonic-gate * either RECLAIM or TIMEOUT. 76887c478bd9Sstevel@tonic-gate * 76897c478bd9Sstevel@tonic-gate * A TD that is marked as TIMEOUT has already been 76907c478bd9Sstevel@tonic-gate * processed by TD timeout handler & client driver 76917c478bd9Sstevel@tonic-gate * has been informed through exception callback. 76927c478bd9Sstevel@tonic-gate */ 76937c478bd9Sstevel@tonic-gate if ((state != HC_TD_RECLAIM) && (state != HC_TD_TIMEOUT)) { 76947c478bd9Sstevel@tonic-gate 76957c478bd9Sstevel@tonic-gate /* Look at the error status */ 76967c478bd9Sstevel@tonic-gate error = ohci_parse_error(ohcip, td); 76977c478bd9Sstevel@tonic-gate 76987c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) { 76997c478bd9Sstevel@tonic-gate ohci_handle_normal_td(ohcip, td, tw); 77007c478bd9Sstevel@tonic-gate } else { 77017c478bd9Sstevel@tonic-gate /* handle the error condition */ 77027c478bd9Sstevel@tonic-gate ohci_handle_error(ohcip, td, error); 77037c478bd9Sstevel@tonic-gate } 77047c478bd9Sstevel@tonic-gate } else { 77057c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77067c478bd9Sstevel@tonic-gate "ohci_traverse_done_list: TD State = %d", state); 77077c478bd9Sstevel@tonic-gate } 77087c478bd9Sstevel@tonic-gate 77097c478bd9Sstevel@tonic-gate /* 77107c478bd9Sstevel@tonic-gate * Save a pointer to the current transfer descriptor 77117c478bd9Sstevel@tonic-gate */ 77127c478bd9Sstevel@tonic-gate old_td = td; 77137c478bd9Sstevel@tonic-gate 77147c478bd9Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_next_td)); 77157c478bd9Sstevel@tonic-gate 77167c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 77177c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, old_td); 77187c478bd9Sstevel@tonic-gate 77197c478bd9Sstevel@tonic-gate /* 77207c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more 77217c478bd9Sstevel@tonic-gate * TD's for the transfer wrapper. ohci_deallocate_tw_resources() 77227c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic endpoint 77237c478bd9Sstevel@tonic-gate * since it will always have a TD attached to it. 77247c478bd9Sstevel@tonic-gate * 77257c478bd9Sstevel@tonic-gate * Do not deallocate the TW if it is a isoc or intr pipe in. 77267c478bd9Sstevel@tonic-gate * The tw's are reused. 77277c478bd9Sstevel@tonic-gate * 77287c478bd9Sstevel@tonic-gate * An TD that is marked as reclaim doesn't have a pipe 77297c478bd9Sstevel@tonic-gate * or a TW associated with it anymore so don't call this 77307c478bd9Sstevel@tonic-gate * function. 77317c478bd9Sstevel@tonic-gate */ 77327c478bd9Sstevel@tonic-gate if (state != HC_TD_RECLAIM) { 77337c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 77347c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 77357c478bd9Sstevel@tonic-gate } 77367c478bd9Sstevel@tonic-gate } 77377c478bd9Sstevel@tonic-gate } 77387c478bd9Sstevel@tonic-gate 77397c478bd9Sstevel@tonic-gate 77407c478bd9Sstevel@tonic-gate /* 77417c478bd9Sstevel@tonic-gate * ohci_reverse_done_list: 77427c478bd9Sstevel@tonic-gate * 77437c478bd9Sstevel@tonic-gate * Reverse the order of the Transfer Descriptor (TD) Done List. 77447c478bd9Sstevel@tonic-gate */ 77457c478bd9Sstevel@tonic-gate static ohci_td_t * 77467c478bd9Sstevel@tonic-gate ohci_reverse_done_list( 77477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 77487c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list) 77497c478bd9Sstevel@tonic-gate { 77507c478bd9Sstevel@tonic-gate ohci_td_t *cpu_new_tail, *cpu_new_head, *cpu_save; 77517c478bd9Sstevel@tonic-gate 77527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77537c478bd9Sstevel@tonic-gate "ohci_reverse_done_list:"); 77547c478bd9Sstevel@tonic-gate 77557c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 77567c478bd9Sstevel@tonic-gate ASSERT(head_done_list != NULL); 77577c478bd9Sstevel@tonic-gate 77587c478bd9Sstevel@tonic-gate /* At first, both the tail and head pointers point to the same elem */ 77597c478bd9Sstevel@tonic-gate cpu_new_tail = cpu_new_head = 77607c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, (uintptr_t)head_done_list); 77617c478bd9Sstevel@tonic-gate 77627c478bd9Sstevel@tonic-gate /* See if the list has only one element */ 77637c478bd9Sstevel@tonic-gate if (Get_TD(cpu_new_head->hctd_next_td) == NULL) { 77647c478bd9Sstevel@tonic-gate 77657c478bd9Sstevel@tonic-gate return (cpu_new_head); 77667c478bd9Sstevel@tonic-gate } 77677c478bd9Sstevel@tonic-gate 77687c478bd9Sstevel@tonic-gate /* Advance the head pointer */ 77697c478bd9Sstevel@tonic-gate cpu_new_head = (ohci_td_t *) 77707c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(cpu_new_head->hctd_next_td)); 77717c478bd9Sstevel@tonic-gate 77727c478bd9Sstevel@tonic-gate /* The new tail now points to nothing */ 77737c478bd9Sstevel@tonic-gate Set_TD(cpu_new_tail->hctd_next_td, NULL); 77747c478bd9Sstevel@tonic-gate 77757c478bd9Sstevel@tonic-gate cpu_save = (ohci_td_t *) 77767c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(cpu_new_head->hctd_next_td)); 77777c478bd9Sstevel@tonic-gate 77787c478bd9Sstevel@tonic-gate /* Reverse the list and store the pointers as CPU addresses */ 77797c478bd9Sstevel@tonic-gate while (cpu_save) { 77807c478bd9Sstevel@tonic-gate Set_TD(cpu_new_head->hctd_next_td, 77817c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, cpu_new_tail)); 77827c478bd9Sstevel@tonic-gate 77837c478bd9Sstevel@tonic-gate cpu_new_tail = cpu_new_head; 77847c478bd9Sstevel@tonic-gate cpu_new_head = cpu_save; 77857c478bd9Sstevel@tonic-gate 77867c478bd9Sstevel@tonic-gate cpu_save = (ohci_td_t *) 77877c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, 77887c478bd9Sstevel@tonic-gate Get_TD(cpu_new_head->hctd_next_td)); 77897c478bd9Sstevel@tonic-gate } 77907c478bd9Sstevel@tonic-gate 77917c478bd9Sstevel@tonic-gate Set_TD(cpu_new_head->hctd_next_td, 77927c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, cpu_new_tail)); 77937c478bd9Sstevel@tonic-gate 77947c478bd9Sstevel@tonic-gate return (cpu_new_head); 77957c478bd9Sstevel@tonic-gate } 77967c478bd9Sstevel@tonic-gate 77977c478bd9Sstevel@tonic-gate 77987c478bd9Sstevel@tonic-gate /* 77997c478bd9Sstevel@tonic-gate * ohci_parse_error: 78007c478bd9Sstevel@tonic-gate * 78017c478bd9Sstevel@tonic-gate * Parse the result for any errors. 78027c478bd9Sstevel@tonic-gate */ 78037c478bd9Sstevel@tonic-gate static usb_cr_t 78047c478bd9Sstevel@tonic-gate ohci_parse_error( 78057c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 78067c478bd9Sstevel@tonic-gate ohci_td_t *td) 78077c478bd9Sstevel@tonic-gate { 78087c478bd9Sstevel@tonic-gate uint_t ctrl; 78097c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd; 78107c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 78117c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 78127c478bd9Sstevel@tonic-gate uint_t flag; 78137c478bd9Sstevel@tonic-gate usb_cr_t error; 78147c478bd9Sstevel@tonic-gate 78157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78167c478bd9Sstevel@tonic-gate "ohci_parse_error:"); 78177c478bd9Sstevel@tonic-gate 78187c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 78197c478bd9Sstevel@tonic-gate 78207c478bd9Sstevel@tonic-gate ASSERT(td != NULL); 78217c478bd9Sstevel@tonic-gate 78227c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */ 78237c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 78247c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)Get_TD(td->hctd_trans_wrapper)); 78257c478bd9Sstevel@tonic-gate 78267c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 78277c478bd9Sstevel@tonic-gate 78287c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 78297c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 78307c478bd9Sstevel@tonic-gate 78317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78327c478bd9Sstevel@tonic-gate "ohci_parse_error: PP 0x%p TW 0x%p", pp, tw); 78337c478bd9Sstevel@tonic-gate 78347c478bd9Sstevel@tonic-gate eptd = &pp->pp_pipe_handle->p_ep; 78357c478bd9Sstevel@tonic-gate 78367c478bd9Sstevel@tonic-gate ctrl = (uint_t)Get_TD(td->hctd_ctrl) & (uint32_t)HC_TD_CC; 78377c478bd9Sstevel@tonic-gate 78387c478bd9Sstevel@tonic-gate /* 78397c478bd9Sstevel@tonic-gate * Check the condition code of completed TD and report errors 78407c478bd9Sstevel@tonic-gate * if any. This checking will be done both for the general and 78417c478bd9Sstevel@tonic-gate * the isochronous TDs. 78427c478bd9Sstevel@tonic-gate */ 78437c478bd9Sstevel@tonic-gate if ((error = ohci_check_for_error(ohcip, pp, tw, td, ctrl)) != 78447c478bd9Sstevel@tonic-gate USB_CR_OK) { 78457c478bd9Sstevel@tonic-gate flag = OHCI_REMOVE_XFER_ALWAYS; 78467c478bd9Sstevel@tonic-gate } else { 78477c478bd9Sstevel@tonic-gate flag = OHCI_REMOVE_XFER_IFLAST; 78487c478bd9Sstevel@tonic-gate } 78497c478bd9Sstevel@tonic-gate 78507c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 78517c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, flag); 78527c478bd9Sstevel@tonic-gate 78537c478bd9Sstevel@tonic-gate /* 78547c478bd9Sstevel@tonic-gate * The isochronous endpoint needs additional error checking 78557c478bd9Sstevel@tonic-gate * and special processing. 78567c478bd9Sstevel@tonic-gate */ 78577c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 78587c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) { 78597c478bd9Sstevel@tonic-gate 78607c478bd9Sstevel@tonic-gate ohci_parse_isoc_error(ohcip, pp, tw, td); 78617c478bd9Sstevel@tonic-gate 78627c478bd9Sstevel@tonic-gate /* always reset error */ 78637c478bd9Sstevel@tonic-gate error = USB_CR_OK; 78647c478bd9Sstevel@tonic-gate } 78657c478bd9Sstevel@tonic-gate 78667c478bd9Sstevel@tonic-gate return (error); 78677c478bd9Sstevel@tonic-gate } 78687c478bd9Sstevel@tonic-gate 78697c478bd9Sstevel@tonic-gate 78707c478bd9Sstevel@tonic-gate /* 78717c478bd9Sstevel@tonic-gate * ohci_parse_isoc_error: 78727c478bd9Sstevel@tonic-gate * 78737c478bd9Sstevel@tonic-gate * Check for any errors in the isochronous data packets. Also fillup 78747c478bd9Sstevel@tonic-gate * the status for each of the isochrnous data packets. 78757c478bd9Sstevel@tonic-gate */ 78767c478bd9Sstevel@tonic-gate void 78777c478bd9Sstevel@tonic-gate ohci_parse_isoc_error( 78787c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 78797c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 78807c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 78817c478bd9Sstevel@tonic-gate ohci_td_t *td) 78827c478bd9Sstevel@tonic-gate { 78837c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp; 78847c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *isoc_pkt_descr; 78857c478bd9Sstevel@tonic-gate uint_t toggle = 0, fc, ctrl, psw; 78867c478bd9Sstevel@tonic-gate int i; 78877c478bd9Sstevel@tonic-gate 78887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78897c478bd9Sstevel@tonic-gate "ohci_parse_isoc_error: td 0x%p", td); 78907c478bd9Sstevel@tonic-gate 78917c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 78927c478bd9Sstevel@tonic-gate 78937c478bd9Sstevel@tonic-gate fc = ((uint_t)Get_TD(td->hctd_ctrl) & 78947c478bd9Sstevel@tonic-gate HC_ITD_FC) >> HC_ITD_FC_SHIFT; 78957c478bd9Sstevel@tonic-gate 78967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 78977c478bd9Sstevel@tonic-gate "ohci_parse_isoc_error: frame count %d", fc); 78987c478bd9Sstevel@tonic-gate 78997c478bd9Sstevel@tonic-gate /* 79007c478bd9Sstevel@tonic-gate * Get the address of current usb isochronous request 79017c478bd9Sstevel@tonic-gate * and array of packet descriptors. 79027c478bd9Sstevel@tonic-gate */ 79037c478bd9Sstevel@tonic-gate isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 79047c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr; 79057c478bd9Sstevel@tonic-gate 79067c478bd9Sstevel@tonic-gate for (i = 0; i <= fc; i++) { 79077c478bd9Sstevel@tonic-gate 79087c478bd9Sstevel@tonic-gate psw = Get_TD(td->hctd_offsets[i / 2]); 79097c478bd9Sstevel@tonic-gate 79107c478bd9Sstevel@tonic-gate if (toggle) { 79117c478bd9Sstevel@tonic-gate ctrl = psw & HC_ITD_ODD_OFFSET; 79127c478bd9Sstevel@tonic-gate toggle = 0; 79137c478bd9Sstevel@tonic-gate } else { 79147c478bd9Sstevel@tonic-gate ctrl = (psw & HC_ITD_EVEN_OFFSET) << 79157c478bd9Sstevel@tonic-gate HC_ITD_OFFSET_SHIFT; 79167c478bd9Sstevel@tonic-gate toggle = 1; 79177c478bd9Sstevel@tonic-gate } 79187c478bd9Sstevel@tonic-gate 79197c478bd9Sstevel@tonic-gate isoc_pkt_descr->isoc_pkt_actual_length = 79207c478bd9Sstevel@tonic-gate (ctrl >> HC_ITD_OFFSET_SHIFT) & HC_ITD_OFFSET_ADDR; 79217c478bd9Sstevel@tonic-gate 79227c478bd9Sstevel@tonic-gate ctrl = (uint_t)(ctrl & (uint32_t)HC_TD_CC); 79237c478bd9Sstevel@tonic-gate 79247c478bd9Sstevel@tonic-gate /* Write the status of isoc data packet */ 79257c478bd9Sstevel@tonic-gate isoc_pkt_descr->isoc_pkt_status = 79267c478bd9Sstevel@tonic-gate ohci_check_for_error(ohcip, pp, tw, td, ctrl); 79277c478bd9Sstevel@tonic-gate 79287c478bd9Sstevel@tonic-gate if (isoc_pkt_descr->isoc_pkt_status) { 79297c478bd9Sstevel@tonic-gate /* Increment isoc data packet error count */ 79307c478bd9Sstevel@tonic-gate isoc_reqp->isoc_error_count++; 79317c478bd9Sstevel@tonic-gate } 79327c478bd9Sstevel@tonic-gate 79337c478bd9Sstevel@tonic-gate /* 79347c478bd9Sstevel@tonic-gate * Get the address of next isoc data packet descriptor. 79357c478bd9Sstevel@tonic-gate */ 79367c478bd9Sstevel@tonic-gate isoc_pkt_descr++; 79377c478bd9Sstevel@tonic-gate } 79387c478bd9Sstevel@tonic-gate } 79397c478bd9Sstevel@tonic-gate 79407c478bd9Sstevel@tonic-gate 79417c478bd9Sstevel@tonic-gate /* 79427c478bd9Sstevel@tonic-gate * ohci_check_for_error: 79437c478bd9Sstevel@tonic-gate * 79447c478bd9Sstevel@tonic-gate * Check for any errors. 79457c478bd9Sstevel@tonic-gate */ 79467c478bd9Sstevel@tonic-gate static usb_cr_t 79477c478bd9Sstevel@tonic-gate ohci_check_for_error( 79487c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 79497c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 79507c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 79517c478bd9Sstevel@tonic-gate ohci_td_t *td, 79527c478bd9Sstevel@tonic-gate uint_t ctrl) 79537c478bd9Sstevel@tonic-gate { 79547c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 79557c478bd9Sstevel@tonic-gate uchar_t ep_attrs = ph->p_ep.bmAttributes; 79567c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK; 79577c478bd9Sstevel@tonic-gate usb_req_attrs_t xfer_attrs; 79587c478bd9Sstevel@tonic-gate 79597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79607c478bd9Sstevel@tonic-gate "ohci_check_for_error: td = 0x%p ctrl = 0x%x", 79617c478bd9Sstevel@tonic-gate td, ctrl); 79627c478bd9Sstevel@tonic-gate 79637c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 79647c478bd9Sstevel@tonic-gate 79657c478bd9Sstevel@tonic-gate switch (ctrl) { 79667c478bd9Sstevel@tonic-gate case HC_TD_CC_NO_E: 79677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79687c478bd9Sstevel@tonic-gate "ohci_check_for_error: No Error"); 79697c478bd9Sstevel@tonic-gate error = USB_CR_OK; 79707c478bd9Sstevel@tonic-gate break; 79717c478bd9Sstevel@tonic-gate case HC_TD_CC_CRC: 79727c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79737c478bd9Sstevel@tonic-gate "ohci_check_for_error: CRC error"); 79747c478bd9Sstevel@tonic-gate error = USB_CR_CRC; 79757c478bd9Sstevel@tonic-gate break; 79767c478bd9Sstevel@tonic-gate case HC_TD_CC_BS: 79777c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79787c478bd9Sstevel@tonic-gate "ohci_check_for_error: Bit stuffing"); 79797c478bd9Sstevel@tonic-gate error = USB_CR_BITSTUFFING; 79807c478bd9Sstevel@tonic-gate break; 79817c478bd9Sstevel@tonic-gate case HC_TD_CC_DTM: 79827c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79837c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data Toggle Mismatch"); 79847c478bd9Sstevel@tonic-gate error = USB_CR_DATA_TOGGLE_MM; 79857c478bd9Sstevel@tonic-gate break; 79867c478bd9Sstevel@tonic-gate case HC_TD_CC_STALL: 79877c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79887c478bd9Sstevel@tonic-gate "ohci_check_for_error: Stall"); 79897c478bd9Sstevel@tonic-gate error = USB_CR_STALL; 79907c478bd9Sstevel@tonic-gate break; 79917c478bd9Sstevel@tonic-gate case HC_TD_CC_DNR: 79927c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79937c478bd9Sstevel@tonic-gate "ohci_check_for_error: Device not responding"); 79947c478bd9Sstevel@tonic-gate error = USB_CR_DEV_NOT_RESP; 79957c478bd9Sstevel@tonic-gate break; 79967c478bd9Sstevel@tonic-gate case HC_TD_CC_PCF: 79977c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79987c478bd9Sstevel@tonic-gate "ohci_check_for_error: PID check failure"); 79997c478bd9Sstevel@tonic-gate error = USB_CR_PID_CHECKFAILURE; 80007c478bd9Sstevel@tonic-gate break; 80017c478bd9Sstevel@tonic-gate case HC_TD_CC_UPID: 80027c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80037c478bd9Sstevel@tonic-gate "ohci_check_for_error: Unexpected PID"); 80047c478bd9Sstevel@tonic-gate error = USB_CR_UNEXP_PID; 80057c478bd9Sstevel@tonic-gate break; 80067c478bd9Sstevel@tonic-gate case HC_TD_CC_DO: 80077c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80087c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data overrrun"); 80097c478bd9Sstevel@tonic-gate error = USB_CR_DATA_OVERRUN; 80107c478bd9Sstevel@tonic-gate break; 80117c478bd9Sstevel@tonic-gate case HC_TD_CC_DU: 80127c478bd9Sstevel@tonic-gate /* 80137c478bd9Sstevel@tonic-gate * Check whether short packets are acceptable. 80147c478bd9Sstevel@tonic-gate * If so don't report error to client drivers 80157c478bd9Sstevel@tonic-gate * and restart the endpoint. Otherwise report 80167c478bd9Sstevel@tonic-gate * data underrun error to client driver. 80177c478bd9Sstevel@tonic-gate */ 80187c478bd9Sstevel@tonic-gate xfer_attrs = ohci_get_xfer_attrs(ohcip, pp, tw); 80197c478bd9Sstevel@tonic-gate 80207c478bd9Sstevel@tonic-gate if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) { 80217c478bd9Sstevel@tonic-gate error = USB_CR_OK; 80227c478bd9Sstevel@tonic-gate if ((ep_attrs & USB_EP_ATTR_MASK) != 80237c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) { 80247c478bd9Sstevel@tonic-gate /* 80257c478bd9Sstevel@tonic-gate * Cleanup the remaining resources that may have 80267c478bd9Sstevel@tonic-gate * been allocated for this transfer. 80277c478bd9Sstevel@tonic-gate */ 80287c478bd9Sstevel@tonic-gate if (ohci_cleanup_data_underrun(ohcip, pp, tw, 80297c478bd9Sstevel@tonic-gate td) == USB_SUCCESS) { 80307c478bd9Sstevel@tonic-gate /* Clear the halt bit */ 80317c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 80327c478bd9Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) & 80337c478bd9Sstevel@tonic-gate ~HC_EPT_Halt)); 80347c478bd9Sstevel@tonic-gate } else { 80357c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR; 80367c478bd9Sstevel@tonic-gate } 80377c478bd9Sstevel@tonic-gate } 80387c478bd9Sstevel@tonic-gate } else { 80397c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80407c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data underrun"); 80417c478bd9Sstevel@tonic-gate 80427c478bd9Sstevel@tonic-gate error = USB_CR_DATA_UNDERRUN; 80437c478bd9Sstevel@tonic-gate } 80447c478bd9Sstevel@tonic-gate 80457c478bd9Sstevel@tonic-gate break; 80467c478bd9Sstevel@tonic-gate case HC_TD_CC_BO: 80477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80487c478bd9Sstevel@tonic-gate "ohci_check_for_error: Buffer overrun"); 80497c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_OVERRUN; 80507c478bd9Sstevel@tonic-gate break; 80517c478bd9Sstevel@tonic-gate case HC_TD_CC_BU: 80527c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80537c478bd9Sstevel@tonic-gate "ohci_check_for_error: Buffer underrun"); 80547c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_UNDERRUN; 80557c478bd9Sstevel@tonic-gate break; 80567c478bd9Sstevel@tonic-gate case HC_TD_CC_NA: 80577c478bd9Sstevel@tonic-gate default: 80587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80597c478bd9Sstevel@tonic-gate "ohci_check_for_error: Not accessed"); 80607c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED; 80617c478bd9Sstevel@tonic-gate break; 80627c478bd9Sstevel@tonic-gate } 80637c478bd9Sstevel@tonic-gate 80647c478bd9Sstevel@tonic-gate if (error) { 80657c478bd9Sstevel@tonic-gate uint_t hced_ctrl = Get_ED(pp->pp_ept->hced_ctrl); 80667c478bd9Sstevel@tonic-gate 80677c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80687c478bd9Sstevel@tonic-gate "ohci_check_for_error: Error %d Device address %d " 80697c478bd9Sstevel@tonic-gate "Endpoint number %d", error, (hced_ctrl & HC_EPT_FUNC), 80707c478bd9Sstevel@tonic-gate ((hced_ctrl & HC_EPT_EP) >> HC_EPT_EP_SHFT)); 80717c478bd9Sstevel@tonic-gate } 80727c478bd9Sstevel@tonic-gate 80737c478bd9Sstevel@tonic-gate return (error); 80747c478bd9Sstevel@tonic-gate } 80757c478bd9Sstevel@tonic-gate 80767c478bd9Sstevel@tonic-gate 80777c478bd9Sstevel@tonic-gate /* 80787c478bd9Sstevel@tonic-gate * ohci_handle_error: 80797c478bd9Sstevel@tonic-gate * 80807c478bd9Sstevel@tonic-gate * Inform USBA about occured transaction errors by calling the USBA callback 80817c478bd9Sstevel@tonic-gate * routine. 80827c478bd9Sstevel@tonic-gate */ 80837c478bd9Sstevel@tonic-gate static void 80847c478bd9Sstevel@tonic-gate ohci_handle_error( 80857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 80867c478bd9Sstevel@tonic-gate ohci_td_t *td, 80877c478bd9Sstevel@tonic-gate usb_cr_t error) 80887c478bd9Sstevel@tonic-gate { 80897c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 80907c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph; 80917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 80927c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 80937c478bd9Sstevel@tonic-gate size_t length = 0; 80947c478bd9Sstevel@tonic-gate uchar_t attributes; 80957c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 80967c478bd9Sstevel@tonic-gate 80977c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80987c478bd9Sstevel@tonic-gate "ohci_handle_error: error = 0x%x", error); 80997c478bd9Sstevel@tonic-gate 81007c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 81017c478bd9Sstevel@tonic-gate 81027c478bd9Sstevel@tonic-gate ASSERT(td != NULL); 81037c478bd9Sstevel@tonic-gate 81047c478bd9Sstevel@tonic-gate /* Print the values in the td */ 81057c478bd9Sstevel@tonic-gate ohci_print_td(ohcip, td); 81067c478bd9Sstevel@tonic-gate 81077c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */ 81087c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 81097c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)Get_TD(td->hctd_trans_wrapper)); 81107c478bd9Sstevel@tonic-gate 81117c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 81127c478bd9Sstevel@tonic-gate 81137c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 81147c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 81157c478bd9Sstevel@tonic-gate 81167c478bd9Sstevel@tonic-gate ph = tw->tw_pipe_private->pp_pipe_handle; 81177c478bd9Sstevel@tonic-gate attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK; 81187c478bd9Sstevel@tonic-gate 81197c478bd9Sstevel@tonic-gate /* 81207c478bd9Sstevel@tonic-gate * Special error handling 81217c478bd9Sstevel@tonic-gate */ 81227c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) { 81237c478bd9Sstevel@tonic-gate 81247c478bd9Sstevel@tonic-gate switch (attributes) { 81257c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 81267c478bd9Sstevel@tonic-gate if (((ph->p_ep.bmAttributes & 81277c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == 81287c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) && 81297c478bd9Sstevel@tonic-gate (Get_TD(td->hctd_ctrl_phase) == 81307c478bd9Sstevel@tonic-gate OHCI_CTRL_SETUP_PHASE)) { 81317c478bd9Sstevel@tonic-gate 81327c478bd9Sstevel@tonic-gate break; 81337c478bd9Sstevel@tonic-gate } 81347c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 81357c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 81367c478bd9Sstevel@tonic-gate /* 81377c478bd9Sstevel@tonic-gate * Call ohci_sendup_td_message 81387c478bd9Sstevel@tonic-gate * to send message to upstream. 81397c478bd9Sstevel@tonic-gate */ 81407c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, error); 81417c478bd9Sstevel@tonic-gate 81427c478bd9Sstevel@tonic-gate return; 81437c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 81447c478bd9Sstevel@tonic-gate curr_intr_reqp = 81457c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 81467c478bd9Sstevel@tonic-gate 81477c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & 81487c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 81497c478bd9Sstevel@tonic-gate 81507c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(ohcip, tw); 81517c478bd9Sstevel@tonic-gate } 81527c478bd9Sstevel@tonic-gate 81537c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 81547c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 81557c478bd9Sstevel@tonic-gate break; 81567c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 81577c478bd9Sstevel@tonic-gate default: 81587c478bd9Sstevel@tonic-gate break; 81597c478bd9Sstevel@tonic-gate } 81607c478bd9Sstevel@tonic-gate } else { 81617c478bd9Sstevel@tonic-gate switch (attributes) { 81627c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 81637c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 81647c478bd9Sstevel@tonic-gate /* 81657c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer 81667c478bd9Sstevel@tonic-gate * Descriptor (TD) is not equal to zero, 81677c478bd9Sstevel@tonic-gate * then we sent less data to the device 81687c478bd9Sstevel@tonic-gate * than requested by client. In that case, 81697c478bd9Sstevel@tonic-gate * return the mblk after updating the 81707c478bd9Sstevel@tonic-gate * data->r_ptr. 81717c478bd9Sstevel@tonic-gate */ 81727c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) { 81737c478bd9Sstevel@tonic-gate usb_opaque_t xfer_reqp = tw->tw_curr_xfer_reqp; 81747c478bd9Sstevel@tonic-gate 81757c478bd9Sstevel@tonic-gate length = Get_TD(td->hctd_cbp) - 81767c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address; 81777c478bd9Sstevel@tonic-gate 81787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 81797c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, 81807c478bd9Sstevel@tonic-gate "ohci_handle_error: requested data %lu " 81817c478bd9Sstevel@tonic-gate "sent data %lu", tw->tw_length, length); 81827c478bd9Sstevel@tonic-gate 81837c478bd9Sstevel@tonic-gate if (attributes == USB_EP_ATTR_BULK) { 81847c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_bulk_req_t *) 81857c478bd9Sstevel@tonic-gate (xfer_reqp))->bulk_data; 81867c478bd9Sstevel@tonic-gate } else { 81877c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_intr_req_t *) 81887c478bd9Sstevel@tonic-gate (xfer_reqp))->intr_data; 81897c478bd9Sstevel@tonic-gate } 81907c478bd9Sstevel@tonic-gate 81917c478bd9Sstevel@tonic-gate /* Increment the read pointer */ 81927c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length; 81937c478bd9Sstevel@tonic-gate } 81947c478bd9Sstevel@tonic-gate break; 81957c478bd9Sstevel@tonic-gate default: 81967c478bd9Sstevel@tonic-gate break; 81977c478bd9Sstevel@tonic-gate } 81987c478bd9Sstevel@tonic-gate } 81997c478bd9Sstevel@tonic-gate 82007c478bd9Sstevel@tonic-gate /* 82017c478bd9Sstevel@tonic-gate * Callback the client with the 82027c478bd9Sstevel@tonic-gate * failure reason. 82037c478bd9Sstevel@tonic-gate */ 82047c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, error); 82057c478bd9Sstevel@tonic-gate 82067c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 82077c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(ohcip, pp); 82087c478bd9Sstevel@tonic-gate } 82097c478bd9Sstevel@tonic-gate 82107c478bd9Sstevel@tonic-gate /* 82117c478bd9Sstevel@tonic-gate * ohci_cleanup_data_underrun: 82127c478bd9Sstevel@tonic-gate * 82137c478bd9Sstevel@tonic-gate * Cleans up resources when a short xfer occurs 82147c478bd9Sstevel@tonic-gate */ 82157c478bd9Sstevel@tonic-gate static int 82167c478bd9Sstevel@tonic-gate ohci_cleanup_data_underrun( 82177c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 82187c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 82197c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 82207c478bd9Sstevel@tonic-gate ohci_td_t *td) 82217c478bd9Sstevel@tonic-gate { 82227c478bd9Sstevel@tonic-gate ohci_td_t *next_td; 82237c478bd9Sstevel@tonic-gate ohci_td_t *last_td; 82247c478bd9Sstevel@tonic-gate ohci_td_t *temp_td; 82257c478bd9Sstevel@tonic-gate uint32_t last_td_addr; 82267c478bd9Sstevel@tonic-gate uint_t hced_head; 82277c478bd9Sstevel@tonic-gate 82287c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 82297c478bd9Sstevel@tonic-gate "ohci_cleanup_data_underrun: td 0x%p, tw 0x%p", td, tw); 82307c478bd9Sstevel@tonic-gate 82317c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 82327c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_head == td); 82337c478bd9Sstevel@tonic-gate 82347c478bd9Sstevel@tonic-gate /* Check if this TD is the last td in the tw */ 82357c478bd9Sstevel@tonic-gate last_td = tw->tw_hctd_tail; 82367c478bd9Sstevel@tonic-gate if (td == last_td) { 82377c478bd9Sstevel@tonic-gate /* There is no need for cleanup */ 82387c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 82397c478bd9Sstevel@tonic-gate } 82407c478bd9Sstevel@tonic-gate 82417c478bd9Sstevel@tonic-gate /* 82427c478bd9Sstevel@tonic-gate * Make sure the ED is halted before we change any td's. 82437c478bd9Sstevel@tonic-gate * If for some reason it is not halted, return error to client 82447c478bd9Sstevel@tonic-gate * driver so they can reset the port. 82457c478bd9Sstevel@tonic-gate */ 82467c478bd9Sstevel@tonic-gate hced_head = Get_ED(pp->pp_ept->hced_headp); 82477c478bd9Sstevel@tonic-gate if (!(hced_head & HC_EPT_Halt)) { 82487c478bd9Sstevel@tonic-gate uint_t hced_ctrl = Get_ED(pp->pp_ept->hced_ctrl); 82497c478bd9Sstevel@tonic-gate 82507c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 82517c478bd9Sstevel@tonic-gate "ohci_cleanup_data_underrun: Unable to clean up a short " 82527c478bd9Sstevel@tonic-gate "xfer error. Client might send/receive irrelevant data." 82537c478bd9Sstevel@tonic-gate " Device address %d Endpoint number %d", 82547c478bd9Sstevel@tonic-gate (hced_ctrl & HC_EPT_FUNC), 82557c478bd9Sstevel@tonic-gate ((hced_ctrl & HC_EPT_EP) >> HC_EPT_EP_SHFT)); 82567c478bd9Sstevel@tonic-gate 82577c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, hced_head | HC_EPT_Halt); 82587c478bd9Sstevel@tonic-gate 82597c478bd9Sstevel@tonic-gate return (USB_FAILURE); 82607c478bd9Sstevel@tonic-gate } 82617c478bd9Sstevel@tonic-gate 82627c478bd9Sstevel@tonic-gate /* 82637c478bd9Sstevel@tonic-gate * Get the address of the first td of the next transfer (tw). 82647c478bd9Sstevel@tonic-gate * This td, may currently be a dummy td, but when a new request 82657c478bd9Sstevel@tonic-gate * arrives, it will be transformed into a regular td. 82667c478bd9Sstevel@tonic-gate */ 82677c478bd9Sstevel@tonic-gate last_td_addr = Get_TD(last_td->hctd_next_td); 82687c478bd9Sstevel@tonic-gate /* Set ED head to this last td */ 82697c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 82707c478bd9Sstevel@tonic-gate (last_td_addr & HC_EPT_TD_HEAD) | 82717c478bd9Sstevel@tonic-gate (hced_head & ~HC_EPT_TD_HEAD)); 82727c478bd9Sstevel@tonic-gate 82737c478bd9Sstevel@tonic-gate /* 82747c478bd9Sstevel@tonic-gate * Start removing all the unused TD's from the TW, 82757c478bd9Sstevel@tonic-gate * but keep the first one. 82767c478bd9Sstevel@tonic-gate */ 82777c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td; 82787c478bd9Sstevel@tonic-gate 82797c478bd9Sstevel@tonic-gate /* 82807c478bd9Sstevel@tonic-gate * Get the last_td, the next td in the tw list. 82817c478bd9Sstevel@tonic-gate * Afterwards completely disassociate the current td from other tds 82827c478bd9Sstevel@tonic-gate */ 82837c478bd9Sstevel@tonic-gate next_td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip, 82847c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td)); 82857c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL); 82867c478bd9Sstevel@tonic-gate 82877c478bd9Sstevel@tonic-gate /* 82887c478bd9Sstevel@tonic-gate * Iterate down the tw list and deallocate them 82897c478bd9Sstevel@tonic-gate */ 82907c478bd9Sstevel@tonic-gate while (next_td != NULL) { 82917c478bd9Sstevel@tonic-gate tw->tw_num_tds--; 82927c478bd9Sstevel@tonic-gate /* Disassociate this td from it's TW and set to RECLAIM */ 82937c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_trans_wrapper, NULL); 82947c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_state, HC_TD_RECLAIM); 82957c478bd9Sstevel@tonic-gate 82967c478bd9Sstevel@tonic-gate temp_td = next_td; 82977c478bd9Sstevel@tonic-gate 82987c478bd9Sstevel@tonic-gate next_td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip, 82997c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td)); 83007c478bd9Sstevel@tonic-gate 83017c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, temp_td); 83027c478bd9Sstevel@tonic-gate } 83037c478bd9Sstevel@tonic-gate 83047c478bd9Sstevel@tonic-gate ASSERT(tw->tw_num_tds == 1); 83057c478bd9Sstevel@tonic-gate 83067c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 83077c478bd9Sstevel@tonic-gate } 83087c478bd9Sstevel@tonic-gate 83097c478bd9Sstevel@tonic-gate /* 83107c478bd9Sstevel@tonic-gate * ohci_handle_normal_td: 83117c478bd9Sstevel@tonic-gate */ 83127c478bd9Sstevel@tonic-gate static void 83137c478bd9Sstevel@tonic-gate ohci_handle_normal_td( 83147c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 83157c478bd9Sstevel@tonic-gate ohci_td_t *td, 83167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 83177c478bd9Sstevel@tonic-gate { 83187c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; /* Pipe private field */ 83197c478bd9Sstevel@tonic-gate 83207c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83217c478bd9Sstevel@tonic-gate "ohci_handle_normal_td:"); 83227c478bd9Sstevel@tonic-gate 83237c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 83247c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 83257c478bd9Sstevel@tonic-gate 83267c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 83277c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 83287c478bd9Sstevel@tonic-gate 83297c478bd9Sstevel@tonic-gate (*tw->tw_handle_td)(ohcip, pp, tw, 83307c478bd9Sstevel@tonic-gate td, tw->tw_handle_callback_value); 83317c478bd9Sstevel@tonic-gate 83327c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 83337c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(ohcip, pp); 83347c478bd9Sstevel@tonic-gate } 83357c478bd9Sstevel@tonic-gate 83367c478bd9Sstevel@tonic-gate 83377c478bd9Sstevel@tonic-gate /* 83387c478bd9Sstevel@tonic-gate * ohci_handle_ctrl_td: 83397c478bd9Sstevel@tonic-gate * 83407c478bd9Sstevel@tonic-gate * Handle a control Transfer Descriptor (TD). 83417c478bd9Sstevel@tonic-gate */ 83427c478bd9Sstevel@tonic-gate /* ARGSUSED */ 83437c478bd9Sstevel@tonic-gate static void 83447c478bd9Sstevel@tonic-gate ohci_handle_ctrl_td( 83457c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 83467c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 83477c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 83487c478bd9Sstevel@tonic-gate ohci_td_t *td, 83497c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 83507c478bd9Sstevel@tonic-gate { 83517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 83527c478bd9Sstevel@tonic-gate 83537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83547c478bd9Sstevel@tonic-gate "ohci_handle_ctrl_td: pp = 0x%p tw = 0x%p td = 0x%p state = 0x%x", 83557c478bd9Sstevel@tonic-gate (void *)pp, (void *)tw, (void *)td, Get_TD(td->hctd_ctrl_phase)); 83567c478bd9Sstevel@tonic-gate 83577c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 83587c478bd9Sstevel@tonic-gate 83597c478bd9Sstevel@tonic-gate /* 83607c478bd9Sstevel@tonic-gate * Check which control transfer phase got completed. 83617c478bd9Sstevel@tonic-gate */ 83627c478bd9Sstevel@tonic-gate tw->tw_num_tds--; 83637c478bd9Sstevel@tonic-gate switch (Get_TD(td->hctd_ctrl_phase)) { 83647c478bd9Sstevel@tonic-gate case OHCI_CTRL_SETUP_PHASE: 83657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83667c478bd9Sstevel@tonic-gate "Setup complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 83677c478bd9Sstevel@tonic-gate 83687c478bd9Sstevel@tonic-gate break; 83697c478bd9Sstevel@tonic-gate case OHCI_CTRL_DATA_PHASE: 83707c478bd9Sstevel@tonic-gate /* 83717c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor (TD) 83727c478bd9Sstevel@tonic-gate * is not equal to zero, then we received less data from 83737c478bd9Sstevel@tonic-gate * the device than requested by us. In that case, get the 83747c478bd9Sstevel@tonic-gate * actual received data size. 83757c478bd9Sstevel@tonic-gate */ 83767c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) { 83777c478bd9Sstevel@tonic-gate size_t length; 83787c478bd9Sstevel@tonic-gate 83797c478bd9Sstevel@tonic-gate length = Get_TD(td->hctd_cbp) - 83807c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address; 83817c478bd9Sstevel@tonic-gate 83827c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83837c478bd9Sstevel@tonic-gate "ohci_handle_ctrl_qtd: requested data %lu " 83847c478bd9Sstevel@tonic-gate "received data %lu", tw->tw_length, length); 83857c478bd9Sstevel@tonic-gate 83867c478bd9Sstevel@tonic-gate /* Save actual received data length */ 83877c478bd9Sstevel@tonic-gate tw->tw_length = length; 83887c478bd9Sstevel@tonic-gate } 83897c478bd9Sstevel@tonic-gate 83907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83917c478bd9Sstevel@tonic-gate "Data complete: pp 0x%p td 0x%p", 83927c478bd9Sstevel@tonic-gate (void *)pp, (void *)td); 83937c478bd9Sstevel@tonic-gate 83947c478bd9Sstevel@tonic-gate break; 83957c478bd9Sstevel@tonic-gate case OHCI_CTRL_STATUS_PHASE: 83967c478bd9Sstevel@tonic-gate if ((tw->tw_length != 0) && 83977c478bd9Sstevel@tonic-gate (tw->tw_direction == HC_TD_IN)) { 83987c478bd9Sstevel@tonic-gate 83997c478bd9Sstevel@tonic-gate /* 84007c478bd9Sstevel@tonic-gate * Call ohci_sendup_td_message 84017c478bd9Sstevel@tonic-gate * to send message to upstream. 84027c478bd9Sstevel@tonic-gate */ 84037c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, 84047c478bd9Sstevel@tonic-gate pp, tw, td, USB_CR_OK); 84057c478bd9Sstevel@tonic-gate } else { 84067c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, 84077c478bd9Sstevel@tonic-gate tw->tw_length - SETUP_SIZE, 84087c478bd9Sstevel@tonic-gate ph->p_ep.bmAttributes, 84097c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress); 84107c478bd9Sstevel@tonic-gate 84117c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 84127c478bd9Sstevel@tonic-gate } 84137c478bd9Sstevel@tonic-gate 84147c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 84157c478bd9Sstevel@tonic-gate "Status complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 84167c478bd9Sstevel@tonic-gate 84177c478bd9Sstevel@tonic-gate break; 84187c478bd9Sstevel@tonic-gate } 84197c478bd9Sstevel@tonic-gate } 84207c478bd9Sstevel@tonic-gate 84217c478bd9Sstevel@tonic-gate 84227c478bd9Sstevel@tonic-gate /* 84237c478bd9Sstevel@tonic-gate * ohci_handle_bulk_td: 84247c478bd9Sstevel@tonic-gate * 84257c478bd9Sstevel@tonic-gate * Handle a bulk Transfer Descriptor (TD). 84267c478bd9Sstevel@tonic-gate */ 84277c478bd9Sstevel@tonic-gate /* ARGSUSED */ 84287c478bd9Sstevel@tonic-gate static void 84297c478bd9Sstevel@tonic-gate ohci_handle_bulk_td( 84307c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 84317c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 84327c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 84337c478bd9Sstevel@tonic-gate ohci_td_t *td, 84347c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 84357c478bd9Sstevel@tonic-gate { 84367c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 84377c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 84387c478bd9Sstevel@tonic-gate 84397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 84407c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td:"); 84417c478bd9Sstevel@tonic-gate 84427c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 84437c478bd9Sstevel@tonic-gate 84447c478bd9Sstevel@tonic-gate /* 84457c478bd9Sstevel@tonic-gate * Decrement the TDs counter and check whether all the bulk 84467c478bd9Sstevel@tonic-gate * data has been send or received. If TDs counter reaches 84477c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 84487c478bd9Sstevel@tonic-gate * bulk request. Other wise wait for completion of other bulk 84497c478bd9Sstevel@tonic-gate * TDs or transactions on this pipe. 84507c478bd9Sstevel@tonic-gate */ 84517c478bd9Sstevel@tonic-gate if (--tw->tw_num_tds != 0) { 84527c478bd9Sstevel@tonic-gate 84537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 84547c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td: Number of TDs %d", tw->tw_num_tds); 84557c478bd9Sstevel@tonic-gate 84567c478bd9Sstevel@tonic-gate return; 84577c478bd9Sstevel@tonic-gate } 84587c478bd9Sstevel@tonic-gate 84597c478bd9Sstevel@tonic-gate /* 84607c478bd9Sstevel@tonic-gate * If this is a bulk in pipe, return the data to the client. 84617c478bd9Sstevel@tonic-gate * For a bulk out pipe, there is no need to do anything. 84627c478bd9Sstevel@tonic-gate */ 84637c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & 84647c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 84657c478bd9Sstevel@tonic-gate 84667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 84677c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td: Bulk out pipe"); 84687c478bd9Sstevel@tonic-gate 84697c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length, 84707c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 84717c478bd9Sstevel@tonic-gate 84727c478bd9Sstevel@tonic-gate /* Do the callback */ 84737c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 84747c478bd9Sstevel@tonic-gate 84757c478bd9Sstevel@tonic-gate return; 84767c478bd9Sstevel@tonic-gate } 84777c478bd9Sstevel@tonic-gate 84787c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to send message to upstream */ 84797c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK); 84807c478bd9Sstevel@tonic-gate } 84817c478bd9Sstevel@tonic-gate 84827c478bd9Sstevel@tonic-gate 84837c478bd9Sstevel@tonic-gate /* 84847c478bd9Sstevel@tonic-gate * ohci_handle_intr_td: 84857c478bd9Sstevel@tonic-gate * 84867c478bd9Sstevel@tonic-gate * Handle a interrupt Transfer Descriptor (TD). 84877c478bd9Sstevel@tonic-gate */ 84887c478bd9Sstevel@tonic-gate /* ARGSUSED */ 84897c478bd9Sstevel@tonic-gate static void 84907c478bd9Sstevel@tonic-gate ohci_handle_intr_td( 84917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 84927c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 84937c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 84947c478bd9Sstevel@tonic-gate ohci_td_t *td, 84957c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 84967c478bd9Sstevel@tonic-gate { 84977c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 84987c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 84997c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 85007c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 85017c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs; 85027c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 85037c478bd9Sstevel@tonic-gate 85047c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85057c478bd9Sstevel@tonic-gate "ohci_handle_intr_td: pp=0x%p tw=0x%p td=0x%p" 85067c478bd9Sstevel@tonic-gate "intr_reqp=0%p data=0x%p", pp, tw, td, curr_intr_reqp, 85077c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_data); 85087c478bd9Sstevel@tonic-gate 85097c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 85107c478bd9Sstevel@tonic-gate 85117c478bd9Sstevel@tonic-gate /* Get the interrupt xfer attributes */ 85127c478bd9Sstevel@tonic-gate attrs = curr_intr_reqp->intr_attributes; 85137c478bd9Sstevel@tonic-gate 85147c478bd9Sstevel@tonic-gate /* 85157c478bd9Sstevel@tonic-gate * For a Interrupt OUT pipe, we just callback and we are done 85167c478bd9Sstevel@tonic-gate */ 85177c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 85187c478bd9Sstevel@tonic-gate 85197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85207c478bd9Sstevel@tonic-gate "ohci_handle_intr_td: Intr out pipe, intr_reqp=0x%p," 85217c478bd9Sstevel@tonic-gate "data=0x%p", curr_intr_reqp, curr_intr_reqp->intr_data); 85227c478bd9Sstevel@tonic-gate 85237c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length, 85247c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 85257c478bd9Sstevel@tonic-gate 85267c478bd9Sstevel@tonic-gate /* Do the callback */ 85277c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 85287c478bd9Sstevel@tonic-gate 85297c478bd9Sstevel@tonic-gate return; 85307c478bd9Sstevel@tonic-gate } 85317c478bd9Sstevel@tonic-gate 85327c478bd9Sstevel@tonic-gate /* Decrement number of interrupt request count */ 85337c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 85347c478bd9Sstevel@tonic-gate 85357c478bd9Sstevel@tonic-gate /* 85367c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_XFER flag is set 85377c478bd9Sstevel@tonic-gate * and if so, free duplicate request. 85387c478bd9Sstevel@tonic-gate */ 85397c478bd9Sstevel@tonic-gate if (attrs & USB_ATTRS_ONE_XFER) { 85407c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(ohcip, tw); 85417c478bd9Sstevel@tonic-gate } 85427c478bd9Sstevel@tonic-gate 85437c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to callback into client */ 85447c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK); 85457c478bd9Sstevel@tonic-gate 85467c478bd9Sstevel@tonic-gate /* 85477c478bd9Sstevel@tonic-gate * If interrupt pipe state is still active, insert next Interrupt 85487c478bd9Sstevel@tonic-gate * request into the Host Controller's Interrupt list. Otherwise 85497c478bd9Sstevel@tonic-gate * you are done. 85507c478bd9Sstevel@tonic-gate */ 85517c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) { 85527c478bd9Sstevel@tonic-gate return; 85537c478bd9Sstevel@tonic-gate } 85547c478bd9Sstevel@tonic-gate 85557c478bd9Sstevel@tonic-gate if ((error = ohci_allocate_periodic_in_resource(ohcip, pp, tw, 0)) == 85567c478bd9Sstevel@tonic-gate USB_SUCCESS) { 85577c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 85587c478bd9Sstevel@tonic-gate 85597c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp != NULL); 85607c478bd9Sstevel@tonic-gate 85617c478bd9Sstevel@tonic-gate tw->tw_num_tds = 1; 85627c478bd9Sstevel@tonic-gate 85637c478bd9Sstevel@tonic-gate if (ohci_allocate_tds_for_tw(ohcip, tw, tw->tw_num_tds) != 85647c478bd9Sstevel@tonic-gate USB_SUCCESS) { 85657c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 85667c478bd9Sstevel@tonic-gate error = USB_FAILURE; 85677c478bd9Sstevel@tonic-gate } 85687c478bd9Sstevel@tonic-gate } 85697c478bd9Sstevel@tonic-gate 85707c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 85717c478bd9Sstevel@tonic-gate /* 85727c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 85737c478bd9Sstevel@tonic-gate * resource. Don't insert any more interrupt polling 85747c478bd9Sstevel@tonic-gate * requests. 85757c478bd9Sstevel@tonic-gate */ 85767c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 85777c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 85787c478bd9Sstevel@tonic-gate } else { 85797c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, pp, tw, 0); 85807c478bd9Sstevel@tonic-gate 85817c478bd9Sstevel@tonic-gate /* Increment number of interrupt request count */ 85827c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 85837c478bd9Sstevel@tonic-gate 85847c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 85857c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 85867c478bd9Sstevel@tonic-gate } 85877c478bd9Sstevel@tonic-gate } 85887c478bd9Sstevel@tonic-gate 85897c478bd9Sstevel@tonic-gate 85907c478bd9Sstevel@tonic-gate /* 85917c478bd9Sstevel@tonic-gate * ohci_handle_one_xfer_completion: 85927c478bd9Sstevel@tonic-gate */ 85937c478bd9Sstevel@tonic-gate static void 85947c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion( 85957c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 85967c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 85977c478bd9Sstevel@tonic-gate { 85987c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = tw->tw_pipe_private->pp_pipe_handle; 85997c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = tw->tw_pipe_private; 86007c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 86017c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 86027c478bd9Sstevel@tonic-gate 86037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86047c478bd9Sstevel@tonic-gate "ohci_handle_one_xfer_completion: tw = 0x%p", tw); 86057c478bd9Sstevel@tonic-gate 86067c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 86077c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER); 86087c478bd9Sstevel@tonic-gate 86097c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 86107c478bd9Sstevel@tonic-gate 86117c478bd9Sstevel@tonic-gate /* 86127c478bd9Sstevel@tonic-gate * For one xfer, we need to copy back data ptr 86137c478bd9Sstevel@tonic-gate * and free current request 86147c478bd9Sstevel@tonic-gate */ 86157c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))-> 86167c478bd9Sstevel@tonic-gate intr_data = ((usb_intr_req_t *) 86177c478bd9Sstevel@tonic-gate (tw->tw_curr_xfer_reqp))->intr_data; 86187c478bd9Sstevel@tonic-gate 86197c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL; 86207c478bd9Sstevel@tonic-gate 86217c478bd9Sstevel@tonic-gate /* Now free duplicate current request */ 86227c478bd9Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp); 86237c478bd9Sstevel@tonic-gate 86247c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 86257c478bd9Sstevel@tonic-gate ph->p_req_count--; 86267c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 86277c478bd9Sstevel@tonic-gate 86287c478bd9Sstevel@tonic-gate /* Make client's request the current request */ 86297c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 86307c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 86317c478bd9Sstevel@tonic-gate } 86327c478bd9Sstevel@tonic-gate 86337c478bd9Sstevel@tonic-gate 86347c478bd9Sstevel@tonic-gate /* 86357c478bd9Sstevel@tonic-gate * ohci_handle_isoc_td: 86367c478bd9Sstevel@tonic-gate * 86377c478bd9Sstevel@tonic-gate * Handle an isochronous Transfer Descriptor (TD). 86387c478bd9Sstevel@tonic-gate */ 86397c478bd9Sstevel@tonic-gate /* ARGSUSED */ 86407c478bd9Sstevel@tonic-gate static void 86417c478bd9Sstevel@tonic-gate ohci_handle_isoc_td( 86427c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 86437c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 86447c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 86457c478bd9Sstevel@tonic-gate ohci_td_t *td, 86467c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 86477c478bd9Sstevel@tonic-gate { 86487c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 86497c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 86507c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp = 86517c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 86527c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 86537c478bd9Sstevel@tonic-gate 86547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86557c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: pp=0x%p tw=0x%p td=0x%p" 86567c478bd9Sstevel@tonic-gate "isoc_reqp=0%p data=0x%p", pp, tw, td, curr_isoc_reqp, 86577c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_data); 86587c478bd9Sstevel@tonic-gate 86597c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 86607c478bd9Sstevel@tonic-gate 86617c478bd9Sstevel@tonic-gate /* 86627c478bd9Sstevel@tonic-gate * Decrement the TDs counter and check whether all the isoc 86637c478bd9Sstevel@tonic-gate * data has been send or received. If TDs counter reaches 86647c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 86657c478bd9Sstevel@tonic-gate * isoc request. Otherwise wait for completion of other isoc 86667c478bd9Sstevel@tonic-gate * TDs or transactions on this pipe. 86677c478bd9Sstevel@tonic-gate */ 86687c478bd9Sstevel@tonic-gate if (--tw->tw_num_tds != 0) { 86697c478bd9Sstevel@tonic-gate 86707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86717c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: Number of TDs %d", tw->tw_num_tds); 86727c478bd9Sstevel@tonic-gate 86737c478bd9Sstevel@tonic-gate return; 86747c478bd9Sstevel@tonic-gate } 86757c478bd9Sstevel@tonic-gate 86767c478bd9Sstevel@tonic-gate /* 86777c478bd9Sstevel@tonic-gate * If this is a isoc in pipe, return the data to the client. 86787c478bd9Sstevel@tonic-gate * For a isoc out pipe, there is no need to do anything. 86797c478bd9Sstevel@tonic-gate */ 86807c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 86817c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86827c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: Isoc out pipe, isoc_reqp=0x%p," 86837c478bd9Sstevel@tonic-gate "data=0x%p", curr_isoc_reqp, curr_isoc_reqp->isoc_data); 86847c478bd9Sstevel@tonic-gate 86857c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length, 86867c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 86877c478bd9Sstevel@tonic-gate 86887c478bd9Sstevel@tonic-gate /* Do the callback */ 86897c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 86907c478bd9Sstevel@tonic-gate 86917c478bd9Sstevel@tonic-gate return; 86927c478bd9Sstevel@tonic-gate } 86937c478bd9Sstevel@tonic-gate 86947c478bd9Sstevel@tonic-gate /* Decrement number of IN isochronous request count */ 86957c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 86967c478bd9Sstevel@tonic-gate 86977c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to send message to upstream */ 86987c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK); 86997c478bd9Sstevel@tonic-gate 87007c478bd9Sstevel@tonic-gate /* 87017c478bd9Sstevel@tonic-gate * If isochronous pipe state is still active, insert next isochronous 87027c478bd9Sstevel@tonic-gate * request into the Host Controller's isochronous list. 87037c478bd9Sstevel@tonic-gate */ 87047c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) { 87057c478bd9Sstevel@tonic-gate return; 87067c478bd9Sstevel@tonic-gate } 87077c478bd9Sstevel@tonic-gate 87087c478bd9Sstevel@tonic-gate if ((error = ohci_allocate_periodic_in_resource(ohcip, pp, tw, 0)) == 87097c478bd9Sstevel@tonic-gate USB_SUCCESS) { 87107c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 87117c478bd9Sstevel@tonic-gate 87127c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL); 87137c478bd9Sstevel@tonic-gate 87147c478bd9Sstevel@tonic-gate tw->tw_num_tds = 87157c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_pkts_count / OHCI_ISOC_PKTS_PER_TD; 87167c478bd9Sstevel@tonic-gate if (curr_isoc_reqp->isoc_pkts_count % OHCI_ISOC_PKTS_PER_TD) { 87177c478bd9Sstevel@tonic-gate tw->tw_num_tds++; 87187c478bd9Sstevel@tonic-gate } 87197c478bd9Sstevel@tonic-gate 87207c478bd9Sstevel@tonic-gate if (ohci_allocate_tds_for_tw(ohcip, tw, tw->tw_num_tds) != 87217c478bd9Sstevel@tonic-gate USB_SUCCESS) { 87227c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 87237c478bd9Sstevel@tonic-gate error = USB_FAILURE; 87247c478bd9Sstevel@tonic-gate } 87257c478bd9Sstevel@tonic-gate } 87267c478bd9Sstevel@tonic-gate 87277c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS || 87287c478bd9Sstevel@tonic-gate ohci_insert_isoc_req(ohcip, pp, tw, 0) != USB_SUCCESS) { 87297c478bd9Sstevel@tonic-gate /* 87307c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 87317c478bd9Sstevel@tonic-gate * resource. Don't insert any more isoch polling 87327c478bd9Sstevel@tonic-gate * requests. 87337c478bd9Sstevel@tonic-gate */ 87347c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 87357c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 87367c478bd9Sstevel@tonic-gate 87377c478bd9Sstevel@tonic-gate } else { 87387c478bd9Sstevel@tonic-gate /* Increment number of IN isochronous request count */ 87397c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 87407c478bd9Sstevel@tonic-gate 87417c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 87427c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 87437c478bd9Sstevel@tonic-gate } 87447c478bd9Sstevel@tonic-gate } 87457c478bd9Sstevel@tonic-gate 87467c478bd9Sstevel@tonic-gate 87477c478bd9Sstevel@tonic-gate /* 87487c478bd9Sstevel@tonic-gate * ohci_sendup_td_message: 87497c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback 87507c478bd9Sstevel@tonic-gate */ 87517c478bd9Sstevel@tonic-gate static void 87527c478bd9Sstevel@tonic-gate ohci_sendup_td_message( 87537c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 87547c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 87557c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 87567c478bd9Sstevel@tonic-gate ohci_td_t *td, 87577c478bd9Sstevel@tonic-gate usb_cr_t error) 87587c478bd9Sstevel@tonic-gate { 87597c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 87607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 87617c478bd9Sstevel@tonic-gate size_t length = 0, skip_len = 0; 87627c478bd9Sstevel@tonic-gate mblk_t *mp; 87637c478bd9Sstevel@tonic-gate uchar_t *buf; 87647c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp; 87657c478bd9Sstevel@tonic-gate 87667c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 87677c478bd9Sstevel@tonic-gate 87687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 87697c478bd9Sstevel@tonic-gate "ohci_sendup_td_message:"); 87707c478bd9Sstevel@tonic-gate 87717c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 87727c478bd9Sstevel@tonic-gate 87737c478bd9Sstevel@tonic-gate length = tw->tw_length; 87747c478bd9Sstevel@tonic-gate 87757c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 87767c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 87777c478bd9Sstevel@tonic-gate /* 87787c478bd9Sstevel@tonic-gate * Get the correct length, adjust it for the setup size 87797c478bd9Sstevel@tonic-gate * which is not part of the data length in control end 87807c478bd9Sstevel@tonic-gate * points. Update tw->tw_length for future references. 87817c478bd9Sstevel@tonic-gate */ 87827c478bd9Sstevel@tonic-gate tw->tw_length = length = length - SETUP_SIZE; 87837c478bd9Sstevel@tonic-gate 87847c478bd9Sstevel@tonic-gate /* Set the length of the buffer to skip */ 87857c478bd9Sstevel@tonic-gate skip_len = SETUP_SIZE; 87867c478bd9Sstevel@tonic-gate 87877c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_ctrl_phase) != OHCI_CTRL_DATA_PHASE) { 87887c478bd9Sstevel@tonic-gate break; 87897c478bd9Sstevel@tonic-gate } 87907c478bd9Sstevel@tonic-gate /* FALLTHRU */ 87917c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 87927c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 87937c478bd9Sstevel@tonic-gate /* 87947c478bd9Sstevel@tonic-gate * If error is "data overrun", do not check for the 87957c478bd9Sstevel@tonic-gate * "CurrentBufferPointer" and return whatever data 87967c478bd9Sstevel@tonic-gate * received to the client driver. 87977c478bd9Sstevel@tonic-gate */ 87987c478bd9Sstevel@tonic-gate if (error == USB_CR_DATA_OVERRUN) { 87997c478bd9Sstevel@tonic-gate break; 88007c478bd9Sstevel@tonic-gate } 88017c478bd9Sstevel@tonic-gate 88027c478bd9Sstevel@tonic-gate /* 88037c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor 88047c478bd9Sstevel@tonic-gate * (TD) is not equal to zero, then we received less 88057c478bd9Sstevel@tonic-gate * data from the device than requested by us. In that 88067c478bd9Sstevel@tonic-gate * case, get the actual received data size. 88077c478bd9Sstevel@tonic-gate */ 88087c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) { 88097c478bd9Sstevel@tonic-gate 88107c478bd9Sstevel@tonic-gate length = Get_TD(td->hctd_cbp) - 88117c478bd9Sstevel@tonic-gate tw->tw_cookie.dmac_address - skip_len; 88127c478bd9Sstevel@tonic-gate 88137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 88147c478bd9Sstevel@tonic-gate "ohci_sendup_qtd_message: requested data %lu " 88157c478bd9Sstevel@tonic-gate "received data %lu", tw->tw_length, length); 88167c478bd9Sstevel@tonic-gate } 88177c478bd9Sstevel@tonic-gate 88187c478bd9Sstevel@tonic-gate break; 88197c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 88207c478bd9Sstevel@tonic-gate default: 88217c478bd9Sstevel@tonic-gate break; 88227c478bd9Sstevel@tonic-gate } 88237c478bd9Sstevel@tonic-gate 88247c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */ 88257c478bd9Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf + skip_len; 88267c478bd9Sstevel@tonic-gate 88277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 88287c478bd9Sstevel@tonic-gate "ohci_sendup_qtd_message: length %lu error %d", length, error); 88297c478bd9Sstevel@tonic-gate 88307c478bd9Sstevel@tonic-gate /* Get the message block */ 88317c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 88327c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 88337c478bd9Sstevel@tonic-gate mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data; 88347c478bd9Sstevel@tonic-gate break; 88357c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 88367c478bd9Sstevel@tonic-gate mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data; 88377c478bd9Sstevel@tonic-gate break; 88387c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 88397c478bd9Sstevel@tonic-gate mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data; 88407c478bd9Sstevel@tonic-gate break; 88417c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 88427c478bd9Sstevel@tonic-gate mp = ((usb_isoc_req_t *)curr_xfer_reqp)->isoc_data; 88437c478bd9Sstevel@tonic-gate break; 88447c478bd9Sstevel@tonic-gate } 88457c478bd9Sstevel@tonic-gate 88467c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 88477c478bd9Sstevel@tonic-gate 88487c478bd9Sstevel@tonic-gate if (length) { 88497c478bd9Sstevel@tonic-gate /* 88507c478bd9Sstevel@tonic-gate * Update kstat byte counts 88517c478bd9Sstevel@tonic-gate * The control endpoints don't have direction bits so in 88527c478bd9Sstevel@tonic-gate * order for control stats to be counted correctly an in 88537c478bd9Sstevel@tonic-gate * bit must be faked on a control read. 88547c478bd9Sstevel@tonic-gate */ 88557c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 88567c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) { 88577c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, length, 88587c478bd9Sstevel@tonic-gate eptd->bmAttributes, USB_EP_DIR_IN); 88597c478bd9Sstevel@tonic-gate } else { 88607c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, length, 88617c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 88627c478bd9Sstevel@tonic-gate } 88637c478bd9Sstevel@tonic-gate 88647c478bd9Sstevel@tonic-gate /* Sync IO buffer */ 88657c478bd9Sstevel@tonic-gate Sync_IO_Buffer(tw->tw_dmahandle, length); 88667c478bd9Sstevel@tonic-gate 88677c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 88687c478bd9Sstevel@tonic-gate ddi_rep_get8(tw->tw_accesshandle, 88697c478bd9Sstevel@tonic-gate mp->b_rptr, buf, length, DDI_DEV_AUTOINCR); 88707c478bd9Sstevel@tonic-gate 88717c478bd9Sstevel@tonic-gate /* Increment the write pointer */ 88727c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length; 88737c478bd9Sstevel@tonic-gate } else { 88747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 88757c478bd9Sstevel@tonic-gate "ohci_sendup_td_message: Zero length packet"); 88767c478bd9Sstevel@tonic-gate } 88777c478bd9Sstevel@tonic-gate 88787c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, error); 88797c478bd9Sstevel@tonic-gate } 88807c478bd9Sstevel@tonic-gate 88817c478bd9Sstevel@tonic-gate 88827c478bd9Sstevel@tonic-gate /* 88837c478bd9Sstevel@tonic-gate * Miscellaneous functions 88847c478bd9Sstevel@tonic-gate */ 88857c478bd9Sstevel@tonic-gate 88867c478bd9Sstevel@tonic-gate /* 88877c478bd9Sstevel@tonic-gate * ohci_obtain_state: 88887c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 88897c478bd9Sstevel@tonic-gate */ 88907c478bd9Sstevel@tonic-gate ohci_state_t * 88917c478bd9Sstevel@tonic-gate ohci_obtain_state(dev_info_t *dip) 88927c478bd9Sstevel@tonic-gate { 88937c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 88947c478bd9Sstevel@tonic-gate ohci_state_t *state = ddi_get_soft_state( 88957c478bd9Sstevel@tonic-gate ohci_statep, instance); 88967c478bd9Sstevel@tonic-gate 88977c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 88987c478bd9Sstevel@tonic-gate 88997c478bd9Sstevel@tonic-gate return (state); 89007c478bd9Sstevel@tonic-gate } 89017c478bd9Sstevel@tonic-gate 89027c478bd9Sstevel@tonic-gate 89037c478bd9Sstevel@tonic-gate /* 89047c478bd9Sstevel@tonic-gate * ohci_state_is_operational: 89057c478bd9Sstevel@tonic-gate * 89067c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 89077c478bd9Sstevel@tonic-gate */ 89087c478bd9Sstevel@tonic-gate int 89097c478bd9Sstevel@tonic-gate ohci_state_is_operational(ohci_state_t *ohcip) 89107c478bd9Sstevel@tonic-gate { 89117c478bd9Sstevel@tonic-gate int val; 89127c478bd9Sstevel@tonic-gate 89137c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 89147c478bd9Sstevel@tonic-gate 89157c478bd9Sstevel@tonic-gate switch (ohcip->ohci_hc_soft_state) { 89167c478bd9Sstevel@tonic-gate case OHCI_CTLR_INIT_STATE: 89177c478bd9Sstevel@tonic-gate case OHCI_CTLR_SUSPEND_STATE: 89187c478bd9Sstevel@tonic-gate val = USB_FAILURE; 89197c478bd9Sstevel@tonic-gate break; 89207c478bd9Sstevel@tonic-gate case OHCI_CTLR_OPERATIONAL_STATE: 89217c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 89227c478bd9Sstevel@tonic-gate break; 89237c478bd9Sstevel@tonic-gate case OHCI_CTLR_ERROR_STATE: 89247c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 89257c478bd9Sstevel@tonic-gate break; 89267c478bd9Sstevel@tonic-gate default: 89277c478bd9Sstevel@tonic-gate val = USB_FAILURE; 89287c478bd9Sstevel@tonic-gate break; 89297c478bd9Sstevel@tonic-gate } 89307c478bd9Sstevel@tonic-gate 89317c478bd9Sstevel@tonic-gate return (val); 89327c478bd9Sstevel@tonic-gate } 89337c478bd9Sstevel@tonic-gate 89347c478bd9Sstevel@tonic-gate 89357c478bd9Sstevel@tonic-gate /* 89367c478bd9Sstevel@tonic-gate * ohci_do_soft_reset 89377c478bd9Sstevel@tonic-gate * 89387c478bd9Sstevel@tonic-gate * Do soft reset of ohci host controller. 89397c478bd9Sstevel@tonic-gate */ 89407c478bd9Sstevel@tonic-gate int 89417c478bd9Sstevel@tonic-gate ohci_do_soft_reset(ohci_state_t *ohcip) 89427c478bd9Sstevel@tonic-gate { 89437c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 89447c478bd9Sstevel@tonic-gate timeout_id_t xfer_timer_id, rh_timer_id; 89457c478bd9Sstevel@tonic-gate ohci_regs_t *ohci_save_regs; 89467c478bd9Sstevel@tonic-gate ohci_td_t *done_head; 89477c478bd9Sstevel@tonic-gate 89487c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 89497c478bd9Sstevel@tonic-gate 89507c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 89517c478bd9Sstevel@tonic-gate ohcip->ohci_hc_error++; 89527c478bd9Sstevel@tonic-gate 89537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89547c478bd9Sstevel@tonic-gate "ohci_do_soft_reset:" 89557c478bd9Sstevel@tonic-gate "Reset ohci host controller 0x%x", ohcip->ohci_hc_error); 89567c478bd9Sstevel@tonic-gate 89577c478bd9Sstevel@tonic-gate /* 89587c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 89597c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 89607c478bd9Sstevel@tonic-gate * fails. 89617c478bd9Sstevel@tonic-gate */ 89627c478bd9Sstevel@tonic-gate ohci_save_regs = (ohci_regs_t *) 89637c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ohci_regs_t), KM_NOSLEEP); 89647c478bd9Sstevel@tonic-gate 89657c478bd9Sstevel@tonic-gate if (ohci_save_regs == NULL) { 89667c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89677c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: kmem_zalloc failed"); 89687c478bd9Sstevel@tonic-gate 89697c478bd9Sstevel@tonic-gate return (USB_FAILURE); 89707c478bd9Sstevel@tonic-gate } 89717c478bd9Sstevel@tonic-gate 89727c478bd9Sstevel@tonic-gate /* Save current ohci registers */ 89737c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_control = Get_OpReg(hcr_control); 89747c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_cmd_status = Get_OpReg(hcr_cmd_status); 89757c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_intr_enable = Get_OpReg(hcr_intr_enable); 89767c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_periodic_strt = Get_OpReg(hcr_periodic_strt); 89777c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_frame_interval = Get_OpReg(hcr_frame_interval); 89787c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_HCCA = Get_OpReg(hcr_HCCA); 89797c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_bulk_head = Get_OpReg(hcr_bulk_head); 89807c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_ctrl_head = Get_OpReg(hcr_ctrl_head); 89817c478bd9Sstevel@tonic-gate 89827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89837c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Save reg = 0x%p", ohci_save_regs); 89847c478bd9Sstevel@tonic-gate 89857c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 89867c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE | 89877c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE))); 89887c478bd9Sstevel@tonic-gate 89897c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SO | 89907c478bd9Sstevel@tonic-gate HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE | 89917c478bd9Sstevel@tonic-gate HCR_INTR_FNO | HCR_INTR_SOF | HCR_INTR_MIE); 89927c478bd9Sstevel@tonic-gate 89937c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 89947c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 89957c478bd9Sstevel@tonic-gate 89967c478bd9Sstevel@tonic-gate /* Root hub interrupt pipe timeout id */ 89977c478bd9Sstevel@tonic-gate rh_timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id; 89987c478bd9Sstevel@tonic-gate 89997c478bd9Sstevel@tonic-gate /* Stop the root hub interrupt timer */ 90007c478bd9Sstevel@tonic-gate if (rh_timer_id) { 90017c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0; 90027c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state = 90037c478bd9Sstevel@tonic-gate OHCI_PIPE_STATE_IDLE; 90047c478bd9Sstevel@tonic-gate 90057c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 90067c478bd9Sstevel@tonic-gate (void) untimeout(rh_timer_id); 90077c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 90087c478bd9Sstevel@tonic-gate } 90097c478bd9Sstevel@tonic-gate 90107c478bd9Sstevel@tonic-gate /* Transfer timeout id */ 90117c478bd9Sstevel@tonic-gate xfer_timer_id = ohcip->ohci_timer_id; 90127c478bd9Sstevel@tonic-gate 90137c478bd9Sstevel@tonic-gate /* Stop the global transfer timer */ 90147c478bd9Sstevel@tonic-gate if (xfer_timer_id) { 90157c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0; 90167c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 90177c478bd9Sstevel@tonic-gate (void) untimeout(xfer_timer_id); 90187c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 90197c478bd9Sstevel@tonic-gate } 90207c478bd9Sstevel@tonic-gate 90217c478bd9Sstevel@tonic-gate /* Process any pending HCCA DoneHead */ 90227c478bd9Sstevel@tonic-gate done_head = (ohci_td_t *)(uintptr_t) 90237c478bd9Sstevel@tonic-gate (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & HCCA_DONE_HEAD_MASK); 90247c478bd9Sstevel@tonic-gate 90257c478bd9Sstevel@tonic-gate if (done_head) { 90267c478bd9Sstevel@tonic-gate /* Reset the done head to NULL */ 90277c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL); 90287c478bd9Sstevel@tonic-gate 90297c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head); 90307c478bd9Sstevel@tonic-gate } 90317c478bd9Sstevel@tonic-gate 90327c478bd9Sstevel@tonic-gate /* Process any pending hcr_done_head value */ 90337c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_done_head)) { 90347c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, 90357c478bd9Sstevel@tonic-gate (ohci_td_t *)(uintptr_t)Get_OpReg(hcr_done_head)); 90367c478bd9Sstevel@tonic-gate } 90377c478bd9Sstevel@tonic-gate 90387c478bd9Sstevel@tonic-gate /* Do soft reset of ohci host controller */ 90397c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET); 90407c478bd9Sstevel@tonic-gate 90417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 90427c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Reset in progress"); 90437c478bd9Sstevel@tonic-gate 90447c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 90457c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESET_TIMEWAIT); 90467c478bd9Sstevel@tonic-gate 90477c478bd9Sstevel@tonic-gate /* Reset HCCA HcFrameNumber */ 90487c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaFrameNo, 0x00000000); 90497c478bd9Sstevel@tonic-gate 90507c478bd9Sstevel@tonic-gate /* 90517c478bd9Sstevel@tonic-gate * Restore previous saved HC register value 90527c478bd9Sstevel@tonic-gate * into the current HC registers. 90537c478bd9Sstevel@tonic-gate */ 90547c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_strt, (uint32_t) 90557c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_periodic_strt); 90567c478bd9Sstevel@tonic-gate 90577c478bd9Sstevel@tonic-gate Set_OpReg(hcr_frame_interval, (uint32_t) 90587c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_frame_interval); 90597c478bd9Sstevel@tonic-gate 90607c478bd9Sstevel@tonic-gate Set_OpReg(hcr_done_head, 0x0); 90617c478bd9Sstevel@tonic-gate 90627c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, 0x0); 90637c478bd9Sstevel@tonic-gate 90647c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, (uint32_t) 90657c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_bulk_head); 90667c478bd9Sstevel@tonic-gate 90677c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, 0x0); 90687c478bd9Sstevel@tonic-gate 90697c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, (uint32_t) 90707c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_ctrl_head); 90717c478bd9Sstevel@tonic-gate 90727c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_curr, 0x0); 90737c478bd9Sstevel@tonic-gate 90747c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, (uint32_t) 90757c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_HCCA); 90767c478bd9Sstevel@tonic-gate 90777c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_status, 0x0); 90787c478bd9Sstevel@tonic-gate 90797c478bd9Sstevel@tonic-gate /* 90807c478bd9Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except 90817c478bd9Sstevel@tonic-gate * Root Hub Status change interrupt. 90827c478bd9Sstevel@tonic-gate */ 90837c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, 90847c478bd9Sstevel@tonic-gate HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE | 90857c478bd9Sstevel@tonic-gate HCR_INTR_FNO | HCR_INTR_SOF | HCR_INTR_MIE); 90867c478bd9Sstevel@tonic-gate 90877c478bd9Sstevel@tonic-gate /* Start Control and Bulk list processing */ 90887c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, (HCR_STATUS_CLF | HCR_STATUS_BLF)); 90897c478bd9Sstevel@tonic-gate 90907c478bd9Sstevel@tonic-gate /* 90917c478bd9Sstevel@tonic-gate * Start up Control, Bulk, Periodic and Isochronous lists 90927c478bd9Sstevel@tonic-gate * processing. 90937c478bd9Sstevel@tonic-gate */ 90947c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (uint32_t) 90957c478bd9Sstevel@tonic-gate (ohci_save_regs->hcr_control & (~HCR_CONTROL_HCFS))); 90967c478bd9Sstevel@tonic-gate 90977c478bd9Sstevel@tonic-gate /* 90987c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 90997c478bd9Sstevel@tonic-gate * HC registers. 91007c478bd9Sstevel@tonic-gate */ 91017c478bd9Sstevel@tonic-gate kmem_free((void *) ohci_save_regs, sizeof (ohci_regs_t)); 91027c478bd9Sstevel@tonic-gate 91037c478bd9Sstevel@tonic-gate /* Resume the host controller */ 91047c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) & 91057c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESUME)); 91067c478bd9Sstevel@tonic-gate 91077c478bd9Sstevel@tonic-gate /* Wait for resume to complete */ 91087c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESUME_TIMEWAIT); 91097c478bd9Sstevel@tonic-gate 91107c478bd9Sstevel@tonic-gate /* Set the Host Controller Functional State to Operational */ 91117c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) & 91127c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_OPERAT)); 91137c478bd9Sstevel@tonic-gate 91147c478bd9Sstevel@tonic-gate /* Wait 10ms for HC to start sending SOF */ 91157c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 91167c478bd9Sstevel@tonic-gate 91177c478bd9Sstevel@tonic-gate /* 91187c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few 91197c478bd9Sstevel@tonic-gate * milliseconds. 91207c478bd9Sstevel@tonic-gate */ 91217c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip); 91227c478bd9Sstevel@tonic-gate 91237c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 91247c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 91257c478bd9Sstevel@tonic-gate 91267c478bd9Sstevel@tonic-gate /* 91277c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for few 91287c478bd9Sstevel@tonic-gate * milliseconds. 91297c478bd9Sstevel@tonic-gate */ 91307c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip); 91317c478bd9Sstevel@tonic-gate 91327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 91337c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Before Frm No 0x%llx After Frm No 0x%llx", 91347c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 91357c478bd9Sstevel@tonic-gate 91367c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 91377c478bd9Sstevel@tonic-gate 91387c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 91397c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Soft reset failed"); 91407c478bd9Sstevel@tonic-gate 91417c478bd9Sstevel@tonic-gate return (USB_FAILURE); 91427c478bd9Sstevel@tonic-gate } 91437c478bd9Sstevel@tonic-gate 91447c478bd9Sstevel@tonic-gate /* Start the timer for the root hub interrupt pipe polling */ 91457c478bd9Sstevel@tonic-gate if (rh_timer_id) { 91467c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 91477c478bd9Sstevel@tonic-gate timeout(ohci_handle_root_hub_status_change, 91487c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME)); 91497c478bd9Sstevel@tonic-gate 91507c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub. 91517c478bd9Sstevel@tonic-gate rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE; 91527c478bd9Sstevel@tonic-gate } 91537c478bd9Sstevel@tonic-gate 91547c478bd9Sstevel@tonic-gate /* Start the global timer */ 91557c478bd9Sstevel@tonic-gate if (xfer_timer_id) { 91567c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = timeout(ohci_xfer_timeout_handler, 91577c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(1000000)); 91587c478bd9Sstevel@tonic-gate } 91597c478bd9Sstevel@tonic-gate 91607c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 91617c478bd9Sstevel@tonic-gate } 91627c478bd9Sstevel@tonic-gate 91637c478bd9Sstevel@tonic-gate 91647c478bd9Sstevel@tonic-gate /* 91657c478bd9Sstevel@tonic-gate * ohci_get_current_frame_number: 91667c478bd9Sstevel@tonic-gate * 91677c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 91687c478bd9Sstevel@tonic-gate */ 91697c478bd9Sstevel@tonic-gate usb_frame_number_t 91707c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohci_state_t *ohcip) 91717c478bd9Sstevel@tonic-gate { 91727c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 91737c478bd9Sstevel@tonic-gate usb_frame_number_t ohci_fno, frame_number; 91747c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = 91757c478bd9Sstevel@tonic-gate &ohcip->ohci_save_intr_sts; 91767c478bd9Sstevel@tonic-gate 91777c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 91787c478bd9Sstevel@tonic-gate 91797c478bd9Sstevel@tonic-gate /* 91807c478bd9Sstevel@tonic-gate * Sync HCCA area only if this function 91817c478bd9Sstevel@tonic-gate * is invoked in non interrupt context. 91827c478bd9Sstevel@tonic-gate */ 91837c478bd9Sstevel@tonic-gate if (!(ohci_intr_sts->ohci_intr_flag & 91847c478bd9Sstevel@tonic-gate OHCI_INTR_HANDLING)) { 91857c478bd9Sstevel@tonic-gate 91867c478bd9Sstevel@tonic-gate /* Sync HCCA area */ 91877c478bd9Sstevel@tonic-gate Sync_HCCA(ohcip); 91887c478bd9Sstevel@tonic-gate } 91897c478bd9Sstevel@tonic-gate 91907c478bd9Sstevel@tonic-gate ohci_fno = ohcip->ohci_fno; 91917c478bd9Sstevel@tonic-gate frame_number = Get_HCCA(ohcip->ohci_hccap->HccaFrameNo); 91927c478bd9Sstevel@tonic-gate 91937c478bd9Sstevel@tonic-gate /* 91947c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 91957c478bd9Sstevel@tonic-gate * 91967c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 91977c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ohci driver 91987c478bd9Sstevel@tonic-gate * gets an FrameNumberOverflow (FNO) interrupt that will 91997c478bd9Sstevel@tonic-gate * adjust Frame higher part. 92007c478bd9Sstevel@tonic-gate * 92017c478bd9Sstevel@tonic-gate * Refer ohci specification 1.0a, section 5.4, page 86. 92027c478bd9Sstevel@tonic-gate */ 92037c478bd9Sstevel@tonic-gate usb_frame_number = ((frame_number & 0x7FFF) | ohci_fno) + 92047c478bd9Sstevel@tonic-gate (((frame_number & 0xFFFF) ^ ohci_fno) & 0x8000); 92057c478bd9Sstevel@tonic-gate 92067c478bd9Sstevel@tonic-gate return (usb_frame_number); 92077c478bd9Sstevel@tonic-gate } 92087c478bd9Sstevel@tonic-gate 92097c478bd9Sstevel@tonic-gate 92107c478bd9Sstevel@tonic-gate /* 92117c478bd9Sstevel@tonic-gate * ohci_cpr_cleanup: 92127c478bd9Sstevel@tonic-gate * 92137c478bd9Sstevel@tonic-gate * Cleanup ohci state and other ohci specific informations across 92147c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 92157c478bd9Sstevel@tonic-gate */ 92167c478bd9Sstevel@tonic-gate static void 92177c478bd9Sstevel@tonic-gate ohci_cpr_cleanup(ohci_state_t *ohcip) 92187c478bd9Sstevel@tonic-gate { 92197c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 92207c478bd9Sstevel@tonic-gate 92217c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 92227c478bd9Sstevel@tonic-gate ohcip->ohci_fno = 0; 92237c478bd9Sstevel@tonic-gate 92247c478bd9Sstevel@tonic-gate /* Reset Schedule Overrrun Error Counter */ 92257c478bd9Sstevel@tonic-gate ohcip->ohci_so_error = 0; 92267c478bd9Sstevel@tonic-gate 92277c478bd9Sstevel@tonic-gate /* Reset HCCA HcFrameNumber */ 92287c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaFrameNo, 0x00000000); 92297c478bd9Sstevel@tonic-gate } 92307c478bd9Sstevel@tonic-gate 92317c478bd9Sstevel@tonic-gate 92327c478bd9Sstevel@tonic-gate /* 92337c478bd9Sstevel@tonic-gate * ohci_get_xfer_attrs: 92347c478bd9Sstevel@tonic-gate * 92357c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 92367c478bd9Sstevel@tonic-gate */ 92377c478bd9Sstevel@tonic-gate static usb_req_attrs_t 92387c478bd9Sstevel@tonic-gate ohci_get_xfer_attrs( 92397c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 92407c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 92417c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 92427c478bd9Sstevel@tonic-gate { 92437c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 92447c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = 0; 92457c478bd9Sstevel@tonic-gate 92467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 92477c478bd9Sstevel@tonic-gate "ohci_get_xfer_attrs:"); 92487c478bd9Sstevel@tonic-gate 92497c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 92507c478bd9Sstevel@tonic-gate 92517c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 92527c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 92537c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 92547c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 92557c478bd9Sstevel@tonic-gate break; 92567c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 92577c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 92587c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 92597c478bd9Sstevel@tonic-gate break; 92607c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 92617c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 92627c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 92637c478bd9Sstevel@tonic-gate break; 92647c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 92657c478bd9Sstevel@tonic-gate attrs = ((usb_isoc_req_t *) 92667c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->isoc_attributes; 92677c478bd9Sstevel@tonic-gate break; 92687c478bd9Sstevel@tonic-gate } 92697c478bd9Sstevel@tonic-gate 92707c478bd9Sstevel@tonic-gate return (attrs); 92717c478bd9Sstevel@tonic-gate } 92727c478bd9Sstevel@tonic-gate 92737c478bd9Sstevel@tonic-gate 92747c478bd9Sstevel@tonic-gate /* 92757c478bd9Sstevel@tonic-gate * ohci_allocate_periodic_in_resource 92767c478bd9Sstevel@tonic-gate * 92777c478bd9Sstevel@tonic-gate * Allocate interrupt/isochronous request structure for the 92787c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. 92797c478bd9Sstevel@tonic-gate */ 92807c478bd9Sstevel@tonic-gate static int 92817c478bd9Sstevel@tonic-gate ohci_allocate_periodic_in_resource( 92827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 92837c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 92847c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 92857c478bd9Sstevel@tonic-gate usb_flags_t flags) 92867c478bd9Sstevel@tonic-gate { 92877c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 92887c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes; 92897c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 92907c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp; 92917c478bd9Sstevel@tonic-gate usb_opaque_t client_periodic_in_reqp; 92927c478bd9Sstevel@tonic-gate size_t length = 0; 92937c478bd9Sstevel@tonic-gate 92947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 92957c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource:" 92967c478bd9Sstevel@tonic-gate "pp = 0x%p tw = 0x%p flags = 0x%x", pp, tw, flags); 92977c478bd9Sstevel@tonic-gate 92987c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 92997c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp == NULL); 93007c478bd9Sstevel@tonic-gate 93017c478bd9Sstevel@tonic-gate /* Get the client periodic in request pointer */ 93027c478bd9Sstevel@tonic-gate client_periodic_in_reqp = pp->pp_client_periodic_in_reqp; 93037c478bd9Sstevel@tonic-gate 93047c478bd9Sstevel@tonic-gate /* 93057c478bd9Sstevel@tonic-gate * If it a periodic IN request and periodic request is NULL, 93067c478bd9Sstevel@tonic-gate * allocate corresponding usb periodic IN request for the 93077c478bd9Sstevel@tonic-gate * current periodic polling request and copy the information 93087c478bd9Sstevel@tonic-gate * from the saved periodic request structure. 93097c478bd9Sstevel@tonic-gate */ 93107c478bd9Sstevel@tonic-gate if ((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 93117c478bd9Sstevel@tonic-gate 93127c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp) { 93137c478bd9Sstevel@tonic-gate 93147c478bd9Sstevel@tonic-gate /* Get the interrupt transfer length */ 93157c478bd9Sstevel@tonic-gate length = ((usb_intr_req_t *) 93167c478bd9Sstevel@tonic-gate client_periodic_in_reqp)->intr_len; 93177c478bd9Sstevel@tonic-gate 93187c478bd9Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req( 93197c478bd9Sstevel@tonic-gate ph->p_dip, (usb_intr_req_t *) 93207c478bd9Sstevel@tonic-gate client_periodic_in_reqp, length, flags); 93217c478bd9Sstevel@tonic-gate } else { 93227c478bd9Sstevel@tonic-gate curr_intr_reqp = usb_alloc_intr_req( 93237c478bd9Sstevel@tonic-gate ph->p_dip, length, flags); 93247c478bd9Sstevel@tonic-gate } 93257c478bd9Sstevel@tonic-gate 93267c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) { 93277c478bd9Sstevel@tonic-gate 93287c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 93297c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource: Interrupt " 93307c478bd9Sstevel@tonic-gate "request structure allocation failed"); 93317c478bd9Sstevel@tonic-gate 93327c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 93337c478bd9Sstevel@tonic-gate } 93347c478bd9Sstevel@tonic-gate 93357c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp == NULL) { 93367c478bd9Sstevel@tonic-gate /* For polled mode */ 93377c478bd9Sstevel@tonic-gate curr_intr_reqp-> 93387c478bd9Sstevel@tonic-gate intr_attributes = USB_ATTRS_SHORT_XFER_OK; 93397c478bd9Sstevel@tonic-gate curr_intr_reqp-> 93407c478bd9Sstevel@tonic-gate intr_len = ph->p_ep.wMaxPacketSize; 93417c478bd9Sstevel@tonic-gate } else { 93427c478bd9Sstevel@tonic-gate /* Check and save the timeout value */ 93437c478bd9Sstevel@tonic-gate tw->tw_timeout = (curr_intr_reqp->intr_attributes & 93447c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) ? 93457c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_timeout: 0; 93467c478bd9Sstevel@tonic-gate } 93477c478bd9Sstevel@tonic-gate 93487c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)curr_intr_reqp; 93497c478bd9Sstevel@tonic-gate tw->tw_length = curr_intr_reqp->intr_len; 93507c478bd9Sstevel@tonic-gate } else { 93517c478bd9Sstevel@tonic-gate ASSERT(client_periodic_in_reqp != NULL); 93527c478bd9Sstevel@tonic-gate 93537c478bd9Sstevel@tonic-gate curr_isoc_reqp = usba_hcdi_dup_isoc_req(ph->p_dip, 93547c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)client_periodic_in_reqp, flags); 93557c478bd9Sstevel@tonic-gate 93567c478bd9Sstevel@tonic-gate if (curr_isoc_reqp == NULL) { 93577c478bd9Sstevel@tonic-gate 93587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 93597c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource: Isochronous" 93607c478bd9Sstevel@tonic-gate "request structure allocation failed"); 93617c478bd9Sstevel@tonic-gate 93627c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 93637c478bd9Sstevel@tonic-gate } 93647c478bd9Sstevel@tonic-gate 93657c478bd9Sstevel@tonic-gate /* 93667c478bd9Sstevel@tonic-gate * Save the client's isochronous request pointer and 93677c478bd9Sstevel@tonic-gate * length of isochronous transfer in transfer wrapper. 93687c478bd9Sstevel@tonic-gate * The dup'ed request is saved in pp_client_periodic_in_reqp 93697c478bd9Sstevel@tonic-gate */ 93707c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = 93717c478bd9Sstevel@tonic-gate (usb_opaque_t)pp->pp_client_periodic_in_reqp; 93727c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = (usb_opaque_t)curr_isoc_reqp; 93737c478bd9Sstevel@tonic-gate tw->tw_length = curr_isoc_reqp->isoc_pkts_length; 93747c478bd9Sstevel@tonic-gate } 93757c478bd9Sstevel@tonic-gate 93767c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 93777c478bd9Sstevel@tonic-gate ph->p_req_count++; 93787c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 93797c478bd9Sstevel@tonic-gate 93807c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_ACTIVE; 93817c478bd9Sstevel@tonic-gate 93827c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 93837c478bd9Sstevel@tonic-gate } 93847c478bd9Sstevel@tonic-gate 93857c478bd9Sstevel@tonic-gate 93867c478bd9Sstevel@tonic-gate /* 93877c478bd9Sstevel@tonic-gate * ohci_wait_for_sof: 93887c478bd9Sstevel@tonic-gate * 93897c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 93907c478bd9Sstevel@tonic-gate */ 93917c478bd9Sstevel@tonic-gate static int 93927c478bd9Sstevel@tonic-gate ohci_wait_for_sof(ohci_state_t *ohcip) 93937c478bd9Sstevel@tonic-gate { 93947c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 93957c478bd9Sstevel@tonic-gate clock_t sof_time_wait; 93967c478bd9Sstevel@tonic-gate int rval, sof_wait_count; 93977c478bd9Sstevel@tonic-gate 93987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 93997c478bd9Sstevel@tonic-gate "ohci_wait_for_sof"); 94007c478bd9Sstevel@tonic-gate 94017c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 94027c478bd9Sstevel@tonic-gate 94037c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 94047c478bd9Sstevel@tonic-gate 94057c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 94067c478bd9Sstevel@tonic-gate 94077c478bd9Sstevel@tonic-gate return (rval); 94087c478bd9Sstevel@tonic-gate } 94097c478bd9Sstevel@tonic-gate 94107c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 94117c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz(OHCI_MAX_SOF_TIMEWAIT * 1000000); 94127c478bd9Sstevel@tonic-gate 94137c478bd9Sstevel@tonic-gate sof_wait_count = 0; 94147c478bd9Sstevel@tonic-gate 94157c478bd9Sstevel@tonic-gate /* 94167c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for the 94177c478bd9Sstevel@tonic-gate * SOF interrupt event. 94187c478bd9Sstevel@tonic-gate */ 94197c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip); 94207c478bd9Sstevel@tonic-gate 94217c478bd9Sstevel@tonic-gate while (sof_wait_count < MAX_SOF_WAIT_COUNT) { 94227c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */ 94237c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF); 94247c478bd9Sstevel@tonic-gate 94257c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_intr_enable) & HCR_INTR_SOF); 94267c478bd9Sstevel@tonic-gate 94277c478bd9Sstevel@tonic-gate /* Wait for the SOF or timeout event */ 94287c478bd9Sstevel@tonic-gate rval = cv_timedwait(&ohcip->ohci_SOF_cv, 94297c478bd9Sstevel@tonic-gate &ohcip->ohci_int_mutex, ddi_get_lbolt() + sof_time_wait); 94307c478bd9Sstevel@tonic-gate 94317c478bd9Sstevel@tonic-gate /* 94327c478bd9Sstevel@tonic-gate * Get the current usb frame number after woken up either 94337c478bd9Sstevel@tonic-gate * from SOF interrupt or timer expired event. 94347c478bd9Sstevel@tonic-gate */ 94357c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip); 94367c478bd9Sstevel@tonic-gate 94377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 94387c478bd9Sstevel@tonic-gate "ohci_wait_for_sof: before 0x%llx, after 0x%llx", 94397c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 94407c478bd9Sstevel@tonic-gate 94417c478bd9Sstevel@tonic-gate /* 94427c478bd9Sstevel@tonic-gate * Return failure, if we are woken up becuase of timer expired 94437c478bd9Sstevel@tonic-gate * event and if usb frame number has not been changed. 94447c478bd9Sstevel@tonic-gate */ 94457c478bd9Sstevel@tonic-gate if ((rval == -1) && 94467c478bd9Sstevel@tonic-gate (after_frame_number <= before_frame_number)) { 94477c478bd9Sstevel@tonic-gate 94487c478bd9Sstevel@tonic-gate if ((ohci_do_soft_reset(ohcip)) != USB_SUCCESS) { 94497c478bd9Sstevel@tonic-gate 94507c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 94517c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, "No SOF interrupts"); 94527c478bd9Sstevel@tonic-gate 94537c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 94547c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = 94557c478bd9Sstevel@tonic-gate OHCI_CTLR_ERROR_STATE; 94567c478bd9Sstevel@tonic-gate 94577c478bd9Sstevel@tonic-gate return (USB_FAILURE); 94587c478bd9Sstevel@tonic-gate } 94597c478bd9Sstevel@tonic-gate 94607c478bd9Sstevel@tonic-gate /* Get new usb frame number */ 94617c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number = 94627c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohcip); 94637c478bd9Sstevel@tonic-gate } 94647c478bd9Sstevel@tonic-gate 94657c478bd9Sstevel@tonic-gate ASSERT(after_frame_number >= before_frame_number); 94667c478bd9Sstevel@tonic-gate 94677c478bd9Sstevel@tonic-gate before_frame_number = after_frame_number; 94687c478bd9Sstevel@tonic-gate sof_wait_count++; 94697c478bd9Sstevel@tonic-gate } 94707c478bd9Sstevel@tonic-gate 94717c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 94727c478bd9Sstevel@tonic-gate } 94737c478bd9Sstevel@tonic-gate 94747c478bd9Sstevel@tonic-gate 94757c478bd9Sstevel@tonic-gate /* 94767c478bd9Sstevel@tonic-gate * ohci_pipe_cleanup 94777c478bd9Sstevel@tonic-gate * 94787c478bd9Sstevel@tonic-gate * Cleanup ohci pipe. 94797c478bd9Sstevel@tonic-gate */ 94807c478bd9Sstevel@tonic-gate static void 94817c478bd9Sstevel@tonic-gate ohci_pipe_cleanup( 94827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 94837c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 94847c478bd9Sstevel@tonic-gate { 94857c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 94867c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 94877c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 94887c478bd9Sstevel@tonic-gate uint_t pipe_state = pp->pp_state; 94897c478bd9Sstevel@tonic-gate uint_t bit = 0; 94907c478bd9Sstevel@tonic-gate 94917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 94927c478bd9Sstevel@tonic-gate "ohci_pipe_cleanup: ph = 0x%p", ph); 94937c478bd9Sstevel@tonic-gate 94947c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 94957c478bd9Sstevel@tonic-gate 94967c478bd9Sstevel@tonic-gate switch (pipe_state) { 94977c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_CLOSE: 94987c478bd9Sstevel@tonic-gate if (OHCI_NON_PERIODIC_ENDPOINT(eptd)) { 94997c478bd9Sstevel@tonic-gate 95007c478bd9Sstevel@tonic-gate bit = ((eptd->bmAttributes & 95017c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) ? 95027c478bd9Sstevel@tonic-gate HCR_CONTROL_CLE: HCR_CONTROL_BLE; 95037c478bd9Sstevel@tonic-gate 95047c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 95057c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(bit))); 95067c478bd9Sstevel@tonic-gate 95077c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 95087c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip); 95097c478bd9Sstevel@tonic-gate 95107c478bd9Sstevel@tonic-gate break; 95117c478bd9Sstevel@tonic-gate } 95127c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 95137c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_RESET: 95147c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_STOP_POLLING: 95157c478bd9Sstevel@tonic-gate /* 95167c478bd9Sstevel@tonic-gate * Set the sKip bit to stop all transactions on 95177c478bd9Sstevel@tonic-gate * this pipe 95187c478bd9Sstevel@tonic-gate */ 95197c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, pp, SET_sKip, 95207c478bd9Sstevel@tonic-gate OHCI_FLAGS_SLEEP | OHCI_FLAGS_DMA_SYNC); 95217c478bd9Sstevel@tonic-gate 95227c478bd9Sstevel@tonic-gate break; 95237c478bd9Sstevel@tonic-gate default: 95247c478bd9Sstevel@tonic-gate return; 95257c478bd9Sstevel@tonic-gate } 95267c478bd9Sstevel@tonic-gate 95277c478bd9Sstevel@tonic-gate /* 95287c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and 95297c478bd9Sstevel@tonic-gate * to send results to upstream. 95307c478bd9Sstevel@tonic-gate */ 95317c478bd9Sstevel@tonic-gate ohci_wait_for_transfers_completion(ohcip, pp); 95327c478bd9Sstevel@tonic-gate 95337c478bd9Sstevel@tonic-gate /* Save the data toggle information */ 95347c478bd9Sstevel@tonic-gate ohci_save_data_toggle(ohcip, ph); 95357c478bd9Sstevel@tonic-gate 95367c478bd9Sstevel@tonic-gate /* 95377c478bd9Sstevel@tonic-gate * Traverse the list of TD's on this endpoint and 95387c478bd9Sstevel@tonic-gate * these TD's have outstanding transfer requests. 95397c478bd9Sstevel@tonic-gate * Since the list processing is stopped, these tds 95407c478bd9Sstevel@tonic-gate * can be deallocated. 95417c478bd9Sstevel@tonic-gate */ 95427c478bd9Sstevel@tonic-gate ohci_traverse_tds(ohcip, ph); 95437c478bd9Sstevel@tonic-gate 95447c478bd9Sstevel@tonic-gate /* 95457c478bd9Sstevel@tonic-gate * If all of the endpoint's TD's have been deallocated, 95467c478bd9Sstevel@tonic-gate * then the DMA mappings can be torn down. If not there 95477c478bd9Sstevel@tonic-gate * are some TD's on the done list that have not been 95487c478bd9Sstevel@tonic-gate * processed. Tag these TD's so that they are thrown 95497c478bd9Sstevel@tonic-gate * away when the done list is processed. 95507c478bd9Sstevel@tonic-gate */ 95517c478bd9Sstevel@tonic-gate ohci_done_list_tds(ohcip, ph); 95527c478bd9Sstevel@tonic-gate 95537c478bd9Sstevel@tonic-gate /* Do callbacks for all unfinished requests */ 95547c478bd9Sstevel@tonic-gate ohci_handle_outstanding_requests(ohcip, pp); 95557c478bd9Sstevel@tonic-gate 95567c478bd9Sstevel@tonic-gate /* Free DMA resources */ 95577c478bd9Sstevel@tonic-gate ohci_free_dma_resources(ohcip, ph); 95587c478bd9Sstevel@tonic-gate 95597c478bd9Sstevel@tonic-gate switch (pipe_state) { 95607c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_CLOSE: 95617c478bd9Sstevel@tonic-gate completion_reason = USB_CR_PIPE_CLOSING; 95627c478bd9Sstevel@tonic-gate break; 95637c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_RESET: 95647c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_STOP_POLLING: 95657c478bd9Sstevel@tonic-gate /* Set completion reason */ 95667c478bd9Sstevel@tonic-gate completion_reason = (pipe_state == 95677c478bd9Sstevel@tonic-gate OHCI_PIPE_STATE_RESET) ? 95687c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING; 95697c478bd9Sstevel@tonic-gate 95707c478bd9Sstevel@tonic-gate /* Restore the data toggle information */ 95717c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(ohcip, ph); 95727c478bd9Sstevel@tonic-gate 95737c478bd9Sstevel@tonic-gate /* 95747c478bd9Sstevel@tonic-gate * Clear the sKip bit to restart all the 95757c478bd9Sstevel@tonic-gate * transactions on this pipe. 95767c478bd9Sstevel@tonic-gate */ 95777c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, pp, 95787c478bd9Sstevel@tonic-gate CLEAR_sKip, OHCI_FLAGS_NOSLEEP); 95797c478bd9Sstevel@tonic-gate 95807c478bd9Sstevel@tonic-gate /* Set pipe state to idle */ 95817c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 95827c478bd9Sstevel@tonic-gate 95837c478bd9Sstevel@tonic-gate break; 95847c478bd9Sstevel@tonic-gate } 95857c478bd9Sstevel@tonic-gate 95867c478bd9Sstevel@tonic-gate ASSERT((Get_ED(pp->pp_ept->hced_tailp) & HC_EPT_TD_TAIL) == 95877c478bd9Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) & HC_EPT_TD_HEAD)); 95887c478bd9Sstevel@tonic-gate 95897c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head == NULL) && (pp->pp_tw_tail == NULL)); 95907c478bd9Sstevel@tonic-gate 95917c478bd9Sstevel@tonic-gate /* 95927c478bd9Sstevel@tonic-gate * Do the callback for the original client 95937c478bd9Sstevel@tonic-gate * periodic IN request. 95947c478bd9Sstevel@tonic-gate */ 95957c478bd9Sstevel@tonic-gate if ((OHCI_PERIODIC_ENDPOINT(eptd)) && 95967c478bd9Sstevel@tonic-gate ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == 95977c478bd9Sstevel@tonic-gate USB_EP_DIR_IN)) { 95987c478bd9Sstevel@tonic-gate 95997c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback( 96007c478bd9Sstevel@tonic-gate ohcip, pp, completion_reason); 96017c478bd9Sstevel@tonic-gate } 96027c478bd9Sstevel@tonic-gate } 96037c478bd9Sstevel@tonic-gate 96047c478bd9Sstevel@tonic-gate 96057c478bd9Sstevel@tonic-gate /* 96067c478bd9Sstevel@tonic-gate * ohci_wait_for_transfers_completion: 96077c478bd9Sstevel@tonic-gate * 96087c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and to send results 96097c478bd9Sstevel@tonic-gate * to upstream. 96107c478bd9Sstevel@tonic-gate */ 96117c478bd9Sstevel@tonic-gate static void 96127c478bd9Sstevel@tonic-gate ohci_wait_for_transfers_completion( 96137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 96147c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 96157c478bd9Sstevel@tonic-gate { 96167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head; 96177c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw; 96187c478bd9Sstevel@tonic-gate clock_t xfer_cmpl_time_wait; 96197c478bd9Sstevel@tonic-gate ohci_td_t *tailp, *headp, *nextp; 96207c478bd9Sstevel@tonic-gate ohci_td_t *head_td, *next_td; 96217c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 96227c478bd9Sstevel@tonic-gate int rval; 96237c478bd9Sstevel@tonic-gate 96247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 96257c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: pp = 0x%p", pp); 96267c478bd9Sstevel@tonic-gate 96277c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 96287c478bd9Sstevel@tonic-gate 96297c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 96307c478bd9Sstevel@tonic-gate Get_ED(ept->hced_headp) & (uint32_t)HC_EPT_TD_HEAD)); 96317c478bd9Sstevel@tonic-gate 96327c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 96337c478bd9Sstevel@tonic-gate Get_ED(ept->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL)); 96347c478bd9Sstevel@tonic-gate 96357c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 96367c478bd9Sstevel@tonic-gate 96377c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 96387c478bd9Sstevel@tonic-gate 96397c478bd9Sstevel@tonic-gate return; 96407c478bd9Sstevel@tonic-gate } 96417c478bd9Sstevel@tonic-gate 96427c478bd9Sstevel@tonic-gate pp->pp_count_done_tds = 0; 96437c478bd9Sstevel@tonic-gate 96447c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */ 96457c478bd9Sstevel@tonic-gate next_tw = head_tw; 96467c478bd9Sstevel@tonic-gate while (next_tw) { 96477c478bd9Sstevel@tonic-gate head_td = (ohci_td_t *)next_tw->tw_hctd_head; 96487c478bd9Sstevel@tonic-gate next_td = head_td; 96497c478bd9Sstevel@tonic-gate 96507c478bd9Sstevel@tonic-gate if (head_td) { 96517c478bd9Sstevel@tonic-gate /* 96527c478bd9Sstevel@tonic-gate * Walk through each TD for this transfer 96537c478bd9Sstevel@tonic-gate * wrapper. If a TD still exists, then it 96547c478bd9Sstevel@tonic-gate * is currently on the done list. 96557c478bd9Sstevel@tonic-gate */ 96567c478bd9Sstevel@tonic-gate while (next_td) { 96577c478bd9Sstevel@tonic-gate 96587c478bd9Sstevel@tonic-gate nextp = headp; 96597c478bd9Sstevel@tonic-gate 96607c478bd9Sstevel@tonic-gate while (nextp != tailp) { 96617c478bd9Sstevel@tonic-gate 96627c478bd9Sstevel@tonic-gate /* TD is on the ED */ 96637c478bd9Sstevel@tonic-gate if (nextp == next_td) { 96647c478bd9Sstevel@tonic-gate break; 96657c478bd9Sstevel@tonic-gate } 96667c478bd9Sstevel@tonic-gate 96677c478bd9Sstevel@tonic-gate nextp = (ohci_td_t *) 96687c478bd9Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip, 96697c478bd9Sstevel@tonic-gate (Get_TD(nextp->hctd_next_td) & 96707c478bd9Sstevel@tonic-gate HC_EPT_TD_TAIL))); 96717c478bd9Sstevel@tonic-gate } 96727c478bd9Sstevel@tonic-gate 96737c478bd9Sstevel@tonic-gate if (nextp == tailp) { 96747c478bd9Sstevel@tonic-gate pp->pp_count_done_tds++; 96757c478bd9Sstevel@tonic-gate } 96767c478bd9Sstevel@tonic-gate 96777c478bd9Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip, 96787c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td)); 96797c478bd9Sstevel@tonic-gate } 96807c478bd9Sstevel@tonic-gate } 96817c478bd9Sstevel@tonic-gate 96827c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next; 96837c478bd9Sstevel@tonic-gate } 96847c478bd9Sstevel@tonic-gate 96857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 96867c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: count_done_tds = 0x%x", 96877c478bd9Sstevel@tonic-gate pp->pp_count_done_tds); 96887c478bd9Sstevel@tonic-gate 96897c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_tds) { 96907c478bd9Sstevel@tonic-gate 96917c478bd9Sstevel@tonic-gate return; 96927c478bd9Sstevel@tonic-gate } 96937c478bd9Sstevel@tonic-gate 96947c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 96957c478bd9Sstevel@tonic-gate xfer_cmpl_time_wait = drv_usectohz(OHCI_XFER_CMPL_TIMEWAIT * 1000000); 96967c478bd9Sstevel@tonic-gate 96977c478bd9Sstevel@tonic-gate (void) cv_timedwait(&pp->pp_xfer_cmpl_cv, 96987c478bd9Sstevel@tonic-gate &ohcip->ohci_int_mutex, 96997c478bd9Sstevel@tonic-gate ddi_get_lbolt() + xfer_cmpl_time_wait); 97007c478bd9Sstevel@tonic-gate 97017c478bd9Sstevel@tonic-gate if (pp->pp_count_done_tds) { 97027c478bd9Sstevel@tonic-gate 97037c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 97047c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: No transfers " 97057c478bd9Sstevel@tonic-gate "completion confirmation received for 0x%x requests", 97067c478bd9Sstevel@tonic-gate pp->pp_count_done_tds); 97077c478bd9Sstevel@tonic-gate } 97087c478bd9Sstevel@tonic-gate } 97097c478bd9Sstevel@tonic-gate 97107c478bd9Sstevel@tonic-gate 97117c478bd9Sstevel@tonic-gate /* 97127c478bd9Sstevel@tonic-gate * ohci_check_for_transfers_completion: 97137c478bd9Sstevel@tonic-gate * 97147c478bd9Sstevel@tonic-gate * Check whether anybody is waiting for transfers completion event. If so, send 97157c478bd9Sstevel@tonic-gate * this event and also stop initiating any new transfers on this pipe. 97167c478bd9Sstevel@tonic-gate */ 97177c478bd9Sstevel@tonic-gate static void 97187c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion( 97197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 97207c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 97217c478bd9Sstevel@tonic-gate { 97227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 97237c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion: pp = 0x%p", pp); 97247c478bd9Sstevel@tonic-gate 97257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 97267c478bd9Sstevel@tonic-gate 97277c478bd9Sstevel@tonic-gate if ((pp->pp_state == OHCI_PIPE_STATE_STOP_POLLING) && 97287c478bd9Sstevel@tonic-gate (pp->pp_error == USB_CR_NO_RESOURCES) && 97297c478bd9Sstevel@tonic-gate (pp->pp_cur_periodic_req_cnt == 0)) { 97307c478bd9Sstevel@tonic-gate 97317c478bd9Sstevel@tonic-gate /* Reset pipe error to zero */ 97327c478bd9Sstevel@tonic-gate pp->pp_error = 0; 97337c478bd9Sstevel@tonic-gate 97347c478bd9Sstevel@tonic-gate /* Do callback for original request */ 97357c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback( 97367c478bd9Sstevel@tonic-gate ohcip, pp, USB_CR_NO_RESOURCES); 97377c478bd9Sstevel@tonic-gate } 97387c478bd9Sstevel@tonic-gate 97397c478bd9Sstevel@tonic-gate if (pp->pp_count_done_tds) { 97407c478bd9Sstevel@tonic-gate 97417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 97427c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion:" 97437c478bd9Sstevel@tonic-gate "count_done_tds = 0x%x", pp->pp_count_done_tds); 97447c478bd9Sstevel@tonic-gate 97457c478bd9Sstevel@tonic-gate /* Decrement the done td count */ 97467c478bd9Sstevel@tonic-gate pp->pp_count_done_tds--; 97477c478bd9Sstevel@tonic-gate 97487c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_tds) { 97497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 97507c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion:" 97517c478bd9Sstevel@tonic-gate "Sent transfers completion event pp = 0x%p", pp); 97527c478bd9Sstevel@tonic-gate 97537c478bd9Sstevel@tonic-gate /* Send the transfer completion signal */ 97547c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_xfer_cmpl_cv); 97557c478bd9Sstevel@tonic-gate } 97567c478bd9Sstevel@tonic-gate } 97577c478bd9Sstevel@tonic-gate } 97587c478bd9Sstevel@tonic-gate 97597c478bd9Sstevel@tonic-gate 97607c478bd9Sstevel@tonic-gate /* 97617c478bd9Sstevel@tonic-gate * ohci_save_data_toggle: 97627c478bd9Sstevel@tonic-gate * 97637c478bd9Sstevel@tonic-gate * Save the data toggle information. 97647c478bd9Sstevel@tonic-gate */ 97657c478bd9Sstevel@tonic-gate static void 97667c478bd9Sstevel@tonic-gate ohci_save_data_toggle( 97677c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 97687c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 97697c478bd9Sstevel@tonic-gate { 97707c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 97717c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 97727c478bd9Sstevel@tonic-gate uint_t data_toggle; 97737c478bd9Sstevel@tonic-gate usb_cr_t error = pp->pp_error; 97747c478bd9Sstevel@tonic-gate ohci_ed_t *ed = pp->pp_ept; 97757c478bd9Sstevel@tonic-gate ohci_td_t *headp, *tailp; 97767c478bd9Sstevel@tonic-gate 97777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 97787c478bd9Sstevel@tonic-gate "ohci_save_data_toggle: ph = 0x%p", ph); 97797c478bd9Sstevel@tonic-gate 97807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 97817c478bd9Sstevel@tonic-gate 97827c478bd9Sstevel@tonic-gate /* Reset the pipe error value */ 97837c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_OK; 97847c478bd9Sstevel@tonic-gate 97857c478bd9Sstevel@tonic-gate /* Return immediately if it is a control or isoc pipe */ 97867c478bd9Sstevel@tonic-gate if (((eptd->bmAttributes & USB_EP_ATTR_MASK) == 97877c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || ((eptd->bmAttributes & 97887c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH)) { 97897c478bd9Sstevel@tonic-gate 97907c478bd9Sstevel@tonic-gate return; 97917c478bd9Sstevel@tonic-gate } 97927c478bd9Sstevel@tonic-gate 97937c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 97947c478bd9Sstevel@tonic-gate Get_ED(ed->hced_headp) & (uint32_t)HC_EPT_TD_HEAD)); 97957c478bd9Sstevel@tonic-gate 97967c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 97977c478bd9Sstevel@tonic-gate Get_ED(ed->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL)); 97987c478bd9Sstevel@tonic-gate 97997c478bd9Sstevel@tonic-gate /* 98007c478bd9Sstevel@tonic-gate * Retrieve the data toggle information either from the endpoint 98017c478bd9Sstevel@tonic-gate * (ED) or from the transfer descriptor (TD) depending on the 98027c478bd9Sstevel@tonic-gate * situation. 98037c478bd9Sstevel@tonic-gate */ 98047c478bd9Sstevel@tonic-gate if ((Get_ED(ed->hced_headp) & HC_EPT_Halt) || (headp == tailp)) { 98057c478bd9Sstevel@tonic-gate 98067c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint */ 98077c478bd9Sstevel@tonic-gate data_toggle = (Get_ED(ed->hced_headp) & 98087c478bd9Sstevel@tonic-gate HC_EPT_Carry)? DATA1:DATA0; 98097c478bd9Sstevel@tonic-gate } else { 98107c478bd9Sstevel@tonic-gate /* 98117c478bd9Sstevel@tonic-gate * Retrieve the data toggle information depending on the 98127c478bd9Sstevel@tonic-gate * master data toggle information saved in the transfer 98137c478bd9Sstevel@tonic-gate * descriptor (TD) at the head of the endpoint (ED). 98147c478bd9Sstevel@tonic-gate * 98157c478bd9Sstevel@tonic-gate * Check for master data toggle information . 98167c478bd9Sstevel@tonic-gate */ 98177c478bd9Sstevel@tonic-gate if (Get_TD(headp->hctd_ctrl) & HC_TD_MS_DT) { 98187c478bd9Sstevel@tonic-gate /* Get the data toggle information from td */ 98197c478bd9Sstevel@tonic-gate data_toggle = (Get_TD(headp->hctd_ctrl) & 98207c478bd9Sstevel@tonic-gate HC_TD_DT_1) ? DATA1:DATA0; 98217c478bd9Sstevel@tonic-gate } else { 98227c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint */ 98237c478bd9Sstevel@tonic-gate data_toggle = (Get_ED(ed->hced_headp) & 98247c478bd9Sstevel@tonic-gate HC_EPT_Carry)? DATA1:DATA0; 98257c478bd9Sstevel@tonic-gate } 98267c478bd9Sstevel@tonic-gate } 98277c478bd9Sstevel@tonic-gate 98287c478bd9Sstevel@tonic-gate /* 98297c478bd9Sstevel@tonic-gate * If error is STALL, then, set 98307c478bd9Sstevel@tonic-gate * data toggle to zero. 98317c478bd9Sstevel@tonic-gate */ 98327c478bd9Sstevel@tonic-gate if (error == USB_CR_STALL) { 98337c478bd9Sstevel@tonic-gate data_toggle = DATA0; 98347c478bd9Sstevel@tonic-gate } 98357c478bd9Sstevel@tonic-gate 98367c478bd9Sstevel@tonic-gate /* 98377c478bd9Sstevel@tonic-gate * Save the data toggle information 98387c478bd9Sstevel@tonic-gate * in the usb device structure. 98397c478bd9Sstevel@tonic-gate */ 98407c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 98417c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress, 98427c478bd9Sstevel@tonic-gate data_toggle); 98437c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 98447c478bd9Sstevel@tonic-gate } 98457c478bd9Sstevel@tonic-gate 98467c478bd9Sstevel@tonic-gate 98477c478bd9Sstevel@tonic-gate /* 98487c478bd9Sstevel@tonic-gate * ohci_restore_data_toggle: 98497c478bd9Sstevel@tonic-gate * 98507c478bd9Sstevel@tonic-gate * Restore the data toggle information. 98517c478bd9Sstevel@tonic-gate */ 98527c478bd9Sstevel@tonic-gate static void 98537c478bd9Sstevel@tonic-gate ohci_restore_data_toggle( 98547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 98557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 98567c478bd9Sstevel@tonic-gate { 98577c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 98587c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 98597c478bd9Sstevel@tonic-gate uint_t data_toggle = 0; 98607c478bd9Sstevel@tonic-gate 98617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 98627c478bd9Sstevel@tonic-gate "ohci_restore_data_toggle: ph = 0x%p", ph); 98637c478bd9Sstevel@tonic-gate 98647c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 98657c478bd9Sstevel@tonic-gate 98667c478bd9Sstevel@tonic-gate /* 98677c478bd9Sstevel@tonic-gate * Return immediately if it is a control or isoc pipe. 98687c478bd9Sstevel@tonic-gate */ 98697c478bd9Sstevel@tonic-gate if (((eptd->bmAttributes & USB_EP_ATTR_MASK) == 98707c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || ((eptd->bmAttributes & 98717c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH)) { 98727c478bd9Sstevel@tonic-gate 98737c478bd9Sstevel@tonic-gate return; 98747c478bd9Sstevel@tonic-gate } 98757c478bd9Sstevel@tonic-gate 98767c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 98777c478bd9Sstevel@tonic-gate 98787c478bd9Sstevel@tonic-gate data_toggle = usba_hcdi_get_data_toggle(ph->p_usba_device, 98797c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress); 98807c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress, 98817c478bd9Sstevel@tonic-gate 0); 98827c478bd9Sstevel@tonic-gate 98837c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 98847c478bd9Sstevel@tonic-gate 98857c478bd9Sstevel@tonic-gate /* 98867c478bd9Sstevel@tonic-gate * Restore the data toggle bit depending on the 98877c478bd9Sstevel@tonic-gate * previous data toggle information. 98887c478bd9Sstevel@tonic-gate */ 98897c478bd9Sstevel@tonic-gate if (data_toggle) { 98907c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 98917c478bd9Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) | HC_EPT_Carry); 98927c478bd9Sstevel@tonic-gate } else { 98937c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 98947c478bd9Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) & (~HC_EPT_Carry)); 98957c478bd9Sstevel@tonic-gate } 98967c478bd9Sstevel@tonic-gate } 98977c478bd9Sstevel@tonic-gate 98987c478bd9Sstevel@tonic-gate 98997c478bd9Sstevel@tonic-gate /* 99007c478bd9Sstevel@tonic-gate * ohci_handle_outstanding_requests 99017c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 99027c478bd9Sstevel@tonic-gate * 99037c478bd9Sstevel@tonic-gate * Deallocate interrupt/isochronous request structure for the 99047c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. Do the callbacks for all 99057c478bd9Sstevel@tonic-gate * unfinished requests. 99067c478bd9Sstevel@tonic-gate */ 99077c478bd9Sstevel@tonic-gate void 99087c478bd9Sstevel@tonic-gate ohci_handle_outstanding_requests( 99097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 99107c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 99117c478bd9Sstevel@tonic-gate { 99127c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 99137c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 99147c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *curr_tw; 99157c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw; 99167c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 99177c478bd9Sstevel@tonic-gate 99187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 99197c478bd9Sstevel@tonic-gate "ohci_handle_outstanding_requests: pp = 0x%p", pp); 99207c478bd9Sstevel@tonic-gate 99217c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 99227c478bd9Sstevel@tonic-gate 99237c478bd9Sstevel@tonic-gate /* 99247c478bd9Sstevel@tonic-gate * Deallocate all the pre-allocated interrupt requests 99257c478bd9Sstevel@tonic-gate */ 99267c478bd9Sstevel@tonic-gate next_tw = pp->pp_tw_head; 99277c478bd9Sstevel@tonic-gate 99287c478bd9Sstevel@tonic-gate while (next_tw) { 99297c478bd9Sstevel@tonic-gate curr_tw = next_tw; 99307c478bd9Sstevel@tonic-gate next_tw = curr_tw->tw_next; 99317c478bd9Sstevel@tonic-gate 99327c478bd9Sstevel@tonic-gate curr_xfer_reqp = curr_tw->tw_curr_xfer_reqp; 99337c478bd9Sstevel@tonic-gate 99347c478bd9Sstevel@tonic-gate /* Deallocate current interrupt request */ 99357c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) { 99367c478bd9Sstevel@tonic-gate 99377c478bd9Sstevel@tonic-gate if ((OHCI_PERIODIC_ENDPOINT(eptd)) && 99387c478bd9Sstevel@tonic-gate (curr_tw->tw_direction == HC_TD_IN)) { 99397c478bd9Sstevel@tonic-gate 99407c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 99417c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 99427c478bd9Sstevel@tonic-gate 99437c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 99447c478bd9Sstevel@tonic-gate ohcip, pp, curr_tw); 99457c478bd9Sstevel@tonic-gate } else { 99467c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, 99477c478bd9Sstevel@tonic-gate curr_tw, USB_CR_FLUSHED); 99487c478bd9Sstevel@tonic-gate } 99497c478bd9Sstevel@tonic-gate } 99507c478bd9Sstevel@tonic-gate } 99517c478bd9Sstevel@tonic-gate } 99527c478bd9Sstevel@tonic-gate 99537c478bd9Sstevel@tonic-gate 99547c478bd9Sstevel@tonic-gate /* 99557c478bd9Sstevel@tonic-gate * ohci_deallocate_periodic_in_resource 99567c478bd9Sstevel@tonic-gate * 99577c478bd9Sstevel@tonic-gate * Deallocate interrupt/isochronous request structure for the 99587c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. 99597c478bd9Sstevel@tonic-gate */ 99607c478bd9Sstevel@tonic-gate static void 99617c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 99627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 99637c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 99647c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 99657c478bd9Sstevel@tonic-gate { 99667c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 99677c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes; 99687c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 99697c478bd9Sstevel@tonic-gate 99707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 99717c478bd9Sstevel@tonic-gate "ohci_deallocate_periodic_in_resource: " 99727c478bd9Sstevel@tonic-gate "pp = 0x%p tw = 0x%p", pp, tw); 99737c478bd9Sstevel@tonic-gate 99747c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 99757c478bd9Sstevel@tonic-gate 99767c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp; 99777c478bd9Sstevel@tonic-gate 99787c478bd9Sstevel@tonic-gate /* Check the current periodic in request pointer */ 99797c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) { 99807c478bd9Sstevel@tonic-gate /* 99817c478bd9Sstevel@tonic-gate * Reset periodic in request usb isoch 99827c478bd9Sstevel@tonic-gate * packet request pointers to null. 99837c478bd9Sstevel@tonic-gate */ 99847c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL; 99857c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = NULL; 99867c478bd9Sstevel@tonic-gate 99877c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 99887c478bd9Sstevel@tonic-gate ph->p_req_count--; 99897c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 99907c478bd9Sstevel@tonic-gate 99917c478bd9Sstevel@tonic-gate /* 99927c478bd9Sstevel@tonic-gate * Free pre-allocated interrupt 99937c478bd9Sstevel@tonic-gate * or isochronous requests. 99947c478bd9Sstevel@tonic-gate */ 99957c478bd9Sstevel@tonic-gate switch (ep_attr & USB_EP_ATTR_MASK) { 99967c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 99977c478bd9Sstevel@tonic-gate usb_free_intr_req( 99987c478bd9Sstevel@tonic-gate (usb_intr_req_t *)curr_xfer_reqp); 99997c478bd9Sstevel@tonic-gate break; 100007c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 100017c478bd9Sstevel@tonic-gate usb_free_isoc_req( 100027c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)curr_xfer_reqp); 100037c478bd9Sstevel@tonic-gate break; 100047c478bd9Sstevel@tonic-gate } 100057c478bd9Sstevel@tonic-gate } 100067c478bd9Sstevel@tonic-gate } 100077c478bd9Sstevel@tonic-gate 100087c478bd9Sstevel@tonic-gate 100097c478bd9Sstevel@tonic-gate /* 100107c478bd9Sstevel@tonic-gate * ohci_do_client_periodic_in_req_callback 100117c478bd9Sstevel@tonic-gate * 100127c478bd9Sstevel@tonic-gate * Do callback for the original client periodic IN request. 100137c478bd9Sstevel@tonic-gate */ 100147c478bd9Sstevel@tonic-gate static void 100157c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback( 100167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 100177c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 100187c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 100197c478bd9Sstevel@tonic-gate { 100207c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 100217c478bd9Sstevel@tonic-gate 100227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 100237c478bd9Sstevel@tonic-gate "ohci_do_client_periodic_in_req_callback: " 100247c478bd9Sstevel@tonic-gate "pp = 0x%p cc = 0x%x", pp, completion_reason); 100257c478bd9Sstevel@tonic-gate 100267c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 100277c478bd9Sstevel@tonic-gate 100287c478bd9Sstevel@tonic-gate /* 100297c478bd9Sstevel@tonic-gate * Check for Interrupt/Isochronous IN, whether we need to do 100307c478bd9Sstevel@tonic-gate * callback for the original client's periodic IN request. 100317c478bd9Sstevel@tonic-gate */ 100327c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) { 100337c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 0); 100347c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, NULL, completion_reason); 100357c478bd9Sstevel@tonic-gate } 100367c478bd9Sstevel@tonic-gate } 100377c478bd9Sstevel@tonic-gate 100387c478bd9Sstevel@tonic-gate 100397c478bd9Sstevel@tonic-gate /* 100407c478bd9Sstevel@tonic-gate * ohci_hcdi_callback() 100417c478bd9Sstevel@tonic-gate * 100427c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() other than root hub. 100437c478bd9Sstevel@tonic-gate */ 100447c478bd9Sstevel@tonic-gate static void 100457c478bd9Sstevel@tonic-gate ohci_hcdi_callback( 100467c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 100477c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 100487c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 100497c478bd9Sstevel@tonic-gate { 100507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 100517c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip); 100527c478bd9Sstevel@tonic-gate uchar_t attributes = ph->p_ep.bmAttributes & 100537c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK; 100547c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 100557c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 100567c478bd9Sstevel@tonic-gate uint_t pipe_state = 0; 100577c478bd9Sstevel@tonic-gate 100587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 100597c478bd9Sstevel@tonic-gate "ohci_hcdi_callback: ph = 0x%p, tw = 0x%p, cr = 0x%x", 100607c478bd9Sstevel@tonic-gate ph, tw, completion_reason); 100617c478bd9Sstevel@tonic-gate 100627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 100637c478bd9Sstevel@tonic-gate 100647c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */ 100657c478bd9Sstevel@tonic-gate switch (completion_reason) { 100667c478bd9Sstevel@tonic-gate case USB_CR_OK: 100677c478bd9Sstevel@tonic-gate pipe_state = pp->pp_state; 100687c478bd9Sstevel@tonic-gate break; 100697c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES: 100707c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED: 100717c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 100727c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 100737c478bd9Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_IDLE; 100747c478bd9Sstevel@tonic-gate break; 100757c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING: 100767c478bd9Sstevel@tonic-gate break; 100777c478bd9Sstevel@tonic-gate default: 100787c478bd9Sstevel@tonic-gate /* 100797c478bd9Sstevel@tonic-gate * Set the pipe state to error 100807c478bd9Sstevel@tonic-gate * except for the isoc pipe. 100817c478bd9Sstevel@tonic-gate */ 100827c478bd9Sstevel@tonic-gate if (attributes != USB_EP_ATTR_ISOCH) { 100837c478bd9Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_ERROR; 100847c478bd9Sstevel@tonic-gate pp->pp_error = completion_reason; 100857c478bd9Sstevel@tonic-gate } 100867c478bd9Sstevel@tonic-gate break; 100877c478bd9Sstevel@tonic-gate 100887c478bd9Sstevel@tonic-gate } 100897c478bd9Sstevel@tonic-gate 100907c478bd9Sstevel@tonic-gate pp->pp_state = pipe_state; 100917c478bd9Sstevel@tonic-gate 100927c478bd9Sstevel@tonic-gate if (tw && tw->tw_curr_xfer_reqp) { 100937c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp; 100947c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL; 100957c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = NULL; 100967c478bd9Sstevel@tonic-gate } else { 100977c478bd9Sstevel@tonic-gate ASSERT(pp->pp_client_periodic_in_reqp != NULL); 100987c478bd9Sstevel@tonic-gate 100997c478bd9Sstevel@tonic-gate curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 101007c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 101017c478bd9Sstevel@tonic-gate } 101027c478bd9Sstevel@tonic-gate 101037c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL); 101047c478bd9Sstevel@tonic-gate 101057c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 101067c478bd9Sstevel@tonic-gate 101077c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 101087c478bd9Sstevel@tonic-gate 101097c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 101107c478bd9Sstevel@tonic-gate } 101117c478bd9Sstevel@tonic-gate 101127c478bd9Sstevel@tonic-gate 101137c478bd9Sstevel@tonic-gate /* 101147c478bd9Sstevel@tonic-gate * ohci kstat functions 101157c478bd9Sstevel@tonic-gate */ 101167c478bd9Sstevel@tonic-gate 101177c478bd9Sstevel@tonic-gate /* 101187c478bd9Sstevel@tonic-gate * ohci_create_stats: 101197c478bd9Sstevel@tonic-gate * 101207c478bd9Sstevel@tonic-gate * Allocate and initialize the ohci kstat structures 101217c478bd9Sstevel@tonic-gate */ 101227c478bd9Sstevel@tonic-gate static void 101237c478bd9Sstevel@tonic-gate ohci_create_stats(ohci_state_t *ohcip) 101247c478bd9Sstevel@tonic-gate { 101257c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 101267c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ohcip->ohci_dip); 101277c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 101287c478bd9Sstevel@tonic-gate {"ctrl", "isoch", "bulk", "intr"}; 101297c478bd9Sstevel@tonic-gate uint_t instance = ohcip->ohci_instance; 101307c478bd9Sstevel@tonic-gate ohci_intrs_stats_t *isp; 101317c478bd9Sstevel@tonic-gate int i; 101327c478bd9Sstevel@tonic-gate 101337c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip) == NULL) { 101347c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 101357c478bd9Sstevel@tonic-gate dname, instance); 101367c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip) = kstat_create("usba", instance, 101377c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 101387c478bd9Sstevel@tonic-gate sizeof (ohci_intrs_stats_t) / sizeof (kstat_named_t), 101397c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 101407c478bd9Sstevel@tonic-gate 101417c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) { 101427c478bd9Sstevel@tonic-gate isp = OHCI_INTRS_STATS_DATA(ohcip); 101437c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_total, 101447c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64); 101457c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_not_claimed, 101467c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64); 101477c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_so, 101487c478bd9Sstevel@tonic-gate "Schedule Overruns", KSTAT_DATA_UINT64); 101497c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_wdh, 101507c478bd9Sstevel@tonic-gate "Writeback Done Head", KSTAT_DATA_UINT64); 101517c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_sof, 101527c478bd9Sstevel@tonic-gate "Start Of Frame", KSTAT_DATA_UINT64); 101537c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_rd, 101547c478bd9Sstevel@tonic-gate "Resume Detected", KSTAT_DATA_UINT64); 101557c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_ue, 101567c478bd9Sstevel@tonic-gate "Unrecoverable Error", KSTAT_DATA_UINT64); 101577c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_fno, 101587c478bd9Sstevel@tonic-gate "Frame No. Overflow", KSTAT_DATA_UINT64); 101597c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_rhsc, 101607c478bd9Sstevel@tonic-gate "Root Hub Status Change", KSTAT_DATA_UINT64); 101617c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_oc, 101627c478bd9Sstevel@tonic-gate "Change In Ownership", KSTAT_DATA_UINT64); 101637c478bd9Sstevel@tonic-gate 101647c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip)->ks_private = ohcip; 101657c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip)->ks_update = nulldev; 101667c478bd9Sstevel@tonic-gate kstat_install(OHCI_INTRS_STATS(ohcip)); 101677c478bd9Sstevel@tonic-gate } 101687c478bd9Sstevel@tonic-gate } 101697c478bd9Sstevel@tonic-gate 101707c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip) == NULL) { 101717c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 101727c478bd9Sstevel@tonic-gate dname, instance); 101737c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS(ohcip) = kstat_create("usba", instance, 101747c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 101757c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 101767c478bd9Sstevel@tonic-gate 101777c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip)) { 101787c478bd9Sstevel@tonic-gate kstat_install(OHCI_TOTAL_STATS(ohcip)); 101797c478bd9Sstevel@tonic-gate } 101807c478bd9Sstevel@tonic-gate } 101817c478bd9Sstevel@tonic-gate 101827c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 101837c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i] == NULL) { 101847c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 101857c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 101867c478bd9Sstevel@tonic-gate ohcip->ohci_count_stats[i] = kstat_create("usba", 101877c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 101887c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 101897c478bd9Sstevel@tonic-gate 101907c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i]) { 101917c478bd9Sstevel@tonic-gate kstat_install(ohcip->ohci_count_stats[i]); 101927c478bd9Sstevel@tonic-gate } 101937c478bd9Sstevel@tonic-gate } 101947c478bd9Sstevel@tonic-gate } 101957c478bd9Sstevel@tonic-gate } 101967c478bd9Sstevel@tonic-gate 101977c478bd9Sstevel@tonic-gate 101987c478bd9Sstevel@tonic-gate /* 101997c478bd9Sstevel@tonic-gate * ohci_destroy_stats: 102007c478bd9Sstevel@tonic-gate * 102017c478bd9Sstevel@tonic-gate * Clean up ohci kstat structures 102027c478bd9Sstevel@tonic-gate */ 102037c478bd9Sstevel@tonic-gate static void 102047c478bd9Sstevel@tonic-gate ohci_destroy_stats(ohci_state_t *ohcip) 102057c478bd9Sstevel@tonic-gate { 102067c478bd9Sstevel@tonic-gate int i; 102077c478bd9Sstevel@tonic-gate 102087c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) { 102097c478bd9Sstevel@tonic-gate kstat_delete(OHCI_INTRS_STATS(ohcip)); 102107c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip) = NULL; 102117c478bd9Sstevel@tonic-gate } 102127c478bd9Sstevel@tonic-gate 102137c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip)) { 102147c478bd9Sstevel@tonic-gate kstat_delete(OHCI_TOTAL_STATS(ohcip)); 102157c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS(ohcip) = NULL; 102167c478bd9Sstevel@tonic-gate } 102177c478bd9Sstevel@tonic-gate 102187c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 102197c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i]) { 102207c478bd9Sstevel@tonic-gate kstat_delete(ohcip->ohci_count_stats[i]); 102217c478bd9Sstevel@tonic-gate ohcip->ohci_count_stats[i] = NULL; 102227c478bd9Sstevel@tonic-gate } 102237c478bd9Sstevel@tonic-gate } 102247c478bd9Sstevel@tonic-gate } 102257c478bd9Sstevel@tonic-gate 102267c478bd9Sstevel@tonic-gate 102277c478bd9Sstevel@tonic-gate /* 102287c478bd9Sstevel@tonic-gate * ohci_do_intrs_stats: 102297c478bd9Sstevel@tonic-gate * 102307c478bd9Sstevel@tonic-gate * ohci status information 102317c478bd9Sstevel@tonic-gate */ 102327c478bd9Sstevel@tonic-gate static void 102337c478bd9Sstevel@tonic-gate ohci_do_intrs_stats( 102347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 102357c478bd9Sstevel@tonic-gate int val) 102367c478bd9Sstevel@tonic-gate { 102377c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) { 102387c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->ohci_hcr_intr_total.value.ui64++; 102397c478bd9Sstevel@tonic-gate switch (val) { 102407c478bd9Sstevel@tonic-gate case HCR_INTR_SO: 102417c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102427c478bd9Sstevel@tonic-gate ohci_hcr_intr_so.value.ui64++; 102437c478bd9Sstevel@tonic-gate break; 102447c478bd9Sstevel@tonic-gate case HCR_INTR_WDH: 102457c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102467c478bd9Sstevel@tonic-gate ohci_hcr_intr_wdh.value.ui64++; 102477c478bd9Sstevel@tonic-gate break; 102487c478bd9Sstevel@tonic-gate case HCR_INTR_SOF: 102497c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102507c478bd9Sstevel@tonic-gate ohci_hcr_intr_sof.value.ui64++; 102517c478bd9Sstevel@tonic-gate break; 102527c478bd9Sstevel@tonic-gate case HCR_INTR_RD: 102537c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102547c478bd9Sstevel@tonic-gate ohci_hcr_intr_rd.value.ui64++; 102557c478bd9Sstevel@tonic-gate break; 102567c478bd9Sstevel@tonic-gate case HCR_INTR_UE: 102577c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102587c478bd9Sstevel@tonic-gate ohci_hcr_intr_ue.value.ui64++; 102597c478bd9Sstevel@tonic-gate break; 102607c478bd9Sstevel@tonic-gate case HCR_INTR_FNO: 102617c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102627c478bd9Sstevel@tonic-gate ohci_hcr_intr_fno.value.ui64++; 102637c478bd9Sstevel@tonic-gate break; 102647c478bd9Sstevel@tonic-gate case HCR_INTR_RHSC: 102657c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102667c478bd9Sstevel@tonic-gate ohci_hcr_intr_rhsc.value.ui64++; 102677c478bd9Sstevel@tonic-gate break; 102687c478bd9Sstevel@tonic-gate case HCR_INTR_OC: 102697c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102707c478bd9Sstevel@tonic-gate ohci_hcr_intr_oc.value.ui64++; 102717c478bd9Sstevel@tonic-gate break; 102727c478bd9Sstevel@tonic-gate default: 102737c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 102747c478bd9Sstevel@tonic-gate ohci_hcr_intr_not_claimed.value.ui64++; 102757c478bd9Sstevel@tonic-gate break; 102767c478bd9Sstevel@tonic-gate } 102777c478bd9Sstevel@tonic-gate } 102787c478bd9Sstevel@tonic-gate } 102797c478bd9Sstevel@tonic-gate 102807c478bd9Sstevel@tonic-gate 102817c478bd9Sstevel@tonic-gate /* 102827c478bd9Sstevel@tonic-gate * ohci_do_byte_stats: 102837c478bd9Sstevel@tonic-gate * 102847c478bd9Sstevel@tonic-gate * ohci data xfer information 102857c478bd9Sstevel@tonic-gate */ 102867c478bd9Sstevel@tonic-gate static void 102877c478bd9Sstevel@tonic-gate ohci_do_byte_stats( 102887c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 102897c478bd9Sstevel@tonic-gate size_t len, 102907c478bd9Sstevel@tonic-gate uint8_t attr, 102917c478bd9Sstevel@tonic-gate uint8_t addr) 102927c478bd9Sstevel@tonic-gate { 102937c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 102947c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 102957c478bd9Sstevel@tonic-gate 102967c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 102977c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->reads++; 102987c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->nread += len; 102997c478bd9Sstevel@tonic-gate switch (type) { 103007c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 103017c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->reads++; 103027c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->nread += len; 103037c478bd9Sstevel@tonic-gate break; 103047c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 103057c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->reads++; 103067c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->nread += len; 103077c478bd9Sstevel@tonic-gate break; 103087c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 103097c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->reads++; 103107c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->nread += len; 103117c478bd9Sstevel@tonic-gate break; 103127c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 103137c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->reads++; 103147c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->nread += len; 103157c478bd9Sstevel@tonic-gate break; 103167c478bd9Sstevel@tonic-gate } 103177c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 103187c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->writes++; 103197c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->nwritten += len; 103207c478bd9Sstevel@tonic-gate switch (type) { 103217c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 103227c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->writes++; 103237c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->nwritten += len; 103247c478bd9Sstevel@tonic-gate break; 103257c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 103267c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->writes++; 103277c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->nwritten += len; 103287c478bd9Sstevel@tonic-gate break; 103297c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 103307c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->writes++; 103317c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->nwritten += len; 103327c478bd9Sstevel@tonic-gate break; 103337c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 103347c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->writes++; 103357c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->nwritten += len; 103367c478bd9Sstevel@tonic-gate break; 103377c478bd9Sstevel@tonic-gate } 103387c478bd9Sstevel@tonic-gate } 103397c478bd9Sstevel@tonic-gate } 103407c478bd9Sstevel@tonic-gate 103417c478bd9Sstevel@tonic-gate 103427c478bd9Sstevel@tonic-gate /* 103437c478bd9Sstevel@tonic-gate * ohci_print_op_regs: 103447c478bd9Sstevel@tonic-gate * 103457c478bd9Sstevel@tonic-gate * Print Host Controller's (HC) Operational registers. 103467c478bd9Sstevel@tonic-gate */ 103477c478bd9Sstevel@tonic-gate static void 103487c478bd9Sstevel@tonic-gate ohci_print_op_regs(ohci_state_t *ohcip) 103497c478bd9Sstevel@tonic-gate { 103507c478bd9Sstevel@tonic-gate uint_t i; 103517c478bd9Sstevel@tonic-gate 103527c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103537c478bd9Sstevel@tonic-gate "\n\tOHCI%d Operational Registers\n", 103547c478bd9Sstevel@tonic-gate ddi_get_instance(ohcip->ohci_dip)); 103557c478bd9Sstevel@tonic-gate 103567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103577c478bd9Sstevel@tonic-gate "\thcr_revision: 0x%x \t\thcr_control: 0x%x", 103587c478bd9Sstevel@tonic-gate Get_OpReg(hcr_revision), Get_OpReg(hcr_control)); 103597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103607c478bd9Sstevel@tonic-gate "\thcr_cmd_status: 0x%x \t\thcr_intr_enable: 0x%x", 103617c478bd9Sstevel@tonic-gate Get_OpReg(hcr_cmd_status), Get_OpReg(hcr_intr_enable)); 103627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103637c478bd9Sstevel@tonic-gate "\thcr_intr_disable: 0x%x \thcr_HCCA: 0x%x", 103647c478bd9Sstevel@tonic-gate Get_OpReg(hcr_intr_disable), Get_OpReg(hcr_HCCA)); 103657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103667c478bd9Sstevel@tonic-gate "\thcr_periodic_curr: 0x%x \t\thcr_ctrl_head: 0x%x", 103677c478bd9Sstevel@tonic-gate Get_OpReg(hcr_periodic_curr), Get_OpReg(hcr_ctrl_head)); 103687c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103697c478bd9Sstevel@tonic-gate "\thcr_ctrl_curr: 0x%x \t\thcr_bulk_head: 0x%x", 103707c478bd9Sstevel@tonic-gate Get_OpReg(hcr_ctrl_curr), Get_OpReg(hcr_bulk_head)); 103717c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103727c478bd9Sstevel@tonic-gate "\thcr_bulk_curr: 0x%x \t\thcr_done_head: 0x%x", 103737c478bd9Sstevel@tonic-gate Get_OpReg(hcr_bulk_curr), Get_OpReg(hcr_done_head)); 103747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103757c478bd9Sstevel@tonic-gate "\thcr_frame_interval: 0x%x " 103767c478bd9Sstevel@tonic-gate "\thcr_frame_remaining: 0x%x", Get_OpReg(hcr_frame_interval), 103777c478bd9Sstevel@tonic-gate Get_OpReg(hcr_frame_remaining)); 103787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103797c478bd9Sstevel@tonic-gate "\thcr_frame_number: 0x%x \thcr_periodic_strt: 0x%x", 103807c478bd9Sstevel@tonic-gate Get_OpReg(hcr_frame_number), Get_OpReg(hcr_periodic_strt)); 103817c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103827c478bd9Sstevel@tonic-gate "\thcr_transfer_ls: 0x%x \t\thcr_rh_descriptorA: 0x%x", 103837c478bd9Sstevel@tonic-gate Get_OpReg(hcr_transfer_ls), Get_OpReg(hcr_rh_descriptorA)); 103847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103857c478bd9Sstevel@tonic-gate "\thcr_rh_descriptorB: 0x%x \thcr_rh_status: 0x%x", 103867c478bd9Sstevel@tonic-gate Get_OpReg(hcr_rh_descriptorB), Get_OpReg(hcr_rh_status)); 103877c478bd9Sstevel@tonic-gate 103887c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103897c478bd9Sstevel@tonic-gate "\tRoot hub port status"); 103907c478bd9Sstevel@tonic-gate 103917c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_OpReg(hcr_rh_descriptorA) & HCR_RHA_NDP); i++) { 103927c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 103937c478bd9Sstevel@tonic-gate "\thcr_rh_portstatus 0x%x: 0x%x ", i, 103947c478bd9Sstevel@tonic-gate Get_OpReg(hcr_rh_portstatus[i])); 103957c478bd9Sstevel@tonic-gate } 103967c478bd9Sstevel@tonic-gate } 103977c478bd9Sstevel@tonic-gate 103987c478bd9Sstevel@tonic-gate 103997c478bd9Sstevel@tonic-gate /* 104007c478bd9Sstevel@tonic-gate * ohci_print_ed: 104017c478bd9Sstevel@tonic-gate */ 104027c478bd9Sstevel@tonic-gate static void 104037c478bd9Sstevel@tonic-gate ohci_print_ed( 104047c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 104057c478bd9Sstevel@tonic-gate ohci_ed_t *ed) 104067c478bd9Sstevel@tonic-gate { 104077c478bd9Sstevel@tonic-gate uint_t ctrl = Get_ED(ed->hced_ctrl); 104087c478bd9Sstevel@tonic-gate 104097c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104107c478bd9Sstevel@tonic-gate "ohci_print_ed: ed = 0x%p", (void *)ed); 104117c478bd9Sstevel@tonic-gate 104127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104137c478bd9Sstevel@tonic-gate "\thced_ctrl: 0x%x %s", ctrl, 104147c478bd9Sstevel@tonic-gate ((Get_ED(ed->hced_headp) & HC_EPT_Halt) ? "halted": "")); 104157c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104167c478bd9Sstevel@tonic-gate "\ttoggle carry: 0x%x", Get_ED(ed->hced_headp) & HC_EPT_Carry); 104177c478bd9Sstevel@tonic-gate 104187c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104197c478bd9Sstevel@tonic-gate "\tctrl: 0x%x", Get_ED(ed->hced_ctrl)); 104207c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104217c478bd9Sstevel@tonic-gate "\ttailp: 0x%x", Get_ED(ed->hced_tailp)); 104227c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104237c478bd9Sstevel@tonic-gate "\theadp: 0x%x", Get_ED(ed->hced_headp)); 104247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104257c478bd9Sstevel@tonic-gate "\tnext: 0x%x", Get_ED(ed->hced_next)); 104267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104277c478bd9Sstevel@tonic-gate "\tprev: 0x%x", Get_ED(ed->hced_prev)); 104287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104297c478bd9Sstevel@tonic-gate "\tnode: 0x%x", Get_ED(ed->hced_node)); 104307c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104317c478bd9Sstevel@tonic-gate "\treclaim_next: 0x%x", Get_ED(ed->hced_reclaim_next)); 104327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104337c478bd9Sstevel@tonic-gate "\treclaim_frame: 0x%x", Get_ED(ed->hced_reclaim_frame)); 104347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104357c478bd9Sstevel@tonic-gate "\tstate: 0x%x", Get_ED(ed->hced_state)); 104367c478bd9Sstevel@tonic-gate } 104377c478bd9Sstevel@tonic-gate 104387c478bd9Sstevel@tonic-gate 104397c478bd9Sstevel@tonic-gate /* 104407c478bd9Sstevel@tonic-gate * ohci_print_td: 104417c478bd9Sstevel@tonic-gate */ 104427c478bd9Sstevel@tonic-gate static void 104437c478bd9Sstevel@tonic-gate ohci_print_td( 104447c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 104457c478bd9Sstevel@tonic-gate ohci_td_t *td) 104467c478bd9Sstevel@tonic-gate { 104477c478bd9Sstevel@tonic-gate uint_t i; 104487c478bd9Sstevel@tonic-gate uint_t ctrl = Get_TD(td->hctd_ctrl); 104497c478bd9Sstevel@tonic-gate 104507c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104517c478bd9Sstevel@tonic-gate "ohci_print_td: td = 0x%p", (void *)td); 104527c478bd9Sstevel@tonic-gate 104537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104547c478bd9Sstevel@tonic-gate "\tPID: 0x%x ", ctrl & HC_TD_PID); 104557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104567c478bd9Sstevel@tonic-gate "\tDelay Intr: 0x%x ", ctrl & HC_TD_DI); 104577c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104587c478bd9Sstevel@tonic-gate "\tData Toggle: 0x%x ", ctrl & HC_TD_DT); 104597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104607c478bd9Sstevel@tonic-gate "\tError Count: 0x%x ", ctrl & HC_TD_EC); 104617c478bd9Sstevel@tonic-gate 104627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104637c478bd9Sstevel@tonic-gate "\tctrl: 0x%x ", Get_TD(td->hctd_ctrl)); 104647c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104657c478bd9Sstevel@tonic-gate "\tcbp: 0x%x ", Get_TD(td->hctd_cbp)); 104667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104677c478bd9Sstevel@tonic-gate "\tnext_td: 0x%x ", Get_TD(td->hctd_next_td)); 104687c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104697c478bd9Sstevel@tonic-gate "\tbuf_end: 0x%x ", Get_TD(td->hctd_buf_end)); 104707c478bd9Sstevel@tonic-gate 104717c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 104727c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104737c478bd9Sstevel@tonic-gate "\toffset[%d]: 0x%x ", i, Get_TD(td->hctd_offsets[i])); 104747c478bd9Sstevel@tonic-gate } 104757c478bd9Sstevel@tonic-gate 104767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104777c478bd9Sstevel@tonic-gate "\ttrans_wrapper: 0x%x ", Get_TD(td->hctd_trans_wrapper)); 104787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104797c478bd9Sstevel@tonic-gate "\tstate: 0x%x ", Get_TD(td->hctd_state)); 104807c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104817c478bd9Sstevel@tonic-gate "\ttw_next_td: 0x%x ", Get_TD(td->hctd_tw_next_td)); 104827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104837c478bd9Sstevel@tonic-gate "\tctrl_phase: 0x%x ", Get_TD(td->hctd_ctrl_phase)); 104847c478bd9Sstevel@tonic-gate } 10485