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 502acac7eSsl * Common Development and Distribution License (the "License"). 602acac7eSsl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*29aca3ebSlc * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Open Host Controller Driver (OHCI) 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * The USB Open Host Controller driver is a software driver which interfaces 327c478bd9Sstevel@tonic-gate * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller. 33*29aca3ebSlc * The interface to USB Open Host Controller is defined by the OpenHCI Host 347c478bd9Sstevel@tonic-gate * Controller Interface. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * NOTE: 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Currently OHCI driver does not support the following features 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * - Handle request with multiple TDs under short xfer conditions except for 417c478bd9Sstevel@tonic-gate * bulk transfers. 427c478bd9Sstevel@tonic-gate */ 437c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohcid.h> 447c478bd9Sstevel@tonic-gate 4502acac7eSsl #include <sys/disp.h> 4602acac7eSsl 477c478bd9Sstevel@tonic-gate /* Pointer to the state structure */ 487c478bd9Sstevel@tonic-gate static void *ohci_statep; 497c478bd9Sstevel@tonic-gate 502df1fe9cSrandyf int force_ohci_off = 1; 512df1fe9cSrandyf 527c478bd9Sstevel@tonic-gate /* Number of instances */ 537c478bd9Sstevel@tonic-gate #define OHCI_INSTS 1 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 564610e4a0Sfrits int ohci_ed_pool_size = OHCI_ED_POOL_SIZE; 574610e4a0Sfrits int ohci_td_pool_size = OHCI_TD_POOL_SIZE; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers for 617c478bd9Sstevel@tonic-gate * the 32ms scheduling lists which starts from the HCCA. 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate static uchar_t ohci_index[NUM_INTR_ED_LISTS / 2] = {0x0, 0x8, 0x4, 0xc, 647c478bd9Sstevel@tonic-gate 0x2, 0xa, 0x6, 0xe, 657c478bd9Sstevel@tonic-gate 0x1, 0x9, 0x5, 0xd, 667c478bd9Sstevel@tonic-gate 0x3, 0xb, 0x7, 0xf}; 677c478bd9Sstevel@tonic-gate /* Debugging information */ 687c478bd9Sstevel@tonic-gate uint_t ohci_errmask = (uint_t)PRINT_MASK_ALL; 697c478bd9Sstevel@tonic-gate uint_t ohci_errlevel = USB_LOG_L2; 707c478bd9Sstevel@tonic-gate uint_t ohci_instance_debug = (uint_t)-1; 717c478bd9Sstevel@tonic-gate 729c75c6bfSgovinda /* 739c75c6bfSgovinda * OHCI MSI tunable: 749c75c6bfSgovinda * 759c75c6bfSgovinda * By default MSI is enabled on all supported platforms. 769c75c6bfSgovinda */ 779c75c6bfSgovinda boolean_t ohci_enable_msi = B_TRUE; 789c75c6bfSgovinda 797c478bd9Sstevel@tonic-gate /* 807c478bd9Sstevel@tonic-gate * HCDI entry points 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * The Host Controller Driver Interfaces (HCDI) are the software interfaces 837c478bd9Sstevel@tonic-gate * between the Universal Serial Bus Driver (USBA) and the Host Controller 847c478bd9Sstevel@tonic-gate * Driver (HCD). The HCDI interfaces or entry points are subject to change. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_open( 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_close( 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_reset( 937c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 947c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 957c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_ctrl_xfer( 967c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 977c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 987c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 997c478bd9Sstevel@tonic-gate static int ohci_hcdi_bulk_transfer_size( 1007c478bd9Sstevel@tonic-gate usba_device_t *usba_device, 1017c478bd9Sstevel@tonic-gate size_t *size); 1027c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_bulk_xfer( 1037c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1047c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 1057c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1067c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_intr_xfer( 1077c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1087c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_req, 1097c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1107c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_stop_intr_polling( 1117c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1127c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1137c478bd9Sstevel@tonic-gate static usb_frame_number_t ohci_hcdi_get_current_frame_number( 1147c478bd9Sstevel@tonic-gate usba_device_t *usba_device); 1157c478bd9Sstevel@tonic-gate static uint_t ohci_hcdi_get_max_isoc_pkts( 1167c478bd9Sstevel@tonic-gate usba_device_t *usba_device); 1177c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_isoc_xfer( 1187c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1197c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 1207c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1217c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_stop_isoc_polling( 1227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1237c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * Internal Function Prototypes 1277c478bd9Sstevel@tonic-gate */ 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */ 1307c478bd9Sstevel@tonic-gate static void ohci_set_dma_attributes(ohci_state_t *ohcip); 1317c478bd9Sstevel@tonic-gate static int ohci_allocate_pools(ohci_state_t *ohcip); 1327c478bd9Sstevel@tonic-gate static void ohci_decode_ddi_dma_addr_bind_handle_result( 1337c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1347c478bd9Sstevel@tonic-gate int result); 1357c478bd9Sstevel@tonic-gate static int ohci_map_regs(ohci_state_t *ohcip); 1367c478bd9Sstevel@tonic-gate static int ohci_register_intrs_and_init_mutex( 1377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 1389c75c6bfSgovinda static int ohci_add_intrs(ohci_state_t *ohcip, 1399c75c6bfSgovinda int intr_type); 1407c478bd9Sstevel@tonic-gate static int ohci_init_ctlr(ohci_state_t *ohcip); 1417c478bd9Sstevel@tonic-gate static int ohci_init_hcca(ohci_state_t *ohcip); 1427c478bd9Sstevel@tonic-gate static void ohci_build_interrupt_lattice( 1437c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 1447c478bd9Sstevel@tonic-gate static int ohci_take_control(ohci_state_t *ohcip); 1457c478bd9Sstevel@tonic-gate static usba_hcdi_ops_t *ohci_alloc_hcdi_ops( 1467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */ 1497c478bd9Sstevel@tonic-gate static int ohci_cleanup(ohci_state_t *ohcip); 1509c75c6bfSgovinda static void ohci_rem_intrs(ohci_state_t *ohcip); 1517c478bd9Sstevel@tonic-gate static int ohci_cpr_suspend(ohci_state_t *ohcip); 1527c478bd9Sstevel@tonic-gate static int ohci_cpr_resume(ohci_state_t *ohcip); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */ 1557c478bd9Sstevel@tonic-gate static int ohci_allocate_bandwidth(ohci_state_t *ohcip, 1567c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1577c478bd9Sstevel@tonic-gate uint_t *node); 1587c478bd9Sstevel@tonic-gate static void ohci_deallocate_bandwidth(ohci_state_t *ohcip, 1597c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1607c478bd9Sstevel@tonic-gate static int ohci_compute_total_bandwidth( 1617c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1627c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1637c478bd9Sstevel@tonic-gate uint_t *bandwidth); 1647c478bd9Sstevel@tonic-gate static int ohci_adjust_polling_interval( 1657c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1667c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1677c478bd9Sstevel@tonic-gate usb_port_status_t port_status); 1687c478bd9Sstevel@tonic-gate static uint_t ohci_lattice_height(uint_t interval); 1697c478bd9Sstevel@tonic-gate static uint_t ohci_lattice_parent(uint_t node); 1707c478bd9Sstevel@tonic-gate static uint_t ohci_leftmost_leaf(uint_t node, 1717c478bd9Sstevel@tonic-gate uint_t height); 1727c478bd9Sstevel@tonic-gate static uint_t ohci_hcca_intr_index( 1737c478bd9Sstevel@tonic-gate uint_t node); 1747c478bd9Sstevel@tonic-gate static uint_t ohci_hcca_leaf_index( 1757c478bd9Sstevel@tonic-gate uint_t leaf); 1767c478bd9Sstevel@tonic-gate static uint_t ohci_pow_2(uint_t x); 1777c478bd9Sstevel@tonic-gate static uint_t ohci_log_2(uint_t x); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* Endpoint Descriptor (ED) related functions */ 1807c478bd9Sstevel@tonic-gate static uint_t ohci_unpack_endpoint(ohci_state_t *ohcip, 1817c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1827c478bd9Sstevel@tonic-gate static void ohci_insert_ed(ohci_state_t *ohcip, 1837c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1847c478bd9Sstevel@tonic-gate static void ohci_insert_ctrl_ed( 1857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1867c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1877c478bd9Sstevel@tonic-gate static void ohci_insert_bulk_ed( 1887c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1897c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1907c478bd9Sstevel@tonic-gate static void ohci_insert_intr_ed( 1917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1927c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1937c478bd9Sstevel@tonic-gate static void ohci_insert_isoc_ed( 1947c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 1957c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 1967c478bd9Sstevel@tonic-gate static void ohci_modify_sKip_bit(ohci_state_t *ohcip, 1977c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 1987c478bd9Sstevel@tonic-gate skip_bit_t action, 1997c478bd9Sstevel@tonic-gate usb_flags_t flag); 2007c478bd9Sstevel@tonic-gate static void ohci_remove_ed(ohci_state_t *ohcip, 2017c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2027c478bd9Sstevel@tonic-gate static void ohci_remove_ctrl_ed( 2037c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2057c478bd9Sstevel@tonic-gate static void ohci_remove_bulk_ed( 2067c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2077c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2087c478bd9Sstevel@tonic-gate static void ohci_remove_periodic_ed( 2097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2107c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2117c478bd9Sstevel@tonic-gate static void ohci_insert_ed_on_reclaim_list( 2127c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2137c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 2147c478bd9Sstevel@tonic-gate static void ohci_detach_ed_from_list( 2157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2167c478bd9Sstevel@tonic-gate ohci_ed_t *ept, 2177c478bd9Sstevel@tonic-gate uint_t ept_type); 2187c478bd9Sstevel@tonic-gate static ohci_ed_t *ohci_ed_iommu_to_cpu( 2197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2207c478bd9Sstevel@tonic-gate uintptr_t addr); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* Transfer Descriptor (TD) related functions */ 2237c478bd9Sstevel@tonic-gate static int ohci_initialize_dummy(ohci_state_t *ohcip, 2247c478bd9Sstevel@tonic-gate ohci_ed_t *ept); 2257c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_ctrl_resources( 2267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2287c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 2297c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2307c478bd9Sstevel@tonic-gate static void ohci_insert_ctrl_req( 2317c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2327c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2337c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 2347c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2357c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2367c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_bulk_resources( 2377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2387c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2397c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 2407c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2417c478bd9Sstevel@tonic-gate static void ohci_insert_bulk_req(ohci_state_t *ohcip, 2427c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2437c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 2447c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2457c478bd9Sstevel@tonic-gate usb_flags_t flags); 2467c478bd9Sstevel@tonic-gate static int ohci_start_pipe_polling(ohci_state_t *ohcip, 2477c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2487c478bd9Sstevel@tonic-gate usb_flags_t flags); 2497c478bd9Sstevel@tonic-gate static void ohci_set_periodic_pipe_polling( 2507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 2527c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_intr_resources( 2537c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2547c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2557c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 2567c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2577c478bd9Sstevel@tonic-gate static void ohci_insert_intr_req(ohci_state_t *ohcip, 2587c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2597c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2607c478bd9Sstevel@tonic-gate usb_flags_t flags); 2617c478bd9Sstevel@tonic-gate static int ohci_stop_periodic_pipe_polling( 2627c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2647c478bd9Sstevel@tonic-gate usb_flags_t flags); 2657c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_isoc_resources( 2667c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2677c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2687c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 2697c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 2707c478bd9Sstevel@tonic-gate static int ohci_insert_isoc_req(ohci_state_t *ohcip, 2717c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2727c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2737c478bd9Sstevel@tonic-gate uint_t flags); 27402acac7eSsl static int ohci_insert_hc_td(ohci_state_t *ohcip, 2757c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 27602acac7eSsl uint32_t hctd_dma_offs, 2777c478bd9Sstevel@tonic-gate size_t hctd_length, 2787c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 2797c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2807c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 2817c478bd9Sstevel@tonic-gate static ohci_td_t *ohci_allocate_td_from_pool( 2827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 2837c478bd9Sstevel@tonic-gate static void ohci_fill_in_td(ohci_state_t *ohcip, 2847c478bd9Sstevel@tonic-gate ohci_td_t *td, 2857c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy, 2867c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 28702acac7eSsl uint32_t hctd_dma_offs, 2887c478bd9Sstevel@tonic-gate size_t hctd_length, 2897c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 2907c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 2917c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 2927c478bd9Sstevel@tonic-gate static void ohci_init_itd( 2937c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 2947c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 2957c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 29602acac7eSsl uint32_t index, 2977c478bd9Sstevel@tonic-gate ohci_td_t *td); 2987c478bd9Sstevel@tonic-gate static int ohci_insert_td_with_frame_number( 2997c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3007c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3017c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3027c478bd9Sstevel@tonic-gate ohci_td_t *current_td, 3037c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td); 3047c478bd9Sstevel@tonic-gate static void ohci_insert_td_on_tw(ohci_state_t *ohcip, 3057c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3067c478bd9Sstevel@tonic-gate ohci_td_t *td); 3077c478bd9Sstevel@tonic-gate static void ohci_done_list_tds(ohci_state_t *ohcip, 3087c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* Transfer Wrapper (TW) functions */ 3117c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_create_transfer_wrapper( 3127c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3137c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3147c478bd9Sstevel@tonic-gate size_t length, 3157c478bd9Sstevel@tonic-gate uint_t usb_flags); 31602acac7eSsl static ohci_trans_wrapper_t *ohci_create_isoc_transfer_wrapper( 31702acac7eSsl ohci_state_t *ohcip, 31802acac7eSsl ohci_pipe_private_t *pp, 31902acac7eSsl size_t length, 32002acac7eSsl usb_isoc_pkt_descr_t *descr, 32102acac7eSsl ushort_t pkt_count, 322*29aca3ebSlc size_t td_count, 32302acac7eSsl uint_t usb_flags); 3247c478bd9Sstevel@tonic-gate static int ohci_allocate_tds_for_tw( 3257c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3267c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3277c478bd9Sstevel@tonic-gate size_t td_count); 3287c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_tw_resources( 3297c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3307c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3317c478bd9Sstevel@tonic-gate size_t length, 3327c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 3337c478bd9Sstevel@tonic-gate size_t td_count); 3347c478bd9Sstevel@tonic-gate static void ohci_free_tw_tds_resources( 3357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3367c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3377c478bd9Sstevel@tonic-gate static void ohci_start_xfer_timer( 3387c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3397c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3407c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3417c478bd9Sstevel@tonic-gate static void ohci_stop_xfer_timer( 3427c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3437c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3447c478bd9Sstevel@tonic-gate uint_t flag); 3457c478bd9Sstevel@tonic-gate static void ohci_xfer_timeout_handler(void *arg); 3467c478bd9Sstevel@tonic-gate static void ohci_remove_tw_from_timeout_list( 3477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3487c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3497c478bd9Sstevel@tonic-gate static void ohci_start_timer(ohci_state_t *ohcip); 3507c478bd9Sstevel@tonic-gate static void ohci_free_dma_resources(ohci_state_t *ohcip, 3517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 3527c478bd9Sstevel@tonic-gate static void ohci_free_tw(ohci_state_t *ohcip, 3537c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 35402acac7eSsl static int ohci_tw_rebind_cookie( 35502acac7eSsl ohci_state_t *ohcip, 35602acac7eSsl ohci_pipe_private_t *pp, 35702acac7eSsl ohci_trans_wrapper_t *tw); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* Interrupt Handling functions */ 3609c75c6bfSgovinda static uint_t ohci_intr(caddr_t arg1, 3619c75c6bfSgovinda caddr_t arg2); 3627c478bd9Sstevel@tonic-gate static void ohci_handle_missed_intr( 3637c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 3647c478bd9Sstevel@tonic-gate static void ohci_handle_ue(ohci_state_t *ohcip); 3657c478bd9Sstevel@tonic-gate static void ohci_handle_endpoint_reclaimation( 3667c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 3677c478bd9Sstevel@tonic-gate static void ohci_traverse_done_list( 3687c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3697c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list); 3707c478bd9Sstevel@tonic-gate static ohci_td_t *ohci_reverse_done_list( 3717c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3727c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list); 3737c478bd9Sstevel@tonic-gate static usb_cr_t ohci_parse_error(ohci_state_t *ohcip, 3747c478bd9Sstevel@tonic-gate ohci_td_t *td); 3757c478bd9Sstevel@tonic-gate static void ohci_parse_isoc_error( 3767c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3777c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3787c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3797c478bd9Sstevel@tonic-gate ohci_td_t *td); 3807c478bd9Sstevel@tonic-gate static usb_cr_t ohci_check_for_error( 3817c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3827c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3837c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3847c478bd9Sstevel@tonic-gate ohci_td_t *td, 3857c478bd9Sstevel@tonic-gate uint_t ctrl); 3867c478bd9Sstevel@tonic-gate static void ohci_handle_error( 3877c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3887c478bd9Sstevel@tonic-gate ohci_td_t *td, 3897c478bd9Sstevel@tonic-gate usb_cr_t error); 3907c478bd9Sstevel@tonic-gate static int ohci_cleanup_data_underrun( 3917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3927c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 3937c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 3947c478bd9Sstevel@tonic-gate ohci_td_t *td); 3957c478bd9Sstevel@tonic-gate static void ohci_handle_normal_td( 3967c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 3977c478bd9Sstevel@tonic-gate ohci_td_t *td, 3987c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 3997c478bd9Sstevel@tonic-gate static void ohci_handle_ctrl_td(ohci_state_t *ohcip, 4007c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4017c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4027c478bd9Sstevel@tonic-gate ohci_td_t *td, 4037c478bd9Sstevel@tonic-gate void *); 4047c478bd9Sstevel@tonic-gate static void ohci_handle_bulk_td(ohci_state_t *ohcip, 4057c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4067c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4077c478bd9Sstevel@tonic-gate ohci_td_t *td, 4087c478bd9Sstevel@tonic-gate void *); 4097c478bd9Sstevel@tonic-gate static void ohci_handle_intr_td(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 void *); 4147c478bd9Sstevel@tonic-gate static void ohci_handle_one_xfer_completion( 4157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 4177c478bd9Sstevel@tonic-gate static void ohci_handle_isoc_td(ohci_state_t *ohcip, 4187c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4197c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4207c478bd9Sstevel@tonic-gate ohci_td_t *td, 4217c478bd9Sstevel@tonic-gate void *); 4227c478bd9Sstevel@tonic-gate static void ohci_sendup_td_message( 4237c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4247c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4257c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4267c478bd9Sstevel@tonic-gate ohci_td_t *td, 4277c478bd9Sstevel@tonic-gate usb_cr_t error); 428688b07c5Sgc static int ohci_check_done_head( 429688b07c5Sgc ohci_state_t *ohcip, 430688b07c5Sgc ohci_td_t *done_head); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* Miscillaneous functions */ 4337c478bd9Sstevel@tonic-gate static void ohci_cpr_cleanup( 4347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 4357c478bd9Sstevel@tonic-gate static usb_req_attrs_t ohci_get_xfer_attrs(ohci_state_t *ohcip, 4367c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4377c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 4387c478bd9Sstevel@tonic-gate static int ohci_allocate_periodic_in_resource( 4397c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4407c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4417c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4427c478bd9Sstevel@tonic-gate usb_flags_t flags); 4437c478bd9Sstevel@tonic-gate static int ohci_wait_for_sof( 4447c478bd9Sstevel@tonic-gate ohci_state_t *ohcip); 4457c478bd9Sstevel@tonic-gate static void ohci_pipe_cleanup( 4467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4477c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 4487c478bd9Sstevel@tonic-gate static void ohci_wait_for_transfers_completion( 4497c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4507c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 4517c478bd9Sstevel@tonic-gate static void ohci_check_for_transfers_completion( 4527c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4537c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp); 4547c478bd9Sstevel@tonic-gate static void ohci_save_data_toggle(ohci_state_t *ohcip, 4557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 4567c478bd9Sstevel@tonic-gate static void ohci_restore_data_toggle(ohci_state_t *ohcip, 4577c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 4587c478bd9Sstevel@tonic-gate static void ohci_deallocate_periodic_in_resource( 4597c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4607c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4617c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw); 4627c478bd9Sstevel@tonic-gate static void ohci_do_client_periodic_in_req_callback( 4637c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4647c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 4657c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 4667c478bd9Sstevel@tonic-gate static void ohci_hcdi_callback( 4677c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 4687c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 4697c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* Kstat Support */ 4727c478bd9Sstevel@tonic-gate static void ohci_create_stats(ohci_state_t *ohcip); 4737c478bd9Sstevel@tonic-gate static void ohci_destroy_stats(ohci_state_t *ohcip); 4747c478bd9Sstevel@tonic-gate static void ohci_do_byte_stats( 4757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4767c478bd9Sstevel@tonic-gate size_t len, 4777c478bd9Sstevel@tonic-gate uint8_t attr, 4787c478bd9Sstevel@tonic-gate uint8_t addr); 4797c478bd9Sstevel@tonic-gate static void ohci_do_intrs_stats( 4807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 4817c478bd9Sstevel@tonic-gate int val); 4827c478bd9Sstevel@tonic-gate static void ohci_print_op_regs(ohci_state_t *ohcip); 4837c478bd9Sstevel@tonic-gate static void ohci_print_ed(ohci_state_t *ohcip, 4847c478bd9Sstevel@tonic-gate ohci_ed_t *ed); 4857c478bd9Sstevel@tonic-gate static void ohci_print_td(ohci_state_t *ohcip, 4867c478bd9Sstevel@tonic-gate ohci_td_t *td); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /* extern */ 4897c478bd9Sstevel@tonic-gate int usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* 4927c478bd9Sstevel@tonic-gate * Device operations (dev_ops) entries function prototypes. 4937c478bd9Sstevel@tonic-gate * 4947c478bd9Sstevel@tonic-gate * We use the hub cbops since all nexus ioctl operations defined so far will 4957c478bd9Sstevel@tonic-gate * be executed by the root hub. The following are the Host Controller Driver 4967c478bd9Sstevel@tonic-gate * (HCD) entry points. 4977c478bd9Sstevel@tonic-gate * 4987c478bd9Sstevel@tonic-gate * the open/close/ioctl functions call the corresponding usba_hubdi_* 4997c478bd9Sstevel@tonic-gate * calls after looking up the dip thru the dev_t. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate static int ohci_open(dev_t *devp, int flags, int otyp, cred_t *credp); 5027c478bd9Sstevel@tonic-gate static int ohci_close(dev_t dev, int flag, int otyp, cred_t *credp); 5037c478bd9Sstevel@tonic-gate static int ohci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 5047c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate static int ohci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 5077c478bd9Sstevel@tonic-gate static int ohci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 5087c478bd9Sstevel@tonic-gate static int ohci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 5097c478bd9Sstevel@tonic-gate void *arg, void **result); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate static struct cb_ops ohci_cb_ops = { 5127c478bd9Sstevel@tonic-gate ohci_open, /* Open */ 5137c478bd9Sstevel@tonic-gate ohci_close, /* Close */ 5147c478bd9Sstevel@tonic-gate nodev, /* Strategy */ 5157c478bd9Sstevel@tonic-gate nodev, /* Print */ 5167c478bd9Sstevel@tonic-gate nodev, /* Dump */ 5177c478bd9Sstevel@tonic-gate nodev, /* Read */ 5187c478bd9Sstevel@tonic-gate nodev, /* Write */ 5197c478bd9Sstevel@tonic-gate ohci_ioctl, /* Ioctl */ 5207c478bd9Sstevel@tonic-gate nodev, /* Devmap */ 5217c478bd9Sstevel@tonic-gate nodev, /* Mmap */ 5227c478bd9Sstevel@tonic-gate nodev, /* Segmap */ 5237c478bd9Sstevel@tonic-gate nochpoll, /* Poll */ 5247c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 5257c478bd9Sstevel@tonic-gate NULL, /* Streamtab */ 5267c478bd9Sstevel@tonic-gate D_MP /* Driver compatibility flag */ 5277c478bd9Sstevel@tonic-gate }; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate static struct dev_ops ohci_ops = { 5307c478bd9Sstevel@tonic-gate DEVO_REV, /* Devo_rev */ 5317c478bd9Sstevel@tonic-gate 0, /* Refcnt */ 5327c478bd9Sstevel@tonic-gate ohci_info, /* Info */ 5337c478bd9Sstevel@tonic-gate nulldev, /* Identify */ 5347c478bd9Sstevel@tonic-gate nulldev, /* Probe */ 5357c478bd9Sstevel@tonic-gate ohci_attach, /* Attach */ 5367c478bd9Sstevel@tonic-gate ohci_detach, /* Detach */ 5377c478bd9Sstevel@tonic-gate nodev, /* Reset */ 5387c478bd9Sstevel@tonic-gate &ohci_cb_ops, /* Driver operations */ 5397c478bd9Sstevel@tonic-gate &usba_hubdi_busops, /* Bus operations */ 5407c478bd9Sstevel@tonic-gate usba_hubdi_root_hub_power /* Power */ 5417c478bd9Sstevel@tonic-gate }; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * The USBA library must be loaded for this driver. 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 5477c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 5487c478bd9Sstevel@tonic-gate "USB OpenHCI Driver %I%", /* Name of the module. */ 5497c478bd9Sstevel@tonic-gate &ohci_ops, /* Driver ops */ 5507c478bd9Sstevel@tonic-gate }; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 5537c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 5547c478bd9Sstevel@tonic-gate }; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate int 5587c478bd9Sstevel@tonic-gate _init(void) 5597c478bd9Sstevel@tonic-gate { 5607c478bd9Sstevel@tonic-gate int error; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* Initialize the soft state structures */ 5637c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&ohci_statep, sizeof (ohci_state_t), 5647c478bd9Sstevel@tonic-gate OHCI_INSTS)) != 0) { 5657c478bd9Sstevel@tonic-gate return (error); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* Install the loadable module */ 5697c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 5707c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ohci_statep); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate return (error); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate int 5787c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 5797c478bd9Sstevel@tonic-gate { 5807c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate int 5857c478bd9Sstevel@tonic-gate _fini(void) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate int error; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) == 0) { 5907c478bd9Sstevel@tonic-gate /* Release per module resources */ 5917c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ohci_statep); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate return (error); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) entry points 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * ohci_attach: 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate static int 6067c478bd9Sstevel@tonic-gate ohci_attach(dev_info_t *dip, 6077c478bd9Sstevel@tonic-gate ddi_attach_cmd_t cmd) 6087c478bd9Sstevel@tonic-gate { 6097c478bd9Sstevel@tonic-gate int instance; 6107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = NULL; 6117c478bd9Sstevel@tonic-gate usba_hcdi_register_args_t hcdi_args; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate switch (cmd) { 6147c478bd9Sstevel@tonic-gate case DDI_ATTACH: 6157c478bd9Sstevel@tonic-gate break; 6167c478bd9Sstevel@tonic-gate case DDI_RESUME: 6177c478bd9Sstevel@tonic-gate ohcip = ohci_obtain_state(dip); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate return (ohci_cpr_resume(ohcip)); 6207c478bd9Sstevel@tonic-gate default: 6217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* Get the instance and create soft state */ 6257c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(ohci_statep, instance) != 0) { 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate ohcip = ddi_get_soft_state(ohci_statep, instance); 6337c478bd9Sstevel@tonic-gate if (ohcip == NULL) { 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate ohcip->ohci_flags = OHCI_ATTACH; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl = usb_alloc_log_hdl(dip, "ohci", &ohci_errlevel, 6417c478bd9Sstevel@tonic-gate &ohci_errmask, &ohci_instance_debug, 0); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_ZALLOC; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* Set host controller soft state to initilization */ 6467c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_INIT_STATE; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 6497c478bd9Sstevel@tonic-gate "ohcip = 0x%p", (void *)ohcip); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 6527c478bd9Sstevel@tonic-gate ohci_set_dma_attributes(ohcip); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate /* Save the dip and instance */ 6557c478bd9Sstevel@tonic-gate ohcip->ohci_dip = dip; 6567c478bd9Sstevel@tonic-gate ohcip->ohci_instance = instance; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* Initialize the kstat structures */ 6597c478bd9Sstevel@tonic-gate ohci_create_stats(ohcip); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate /* Create the td and ed pools */ 6627c478bd9Sstevel@tonic-gate if (ohci_allocate_pools(ohcip) != DDI_SUCCESS) { 6637c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Map the registers */ 6697c478bd9Sstevel@tonic-gate if (ohci_map_regs(ohcip) != DDI_SUCCESS) { 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 /* Register interrupts */ 6767c478bd9Sstevel@tonic-gate if (ohci_register_intrs_and_init_mutex(ohcip) != DDI_SUCCESS) { 6777c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* Initialize the controller */ 6857c478bd9Sstevel@tonic-gate if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) { 6867c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 6877c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /* 6937c478bd9Sstevel@tonic-gate * At this point, the hardware wiil be okay. 6947c478bd9Sstevel@tonic-gate * Initialize the usba_hcdi structure 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate ohcip->ohci_hcdi_ops = ohci_alloc_hcdi_ops(ohcip); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * Make this HCD instance known to USBA 7027c478bd9Sstevel@tonic-gate * (dma_attr must be passed for USBA busctl's) 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION; 7057c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dip = dip; 7067c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_ops = ohcip->ohci_hcdi_ops; 7077c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dma_attr = &ohcip->ohci_dma_attr; 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * Priority and iblock_cookie are one and the same 7117c478bd9Sstevel@tonic-gate * (However, retaining hcdi_soft_iblock_cookie for now 7127c478bd9Sstevel@tonic-gate * assigning it w/ priority. In future all iblock_cookie 7137c478bd9Sstevel@tonic-gate * could just go) 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_iblock_cookie = 716abdbd06dSagiri (ddi_iblock_cookie_t)(uintptr_t)ohcip->ohci_intr_pri; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) { 7197c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_USBAREG; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if ((ohci_init_root_hub(ohcip)) != USB_SUCCESS) { 7287c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 7297c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate /* Finally load the root hub driver */ 7377c478bd9Sstevel@tonic-gate if (ohci_load_root_hub_driver(ohcip) != USB_SUCCESS) { 7387c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip); 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_RHREG; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* Display information in the banner */ 7457c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate /* Reset the ohci initilization flag */ 7507c478bd9Sstevel@tonic-gate ohcip->ohci_flags &= ~OHCI_ATTACH; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* Print the Host Control's Operational registers */ 7537c478bd9Sstevel@tonic-gate ohci_print_op_regs(ohcip); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* For RIO we need to call pci_report_pmcap */ 7567c478bd9Sstevel@tonic-gate if (OHCI_IS_RIO(ohcip)) { 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 7647c478bd9Sstevel@tonic-gate "ohci_attach: dip = 0x%p done", (void *)dip); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * ohci_detach: 7727c478bd9Sstevel@tonic-gate */ 7737c478bd9Sstevel@tonic-gate int 7747c478bd9Sstevel@tonic-gate ohci_detach(dev_info_t *dip, 7757c478bd9Sstevel@tonic-gate ddi_detach_cmd_t cmd) 7767c478bd9Sstevel@tonic-gate { 7777c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(dip); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_detach:"); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate switch (cmd) { 7827c478bd9Sstevel@tonic-gate case DDI_DETACH: 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate return (ohci_cleanup(ohcip)); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate return (ohci_cpr_suspend(ohcip)); 7897c478bd9Sstevel@tonic-gate default: 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * ohci_info: 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8007c478bd9Sstevel@tonic-gate static int 8017c478bd9Sstevel@tonic-gate ohci_info(dev_info_t *dip, 8027c478bd9Sstevel@tonic-gate ddi_info_cmd_t infocmd, 8037c478bd9Sstevel@tonic-gate void *arg, 8047c478bd9Sstevel@tonic-gate void **result) 8057c478bd9Sstevel@tonic-gate { 8067c478bd9Sstevel@tonic-gate dev_t dev; 8077c478bd9Sstevel@tonic-gate ohci_state_t *ohcip; 8087c478bd9Sstevel@tonic-gate int instance; 8097c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate switch (infocmd) { 8127c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 8137c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 8147c478bd9Sstevel@tonic-gate instance = OHCI_UNIT(dev); 8157c478bd9Sstevel@tonic-gate ohcip = ddi_get_soft_state(ohci_statep, instance); 8167c478bd9Sstevel@tonic-gate if (ohcip != NULL) { 8177c478bd9Sstevel@tonic-gate *result = (void *)ohcip->ohci_dip; 8187c478bd9Sstevel@tonic-gate if (*result != NULL) { 8197c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate } else { 8227c478bd9Sstevel@tonic-gate *result = NULL; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate break; 8267c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 8277c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 8287c478bd9Sstevel@tonic-gate instance = OHCI_UNIT(dev); 8297c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 8307c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 8317c478bd9Sstevel@tonic-gate break; 8327c478bd9Sstevel@tonic-gate default: 8337c478bd9Sstevel@tonic-gate break; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate return (error); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate /* 8417c478bd9Sstevel@tonic-gate * cb_ops entry points 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate static dev_info_t * 8447c478bd9Sstevel@tonic-gate ohci_get_dip(dev_t dev) 8457c478bd9Sstevel@tonic-gate { 8467c478bd9Sstevel@tonic-gate int instance = OHCI_UNIT(dev); 8477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ddi_get_soft_state(ohci_statep, instance); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (ohcip) { 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate return (ohcip->ohci_dip); 8527c478bd9Sstevel@tonic-gate } else { 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate return (NULL); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate static int 8607c478bd9Sstevel@tonic-gate ohci_open(dev_t *devp, 8617c478bd9Sstevel@tonic-gate int flags, 8627c478bd9Sstevel@tonic-gate int otyp, 8637c478bd9Sstevel@tonic-gate cred_t *credp) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(*devp); 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate return (usba_hubdi_open(dip, devp, flags, otyp, credp)); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate static int 8727c478bd9Sstevel@tonic-gate ohci_close(dev_t dev, 8737c478bd9Sstevel@tonic-gate int flag, 8747c478bd9Sstevel@tonic-gate int otyp, 8757c478bd9Sstevel@tonic-gate cred_t *credp) 8767c478bd9Sstevel@tonic-gate { 8777c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(dev); 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate return (usba_hubdi_close(dip, dev, flag, otyp, credp)); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate static int 8847c478bd9Sstevel@tonic-gate ohci_ioctl(dev_t dev, 8857c478bd9Sstevel@tonic-gate int cmd, 8867c478bd9Sstevel@tonic-gate intptr_t arg, 8877c478bd9Sstevel@tonic-gate int mode, 8887c478bd9Sstevel@tonic-gate cred_t *credp, 8897c478bd9Sstevel@tonic-gate int *rvalp) 8907c478bd9Sstevel@tonic-gate { 8917c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(dev); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate return (usba_hubdi_ioctl(dip, 8947c478bd9Sstevel@tonic-gate dev, cmd, arg, mode, credp, rvalp)); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* 9037c478bd9Sstevel@tonic-gate * ohci_set_dma_attributes: 9047c478bd9Sstevel@tonic-gate * 9057c478bd9Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used 9067c478bd9Sstevel@tonic-gate * in the DMA limit structres are the default values as specified by the 9077c478bd9Sstevel@tonic-gate * Writing PCI device drivers document. 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate static void 9107c478bd9Sstevel@tonic-gate ohci_set_dma_attributes(ohci_state_t *ohcip) 9117c478bd9Sstevel@tonic-gate { 9127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 9137c478bd9Sstevel@tonic-gate "ohci_set_dma_attributes:"); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 9167c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_version = DMA_ATTR_V0; 9177c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_addr_lo = 0x00000000ull; 9187c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_addr_hi = 0xfffffffeull; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* 32 bit addressing */ 9217c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_count_max = OHCI_DMA_ATTR_COUNT_MAX; 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate /* Byte alignment */ 9247c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * Since PCI specification is byte alignment, the 9287c478bd9Sstevel@tonic-gate * burstsize field should be set to 1 for PCI devices. 9297c478bd9Sstevel@tonic-gate */ 9307c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_burstsizes = 0x1; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_minxfer = 0x1; 9337c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_maxxfer = OHCI_DMA_ATTR_MAX_XFER; 9347c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_seg = 0xffffffffull; 9357c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_sgllen = 1; 9367c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_granular = OHCI_DMA_ATTR_GRANULAR; 9377c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_flags = 0; 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * ohci_allocate_pools: 9437c478bd9Sstevel@tonic-gate * 9447c478bd9Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (ED) and for the 9457c478bd9Sstevel@tonic-gate * Transfer Descriptor (TD) pools. Both ED and TD structures must be aligned 9467c478bd9Sstevel@tonic-gate * to a 16 byte boundary. 9477c478bd9Sstevel@tonic-gate */ 9487c478bd9Sstevel@tonic-gate static int 9497c478bd9Sstevel@tonic-gate ohci_allocate_pools(ohci_state_t *ohcip) 9507c478bd9Sstevel@tonic-gate { 9517c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 9527c478bd9Sstevel@tonic-gate size_t real_length; 9537c478bd9Sstevel@tonic-gate int result; 9547c478bd9Sstevel@tonic-gate uint_t ccount; 9557c478bd9Sstevel@tonic-gate int i; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 9587c478bd9Sstevel@tonic-gate "ohci_allocate_pools:"); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 9617c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9627c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 9637c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* Byte alignment to TD alignment */ 9667c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_TD_ALIGNMENT; 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* Allocate the TD pool DMA handle */ 9697c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, &ohcip->ohci_dma_attr, 970*29aca3ebSlc DDI_DMA_SLEEP, 0, 971*29aca3ebSlc &ohcip->ohci_td_pool_dma_handle) != DDI_SUCCESS) { 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate /* Allocate the memory for the TD pool */ 9777c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_td_pool_dma_handle, 978*29aca3ebSlc ohci_td_pool_size * sizeof (ohci_td_t), 979*29aca3ebSlc &dev_attr, 980*29aca3ebSlc DDI_DMA_CONSISTENT, 981*29aca3ebSlc DDI_DMA_SLEEP, 982*29aca3ebSlc 0, 983*29aca3ebSlc (caddr_t *)&ohcip->ohci_td_pool_addr, 984*29aca3ebSlc &real_length, 985*29aca3ebSlc &ohcip->ohci_td_pool_mem_handle)) { 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* Map the TD pool into the I/O address space */ 9917c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle( 992*29aca3ebSlc ohcip->ohci_td_pool_dma_handle, 993*29aca3ebSlc NULL, 994*29aca3ebSlc (caddr_t)ohcip->ohci_td_pool_addr, 995*29aca3ebSlc real_length, 996*29aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 997*29aca3ebSlc DDI_DMA_SLEEP, 998*29aca3ebSlc NULL, 999*29aca3ebSlc &ohcip->ohci_td_pool_cookie, 1000*29aca3ebSlc &ccount); 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_td_pool_addr, 1003*29aca3ebSlc ohci_td_pool_size * sizeof (ohci_td_t)); 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* Process the result */ 10067c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 10077c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 10087c478bd9Sstevel@tonic-gate if (ccount != 1) { 10097c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 10107c478bd9Sstevel@tonic-gate "ohci_allocate_pools: More than 1 cookie"); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate } else { 10157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 10167c478bd9Sstevel@tonic-gate "ohci_allocate_pools: Result = %d", result); 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * DMA addresses for TD pools are bound 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate ohcip->ohci_dma_addr_bind_flag |= OHCI_TD_POOL_BOUND; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* Initialize the TD pool */ 10297c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) { 10307c478bd9Sstevel@tonic-gate Set_TD(ohcip->ohci_td_pool_addr[i].hctd_state, HC_TD_FREE); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* Byte alignment to ED alignment */ 10347c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ED_ALIGNMENT; 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* Allocate the ED pool DMA handle */ 10377c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, 1038*29aca3ebSlc &ohcip->ohci_dma_attr, 1039*29aca3ebSlc DDI_DMA_SLEEP, 1040*29aca3ebSlc 0, 1041*29aca3ebSlc &ohcip->ohci_ed_pool_dma_handle) != DDI_SUCCESS) { 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* Allocate the memory for the ED pool */ 10477c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_ed_pool_dma_handle, 1048*29aca3ebSlc ohci_ed_pool_size * sizeof (ohci_ed_t), 1049*29aca3ebSlc &dev_attr, 1050*29aca3ebSlc DDI_DMA_CONSISTENT, 1051*29aca3ebSlc DDI_DMA_SLEEP, 1052*29aca3ebSlc 0, 1053*29aca3ebSlc (caddr_t *)&ohcip->ohci_ed_pool_addr, 1054*29aca3ebSlc &real_length, 1055*29aca3ebSlc &ohcip->ohci_ed_pool_mem_handle) != DDI_SUCCESS) { 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ohcip->ohci_ed_pool_dma_handle, 1061*29aca3ebSlc NULL, 1062*29aca3ebSlc (caddr_t)ohcip->ohci_ed_pool_addr, 1063*29aca3ebSlc real_length, 1064*29aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1065*29aca3ebSlc DDI_DMA_SLEEP, 1066*29aca3ebSlc NULL, 1067*29aca3ebSlc &ohcip->ohci_ed_pool_cookie, 1068*29aca3ebSlc &ccount); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_ed_pool_addr, 1071*29aca3ebSlc ohci_ed_pool_size * sizeof (ohci_ed_t)); 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* Process the result */ 10747c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 10757c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 10767c478bd9Sstevel@tonic-gate if (ccount != 1) { 10777c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 10787c478bd9Sstevel@tonic-gate "ohci_allocate_pools: More than 1 cookie"); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate } else { 10837c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * DMA addresses for ED pools are bound 10907c478bd9Sstevel@tonic-gate */ 10917c478bd9Sstevel@tonic-gate ohcip->ohci_dma_addr_bind_flag |= OHCI_ED_POOL_BOUND; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate /* Initialize the ED pool */ 10947c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_ed_pool_size; i ++) { 10957c478bd9Sstevel@tonic-gate Set_ED(ohcip->ohci_ed_pool_addr[i].hced_state, HC_EPT_FREE); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate /* 11037c478bd9Sstevel@tonic-gate * ohci_decode_ddi_dma_addr_bind_handle_result: 11047c478bd9Sstevel@tonic-gate * 11057c478bd9Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle() 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate static void 11087c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result( 11097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 11107c478bd9Sstevel@tonic-gate int result) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 11137c478bd9Sstevel@tonic-gate "ohci_decode_ddi_dma_addr_bind_handle_result:"); 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate switch (result) { 11167c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 11177c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11187c478bd9Sstevel@tonic-gate "Partial transfers not allowed"); 11197c478bd9Sstevel@tonic-gate break; 11207c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 11217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11227c478bd9Sstevel@tonic-gate "Handle is in use"); 11237c478bd9Sstevel@tonic-gate break; 11247c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 11257c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11267c478bd9Sstevel@tonic-gate "No resources"); 11277c478bd9Sstevel@tonic-gate break; 11287c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 11297c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11307c478bd9Sstevel@tonic-gate "No mapping"); 11317c478bd9Sstevel@tonic-gate break; 11327c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 11337c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11347c478bd9Sstevel@tonic-gate "Object is too big"); 11357c478bd9Sstevel@tonic-gate break; 11367c478bd9Sstevel@tonic-gate default: 11377c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl, 11387c478bd9Sstevel@tonic-gate "Unknown dma error"); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * ohci_map_regs: 11457c478bd9Sstevel@tonic-gate * 11467c478bd9Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers 11477c478bd9Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system 11487c478bd9Sstevel@tonic-gate * addressable space. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate static int 11517c478bd9Sstevel@tonic-gate ohci_map_regs(ohci_state_t *ohcip) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 11547c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_map_regs:"); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 11597c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 11607c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 11617c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* Map in operational registers */ 11647c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ohcip->ohci_dip, 1, 11657c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_regsp, 0, 11667c478bd9Sstevel@tonic-gate sizeof (ohci_regs_t), &attr, 11677c478bd9Sstevel@tonic-gate &ohcip->ohci_regs_handle) != DDI_SUCCESS) { 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11707c478bd9Sstevel@tonic-gate "ohci_map_regs: Map setup error"); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate if (pci_config_setup(ohcip->ohci_dip, 11767c478bd9Sstevel@tonic-gate &ohcip->ohci_config_handle) != DDI_SUCCESS) { 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11797c478bd9Sstevel@tonic-gate "ohci_map_regs: Config error"); 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* Make sure Memory Access Enable and Master Enable are set */ 11857c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ohcip->ohci_config_handle, PCI_CONF_COMM); 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) { 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 11907c478bd9Sstevel@tonic-gate "ohci_map_regs: Memory base address access disabled"); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate pci_config_put16(ohcip->ohci_config_handle, PCI_CONF_COMM, cmd_reg); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 120228cdc3d7Sszhou /* 120328cdc3d7Sszhou * The following simulated polling is for debugging purposes only. 120428cdc3d7Sszhou * It is activated on x86 by setting usb-polling=true in GRUB or ohci.conf. 120528cdc3d7Sszhou */ 120628cdc3d7Sszhou static int 120728cdc3d7Sszhou ohci_is_polled(dev_info_t *dip) 120828cdc3d7Sszhou { 120928cdc3d7Sszhou int ret; 121028cdc3d7Sszhou char *propval; 121128cdc3d7Sszhou 121228cdc3d7Sszhou if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 121328cdc3d7Sszhou "usb-polling", &propval) != DDI_SUCCESS) 121428cdc3d7Sszhou 121528cdc3d7Sszhou return (0); 121628cdc3d7Sszhou 121728cdc3d7Sszhou ret = (strcmp(propval, "true") == 0); 121828cdc3d7Sszhou ddi_prop_free(propval); 121928cdc3d7Sszhou 122028cdc3d7Sszhou return (ret); 122128cdc3d7Sszhou } 122228cdc3d7Sszhou 122328cdc3d7Sszhou static void 122428cdc3d7Sszhou ohci_poll_intr(void *arg) 122528cdc3d7Sszhou { 122628cdc3d7Sszhou /* poll every millisecond */ 122728cdc3d7Sszhou for (;;) { 122828cdc3d7Sszhou (void) ohci_intr(arg, NULL); 122928cdc3d7Sszhou delay(drv_usectohz(1000)); 123028cdc3d7Sszhou } 123128cdc3d7Sszhou } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * ohci_register_intrs_and_init_mutex: 12357c478bd9Sstevel@tonic-gate * 12367c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate static int 12397c478bd9Sstevel@tonic-gate ohci_register_intrs_and_init_mutex(ohci_state_t *ohcip) 12407c478bd9Sstevel@tonic-gate { 12419c75c6bfSgovinda int intr_types; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12447c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex:"); 12457c478bd9Sstevel@tonic-gate 124628cdc3d7Sszhou if (ohci_is_polled(ohcip->ohci_dip)) { 124728cdc3d7Sszhou extern pri_t maxclsyspri; 124828cdc3d7Sszhou 12498668df41Slg USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 125028cdc3d7Sszhou "ohci_register_intrs_and_init_mutex: " 125128cdc3d7Sszhou "running in simulated polled mode"); 125228cdc3d7Sszhou 125328cdc3d7Sszhou (void) thread_create(NULL, 0, ohci_poll_intr, ohcip, 0, &p0, 125428cdc3d7Sszhou TS_RUN, maxclsyspri); 125528cdc3d7Sszhou 125628cdc3d7Sszhou goto skip_intr; 125728cdc3d7Sszhou } 125828cdc3d7Sszhou 12599c75c6bfSgovinda /* Get supported interrupt types */ 12609c75c6bfSgovinda if (ddi_intr_get_supported_types(ohcip->ohci_dip, 12619c75c6bfSgovinda &intr_types) != DDI_SUCCESS) { 12627c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12637c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: " 12649c75c6bfSgovinda "ddi_intr_get_supported_types failed"); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12699c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12709c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: " 12719c75c6bfSgovinda "supported interrupt types 0x%x", intr_types); 12729c75c6bfSgovinda 12739c75c6bfSgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ohci_enable_msi) { 12749c75c6bfSgovinda if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_MSI) 12759c75c6bfSgovinda != DDI_SUCCESS) { 12769c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12779c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: MSI " 12789c75c6bfSgovinda "registration failed, trying FIXED interrupt \n"); 12799c75c6bfSgovinda } else { 12809c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12819c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: " 12829c75c6bfSgovinda "Using MSI interrupt type\n"); 12837c478bd9Sstevel@tonic-gate 12849c75c6bfSgovinda ohcip->ohci_intr_type = DDI_INTR_TYPE_MSI; 12859c75c6bfSgovinda ohcip->ohci_flags |= OHCI_INTR; 12869c75c6bfSgovinda } 12879c75c6bfSgovinda } 12889c75c6bfSgovinda 12899c75c6bfSgovinda if ((!(ohcip->ohci_flags & OHCI_INTR)) && 12909c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) { 12919c75c6bfSgovinda if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_FIXED) 12929c75c6bfSgovinda != DDI_SUCCESS) { 12939c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 12949c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: " 12959c75c6bfSgovinda "FIXED interrupt registration failed\n"); 12969c75c6bfSgovinda 12979c75c6bfSgovinda return (DDI_FAILURE); 12989c75c6bfSgovinda } 12999c75c6bfSgovinda 13009c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13017c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: " 13029c75c6bfSgovinda "Using FIXED interrupt type\n"); 13039c75c6bfSgovinda 13049c75c6bfSgovinda ohcip->ohci_intr_type = DDI_INTR_TYPE_FIXED; 13059c75c6bfSgovinda ohcip->ohci_flags |= OHCI_INTR; 13069c75c6bfSgovinda } 13079c75c6bfSgovinda 130828cdc3d7Sszhou skip_intr: 13099c75c6bfSgovinda /* Create prototype for SOF condition variable */ 13109c75c6bfSgovinda cv_init(&ohcip->ohci_SOF_cv, NULL, CV_DRIVER, NULL); 13119c75c6bfSgovinda 13129c75c6bfSgovinda /* Semaphore to serialize opens and closes */ 13139c75c6bfSgovinda sema_init(&ohcip->ohci_ocsem, 1, NULL, SEMA_DRIVER, NULL); 13149c75c6bfSgovinda 13159c75c6bfSgovinda return (DDI_SUCCESS); 13169c75c6bfSgovinda } 13179c75c6bfSgovinda 13189c75c6bfSgovinda 13199c75c6bfSgovinda /* 13209c75c6bfSgovinda * ohci_add_intrs: 13219c75c6bfSgovinda * 13229c75c6bfSgovinda * Register FIXED or MSI interrupts. 13239c75c6bfSgovinda */ 13249c75c6bfSgovinda static int 13259c75c6bfSgovinda ohci_add_intrs(ohci_state_t *ohcip, 13269c75c6bfSgovinda int intr_type) 13279c75c6bfSgovinda { 13289c75c6bfSgovinda int actual, avail, intr_size, count = 0; 1329*29aca3ebSlc int i, flag, ret; 13309c75c6bfSgovinda 13319c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13329c75c6bfSgovinda "ohci_add_intrs: interrupt type 0x%x", intr_type); 13339c75c6bfSgovinda 13349c75c6bfSgovinda /* Get number of interrupts */ 13359c75c6bfSgovinda ret = ddi_intr_get_nintrs(ohcip->ohci_dip, intr_type, &count); 13369c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) { 13379c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13389c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_nintrs() failure, " 13399c75c6bfSgovinda "ret: %d, count: %d", ret, count); 13409c75c6bfSgovinda 13419c75c6bfSgovinda return (DDI_FAILURE); 13429c75c6bfSgovinda } 13439c75c6bfSgovinda 13449c75c6bfSgovinda /* Get number of available interrupts */ 13459c75c6bfSgovinda ret = ddi_intr_get_navail(ohcip->ohci_dip, intr_type, &avail); 13469c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) { 13479c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13489c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_navail() failure, " 13499c75c6bfSgovinda "ret: %d, count: %d", ret, count); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate 13549c75c6bfSgovinda if (avail < count) { 13559c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13569c75c6bfSgovinda "ohci_add_intrs: ohci_add_intrs: nintrs () " 13579c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail); 13589c75c6bfSgovinda } 13599c75c6bfSgovinda 13609c75c6bfSgovinda /* Allocate an array of interrupt handles */ 13619c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t); 13629c75c6bfSgovinda ohcip->ohci_htable = kmem_zalloc(intr_size, KM_SLEEP); 13639c75c6bfSgovinda 13649c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ? 13659c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 13669c75c6bfSgovinda 13679c75c6bfSgovinda /* call ddi_intr_alloc() */ 13687c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ohcip->ohci_dip, ohcip->ohci_htable, 13699c75c6bfSgovinda intr_type, 0, count, &actual, flag); 13707c478bd9Sstevel@tonic-gate 13719c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) { 13727c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13739c75c6bfSgovinda "ohci_add_intrs: ddi_intr_alloc() failed %d", ret); 13747c478bd9Sstevel@tonic-gate 13759c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13809c75c6bfSgovinda if (actual < count) { 13819c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13829c75c6bfSgovinda "ohci_add_intrs: Requested: %d, Received: %d\n", 13839c75c6bfSgovinda count, actual); 13847c478bd9Sstevel@tonic-gate 13859c75c6bfSgovinda for (i = 0; i < actual; i++) 13869c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 13879c75c6bfSgovinda 13889c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 13899c75c6bfSgovinda 13909c75c6bfSgovinda return (DDI_FAILURE); 13919c75c6bfSgovinda } 13929c75c6bfSgovinda 13939c75c6bfSgovinda ohcip->ohci_intr_cnt = actual; 13949c75c6bfSgovinda 13959c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ohcip->ohci_htable[0], 13969c75c6bfSgovinda &ohcip->ohci_intr_pri)) != DDI_SUCCESS) { 13977c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 13989c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_pri() failed %d", ret); 13997c478bd9Sstevel@tonic-gate 14009c75c6bfSgovinda for (i = 0; i < actual; i++) 14019c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 14029c75c6bfSgovinda 14039c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14089c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14099c75c6bfSgovinda "ohci_add_intrs: Supported Interrupt priority 0x%x", 14109c75c6bfSgovinda ohcip->ohci_intr_pri); 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 14137c478bd9Sstevel@tonic-gate if (ohcip->ohci_intr_pri >= ddi_intr_get_hilevel_pri()) { 14147c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14159c75c6bfSgovinda "ohci_add_intrs: Hi level interrupt not supported"); 14169c75c6bfSgovinda 14179c75c6bfSgovinda for (i = 0; i < actual; i++) 14189c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 14197c478bd9Sstevel@tonic-gate 14209c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 14267c478bd9Sstevel@tonic-gate mutex_init(&ohcip->ohci_int_mutex, NULL, MUTEX_DRIVER, 1427a195726fSgovinda DDI_INTR_PRI(ohcip->ohci_intr_pri)); 14287c478bd9Sstevel@tonic-gate 14299c75c6bfSgovinda /* Call ddi_intr_add_handler() */ 14309c75c6bfSgovinda for (i = 0; i < actual; i++) { 14319c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ohcip->ohci_htable[i], 14329c75c6bfSgovinda ohci_intr, (caddr_t)ohcip, 14339c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 14349c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14359c75c6bfSgovinda "ohci_add_intrs: ddi_intr_add_handler() " 14369c75c6bfSgovinda "failed %d", ret); 14377c478bd9Sstevel@tonic-gate 14389c75c6bfSgovinda for (i = 0; i < actual; i++) 14399c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 14407c478bd9Sstevel@tonic-gate 14419c75c6bfSgovinda mutex_destroy(&ohcip->ohci_int_mutex); 14429c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 14439c75c6bfSgovinda 14449c75c6bfSgovinda return (DDI_FAILURE); 14459c75c6bfSgovinda } 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14489c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ohcip->ohci_htable[0], 14499c75c6bfSgovinda &ohcip->ohci_intr_cap)) != DDI_SUCCESS) { 14507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14519c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_cap() failed %d", ret); 14529c75c6bfSgovinda 14539c75c6bfSgovinda for (i = 0; i < actual; i++) { 14549c75c6bfSgovinda (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]); 14559c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 14569c75c6bfSgovinda } 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate mutex_destroy(&ohcip->ohci_int_mutex); 14599c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size); 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14649c75c6bfSgovinda /* Enable all interrupts */ 14659c75c6bfSgovinda if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) { 14669c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */ 14679c75c6bfSgovinda (void) ddi_intr_block_enable(ohcip->ohci_htable, 14689c75c6bfSgovinda ohcip->ohci_intr_cnt); 14699c75c6bfSgovinda } else { 14709c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */ 14719c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) 14729c75c6bfSgovinda (void) ddi_intr_enable(ohcip->ohci_htable[i]); 14739c75c6bfSgovinda } 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * ohci_init_ctlr: 14817c478bd9Sstevel@tonic-gate * 14827c478bd9Sstevel@tonic-gate * Initialize the Host Controller (HC). 14837c478bd9Sstevel@tonic-gate */ 14847c478bd9Sstevel@tonic-gate static int 14857c478bd9Sstevel@tonic-gate ohci_init_ctlr(ohci_state_t *ohcip) 14867c478bd9Sstevel@tonic-gate { 14877c478bd9Sstevel@tonic-gate int revision, curr_control, max_packet = 0; 14887c478bd9Sstevel@tonic-gate clock_t sof_time_wait; 1489cbab2b26Slg int retry = 0; 1490cbab2b26Slg int ohci_frame_interval; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_ctlr:"); 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (ohci_take_control(ohcip) != DDI_SUCCESS) { 14957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 14967c478bd9Sstevel@tonic-gate "ohci_init_ctlr: ohci_take_control failed\n"); 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate /* 15027c478bd9Sstevel@tonic-gate * Soft reset the host controller. 15037c478bd9Sstevel@tonic-gate * 15047c478bd9Sstevel@tonic-gate * On soft reset, the ohci host controller moves to the 15057c478bd9Sstevel@tonic-gate * USB Suspend state in which most of the ohci operational 15067c478bd9Sstevel@tonic-gate * registers are reset except stated ones. The soft reset 15077c478bd9Sstevel@tonic-gate * doesn't cause a reset to the ohci root hub and even no 15087c478bd9Sstevel@tonic-gate * subsequent reset signaling should be asserterd to its 15097c478bd9Sstevel@tonic-gate * down stream. 15107c478bd9Sstevel@tonic-gate */ 15117c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET); 15127c478bd9Sstevel@tonic-gate 1513*29aca3ebSlc mutex_exit(&ohcip->ohci_int_mutex); 15147c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 1515*29aca3ebSlc delay(drv_usectohz(OHCI_RESET_TIMEWAIT)); 1516*29aca3ebSlc mutex_enter(&ohcip->ohci_int_mutex); 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /* 15197c478bd9Sstevel@tonic-gate * Do hard reset the host controller. 15207c478bd9Sstevel@tonic-gate * 15217c478bd9Sstevel@tonic-gate * Now perform USB reset in order to reset the ohci root 15227c478bd9Sstevel@tonic-gate * hub. 15237c478bd9Sstevel@tonic-gate */ 15247c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, HCR_CONTROL_RESET); 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * According to Section 5.1.2.3 of the specification, the 15287c478bd9Sstevel@tonic-gate * host controller will go into suspend state immediately 15297c478bd9Sstevel@tonic-gate * after the reset. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate /* Verify the version number */ 15337c478bd9Sstevel@tonic-gate revision = Get_OpReg(hcr_revision); 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate if ((revision & HCR_REVISION_MASK) != HCR_REVISION_1_0) { 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 15417c478bd9Sstevel@tonic-gate "ohci_init_ctlr: Revision verified"); 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate /* hcca area need not be initialized on resume */ 15447c478bd9Sstevel@tonic-gate if (ohcip->ohci_hc_soft_state == OHCI_CTLR_INIT_STATE) { 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate /* Get the ohci chip vendor and device id */ 15477c478bd9Sstevel@tonic-gate ohcip->ohci_vendor_id = pci_config_get16( 15487c478bd9Sstevel@tonic-gate ohcip->ohci_config_handle, PCI_CONF_VENID); 15497c478bd9Sstevel@tonic-gate ohcip->ohci_device_id = pci_config_get16( 15507c478bd9Sstevel@tonic-gate ohcip->ohci_config_handle, PCI_CONF_DEVID); 15517c478bd9Sstevel@tonic-gate ohcip->ohci_rev_id = pci_config_get8( 15527c478bd9Sstevel@tonic-gate ohcip->ohci_config_handle, PCI_CONF_REVID); 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate /* Initialize the hcca area */ 15557c478bd9Sstevel@tonic-gate if (ohci_init_hcca(ohcip) != DDI_SUCCESS) { 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 1561f806f48bShs /* 1562f806f48bShs * Workaround for ULI1575 chipset. Following OHCI Operational Memory 1563f806f48bShs * Registers are not cleared to their default value on reset. 1564f806f48bShs * Explicitly set the registers to default value. 1565f806f48bShs */ 1566f806f48bShs if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID && 1567*29aca3ebSlc ohcip->ohci_device_id == PCI_ULI1575_DEVID) { 1568f806f48bShs Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT); 1569f806f48bShs Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT); 1570f806f48bShs Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT); 1571f806f48bShs Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT); 1572f806f48bShs Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT); 1573f806f48bShs Set_OpReg(hcr_frame_interval, HCR_FRAME_INTERVAL_DEFAULT); 1574f806f48bShs Set_OpReg(hcr_periodic_strt, HCR_PERIODIC_START_DEFAULT); 1575f806f48bShs } 1576f806f48bShs 15777c478bd9Sstevel@tonic-gate /* Set the HcHCCA to the physical address of the HCCA block */ 15787c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, (uint_t)ohcip->ohci_hcca_cookie.dmac_address); 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except Root 15827c478bd9Sstevel@tonic-gate * Hub Status change and SOF interrupts. 15837c478bd9Sstevel@tonic-gate */ 15847c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SO | HCR_INTR_WDH | 15857c478bd9Sstevel@tonic-gate HCR_INTR_RD | HCR_INTR_UE | HCR_INTR_FNO | HCR_INTR_MIE); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * For non-periodic transfers, reserve atleast for one low-speed 15897c478bd9Sstevel@tonic-gate * device transaction. According to USB Bandwidth Analysis white 15907c478bd9Sstevel@tonic-gate * paper and also as per OHCI Specification 1.0a, section 7.3.5, 15917c478bd9Sstevel@tonic-gate * page 123, one low-speed transaction takes 0x628h full speed 15927c478bd9Sstevel@tonic-gate * bits (197 bytes), which comes to around 13% of USB frame time. 15937c478bd9Sstevel@tonic-gate * 15947c478bd9Sstevel@tonic-gate * The periodic transfers will get around 87% of USB frame time. 15957c478bd9Sstevel@tonic-gate */ 15967c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_strt, 15977c478bd9Sstevel@tonic-gate ((PERIODIC_XFER_STARTS * BITS_PER_BYTE) - 1)); 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate /* Save the contents of the Frame Interval Registers */ 16007c478bd9Sstevel@tonic-gate ohcip->ohci_frame_interval = Get_OpReg(hcr_frame_interval); 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate /* 16037c478bd9Sstevel@tonic-gate * Initialize the FSLargestDataPacket value in the frame interval 16047c478bd9Sstevel@tonic-gate * register. The controller compares the value of MaxPacketSize to 16057c478bd9Sstevel@tonic-gate * this value to see if the entire packet may be sent out before 16067c478bd9Sstevel@tonic-gate * the EOF. 16077c478bd9Sstevel@tonic-gate */ 16087c478bd9Sstevel@tonic-gate max_packet = ((((ohcip->ohci_frame_interval - 16097c478bd9Sstevel@tonic-gate MAX_OVERHEAD) * 6) / 7) << HCR_FRME_FSMPS_SHFT); 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate Set_OpReg(hcr_frame_interval, 16127c478bd9Sstevel@tonic-gate (max_packet | ohcip->ohci_frame_interval)); 16137c478bd9Sstevel@tonic-gate 1614cbab2b26Slg /* 1615cbab2b26Slg * Sometimes the HcFmInterval register in OHCI controller does not 1616cbab2b26Slg * maintain its value after the first write. This problem is found 1617cbab2b26Slg * on ULI M1575 South Bridge. To workaround the hardware problem, 1618cbab2b26Slg * check the value after write and retry if the last write failed. 1619cbab2b26Slg */ 1620cbab2b26Slg if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID && 1621cbab2b26Slg ohcip->ohci_device_id == PCI_ULI1575_DEVID) { 1622cbab2b26Slg ohci_frame_interval = Get_OpReg(hcr_frame_interval); 1623cbab2b26Slg while ((ohci_frame_interval != (max_packet | 1624cbab2b26Slg ohcip->ohci_frame_interval))) { 1625cbab2b26Slg if (retry >= 10) { 1626cbab2b26Slg USB_DPRINTF_L1(PRINT_MASK_ATTA, 16278668df41Slg ohcip->ohci_log_hdl, "Failed to program" 16288668df41Slg " Frame Interval Register."); 1629cbab2b26Slg 1630cbab2b26Slg return (DDI_FAILURE); 1631cbab2b26Slg } 1632cbab2b26Slg retry++; 1633cbab2b26Slg USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 1634cbab2b26Slg "ohci_init_ctlr: Failed to program Frame" 1635cbab2b26Slg " Interval Register, retry=%d", retry); 1636cbab2b26Slg Set_OpReg(hcr_frame_interval, 1637cbab2b26Slg (max_packet | ohcip->ohci_frame_interval)); 1638cbab2b26Slg ohci_frame_interval = Get_OpReg(hcr_frame_interval); 1639cbab2b26Slg } 1640cbab2b26Slg } 1641cbab2b26Slg 16427c478bd9Sstevel@tonic-gate /* Begin sending SOFs */ 16437c478bd9Sstevel@tonic-gate curr_control = Get_OpReg(hcr_control); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16467c478bd9Sstevel@tonic-gate "ohci_init_ctlr: curr_control=0x%x", curr_control); 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate /* Set the state to operational */ 16497c478bd9Sstevel@tonic-gate curr_control = (curr_control & 16507c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_OPERAT; 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, curr_control); 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate ASSERT((Get_OpReg(hcr_control) & 16557c478bd9Sstevel@tonic-gate HCR_CONTROL_HCFS) == HCR_CONTROL_OPERAT); 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */ 16587c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_OPERATIONAL_STATE; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 16617c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz(OHCI_MAX_SOF_TIMEWAIT * 1000000); 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* Clear ohci_sof_flag indicating waiting for SOF interrupt */ 16647c478bd9Sstevel@tonic-gate ohcip->ohci_sof_flag = B_FALSE; 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */ 16677c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF); 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_intr_enable) & HCR_INTR_SOF); 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ohcip->ohci_SOF_cv, 16727c478bd9Sstevel@tonic-gate &ohcip->ohci_int_mutex, ddi_get_lbolt() + sof_time_wait); 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate /* Wait for the SOF or timeout event */ 16757c478bd9Sstevel@tonic-gate if (ohcip->ohci_sof_flag == B_FALSE) { 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 16787c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_ERROR_STATE; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16817c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB OHCI host" 16827c478bd9Sstevel@tonic-gate "controller is unusable"); 16837c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 16877c478bd9Sstevel@tonic-gate "ohci_init_ctlr: SOF's have started"); 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * ohci_init_hcca: 16957c478bd9Sstevel@tonic-gate * 16967c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller Communication 16977c478bd9Sstevel@tonic-gate * Area (HCCA). The HCCA structure must be aligned to a 256-byte boundary. 16987c478bd9Sstevel@tonic-gate */ 16997c478bd9Sstevel@tonic-gate static int 17007c478bd9Sstevel@tonic-gate ohci_init_hcca(ohci_state_t *ohcip) 17017c478bd9Sstevel@tonic-gate { 17027c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 17037c478bd9Sstevel@tonic-gate size_t real_length; 17047c478bd9Sstevel@tonic-gate uint_t mask, ccount; 17057c478bd9Sstevel@tonic-gate int result; 17067c478bd9Sstevel@tonic-gate uintptr_t addr; 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_hcca:"); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 17137c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 17147c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 17157c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* Byte alignment to HCCA alignment */ 17187c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_HCCA_ALIGNMENT; 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate /* Create space for the HCCA block */ 17217c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, &ohcip->ohci_dma_attr, 1722*29aca3ebSlc DDI_DMA_SLEEP, 1723*29aca3ebSlc 0, 1724*29aca3ebSlc &ohcip->ohci_hcca_dma_handle) 1725*29aca3ebSlc != DDI_SUCCESS) { 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_hcca_dma_handle, 1731*29aca3ebSlc 2 * sizeof (ohci_hcca_t), 1732*29aca3ebSlc &dev_attr, 1733*29aca3ebSlc DDI_DMA_CONSISTENT, 1734*29aca3ebSlc DDI_DMA_SLEEP, 1735*29aca3ebSlc 0, 1736*29aca3ebSlc (caddr_t *)&ohcip->ohci_hccap, 1737*29aca3ebSlc &real_length, 1738*29aca3ebSlc &ohcip->ohci_hcca_mem_handle)) { 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_hccap, real_length); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate /* Figure out the alignment requirements */ 17467c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, 0xFFFFFFFF); 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate /* 17497c478bd9Sstevel@tonic-gate * Read the hcr_HCCA register until 17507c478bd9Sstevel@tonic-gate * contenets are non-zero. 17517c478bd9Sstevel@tonic-gate */ 17527c478bd9Sstevel@tonic-gate mask = Get_OpReg(hcr_HCCA); 17537c478bd9Sstevel@tonic-gate 1754*29aca3ebSlc mutex_exit(&ohcip->ohci_int_mutex); 17557c478bd9Sstevel@tonic-gate while (mask == 0) { 1756*29aca3ebSlc delay(drv_usectohz(OHCI_TIMEWAIT)); 17577c478bd9Sstevel@tonic-gate mask = Get_OpReg(hcr_HCCA); 17587c478bd9Sstevel@tonic-gate } 1759*29aca3ebSlc mutex_enter(&ohcip->ohci_int_mutex); 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate ASSERT(mask != 0); 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate addr = (uintptr_t)ohcip->ohci_hccap; 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17667c478bd9Sstevel@tonic-gate "ohci_init_hcca: addr=0x%lx, mask=0x%x", addr, mask); 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate while (addr & (~mask)) { 17697c478bd9Sstevel@tonic-gate addr++; 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate ohcip->ohci_hccap = (ohci_hcca_t *)addr; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17757c478bd9Sstevel@tonic-gate "ohci_init_hcca: Real length %lu", real_length); 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17787c478bd9Sstevel@tonic-gate "ohci_init_hcca: virtual hcca 0x%p", (void *)ohcip->ohci_hccap); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /* Map the whole HCCA into the I/O address space */ 17817c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ohcip->ohci_hcca_dma_handle, 1782*29aca3ebSlc NULL, 1783*29aca3ebSlc (caddr_t)ohcip->ohci_hccap, 1784*29aca3ebSlc real_length, 1785*29aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1786*29aca3ebSlc DDI_DMA_SLEEP, NULL, 1787*29aca3ebSlc &ohcip->ohci_hcca_cookie, 1788*29aca3ebSlc &ccount); 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 17917c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 17927c478bd9Sstevel@tonic-gate if (ccount != 1) { 17937c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 17947c478bd9Sstevel@tonic-gate "ohci_init_hcca: More than 1 cookie"); 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17977c478bd9Sstevel@tonic-gate } 17987c478bd9Sstevel@tonic-gate } else { 17997c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18046d9a41ffSqz /* 18056d9a41ffSqz * DMA addresses for HCCA are bound 18066d9a41ffSqz */ 18076d9a41ffSqz ohcip->ohci_dma_addr_bind_flag |= OHCI_HCCA_DMA_BOUND; 18086d9a41ffSqz 18097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18107c478bd9Sstevel@tonic-gate "ohci_init_hcca: physical 0x%p", 18117c478bd9Sstevel@tonic-gate (void *)(uintptr_t)ohcip->ohci_hcca_cookie.dmac_address); 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18147c478bd9Sstevel@tonic-gate "ohci_init_hcca: size %lu", ohcip->ohci_hcca_cookie.dmac_size); 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate /* Initialize the interrupt lists */ 18177c478bd9Sstevel@tonic-gate ohci_build_interrupt_lattice(ohcip); 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18207c478bd9Sstevel@tonic-gate "ohci_init_hcca: End"); 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * ohci_build_interrupt_lattice: 18287c478bd9Sstevel@tonic-gate * 18297c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 18307c478bd9Sstevel@tonic-gate * (ED). This interrupt lattice tree will have total of 32 interrupt ED 18317c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt ED list in 18327c478bd9Sstevel@tonic-gate * every frame. The lower five bits of the current frame number indexes 18337c478bd9Sstevel@tonic-gate * into an array of 32 interrupt Endpoint Descriptor lists found in the 18347c478bd9Sstevel@tonic-gate * HCCA. 18357c478bd9Sstevel@tonic-gate */ 18367c478bd9Sstevel@tonic-gate static void 18377c478bd9Sstevel@tonic-gate ohci_build_interrupt_lattice(ohci_state_t *ohcip) 18387c478bd9Sstevel@tonic-gate { 18397c478bd9Sstevel@tonic-gate ohci_ed_t *list_array = ohcip->ohci_ed_pool_addr; 18407c478bd9Sstevel@tonic-gate int half_list = NUM_INTR_ED_LISTS / 2; 18417c478bd9Sstevel@tonic-gate ohci_hcca_t *hccap = ohcip->ohci_hccap; 18427c478bd9Sstevel@tonic-gate uintptr_t addr; 18437c478bd9Sstevel@tonic-gate int i; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 18467c478bd9Sstevel@tonic-gate "ohci_build_interrupt_lattice:"); 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * Reserve the first 31 Endpoint Descriptor (ED) structures 18507c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 18517c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 18527c478bd9Sstevel@tonic-gate */ 18537c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_STATIC_NODES; i++) { 18547c478bd9Sstevel@tonic-gate Set_ED(list_array[i].hced_ctrl, HC_EPT_sKip); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate Set_ED(list_array[i].hced_state, HC_EPT_STATIC); 18577c478bd9Sstevel@tonic-gate } 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 18607c478bd9Sstevel@tonic-gate for (i = 0; i < half_list - 1; i++) { 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate /* 18637c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 18647c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 18657c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 18667c478bd9Sstevel@tonic-gate * starting iommu address. 18677c478bd9Sstevel@tonic-gate */ 18687c478bd9Sstevel@tonic-gate addr = ohci_ed_cpu_to_iommu(ohcip, (ohci_ed_t *)&list_array[i]); 18697c478bd9Sstevel@tonic-gate 18707c478bd9Sstevel@tonic-gate Set_ED(list_array[2*i + 1].hced_next, addr); 18717c478bd9Sstevel@tonic-gate Set_ED(list_array[2*i + 2].hced_next, addr); 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate /* 18757c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the HCCA so that it points 18767c478bd9Sstevel@tonic-gate * to the bottom of the tree. 18777c478bd9Sstevel@tonic-gate */ 18787c478bd9Sstevel@tonic-gate for (i = 0; i < half_list; i++) { 18797c478bd9Sstevel@tonic-gate addr = ohci_ed_cpu_to_iommu(ohcip, 18807c478bd9Sstevel@tonic-gate (ohci_ed_t *)&list_array[half_list - 1 + ohci_index[i]]); 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate ASSERT(Get_ED(list_array[half_list - 1 + 18837c478bd9Sstevel@tonic-gate ohci_index[i]].hced_ctrl)); 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate ASSERT(addr != 0); 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate Set_HCCA(hccap->HccaIntTble[i], addr); 18887c478bd9Sstevel@tonic-gate Set_HCCA(hccap->HccaIntTble[i + half_list], addr); 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate } 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate /* 18947c478bd9Sstevel@tonic-gate * ohci_take_control: 18957c478bd9Sstevel@tonic-gate * 18967c478bd9Sstevel@tonic-gate * Take control of the host controller. OpenHCI allows for optional support 18977c478bd9Sstevel@tonic-gate * of legacy devices through the use of System Management Mode software and 18987c478bd9Sstevel@tonic-gate * system Management interrupt hardware. See section 5.1.1.3 of the OpenHCI 18997c478bd9Sstevel@tonic-gate * spec for more details. 19007c478bd9Sstevel@tonic-gate */ 19017c478bd9Sstevel@tonic-gate static int 19027c478bd9Sstevel@tonic-gate ohci_take_control(ohci_state_t *ohcip) 19037c478bd9Sstevel@tonic-gate { 19047c478bd9Sstevel@tonic-gate #if defined(__x86) 19057c478bd9Sstevel@tonic-gate uint32_t hcr_control_val; 19067c478bd9Sstevel@tonic-gate uint32_t hcr_cmd_status_val; 19077c478bd9Sstevel@tonic-gate int wait; 19087c478bd9Sstevel@tonic-gate #endif /* __x86 */ 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19117c478bd9Sstevel@tonic-gate "ohci_take_control:"); 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate #if defined(__x86) 19147c478bd9Sstevel@tonic-gate /* 19157c478bd9Sstevel@tonic-gate * On x86, we must tell the BIOS we want the controller, 19167c478bd9Sstevel@tonic-gate * and wait for it to respond that we can have it. 19177c478bd9Sstevel@tonic-gate */ 19187c478bd9Sstevel@tonic-gate hcr_control_val = Get_OpReg(hcr_control); 19197c478bd9Sstevel@tonic-gate if ((hcr_control_val & HCR_CONTROL_IR) == 0) { 19207c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19217c478bd9Sstevel@tonic-gate "ohci_take_control: InterruptRouting off\n"); 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate /* attempt the OwnershipChange request */ 19277c478bd9Sstevel@tonic-gate hcr_cmd_status_val = Get_OpReg(hcr_cmd_status); 19287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19297c478bd9Sstevel@tonic-gate "ohci_take_control: hcr_cmd_status: 0x%x\n", 19307c478bd9Sstevel@tonic-gate hcr_cmd_status_val); 19317c478bd9Sstevel@tonic-gate hcr_cmd_status_val |= HCR_STATUS_OCR; 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, hcr_cmd_status_val); 19347c478bd9Sstevel@tonic-gate 1935*29aca3ebSlc 1936*29aca3ebSlc mutex_exit(&ohcip->ohci_int_mutex); 19377c478bd9Sstevel@tonic-gate /* now wait for 5 seconds for InterruptRouting to go away */ 19387c478bd9Sstevel@tonic-gate for (wait = 0; wait < 5000; wait++) { 19397c478bd9Sstevel@tonic-gate if ((Get_OpReg(hcr_control) & HCR_CONTROL_IR) == 0) 19407c478bd9Sstevel@tonic-gate break; 1941*29aca3ebSlc delay(drv_usectohz(1000)); 19427c478bd9Sstevel@tonic-gate } 1943*29aca3ebSlc mutex_enter(&ohcip->ohci_int_mutex); 1944*29aca3ebSlc 19457c478bd9Sstevel@tonic-gate if (wait >= 5000) { 19467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19477c478bd9Sstevel@tonic-gate "ohci_take_control: couldn't take control from BIOS\n"); 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate #else /* __x86 */ 19527c478bd9Sstevel@tonic-gate /* 19537c478bd9Sstevel@tonic-gate * On Sparc, there won't be special System Management Mode 19547c478bd9Sstevel@tonic-gate * hardware for legacy devices, while the x86 platforms may 19557c478bd9Sstevel@tonic-gate * have to deal with this. This function may be platform 19567c478bd9Sstevel@tonic-gate * specific. 19577c478bd9Sstevel@tonic-gate * 19587c478bd9Sstevel@tonic-gate * The interrupt routing bit should not be set. 19597c478bd9Sstevel@tonic-gate */ 19607c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_control) & HCR_CONTROL_IR) { 19617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19627c478bd9Sstevel@tonic-gate "ohci_take_control: Routing bit set"); 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate #endif /* __x86 */ 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19697c478bd9Sstevel@tonic-gate "ohci_take_control: End"); 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate 19744610e4a0Sfrits /* 19754610e4a0Sfrits * ohci_pm_support: 19764610e4a0Sfrits * always return success since PM has been quite reliable on ohci 19774610e4a0Sfrits */ 19784610e4a0Sfrits /*ARGSUSED*/ 19794610e4a0Sfrits int 19804610e4a0Sfrits ohci_hcdi_pm_support(dev_info_t *dip) 19814610e4a0Sfrits { 19824610e4a0Sfrits return (USB_SUCCESS); 19834610e4a0Sfrits } 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate /* 19867c478bd9Sstevel@tonic-gate * ohci_alloc_hcdi_ops: 19877c478bd9Sstevel@tonic-gate * 19887c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 19897c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 19907c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 19917c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 19927c478bd9Sstevel@tonic-gate */ 19937c478bd9Sstevel@tonic-gate static usba_hcdi_ops_t * 19947c478bd9Sstevel@tonic-gate ohci_alloc_hcdi_ops(ohci_state_t *ohcip) 19957c478bd9Sstevel@tonic-gate { 19967c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 19997c478bd9Sstevel@tonic-gate "ohci_alloc_hcdi_ops:"); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 20047c478bd9Sstevel@tonic-gate 20054610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ohci_hcdi_pm_support; 20067c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ohci_hcdi_pipe_open; 20077c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ohci_hcdi_pipe_close; 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ohci_hcdi_pipe_reset; 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ohci_hcdi_pipe_ctrl_xfer; 20127c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ohci_hcdi_pipe_bulk_xfer; 20137c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ohci_hcdi_pipe_intr_xfer; 20147c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ohci_hcdi_pipe_isoc_xfer; 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 2017*29aca3ebSlc ohci_hcdi_bulk_transfer_size; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 2020*29aca3ebSlc ohci_hcdi_pipe_stop_intr_polling; 20217c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 2022*29aca3ebSlc ohci_hcdi_pipe_stop_isoc_polling; 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 2025*29aca3ebSlc ohci_hcdi_get_current_frame_number; 20267c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 2027*29aca3ebSlc ohci_hcdi_get_max_isoc_pkts; 20287c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 2029*29aca3ebSlc ohci_hcdi_polled_input_init; 20307c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 2031*29aca3ebSlc ohci_hcdi_polled_input_enter; 20327c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = ohci_hcdi_polled_read; 20337c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 2034*29aca3ebSlc ohci_hcdi_polled_input_exit; 20357c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 2036*29aca3ebSlc ohci_hcdi_polled_input_fini; 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate /* 20437c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 20447c478bd9Sstevel@tonic-gate */ 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate /* 20477c478bd9Sstevel@tonic-gate * ohci_cleanup: 20487c478bd9Sstevel@tonic-gate * 20497c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 20507c478bd9Sstevel@tonic-gate */ 20517c478bd9Sstevel@tonic-gate static int 20527c478bd9Sstevel@tonic-gate ohci_cleanup(ohci_state_t *ohcip) 20537c478bd9Sstevel@tonic-gate { 20547c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 20557c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 20567c478bd9Sstevel@tonic-gate ohci_td_t *td; 20577c478bd9Sstevel@tonic-gate int i, state, rval; 20587c478bd9Sstevel@tonic-gate int flags = ohcip->ohci_flags; 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_cleanup:"); 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate if (flags & OHCI_RHREG) { 20637c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 20647c478bd9Sstevel@tonic-gate if (ohci_unload_root_hub_driver(ohcip) != USB_SUCCESS) { 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate if (flags & OHCI_USBAREG) { 20717c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 20727c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ohcip->ohci_dip); 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate if (flags & OHCI_INTR) { 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate /* Disable all HC ED list processing */ 20807c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 20817c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE | 20827c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE))); 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate /* Disable all HC interrupts */ 20857c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, 20867c478bd9Sstevel@tonic-gate (HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE)); 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 20897c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip); 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate /* Disable Master and SOF interrupts */ 20927c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, (HCR_INTR_MIE | HCR_INTR_SOF)); 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate /* Set the Host Controller Functional State to Reset */ 20957c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) & 20967c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESET)); 20977c478bd9Sstevel@tonic-gate 2098*29aca3ebSlc mutex_exit(&ohcip->ohci_int_mutex); 20997c478bd9Sstevel@tonic-gate /* Wait for sometime */ 2100*29aca3ebSlc delay(drv_usectohz(OHCI_TIMEWAIT)); 2101*29aca3ebSlc mutex_enter(&ohcip->ohci_int_mutex); 21027c478bd9Sstevel@tonic-gate 2103f806f48bShs /* 2104f806f48bShs * Workaround for ULI1575 chipset. Following OHCI Operational 2105f806f48bShs * Memory Registers are not cleared to their default value 2106f806f48bShs * on reset. Explicitly set the registers to default value. 2107f806f48bShs */ 2108f806f48bShs if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID && 2109*29aca3ebSlc ohcip->ohci_device_id == PCI_ULI1575_DEVID) { 2110f806f48bShs Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT); 2111f806f48bShs Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT); 2112f806f48bShs Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT); 2113f806f48bShs Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT); 2114f806f48bShs Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT); 2115f806f48bShs Set_OpReg(hcr_frame_interval, 2116*29aca3ebSlc HCR_FRAME_INTERVAL_DEFAULT); 2117f806f48bShs Set_OpReg(hcr_periodic_strt, 2118*29aca3ebSlc HCR_PERIODIC_START_DEFAULT); 2119f806f48bShs } 2120f806f48bShs 21217c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 21227c478bd9Sstevel@tonic-gate 21239c75c6bfSgovinda ohci_rem_intrs(ohcip); 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* Unmap the OHCI registers */ 21277c478bd9Sstevel@tonic-gate if (ohcip->ohci_regs_handle) { 21287c478bd9Sstevel@tonic-gate /* Reset the host controller */ 21297c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET); 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ohcip->ohci_regs_handle); 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate if (ohcip->ohci_config_handle) { 21357c478bd9Sstevel@tonic-gate pci_config_teardown(&ohcip->ohci_config_handle); 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate /* Free all the buffers */ 21397c478bd9Sstevel@tonic-gate if (ohcip->ohci_td_pool_addr && ohcip->ohci_td_pool_mem_handle) { 21407c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) { 21417c478bd9Sstevel@tonic-gate td = &ohcip->ohci_td_pool_addr[i]; 21427c478bd9Sstevel@tonic-gate state = Get_TD(ohcip->ohci_td_pool_addr[i].hctd_state); 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate if ((state != HC_TD_FREE) && (state != HC_TD_DUMMY) && 21457c478bd9Sstevel@tonic-gate (td->hctd_trans_wrapper)) { 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 2150*29aca3ebSlc OHCI_LOOKUP_ID((uint32_t) 2151*29aca3ebSlc Get_TD(td->hctd_trans_wrapper)); 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 21547c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 21577c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, 2158*29aca3ebSlc OHCI_REMOVE_XFER_ALWAYS); 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 21637c478bd9Sstevel@tonic-gate } 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate /* 21677c478bd9Sstevel@tonic-gate * If OHCI_TD_POOL_BOUND flag is set, then unbind 21687c478bd9Sstevel@tonic-gate * the handle for TD pools. 21697c478bd9Sstevel@tonic-gate */ 21707c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag & 21717c478bd9Sstevel@tonic-gate OHCI_TD_POOL_BOUND) == OHCI_TD_POOL_BOUND) { 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 21747c478bd9Sstevel@tonic-gate ohcip->ohci_td_pool_dma_handle); 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_td_pool_mem_handle); 21797c478bd9Sstevel@tonic-gate } 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate /* Free the TD pool */ 21827c478bd9Sstevel@tonic-gate if (ohcip->ohci_td_pool_dma_handle) { 21837c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_td_pool_dma_handle); 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate if (ohcip->ohci_ed_pool_addr && ohcip->ohci_ed_pool_mem_handle) { 21877c478bd9Sstevel@tonic-gate /* 21887c478bd9Sstevel@tonic-gate * If OHCI_ED_POOL_BOUND flag is set, then unbind 21897c478bd9Sstevel@tonic-gate * the handle for ED pools. 21907c478bd9Sstevel@tonic-gate */ 21917c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag & 21927c478bd9Sstevel@tonic-gate OHCI_ED_POOL_BOUND) == OHCI_ED_POOL_BOUND) { 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 21957c478bd9Sstevel@tonic-gate ohcip->ohci_ed_pool_dma_handle); 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 21987c478bd9Sstevel@tonic-gate } 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_ed_pool_mem_handle); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate /* Free the ED pool */ 22047c478bd9Sstevel@tonic-gate if (ohcip->ohci_ed_pool_dma_handle) { 22057c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_ed_pool_dma_handle); 22067c478bd9Sstevel@tonic-gate } 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate /* Free the HCCA area */ 22097c478bd9Sstevel@tonic-gate if (ohcip->ohci_hccap && ohcip->ohci_hcca_mem_handle) { 22107c478bd9Sstevel@tonic-gate /* 22117c478bd9Sstevel@tonic-gate * If OHCI_HCCA_DMA_BOUND flag is set, then unbind 22127c478bd9Sstevel@tonic-gate * the handle for HCCA. 22137c478bd9Sstevel@tonic-gate */ 22147c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag & 22157c478bd9Sstevel@tonic-gate OHCI_HCCA_DMA_BOUND) == OHCI_HCCA_DMA_BOUND) { 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 22187c478bd9Sstevel@tonic-gate ohcip->ohci_hcca_dma_handle); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 22217c478bd9Sstevel@tonic-gate } 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_hcca_mem_handle); 22247c478bd9Sstevel@tonic-gate } 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate if (ohcip->ohci_hcca_dma_handle) { 22277c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_hcca_dma_handle); 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate if (flags & OHCI_INTR) { 22317c478bd9Sstevel@tonic-gate 22327c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 22337c478bd9Sstevel@tonic-gate mutex_destroy(&ohcip->ohci_int_mutex); 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate /* Destroy the SOF condition varibale */ 22367c478bd9Sstevel@tonic-gate cv_destroy(&ohcip->ohci_SOF_cv); 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* Destroy the serialize opens and closes semaphore */ 22397c478bd9Sstevel@tonic-gate sema_destroy(&ohcip->ohci_ocsem); 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate 22427c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 22437c478bd9Sstevel@tonic-gate ohci_destroy_stats(ohcip); 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate /* Free ohci hcdi ops */ 22467c478bd9Sstevel@tonic-gate if (ohcip->ohci_hcdi_ops) { 22477c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ohcip->ohci_hcdi_ops); 22487c478bd9Sstevel@tonic-gate } 22497c478bd9Sstevel@tonic-gate 22507c478bd9Sstevel@tonic-gate if (flags & OHCI_ZALLOC) { 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate usb_free_log_hdl(ohcip->ohci_log_hdl); 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 22557c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ohcip->ohci_dip); 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate /* Free the soft state */ 22587c478bd9Sstevel@tonic-gate ddi_soft_state_free(ohci_statep, 2259*29aca3ebSlc ddi_get_instance(ohcip->ohci_dip)); 22607c478bd9Sstevel@tonic-gate } 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate 22657c478bd9Sstevel@tonic-gate 22669c75c6bfSgovinda /* 22679c75c6bfSgovinda * ohci_rem_intrs: 22689c75c6bfSgovinda * 22699c75c6bfSgovinda * Unregister FIXED or MSI interrupts 22709c75c6bfSgovinda */ 22719c75c6bfSgovinda static void 22729c75c6bfSgovinda ohci_rem_intrs(ohci_state_t *ohcip) 22739c75c6bfSgovinda { 22749c75c6bfSgovinda int i; 22759c75c6bfSgovinda 22769c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 22779c75c6bfSgovinda "ohci_rem_intrs: interrupt type 0x%x", ohcip->ohci_intr_type); 22789c75c6bfSgovinda 22799c75c6bfSgovinda /* Disable all interrupts */ 22809c75c6bfSgovinda if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) { 22819c75c6bfSgovinda (void) ddi_intr_block_disable(ohcip->ohci_htable, 22829c75c6bfSgovinda ohcip->ohci_intr_cnt); 22839c75c6bfSgovinda } else { 22849c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) { 22859c75c6bfSgovinda (void) ddi_intr_disable(ohcip->ohci_htable[i]); 22869c75c6bfSgovinda } 22879c75c6bfSgovinda } 22889c75c6bfSgovinda 22899c75c6bfSgovinda /* Call ddi_intr_remove_handler() */ 22909c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) { 22919c75c6bfSgovinda (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]); 22929c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]); 22939c75c6bfSgovinda } 22949c75c6bfSgovinda 22959c75c6bfSgovinda kmem_free(ohcip->ohci_htable, 22969c75c6bfSgovinda ohcip->ohci_intr_cnt * sizeof (ddi_intr_handle_t)); 22979c75c6bfSgovinda } 22989c75c6bfSgovinda 22999c75c6bfSgovinda 23007c478bd9Sstevel@tonic-gate /* 23017c478bd9Sstevel@tonic-gate * ohci_cpr_suspend 23027c478bd9Sstevel@tonic-gate */ 23037c478bd9Sstevel@tonic-gate static int 23047c478bd9Sstevel@tonic-gate ohci_cpr_suspend(ohci_state_t *ohcip) 23057c478bd9Sstevel@tonic-gate { 23067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23077c478bd9Sstevel@tonic-gate "ohci_cpr_suspend:"); 23087c478bd9Sstevel@tonic-gate 23097c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 23107c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ohcip->ohci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 23167c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_pipe_count > 1) { 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23217c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: fails as open pipe count = %d", 23227c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count); 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23307c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable HC ED list processing"); 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate /* Disable all HC ED list processing */ 23337c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE | 23347c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE))); 23357c478bd9Sstevel@tonic-gate 23367c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23377c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable HC interrupts"); 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate /* Disable all HC interrupts */ 23407c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, ~(HCR_INTR_MIE|HCR_INTR_SOF)); 23417c478bd9Sstevel@tonic-gate 23427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23437c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Wait for the next SOF"); 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 23467c478bd9Sstevel@tonic-gate if (ohci_wait_for_sof(ohcip) != USB_SUCCESS) { 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23497c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: ohci host controller suspend failed"); 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 23537c478bd9Sstevel@tonic-gate } 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23567c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable Master interrupt"); 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate /* 23597c478bd9Sstevel@tonic-gate * Disable Master interrupt so that ohci driver don't 23607c478bd9Sstevel@tonic-gate * get any ohci interrupts. 23617c478bd9Sstevel@tonic-gate */ 23627c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE); 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate /* 23657c478bd9Sstevel@tonic-gate * Suspend the ohci host controller 23667c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 23677c478bd9Sstevel@tonic-gate */ 23682df1fe9cSrandyf if (ohcip->ohci_polled_kbd_count == 0 || force_ohci_off != 0) { 23697c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, HCR_CONTROL_SUSPD); 23707c478bd9Sstevel@tonic-gate } 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 23737c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_SUSPEND_STATE; 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate * ohci_cpr_resume 23837c478bd9Sstevel@tonic-gate */ 23847c478bd9Sstevel@tonic-gate static int 23857c478bd9Sstevel@tonic-gate ohci_cpr_resume(ohci_state_t *ohcip) 23867c478bd9Sstevel@tonic-gate { 23877c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23907c478bd9Sstevel@tonic-gate "ohci_cpr_resume: Restart the controller"); 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate /* Cleanup ohci specific information across cpr */ 23937c478bd9Sstevel@tonic-gate ohci_cpr_cleanup(ohcip); 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate /* Restart the controller */ 23967c478bd9Sstevel@tonic-gate if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) { 23977c478bd9Sstevel@tonic-gate 2398d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 23997c478bd9Sstevel@tonic-gate "ohci_cpr_resume: ohci host controller resume failed "); 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 24047c478bd9Sstevel@tonic-gate } 24057c478bd9Sstevel@tonic-gate 24067c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 24097c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ohcip->ohci_dip, DDI_RESUME) != DDI_SUCCESS) { 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 24127c478bd9Sstevel@tonic-gate } 24137c478bd9Sstevel@tonic-gate 24147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 24157c478bd9Sstevel@tonic-gate } 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate /* 24197c478bd9Sstevel@tonic-gate * HCDI entry points 24207c478bd9Sstevel@tonic-gate * 24217c478bd9Sstevel@tonic-gate * The Host Controller Driver Interfaces (HCDI) are the software interfaces 24227c478bd9Sstevel@tonic-gate * between the Universal Serial Bus Layer (USBA) and the Host Controller 24237c478bd9Sstevel@tonic-gate * Driver (HCD). The HCDI interfaces or entry points are subject to change. 24247c478bd9Sstevel@tonic-gate */ 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_open: 24287c478bd9Sstevel@tonic-gate * 24297c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during client specific pipe open 24307c478bd9Sstevel@tonic-gate * Add the pipe to the data structure representing the device and allocate 24317c478bd9Sstevel@tonic-gate * bandwidth for the pipe if it is a interrupt or isochronous endpoint. 24327c478bd9Sstevel@tonic-gate */ 24337c478bd9Sstevel@tonic-gate static int 24347c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_open( 24357c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 24367c478bd9Sstevel@tonic-gate usb_flags_t flags) 24377c478bd9Sstevel@tonic-gate { 24387c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2439*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 24407c478bd9Sstevel@tonic-gate usb_ep_descr_t *epdt = &ph->p_ep; 24417c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS; 24427c478bd9Sstevel@tonic-gate int kmflag = (flags & USB_FLAGS_SLEEP) ? 2443*29aca3ebSlc KM_SLEEP : KM_NOSLEEP; 24447c478bd9Sstevel@tonic-gate uint_t node = 0; 24457c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 24467c478bd9Sstevel@tonic-gate 24477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 24487c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: addr = 0x%x, ep%d", 24497c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_addr, 24507c478bd9Sstevel@tonic-gate epdt->bEndpointAddress & USB_EP_NUM_MASK); 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate sema_p(&ohcip->ohci_ocsem); 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 24557c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 24567c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 24597c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate return (rval); 24627c478bd9Sstevel@tonic-gate } 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate /* 24657c478bd9Sstevel@tonic-gate * Check and handle root hub pipe open. 24667c478bd9Sstevel@tonic-gate */ 24677c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 24707c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_open(ph, flags); 24717c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 24727c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate return (error); 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate /* 24787c478bd9Sstevel@tonic-gate * Opening of other pipes excluding root hub pipe are 24797c478bd9Sstevel@tonic-gate * handled below. Check whether pipe is already opened. 24807c478bd9Sstevel@tonic-gate */ 24817c478bd9Sstevel@tonic-gate if (ph->p_hcd_private) { 24827c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 24837c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: Pipe is already opened"); 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 24867c478bd9Sstevel@tonic-gate 24877c478bd9Sstevel@tonic-gate return (USB_FAILURE); 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate 24907c478bd9Sstevel@tonic-gate /* 24917c478bd9Sstevel@tonic-gate * A portion of the bandwidth is reserved for the non-periodic 24927c478bd9Sstevel@tonic-gate * transfers, i.e control and bulk transfers in each of one 24937c478bd9Sstevel@tonic-gate * millisecond frame period & usually it will be 10% of frame 24947c478bd9Sstevel@tonic-gate * period. Hence there is no need to check for the available 24957c478bd9Sstevel@tonic-gate * bandwidth before adding the control or bulk endpoints. 24967c478bd9Sstevel@tonic-gate * 24977c478bd9Sstevel@tonic-gate * There is a need to check for the available bandwidth before 24987c478bd9Sstevel@tonic-gate * adding the periodic transfers, i.e interrupt & isochronous, 24997c478bd9Sstevel@tonic-gate * since all these periodic transfers are guaranteed transfers. 25007c478bd9Sstevel@tonic-gate * Usually 90% of the total frame time is reserved for periodic 25017c478bd9Sstevel@tonic-gate * transfers. 25027c478bd9Sstevel@tonic-gate */ 25037c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) { 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 25067c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate error = ohci_allocate_bandwidth(ohcip, ph, &node); 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 25137c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: Bandwidth allocation failed"); 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 25167c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 25177c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate return (error); 25207c478bd9Sstevel@tonic-gate } 25217c478bd9Sstevel@tonic-gate 25227c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 25237c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate /* Create the HCD pipe private structure */ 25277c478bd9Sstevel@tonic-gate pp = kmem_zalloc(sizeof (ohci_pipe_private_t), kmflag); 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate /* 25307c478bd9Sstevel@tonic-gate * Return failure if ohci pipe private 25317c478bd9Sstevel@tonic-gate * structure allocation fails. 25327c478bd9Sstevel@tonic-gate */ 25337c478bd9Sstevel@tonic-gate if (pp == NULL) { 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 25367c478bd9Sstevel@tonic-gate 25377c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 25387c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) { 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 25417c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph); 25427c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 25437c478bd9Sstevel@tonic-gate } 25447c478bd9Sstevel@tonic-gate 25457c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 25467c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 25477c478bd9Sstevel@tonic-gate 25487c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate /* Store the node in the interrupt lattice */ 25547c478bd9Sstevel@tonic-gate pp->pp_node = node; 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* Create prototype for xfer completion condition variable */ 25577c478bd9Sstevel@tonic-gate cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL); 25587c478bd9Sstevel@tonic-gate 25597c478bd9Sstevel@tonic-gate /* Set the state of pipe as idle */ 25607c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate /* Store a pointer to the pipe handle */ 25637c478bd9Sstevel@tonic-gate pp->pp_pipe_handle = ph; 25647c478bd9Sstevel@tonic-gate 25657c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 25667c478bd9Sstevel@tonic-gate 25677c478bd9Sstevel@tonic-gate /* Store the pointer in the pipe handle */ 25687c478bd9Sstevel@tonic-gate ph->p_hcd_private = (usb_opaque_t)pp; 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate /* Store a copy of the pipe policy */ 25717c478bd9Sstevel@tonic-gate bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t)); 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 25747c478bd9Sstevel@tonic-gate 25757c478bd9Sstevel@tonic-gate /* Allocate the host controller endpoint descriptor */ 25767c478bd9Sstevel@tonic-gate pp->pp_ept = ohci_alloc_hc_ed(ohcip, ph); 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate if (pp->pp_ept == NULL) { 25797c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 25807c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: ED allocation failed"); 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 25857c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) { 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph); 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate 25907c478bd9Sstevel@tonic-gate /* Destroy the xfer completion condition varibale */ 25917c478bd9Sstevel@tonic-gate cv_destroy(&pp->pp_xfer_cmpl_cv); 25927c478bd9Sstevel@tonic-gate 25937c478bd9Sstevel@tonic-gate /* 25947c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion 25957c478bd9Sstevel@tonic-gate * of the pipe handle. 25967c478bd9Sstevel@tonic-gate */ 25977c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (ohci_pipe_private_t)); 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate /* 26007c478bd9Sstevel@tonic-gate * Set the private structure in the 26017c478bd9Sstevel@tonic-gate * pipe handle equal to NULL. 26027c478bd9Sstevel@tonic-gate */ 26037c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL; 26047c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 26057c478bd9Sstevel@tonic-gate 26067c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 26077c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 26107c478bd9Sstevel@tonic-gate } 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate /* Restore the data toggle information */ 26137c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(ohcip, ph); 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate /* 26167c478bd9Sstevel@tonic-gate * Insert the endpoint onto the host controller's 26177c478bd9Sstevel@tonic-gate * appropriate endpoint list. The host controller 26187c478bd9Sstevel@tonic-gate * will not schedule this endpoint and will not have 26197c478bd9Sstevel@tonic-gate * any TD's to process. 26207c478bd9Sstevel@tonic-gate */ 26217c478bd9Sstevel@tonic-gate ohci_insert_ed(ohcip, ph); 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 26247c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: ph = 0x%p", (void *)ph); 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count++; 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 26297c478bd9Sstevel@tonic-gate 26307c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate 26367c478bd9Sstevel@tonic-gate /* 26377c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_close: 26387c478bd9Sstevel@tonic-gate * 26397c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during the client specific pipe 26407c478bd9Sstevel@tonic-gate * close. Remove the pipe and the data structure representing the device. 26417c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the pipe if it is a interrupt or isochronous 26427c478bd9Sstevel@tonic-gate * endpoint. 26437c478bd9Sstevel@tonic-gate */ 26447c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26457c478bd9Sstevel@tonic-gate static int 26467c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_close( 26477c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 26487c478bd9Sstevel@tonic-gate usb_flags_t flags) 26497c478bd9Sstevel@tonic-gate { 26507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2651*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 26527c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 26537c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 26547c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 26557c478bd9Sstevel@tonic-gate 26567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 26577c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_close: addr = 0x%x, ep%d", 26587c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_addr, 26597c478bd9Sstevel@tonic-gate eptd->bEndpointAddress & USB_EP_NUM_MASK); 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate sema_p(&ohcip->ohci_ocsem); 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate /* Check and handle root hub pipe close */ 26647c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 26677c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_close(ph); 26687c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 26697c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate return (error); 26727c478bd9Sstevel@tonic-gate } 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate ASSERT(ph->p_hcd_private != NULL); 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 26777c478bd9Sstevel@tonic-gate 26787c478bd9Sstevel@tonic-gate /* Set pipe state to pipe close */ 26797c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_CLOSE; 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph); 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate /* 26847c478bd9Sstevel@tonic-gate * Remove the endoint descriptor from Host 26857c478bd9Sstevel@tonic-gate * Controller's appropriate endpoint list. 26867c478bd9Sstevel@tonic-gate */ 26877c478bd9Sstevel@tonic-gate ohci_remove_ed(ohcip, pp); 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */ 26907c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(eptd)) { 26917c478bd9Sstevel@tonic-gate 26927c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 26937c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph); 26947c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate /* Destroy the xfer completion condition varibale */ 27007c478bd9Sstevel@tonic-gate cv_destroy(&pp->pp_xfer_cmpl_cv); 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate /* 27037c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion 27047c478bd9Sstevel@tonic-gate * of the pipe handle. 27057c478bd9Sstevel@tonic-gate */ 27067c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (ohci_pipe_private_t)); 27077c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL; 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 27127c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_close: ph = 0x%p", (void *)ph); 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count--; 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27177c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem); 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate return (error); 27207c478bd9Sstevel@tonic-gate } 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate /* 27247c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_reset: 27257c478bd9Sstevel@tonic-gate */ 27267c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27277c478bd9Sstevel@tonic-gate static int 27287c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_reset( 27297c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 27307c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 27317c478bd9Sstevel@tonic-gate { 27327c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2733*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 27347c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 27357c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 27387c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_reset: ph = 0x%p ", (void *)ph); 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate /* 27417c478bd9Sstevel@tonic-gate * Check and handle root hub pipe reset. 27427c478bd9Sstevel@tonic-gate */ 27437c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_reset(ph, usb_flags); 27467c478bd9Sstevel@tonic-gate return (error); 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate /* Set pipe state to pipe reset */ 27527c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_RESET; 27537c478bd9Sstevel@tonic-gate 27547c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph); 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate return (error); 27597c478bd9Sstevel@tonic-gate } 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate /* 27637c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_ctrl_xfer: 27647c478bd9Sstevel@tonic-gate */ 27657c478bd9Sstevel@tonic-gate static int 27667c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_ctrl_xfer( 27677c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 27687c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 27697c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 27707c478bd9Sstevel@tonic-gate { 27717c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2772*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 27737c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 27747c478bd9Sstevel@tonic-gate int rval; 27757c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 27767c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 27777c478bd9Sstevel@tonic-gate 27787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 27797c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_ctrl_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 27807c478bd9Sstevel@tonic-gate (void *)ph, ctrl_reqp, usb_flags); 27817c478bd9Sstevel@tonic-gate 27827c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 27837c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 27847c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate return (rval); 27897c478bd9Sstevel@tonic-gate } 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate /* 27927c478bd9Sstevel@tonic-gate * Check and handle root hub control request. 27937c478bd9Sstevel@tonic-gate */ 27947c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_request(ohcip, ph, ctrl_reqp); 27977c478bd9Sstevel@tonic-gate 27987c478bd9Sstevel@tonic-gate return (error); 27997c478bd9Sstevel@tonic-gate } 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate /* 28047c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 28057c478bd9Sstevel@tonic-gate */ 28067c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) { 28077c478bd9Sstevel@tonic-gate 28087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 28097c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_ctrl_xfer:" 28107c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28137c478bd9Sstevel@tonic-gate 28147c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28157c478bd9Sstevel@tonic-gate } 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate /* Allocate a transfer wrapper */ 28187c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_ctrl_resources(ohcip, pp, ctrl_reqp, 28197c478bd9Sstevel@tonic-gate usb_flags)) == NULL) { 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 28227c478bd9Sstevel@tonic-gate } else { 28237c478bd9Sstevel@tonic-gate /* Insert the td's on the endpoint */ 28247c478bd9Sstevel@tonic-gate ohci_insert_ctrl_req(ohcip, ph, ctrl_reqp, tw, usb_flags); 28257c478bd9Sstevel@tonic-gate } 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate return (error); 28307c478bd9Sstevel@tonic-gate } 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate /* 28347c478bd9Sstevel@tonic-gate * ohci_hcdi_bulk_transfer_size: 28357c478bd9Sstevel@tonic-gate * 28367c478bd9Sstevel@tonic-gate * Return maximum bulk transfer size 28377c478bd9Sstevel@tonic-gate */ 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28407c478bd9Sstevel@tonic-gate static int 28417c478bd9Sstevel@tonic-gate ohci_hcdi_bulk_transfer_size( 28427c478bd9Sstevel@tonic-gate usba_device_t *usba_device, 28437c478bd9Sstevel@tonic-gate size_t *size) 28447c478bd9Sstevel@tonic-gate { 28457c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2846*29aca3ebSlc usba_device->usb_root_hub_dip); 28477c478bd9Sstevel@tonic-gate int rval; 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 28507c478bd9Sstevel@tonic-gate "ohci_hcdi_bulk_transfer_size:"); 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 28537c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 28547c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate return (rval); 28597c478bd9Sstevel@tonic-gate } 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate *size = OHCI_MAX_BULK_XFER_SIZE; 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 28647c478bd9Sstevel@tonic-gate } 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate 28677c478bd9Sstevel@tonic-gate /* 28687c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_bulk_xfer: 28697c478bd9Sstevel@tonic-gate */ 28707c478bd9Sstevel@tonic-gate static int 28717c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_bulk_xfer( 28727c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 28737c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 28747c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 28757c478bd9Sstevel@tonic-gate { 28767c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2877*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 28787c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 28797c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS; 28807c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 28817c478bd9Sstevel@tonic-gate 28827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 28837c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 28847c478bd9Sstevel@tonic-gate (void *)ph, bulk_reqp, usb_flags); 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 28877c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 28887c478bd9Sstevel@tonic-gate 28897c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 28907c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate return (rval); 28937c478bd9Sstevel@tonic-gate } 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate /* 28967c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 28977c478bd9Sstevel@tonic-gate */ 28987c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) { 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 29017c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_bulk_xfer:" 29027c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29057c478bd9Sstevel@tonic-gate 29067c478bd9Sstevel@tonic-gate return (USB_FAILURE); 29077c478bd9Sstevel@tonic-gate } 29087c478bd9Sstevel@tonic-gate 29097c478bd9Sstevel@tonic-gate /* Allocate a transfer wrapper */ 29107c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_bulk_resources(ohcip, pp, bulk_reqp, 29117c478bd9Sstevel@tonic-gate usb_flags)) == NULL) { 29127c478bd9Sstevel@tonic-gate 29137c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 29147c478bd9Sstevel@tonic-gate } else { 29157c478bd9Sstevel@tonic-gate /* Add the TD into the Host Controller's bulk list */ 29167c478bd9Sstevel@tonic-gate ohci_insert_bulk_req(ohcip, ph, bulk_reqp, tw, usb_flags); 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate 29197c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate return (error); 29227c478bd9Sstevel@tonic-gate } 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate /* 29267c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_intr_xfer: 29277c478bd9Sstevel@tonic-gate */ 29287c478bd9Sstevel@tonic-gate static int 29297c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_intr_xfer( 29307c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 29317c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 29327c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 29337c478bd9Sstevel@tonic-gate { 29347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2935*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 29367c478bd9Sstevel@tonic-gate int pipe_dir, rval, error = USB_SUCCESS; 29377c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 29407c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_intr_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 29417c478bd9Sstevel@tonic-gate (void *)ph, intr_reqp, usb_flags); 29427c478bd9Sstevel@tonic-gate 29437c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 29447c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 29477c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29487c478bd9Sstevel@tonic-gate 29497c478bd9Sstevel@tonic-gate return (rval); 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate /* Get the pipe direction */ 29537c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 29547c478bd9Sstevel@tonic-gate 29557c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 29567c478bd9Sstevel@tonic-gate error = ohci_start_periodic_pipe_polling(ohcip, ph, 29577c478bd9Sstevel@tonic-gate (usb_opaque_t)intr_reqp, usb_flags); 29587c478bd9Sstevel@tonic-gate } else { 29597c478bd9Sstevel@tonic-gate /* Allocate transaction resources */ 29607c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_intr_resources(ohcip, ph, 29617c478bd9Sstevel@tonic-gate intr_reqp, usb_flags)) == NULL) { 29627c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 29637c478bd9Sstevel@tonic-gate } else { 29647c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, 29657c478bd9Sstevel@tonic-gate (ohci_pipe_private_t *)ph->p_hcd_private, 29667c478bd9Sstevel@tonic-gate tw, usb_flags); 29677c478bd9Sstevel@tonic-gate } 29687c478bd9Sstevel@tonic-gate } 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29717c478bd9Sstevel@tonic-gate 29727c478bd9Sstevel@tonic-gate return (error); 29737c478bd9Sstevel@tonic-gate } 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate /* 29777c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_stop_intr_polling() 29787c478bd9Sstevel@tonic-gate */ 29797c478bd9Sstevel@tonic-gate static int 29807c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_intr_polling( 29817c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 29827c478bd9Sstevel@tonic-gate usb_flags_t flags) 29837c478bd9Sstevel@tonic-gate { 29847c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 2985*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 29867c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 29897c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x", 29907c478bd9Sstevel@tonic-gate ph, flags); 29917c478bd9Sstevel@tonic-gate 29927c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate error = ohci_stop_periodic_pipe_polling(ohcip, ph, flags); 29957c478bd9Sstevel@tonic-gate 29967c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate return (error); 29997c478bd9Sstevel@tonic-gate } 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate 30027c478bd9Sstevel@tonic-gate /* 30037c478bd9Sstevel@tonic-gate * ohci_hcdi_get_current_frame_number: 30047c478bd9Sstevel@tonic-gate * 30057c478bd9Sstevel@tonic-gate * Return the current usb frame number 30067c478bd9Sstevel@tonic-gate */ 30077c478bd9Sstevel@tonic-gate static usb_frame_number_t 30087c478bd9Sstevel@tonic-gate ohci_hcdi_get_current_frame_number(usba_device_t *usba_device) 30097c478bd9Sstevel@tonic-gate { 30107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 3011*29aca3ebSlc usba_device->usb_root_hub_dip); 30127c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number; 30137c478bd9Sstevel@tonic-gate int rval; 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate ohcip = ohci_obtain_state(usba_device->usb_root_hub_dip); 30167c478bd9Sstevel@tonic-gate 30177c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 30187c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 30217c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate return (rval); 30247c478bd9Sstevel@tonic-gate } 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate frame_number = ohci_get_current_frame_number(ohcip); 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 30317c478bd9Sstevel@tonic-gate "ohci_hcdi_get_current_frame_number:" 30327c478bd9Sstevel@tonic-gate "Current frame number 0x%llx", frame_number); 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate return (frame_number); 30357c478bd9Sstevel@tonic-gate } 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate /* 30397c478bd9Sstevel@tonic-gate * ohci_hcdi_get_max_isoc_pkts: 30407c478bd9Sstevel@tonic-gate * 30417c478bd9Sstevel@tonic-gate * Return maximum isochronous packets per usb isochronous request 30427c478bd9Sstevel@tonic-gate */ 30437c478bd9Sstevel@tonic-gate static uint_t 30447c478bd9Sstevel@tonic-gate ohci_hcdi_get_max_isoc_pkts(usba_device_t *usba_device) 30457c478bd9Sstevel@tonic-gate { 30467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 3047*29aca3ebSlc usba_device->usb_root_hub_dip); 30487c478bd9Sstevel@tonic-gate uint_t max_isoc_pkts_per_request; 30497c478bd9Sstevel@tonic-gate int rval; 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 30527c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 30537c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 30567c478bd9Sstevel@tonic-gate 30577c478bd9Sstevel@tonic-gate return (rval); 30587c478bd9Sstevel@tonic-gate } 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate max_isoc_pkts_per_request = OHCI_MAX_ISOC_PKTS_PER_XFER; 30617c478bd9Sstevel@tonic-gate 30627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 30637c478bd9Sstevel@tonic-gate "ohci_hcdi_get_max_isoc_pkts: maximum isochronous" 30647c478bd9Sstevel@tonic-gate "packets per usb isochronous request = 0x%x", 30657c478bd9Sstevel@tonic-gate max_isoc_pkts_per_request); 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate return (max_isoc_pkts_per_request); 30687c478bd9Sstevel@tonic-gate } 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate /* 30727c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_isoc_xfer: 30737c478bd9Sstevel@tonic-gate */ 30747c478bd9Sstevel@tonic-gate static int 30757c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_isoc_xfer( 30767c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 30777c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 30787c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 30797c478bd9Sstevel@tonic-gate { 30807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 3081*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 30827c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 30837c478bd9Sstevel@tonic-gate int pipe_dir, rval; 30847c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 30857c478bd9Sstevel@tonic-gate 30867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 30877c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_isoc_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 30887c478bd9Sstevel@tonic-gate (void *)ph, isoc_reqp, usb_flags); 30897c478bd9Sstevel@tonic-gate 30907c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 30917c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 30927c478bd9Sstevel@tonic-gate 30937c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 30947c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 30957c478bd9Sstevel@tonic-gate 30967c478bd9Sstevel@tonic-gate return (rval); 30977c478bd9Sstevel@tonic-gate } 30987c478bd9Sstevel@tonic-gate 30997c478bd9Sstevel@tonic-gate /* Get the isochronous pipe direction */ 31007c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 31037c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_isoc_xfer: isoc_reqp = 0x%p, uf = 0x%x", 31047c478bd9Sstevel@tonic-gate isoc_reqp, usb_flags); 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 31077c478bd9Sstevel@tonic-gate error = ohci_start_periodic_pipe_polling(ohcip, ph, 31087c478bd9Sstevel@tonic-gate (usb_opaque_t)isoc_reqp, usb_flags); 31097c478bd9Sstevel@tonic-gate } else { 31107c478bd9Sstevel@tonic-gate /* Allocate transaction resources */ 31117c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_isoc_resources(ohcip, ph, 31127c478bd9Sstevel@tonic-gate isoc_reqp, usb_flags)) == NULL) { 31137c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 31147c478bd9Sstevel@tonic-gate } else { 31157c478bd9Sstevel@tonic-gate error = ohci_insert_isoc_req(ohcip, 31167c478bd9Sstevel@tonic-gate (ohci_pipe_private_t *)ph->p_hcd_private, 31177c478bd9Sstevel@tonic-gate tw, usb_flags); 31187c478bd9Sstevel@tonic-gate } 31197c478bd9Sstevel@tonic-gate } 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 31227c478bd9Sstevel@tonic-gate 31237c478bd9Sstevel@tonic-gate return (error); 31247c478bd9Sstevel@tonic-gate } 31257c478bd9Sstevel@tonic-gate 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate /* 31287c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_stop_isoc_polling() 31297c478bd9Sstevel@tonic-gate */ 31307c478bd9Sstevel@tonic-gate static int 31317c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_isoc_polling( 31327c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 31337c478bd9Sstevel@tonic-gate usb_flags_t flags) 31347c478bd9Sstevel@tonic-gate { 31357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 3136*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 31377c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS; 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl, 31407c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", 31417c478bd9Sstevel@tonic-gate (void *)ph, flags); 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 31447c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 31457c478bd9Sstevel@tonic-gate 31467c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 31477c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 31487c478bd9Sstevel@tonic-gate return (rval); 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate 31517c478bd9Sstevel@tonic-gate error = ohci_stop_periodic_pipe_polling(ohcip, ph, flags); 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 31547c478bd9Sstevel@tonic-gate return (error); 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate 31577c478bd9Sstevel@tonic-gate 31587c478bd9Sstevel@tonic-gate /* 31597c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 31607c478bd9Sstevel@tonic-gate */ 31617c478bd9Sstevel@tonic-gate 31627c478bd9Sstevel@tonic-gate /* 31637c478bd9Sstevel@tonic-gate * ohci_allocate_bandwidth: 31647c478bd9Sstevel@tonic-gate * 31657c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 31667c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 31677c478bd9Sstevel@tonic-gate * can not be supported. 31687c478bd9Sstevel@tonic-gate * 31697c478bd9Sstevel@tonic-gate * The lattice structure looks like this with the bottom leaf actually 3170*29aca3ebSlc * being an array. There is a total of 63 nodes in this tree. The lattice tree 31717c478bd9Sstevel@tonic-gate * itself is 0 based, while the bottom leaf array is 0 based. The 0 bucket in 31727c478bd9Sstevel@tonic-gate * the bottom leaf array is used to store the smalled allocated bandwidth of all 31737c478bd9Sstevel@tonic-gate * the leaves. 31747c478bd9Sstevel@tonic-gate * 3175*29aca3ebSlc * 0 31767c478bd9Sstevel@tonic-gate * 1 2 31777c478bd9Sstevel@tonic-gate * 3 4 5 6 31787c478bd9Sstevel@tonic-gate * ... 3179*29aca3ebSlc * (32 33 ... 62 63) <-- last row does not exist in lattice, but an array 31807c478bd9Sstevel@tonic-gate * 0 1 2 3 ... 30 31 31817c478bd9Sstevel@tonic-gate * 3182*29aca3ebSlc * We keep track of the bandwidth that each leaf uses. First we search for the 31837c478bd9Sstevel@tonic-gate * first leaf with the smallest used bandwidth. Based on that leaf we find the 31847c478bd9Sstevel@tonic-gate * parent node of that leaf based on the interval time. 31857c478bd9Sstevel@tonic-gate * 31867c478bd9Sstevel@tonic-gate * From the parent node, we find all the leafs of that subtree and update the 31877c478bd9Sstevel@tonic-gate * additional bandwidth needed. In order to balance the load the leaves are not 31887c478bd9Sstevel@tonic-gate * executed directly from left to right, but scattered. For a better picture 31897c478bd9Sstevel@tonic-gate * refer to Section 3.3.2 in the OpenHCI 1.0 spec, there should be a figure 31907c478bd9Sstevel@tonic-gate * showing the Interrupt ED Structure. 31917c478bd9Sstevel@tonic-gate */ 31927c478bd9Sstevel@tonic-gate static int 31937c478bd9Sstevel@tonic-gate ohci_allocate_bandwidth( 31947c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 31957c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 31967c478bd9Sstevel@tonic-gate uint_t *node) 31977c478bd9Sstevel@tonic-gate { 31987c478bd9Sstevel@tonic-gate int interval, error, i; 31997c478bd9Sstevel@tonic-gate uint_t min, min_index, height; 32007c478bd9Sstevel@tonic-gate uint_t leftmost, list, bandwidth; 32017c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate /* This routine is protected by the ohci_int_mutex */ 32047c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 32057c478bd9Sstevel@tonic-gate 32067c478bd9Sstevel@tonic-gate /* 32077c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 32087c478bd9Sstevel@tonic-gate * periodic endpoint. 32097c478bd9Sstevel@tonic-gate */ 32107c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 32117c478bd9Sstevel@tonic-gate error = ohci_compute_total_bandwidth( 32127c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status, &bandwidth); 32137c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 32147c478bd9Sstevel@tonic-gate 32157c478bd9Sstevel@tonic-gate /* 32167c478bd9Sstevel@tonic-gate * If length is zero, then, it means endpoint maximum packet 32177c478bd9Sstevel@tonic-gate * supported is zero. In that case, return failure without 32187c478bd9Sstevel@tonic-gate * allocating any bandwidth. 32197c478bd9Sstevel@tonic-gate */ 32207c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 32217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32227c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Periodic endpoint with " 32237c478bd9Sstevel@tonic-gate "zero endpoint maximum packet size is not supported"); 32247c478bd9Sstevel@tonic-gate 32257c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 32267c478bd9Sstevel@tonic-gate } 32277c478bd9Sstevel@tonic-gate 32287c478bd9Sstevel@tonic-gate /* 32297c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 32307c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 32317c478bd9Sstevel@tonic-gate */ 32327c478bd9Sstevel@tonic-gate if ((ohcip->ohci_periodic_minimum_bandwidth + bandwidth) > 32337c478bd9Sstevel@tonic-gate (MAX_PERIODIC_BANDWIDTH)) { 32347c478bd9Sstevel@tonic-gate 32357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32367c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Reached maximum " 32377c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth " 32387c478bd9Sstevel@tonic-gate "for a given periodic endpoint"); 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 32417c478bd9Sstevel@tonic-gate } 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 32447c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 32457c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, 32467c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status); 32477c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 32487c478bd9Sstevel@tonic-gate 32497c478bd9Sstevel@tonic-gate /* 32507c478bd9Sstevel@tonic-gate * If this interval can't be supported, 32517c478bd9Sstevel@tonic-gate * return allocation failure. 32527c478bd9Sstevel@tonic-gate */ 32537c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32567c478bd9Sstevel@tonic-gate } 32577c478bd9Sstevel@tonic-gate 32587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32597c478bd9Sstevel@tonic-gate "The new interval is %d", interval); 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 32627c478bd9Sstevel@tonic-gate min_index = 0; 32637c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0]; 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) { 32667c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) { 32677c478bd9Sstevel@tonic-gate min_index = i; 32687c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i]; 32697c478bd9Sstevel@tonic-gate } 32707c478bd9Sstevel@tonic-gate } 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32737c478bd9Sstevel@tonic-gate "The leaf %d for minimal bandwidth %d", min_index, min); 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate /* Adjust min for the lattice */ 32767c478bd9Sstevel@tonic-gate min_index = min_index + NUM_INTR_ED_LISTS - 1; 32777c478bd9Sstevel@tonic-gate 32787c478bd9Sstevel@tonic-gate /* 32797c478bd9Sstevel@tonic-gate * Find the index into the lattice given the 32807c478bd9Sstevel@tonic-gate * leaf with the smallest allocated bandwidth. 32817c478bd9Sstevel@tonic-gate */ 32827c478bd9Sstevel@tonic-gate height = ohci_lattice_height(interval); 32837c478bd9Sstevel@tonic-gate 32847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32857c478bd9Sstevel@tonic-gate "The height is %d", height); 32867c478bd9Sstevel@tonic-gate 32877c478bd9Sstevel@tonic-gate *node = min_index; 32887c478bd9Sstevel@tonic-gate 32897c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 32907c478bd9Sstevel@tonic-gate *node = ohci_lattice_parent(*node); 32917c478bd9Sstevel@tonic-gate } 32927c478bd9Sstevel@tonic-gate 32937c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 32947c478bd9Sstevel@tonic-gate "Real node is %d", *node); 32957c478bd9Sstevel@tonic-gate 32967c478bd9Sstevel@tonic-gate /* 32977c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree 32987c478bd9Sstevel@tonic-gate * specified by the node. 32997c478bd9Sstevel@tonic-gate */ 33007c478bd9Sstevel@tonic-gate leftmost = ohci_leftmost_leaf(*node, height); 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl, 33037c478bd9Sstevel@tonic-gate "Leftmost %d", leftmost); 33047c478bd9Sstevel@tonic-gate 33057c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) { 33067c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i); 33077c478bd9Sstevel@tonic-gate if ((ohcip->ohci_periodic_bandwidth[list] + 33087c478bd9Sstevel@tonic-gate bandwidth) > MAX_PERIODIC_BANDWIDTH) { 33097c478bd9Sstevel@tonic-gate 33107c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 33117c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Reached maximum " 33127c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth " 33137c478bd9Sstevel@tonic-gate "for periodic endpoint"); 33147c478bd9Sstevel@tonic-gate 33157c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 33167c478bd9Sstevel@tonic-gate } 33177c478bd9Sstevel@tonic-gate } 33187c478bd9Sstevel@tonic-gate 33197c478bd9Sstevel@tonic-gate /* 33207c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 33217c478bd9Sstevel@tonic-gate */ 33227c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) { 33237c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i); 33247c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_bandwidth[list] += bandwidth; 33257c478bd9Sstevel@tonic-gate } 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 33287c478bd9Sstevel@tonic-gate min_index = 0; 33297c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0]; 33307c478bd9Sstevel@tonic-gate 33317c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) { 33327c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) { 33337c478bd9Sstevel@tonic-gate min_index = i; 33347c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i]; 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate } 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 33397c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_minimum_bandwidth = min; 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 33427c478bd9Sstevel@tonic-gate } 33437c478bd9Sstevel@tonic-gate 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate /* 33467c478bd9Sstevel@tonic-gate * ohci_deallocate_bandwidth: 33477c478bd9Sstevel@tonic-gate * 33487c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 33497c478bd9Sstevel@tonic-gate * of transfer. 33507c478bd9Sstevel@tonic-gate */ 33517c478bd9Sstevel@tonic-gate static void 33527c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth( 33537c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 33547c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 33557c478bd9Sstevel@tonic-gate { 33567c478bd9Sstevel@tonic-gate uint_t min, node, bandwidth; 33577c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 33587c478bd9Sstevel@tonic-gate int i, interval; 33597c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 33607c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 33617c478bd9Sstevel@tonic-gate 33627c478bd9Sstevel@tonic-gate /* This routine is protected by the ohci_int_mutex */ 33637c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 33647c478bd9Sstevel@tonic-gate 33657c478bd9Sstevel@tonic-gate /* Obtain the length */ 33667c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 33677c478bd9Sstevel@tonic-gate (void) ohci_compute_total_bandwidth( 33687c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status, &bandwidth); 33697c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 33707c478bd9Sstevel@tonic-gate 33717c478bd9Sstevel@tonic-gate /* Obtain the node */ 33727c478bd9Sstevel@tonic-gate node = pp->pp_node; 33737c478bd9Sstevel@tonic-gate 33747c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 33757c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 33767c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, 33777c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status); 33787c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 33797c478bd9Sstevel@tonic-gate 33807c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 33817c478bd9Sstevel@tonic-gate height = ohci_lattice_height(interval); 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate /* 33847c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 33857c478bd9Sstevel@tonic-gate */ 33867c478bd9Sstevel@tonic-gate leftmost = ohci_leftmost_leaf(node, height); 33877c478bd9Sstevel@tonic-gate 33887c478bd9Sstevel@tonic-gate /* Delete the bandwith from the appropriate lists */ 33897c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) { 33907c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i); 33917c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_bandwidth[list] -= bandwidth; 33927c478bd9Sstevel@tonic-gate } 33937c478bd9Sstevel@tonic-gate 33947c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0]; 33957c478bd9Sstevel@tonic-gate 33967c478bd9Sstevel@tonic-gate /* Recompute the minimum */ 33977c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) { 33987c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) { 33997c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i]; 34007c478bd9Sstevel@tonic-gate } 34017c478bd9Sstevel@tonic-gate } 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 34047c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_minimum_bandwidth = min; 34057c478bd9Sstevel@tonic-gate } 34067c478bd9Sstevel@tonic-gate 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate /* 34097c478bd9Sstevel@tonic-gate * ohci_compute_total_bandwidth: 34107c478bd9Sstevel@tonic-gate * 34117c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 34127c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The OpenHCI host controller traverses the 34137c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 34147c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 34157c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 34167c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 34177c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 34187c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 34197c478bd9Sstevel@tonic-gate * 34207c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 34217c478bd9Sstevel@tonic-gate * bytes and it is for the single USB full speed and low speed transaction 34227c478bd9Sstevel@tonic-gate * respectively. The protocol overheads will be different for each of type 34237c478bd9Sstevel@tonic-gate * of USB transfer and all these formulas & protocol overheads are derived 34247c478bd9Sstevel@tonic-gate * from the 5.9.3 section of USB Specification & with the help of Bandwidth 34257c478bd9Sstevel@tonic-gate * Analysis white paper which is posted on the USB developer forum. 34267c478bd9Sstevel@tonic-gate * 34277c478bd9Sstevel@tonic-gate * Full-Speed: 34287c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPacketSize * 7)/6 ) + Host_Delay 34297c478bd9Sstevel@tonic-gate * 34307c478bd9Sstevel@tonic-gate * Low-Speed: 34317c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 34327c478bd9Sstevel@tonic-gate * (Low-Speed clock * ((MaxPacketSize * 7)/6 )) + Host_Delay 34337c478bd9Sstevel@tonic-gate */ 34347c478bd9Sstevel@tonic-gate static int 34357c478bd9Sstevel@tonic-gate ohci_compute_total_bandwidth( 34367c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 34377c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 34387c478bd9Sstevel@tonic-gate uint_t *bandwidth) 34397c478bd9Sstevel@tonic-gate { 34407c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate /* 34437c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 34447c478bd9Sstevel@tonic-gate */ 34457c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 34467c478bd9Sstevel@tonic-gate 34477c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 34487c478bd9Sstevel@tonic-gate } 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 34517c478bd9Sstevel@tonic-gate *bandwidth = HOST_CONTROLLER_DELAY; 34527c478bd9Sstevel@tonic-gate 34537c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 34547c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 34557c478bd9Sstevel@tonic-gate 34567c478bd9Sstevel@tonic-gate /* Low Speed interrupt transaction */ 34577c478bd9Sstevel@tonic-gate if (port_status == USBA_LOW_SPEED_DEV) { 34587c478bd9Sstevel@tonic-gate /* Low Speed interrupt transaction */ 34597c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 34607c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 34617c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 34627c478bd9Sstevel@tonic-gate } else { 34637c478bd9Sstevel@tonic-gate /* Full Speed transaction */ 34647c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 34657c478bd9Sstevel@tonic-gate 34667c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 34677c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 34687c478bd9Sstevel@tonic-gate /* Full Speed interrupt transaction */ 34697c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 34707c478bd9Sstevel@tonic-gate } else { 34717c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 34727c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 34737c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 34747c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 34757c478bd9Sstevel@tonic-gate } else { 34767c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 34777c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 34787c478bd9Sstevel@tonic-gate } 34797c478bd9Sstevel@tonic-gate } 34807c478bd9Sstevel@tonic-gate } 34817c478bd9Sstevel@tonic-gate 34827c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 34837c478bd9Sstevel@tonic-gate } 34847c478bd9Sstevel@tonic-gate 34857c478bd9Sstevel@tonic-gate 34867c478bd9Sstevel@tonic-gate /* 34877c478bd9Sstevel@tonic-gate * ohci_adjust_polling_interval: 34887c478bd9Sstevel@tonic-gate */ 34897c478bd9Sstevel@tonic-gate static int 34907c478bd9Sstevel@tonic-gate ohci_adjust_polling_interval( 34917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 34927c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 34937c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 34947c478bd9Sstevel@tonic-gate { 34957c478bd9Sstevel@tonic-gate uint_t interval; 34967c478bd9Sstevel@tonic-gate int i = 0; 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate /* 34997c478bd9Sstevel@tonic-gate * Get the polling interval from the endpoint descriptor 35007c478bd9Sstevel@tonic-gate */ 35017c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 35027c478bd9Sstevel@tonic-gate 35037c478bd9Sstevel@tonic-gate /* 35047c478bd9Sstevel@tonic-gate * The bInterval value in the endpoint descriptor can range 35057c478bd9Sstevel@tonic-gate * from 1 to 255ms. The interrupt lattice has 32 leaf nodes, 35067c478bd9Sstevel@tonic-gate * and the host controller cycles through these nodes every 35077c478bd9Sstevel@tonic-gate * 32ms. The longest polling interval that the controller 35087c478bd9Sstevel@tonic-gate * supports is 32ms. 35097c478bd9Sstevel@tonic-gate */ 35107c478bd9Sstevel@tonic-gate 35117c478bd9Sstevel@tonic-gate /* 35127c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less than 1ms 35137c478bd9Sstevel@tonic-gate * and greater than 255ms 35147c478bd9Sstevel@tonic-gate */ 35157c478bd9Sstevel@tonic-gate if ((interval < MIN_POLL_INTERVAL) || 35167c478bd9Sstevel@tonic-gate (interval > MAX_POLL_INTERVAL)) { 35177c478bd9Sstevel@tonic-gate 3518d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 35197c478bd9Sstevel@tonic-gate "ohci_adjust_polling_interval: " 35207c478bd9Sstevel@tonic-gate "Endpoint's poll interval must be between %d and %d ms", 35217c478bd9Sstevel@tonic-gate MIN_POLL_INTERVAL, MAX_POLL_INTERVAL); 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate return (USB_FAILURE); 35247c478bd9Sstevel@tonic-gate } 35257c478bd9Sstevel@tonic-gate 35267c478bd9Sstevel@tonic-gate /* 35277c478bd9Sstevel@tonic-gate * According USB Specifications, a full-speed endpoint can 35287c478bd9Sstevel@tonic-gate * specify a desired polling interval 1ms to 255ms and a low 35297c478bd9Sstevel@tonic-gate * speed endpoints are limited to specifying only 10ms to 35307c478bd9Sstevel@tonic-gate * 255ms. But some old keyboards & mice uses polling interval 35317c478bd9Sstevel@tonic-gate * of 8ms. For compatibility purpose, we are using polling 35327c478bd9Sstevel@tonic-gate * interval between 8ms & 255ms for low speed endpoints. But 35337c478bd9Sstevel@tonic-gate * ohci driver will reject the any low speed endpoints which 35347c478bd9Sstevel@tonic-gate * request polling interval less than 8ms. 35357c478bd9Sstevel@tonic-gate */ 35367c478bd9Sstevel@tonic-gate if ((port_status == USBA_LOW_SPEED_DEV) && 35377c478bd9Sstevel@tonic-gate (interval < MIN_LOW_SPEED_POLL_INTERVAL)) { 35387c478bd9Sstevel@tonic-gate 3539d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl, 35407c478bd9Sstevel@tonic-gate "ohci_adjust_polling_interval: " 35417c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 35427c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 35437c478bd9Sstevel@tonic-gate interval, MIN_LOW_SPEED_POLL_INTERVAL); 35447c478bd9Sstevel@tonic-gate 35457c478bd9Sstevel@tonic-gate interval = MIN_LOW_SPEED_POLL_INTERVAL; 35467c478bd9Sstevel@tonic-gate } 35477c478bd9Sstevel@tonic-gate 35487c478bd9Sstevel@tonic-gate /* 35497c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 35507c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 35517c478bd9Sstevel@tonic-gate */ 35527c478bd9Sstevel@tonic-gate if (interval > NUM_INTR_ED_LISTS) { 35537c478bd9Sstevel@tonic-gate interval = NUM_INTR_ED_LISTS; 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate 35567c478bd9Sstevel@tonic-gate /* 35577c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that'sless 35587c478bd9Sstevel@tonic-gate * than interval. 35597c478bd9Sstevel@tonic-gate */ 35607c478bd9Sstevel@tonic-gate while ((ohci_pow_2(i)) <= interval) { 35617c478bd9Sstevel@tonic-gate i++; 35627c478bd9Sstevel@tonic-gate } 35637c478bd9Sstevel@tonic-gate 35647c478bd9Sstevel@tonic-gate return (ohci_pow_2((i - 1))); 35657c478bd9Sstevel@tonic-gate } 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate 35687c478bd9Sstevel@tonic-gate /* 35697c478bd9Sstevel@tonic-gate * ohci_lattice_height: 35707c478bd9Sstevel@tonic-gate * 35717c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 35727c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 35737c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 35747c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 35757c478bd9Sstevel@tonic-gate */ 35767c478bd9Sstevel@tonic-gate static uint_t 35777c478bd9Sstevel@tonic-gate ohci_lattice_height(uint_t interval) 35787c478bd9Sstevel@tonic-gate { 35797c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ohci_log_2(interval))); 35807c478bd9Sstevel@tonic-gate } 35817c478bd9Sstevel@tonic-gate 35827c478bd9Sstevel@tonic-gate 35837c478bd9Sstevel@tonic-gate /* 35847c478bd9Sstevel@tonic-gate * ohci_lattice_parent: 35857c478bd9Sstevel@tonic-gate */ 35867c478bd9Sstevel@tonic-gate static uint_t 35877c478bd9Sstevel@tonic-gate ohci_lattice_parent(uint_t node) 35887c478bd9Sstevel@tonic-gate { 35897c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 35907c478bd9Sstevel@tonic-gate return ((node/2) - 1); 35917c478bd9Sstevel@tonic-gate } else { 35927c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 35937c478bd9Sstevel@tonic-gate } 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate 35967c478bd9Sstevel@tonic-gate 35977c478bd9Sstevel@tonic-gate /* 35987c478bd9Sstevel@tonic-gate * ohci_leftmost_leaf: 35997c478bd9Sstevel@tonic-gate * 36007c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 36017c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 36027c478bd9Sstevel@tonic-gate * node. 36037c478bd9Sstevel@tonic-gate * 36047c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 36057c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 36067c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 36077c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 36087c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (NUM_INTR_ED_LIST - 1) = 36097c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - NUM_INTR_ED_LIST = 36107c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - NUM_INTR_ED_LIST 3611*29aca3ebSlc * 0 3612*29aca3ebSlc * 1 2 3613*29aca3ebSlc * 0 1 2 3 36147c478bd9Sstevel@tonic-gate */ 36157c478bd9Sstevel@tonic-gate static uint_t 36167c478bd9Sstevel@tonic-gate ohci_leftmost_leaf( 36177c478bd9Sstevel@tonic-gate uint_t node, 36187c478bd9Sstevel@tonic-gate uint_t height) 36197c478bd9Sstevel@tonic-gate { 36207c478bd9Sstevel@tonic-gate return ((ohci_pow_2(height) * (node + 1)) - NUM_INTR_ED_LISTS); 36217c478bd9Sstevel@tonic-gate } 36227c478bd9Sstevel@tonic-gate 36237c478bd9Sstevel@tonic-gate /* 36247c478bd9Sstevel@tonic-gate * ohci_hcca_intr_index: 36257c478bd9Sstevel@tonic-gate * 36267c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index for the hcca interrupt table 36277c478bd9Sstevel@tonic-gate */ 36287c478bd9Sstevel@tonic-gate static uint_t 36297c478bd9Sstevel@tonic-gate ohci_hcca_intr_index(uint_t node) 36307c478bd9Sstevel@tonic-gate { 36317c478bd9Sstevel@tonic-gate /* 36327c478bd9Sstevel@tonic-gate * Adjust the node to the array representing 36337c478bd9Sstevel@tonic-gate * the bottom of the tree. 36347c478bd9Sstevel@tonic-gate */ 36357c478bd9Sstevel@tonic-gate node = node - NUM_STATIC_NODES; 36367c478bd9Sstevel@tonic-gate 36377c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 36387c478bd9Sstevel@tonic-gate return (ohci_index[node / 2]); 36397c478bd9Sstevel@tonic-gate } else { 36407c478bd9Sstevel@tonic-gate return (ohci_index[node / 2] + (NUM_INTR_ED_LISTS / 2)); 36417c478bd9Sstevel@tonic-gate } 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate /* 36457c478bd9Sstevel@tonic-gate * ohci_hcca_leaf_index: 36467c478bd9Sstevel@tonic-gate * 36477c478bd9Sstevel@tonic-gate * Given a node in the bottom leaf array of the lattice, find the index 36487c478bd9Sstevel@tonic-gate * for the hcca interrupt table 36497c478bd9Sstevel@tonic-gate */ 36507c478bd9Sstevel@tonic-gate static uint_t 36517c478bd9Sstevel@tonic-gate ohci_hcca_leaf_index(uint_t leaf) 36527c478bd9Sstevel@tonic-gate { 36537c478bd9Sstevel@tonic-gate if ((leaf % 2) == 0) { 36547c478bd9Sstevel@tonic-gate return (ohci_index[leaf / 2]); 36557c478bd9Sstevel@tonic-gate } else { 36567c478bd9Sstevel@tonic-gate return (ohci_index[leaf / 2] + (NUM_INTR_ED_LISTS / 2)); 36577c478bd9Sstevel@tonic-gate } 36587c478bd9Sstevel@tonic-gate } 36597c478bd9Sstevel@tonic-gate 36607c478bd9Sstevel@tonic-gate /* 36617c478bd9Sstevel@tonic-gate * ohci_pow_2: 36627c478bd9Sstevel@tonic-gate * 36637c478bd9Sstevel@tonic-gate * Compute 2 to the power 36647c478bd9Sstevel@tonic-gate */ 36657c478bd9Sstevel@tonic-gate static uint_t 36667c478bd9Sstevel@tonic-gate ohci_pow_2(uint_t x) 36677c478bd9Sstevel@tonic-gate { 36687c478bd9Sstevel@tonic-gate if (x == 0) { 36697c478bd9Sstevel@tonic-gate return (1); 36707c478bd9Sstevel@tonic-gate } else { 36717c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 36727c478bd9Sstevel@tonic-gate } 36737c478bd9Sstevel@tonic-gate } 36747c478bd9Sstevel@tonic-gate 36757c478bd9Sstevel@tonic-gate 36767c478bd9Sstevel@tonic-gate /* 36777c478bd9Sstevel@tonic-gate * ohci_log_2: 36787c478bd9Sstevel@tonic-gate * 36797c478bd9Sstevel@tonic-gate * Compute log base 2 of x 36807c478bd9Sstevel@tonic-gate */ 36817c478bd9Sstevel@tonic-gate static uint_t 36827c478bd9Sstevel@tonic-gate ohci_log_2(uint_t x) 36837c478bd9Sstevel@tonic-gate { 36847c478bd9Sstevel@tonic-gate int i = 0; 36857c478bd9Sstevel@tonic-gate 36867c478bd9Sstevel@tonic-gate while (x != 1) { 36877c478bd9Sstevel@tonic-gate x = x >> 1; 36887c478bd9Sstevel@tonic-gate i++; 36897c478bd9Sstevel@tonic-gate } 36907c478bd9Sstevel@tonic-gate 36917c478bd9Sstevel@tonic-gate return (i); 36927c478bd9Sstevel@tonic-gate } 36937c478bd9Sstevel@tonic-gate 36947c478bd9Sstevel@tonic-gate 36957c478bd9Sstevel@tonic-gate /* 36967c478bd9Sstevel@tonic-gate * Endpoint Descriptor (ED) manipulations functions 36977c478bd9Sstevel@tonic-gate */ 36987c478bd9Sstevel@tonic-gate 36997c478bd9Sstevel@tonic-gate /* 37007c478bd9Sstevel@tonic-gate * ohci_alloc_hc_ed: 37017c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 37027c478bd9Sstevel@tonic-gate * 37037c478bd9Sstevel@tonic-gate * Allocate an endpoint descriptor (ED) 37047c478bd9Sstevel@tonic-gate */ 37057c478bd9Sstevel@tonic-gate ohci_ed_t * 37067c478bd9Sstevel@tonic-gate ohci_alloc_hc_ed( 37077c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 37087c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 37097c478bd9Sstevel@tonic-gate { 37107c478bd9Sstevel@tonic-gate int i, state; 37117c478bd9Sstevel@tonic-gate ohci_ed_t *hc_ed; 37127c478bd9Sstevel@tonic-gate 37137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 37147c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: ph = 0x%p", (void *)ph); 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 37177c478bd9Sstevel@tonic-gate 37187c478bd9Sstevel@tonic-gate /* 37197c478bd9Sstevel@tonic-gate * The first 31 endpoints in the Endpoint Descriptor (ED) 37207c478bd9Sstevel@tonic-gate * buffer pool are reserved for building interrupt lattice 37217c478bd9Sstevel@tonic-gate * tree. Search for a blank endpoint descriptor in the ED 37227c478bd9Sstevel@tonic-gate * buffer pool. 37237c478bd9Sstevel@tonic-gate */ 37247c478bd9Sstevel@tonic-gate for (i = NUM_STATIC_NODES; i < ohci_ed_pool_size; i ++) { 37257c478bd9Sstevel@tonic-gate state = Get_ED(ohcip->ohci_ed_pool_addr[i].hced_state); 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate if (state == HC_EPT_FREE) { 37287c478bd9Sstevel@tonic-gate break; 37297c478bd9Sstevel@tonic-gate } 37307c478bd9Sstevel@tonic-gate } 37317c478bd9Sstevel@tonic-gate 37327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 37337c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: Allocated %d", i); 37347c478bd9Sstevel@tonic-gate 37357c478bd9Sstevel@tonic-gate if (i == ohci_ed_pool_size) { 37367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 37377c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: ED exhausted"); 37387c478bd9Sstevel@tonic-gate 37397c478bd9Sstevel@tonic-gate return (NULL); 37407c478bd9Sstevel@tonic-gate } else { 37417c478bd9Sstevel@tonic-gate 37427c478bd9Sstevel@tonic-gate hc_ed = &ohcip->ohci_ed_pool_addr[i]; 37437c478bd9Sstevel@tonic-gate 37447c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 37457c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: Allocated address 0x%p", (void *)hc_ed); 37467c478bd9Sstevel@tonic-gate 37477c478bd9Sstevel@tonic-gate ohci_print_ed(ohcip, hc_ed); 37487c478bd9Sstevel@tonic-gate 37497c478bd9Sstevel@tonic-gate /* Unpack the endpoint descriptor into a control field */ 37507c478bd9Sstevel@tonic-gate if (ph) { 37517c478bd9Sstevel@tonic-gate if ((ohci_initialize_dummy(ohcip, 37527c478bd9Sstevel@tonic-gate hc_ed)) == USB_NO_RESOURCES) { 37537c478bd9Sstevel@tonic-gate bzero((void *)hc_ed, sizeof (ohci_ed_t)); 37547c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_FREE); 37557c478bd9Sstevel@tonic-gate return (NULL); 37567c478bd9Sstevel@tonic-gate } 37577c478bd9Sstevel@tonic-gate 37587c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_prev, NULL); 37597c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_next, NULL); 37607c478bd9Sstevel@tonic-gate 37617c478bd9Sstevel@tonic-gate /* Change ED's state Active */ 37627c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_ACTIVE); 37637c478bd9Sstevel@tonic-gate 37647c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_ctrl, 37657c478bd9Sstevel@tonic-gate ohci_unpack_endpoint(ohcip, ph)); 37667c478bd9Sstevel@tonic-gate } else { 37677c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_ctrl, HC_EPT_sKip); 37687c478bd9Sstevel@tonic-gate 37697c478bd9Sstevel@tonic-gate /* Change ED's state Static */ 37707c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_STATIC); 37717c478bd9Sstevel@tonic-gate } 37727c478bd9Sstevel@tonic-gate 37737c478bd9Sstevel@tonic-gate return (hc_ed); 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate } 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate 37787c478bd9Sstevel@tonic-gate /* 37797c478bd9Sstevel@tonic-gate * ohci_unpack_endpoint: 37807c478bd9Sstevel@tonic-gate * 37817c478bd9Sstevel@tonic-gate * Unpack the information in the pipe handle and create the first byte 37827c478bd9Sstevel@tonic-gate * of the Host Controller's (HC) Endpoint Descriptor (ED). 37837c478bd9Sstevel@tonic-gate */ 37847c478bd9Sstevel@tonic-gate static uint_t 37857c478bd9Sstevel@tonic-gate ohci_unpack_endpoint( 37867c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 37877c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 37887c478bd9Sstevel@tonic-gate { 37897c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 37907c478bd9Sstevel@tonic-gate uint_t maxpacketsize, addr, ctrl = 0; 37917c478bd9Sstevel@tonic-gate 37927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 37937c478bd9Sstevel@tonic-gate "ohci_unpack_endpoint:"); 37947c478bd9Sstevel@tonic-gate 37957c478bd9Sstevel@tonic-gate ctrl = ph->p_usba_device->usb_addr; 37967c478bd9Sstevel@tonic-gate 37977c478bd9Sstevel@tonic-gate addr = endpoint->bEndpointAddress; 37987c478bd9Sstevel@tonic-gate 37997c478bd9Sstevel@tonic-gate /* Assign the endpoint's address */ 38007c478bd9Sstevel@tonic-gate ctrl = ctrl | ((addr & USB_EP_NUM_MASK) << HC_EPT_EP_SHFT); 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate /* 38037c478bd9Sstevel@tonic-gate * Assign the direction. If the endpoint is a control endpoint, 38047c478bd9Sstevel@tonic-gate * the direction is assigned by the Transfer Descriptor (TD). 38057c478bd9Sstevel@tonic-gate */ 38067c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 38077c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) != USB_EP_ATTR_CONTROL) { 38087c478bd9Sstevel@tonic-gate if (addr & USB_EP_DIR_MASK) { 38097c478bd9Sstevel@tonic-gate /* The direction is IN */ 38107c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_DF_IN; 38117c478bd9Sstevel@tonic-gate } else { 38127c478bd9Sstevel@tonic-gate /* The direction is OUT */ 38137c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_DF_OUT; 38147c478bd9Sstevel@tonic-gate } 38157c478bd9Sstevel@tonic-gate } 38167c478bd9Sstevel@tonic-gate 38177c478bd9Sstevel@tonic-gate /* Assign the speed */ 38187c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 38197c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status == USBA_LOW_SPEED_DEV) { 38207c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_Speed; 38217c478bd9Sstevel@tonic-gate } 38227c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 38237c478bd9Sstevel@tonic-gate 38247c478bd9Sstevel@tonic-gate /* Assign the format */ 38257c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 38267c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 38277c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_Format; 38287c478bd9Sstevel@tonic-gate } 38297c478bd9Sstevel@tonic-gate 38307c478bd9Sstevel@tonic-gate maxpacketsize = endpoint->wMaxPacketSize; 38317c478bd9Sstevel@tonic-gate maxpacketsize = maxpacketsize << HC_EPT_MAXPKTSZ; 38327c478bd9Sstevel@tonic-gate ctrl = ctrl | (maxpacketsize & HC_EPT_MPS); 38337c478bd9Sstevel@tonic-gate 38347c478bd9Sstevel@tonic-gate return (ctrl); 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate 38377c478bd9Sstevel@tonic-gate 38387c478bd9Sstevel@tonic-gate /* 38397c478bd9Sstevel@tonic-gate * ohci_insert_ed: 38407c478bd9Sstevel@tonic-gate * 38417c478bd9Sstevel@tonic-gate * Add the Endpoint Descriptor (ED) into the Host Controller's 38427c478bd9Sstevel@tonic-gate * (HC) appropriate endpoint list. 38437c478bd9Sstevel@tonic-gate */ 38447c478bd9Sstevel@tonic-gate static void 38457c478bd9Sstevel@tonic-gate ohci_insert_ed( 38467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 38477c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 38487c478bd9Sstevel@tonic-gate { 38497c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 38527c478bd9Sstevel@tonic-gate "ohci_insert_ed:"); 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 38557c478bd9Sstevel@tonic-gate 38567c478bd9Sstevel@tonic-gate switch (ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) { 38577c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 38587c478bd9Sstevel@tonic-gate ohci_insert_ctrl_ed(ohcip, pp); 38597c478bd9Sstevel@tonic-gate break; 38607c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 38617c478bd9Sstevel@tonic-gate ohci_insert_bulk_ed(ohcip, pp); 38627c478bd9Sstevel@tonic-gate break; 38637c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 38647c478bd9Sstevel@tonic-gate ohci_insert_intr_ed(ohcip, pp); 38657c478bd9Sstevel@tonic-gate break; 38667c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 38677c478bd9Sstevel@tonic-gate ohci_insert_isoc_ed(ohcip, pp); 38687c478bd9Sstevel@tonic-gate break; 38697c478bd9Sstevel@tonic-gate } 38707c478bd9Sstevel@tonic-gate } 38717c478bd9Sstevel@tonic-gate 38727c478bd9Sstevel@tonic-gate 38737c478bd9Sstevel@tonic-gate /* 38747c478bd9Sstevel@tonic-gate * ohci_insert_ctrl_ed: 38757c478bd9Sstevel@tonic-gate * 38767c478bd9Sstevel@tonic-gate * Insert a control endpoint into the Host Controller's (HC) 38777c478bd9Sstevel@tonic-gate * control endpoint list. 38787c478bd9Sstevel@tonic-gate */ 38797c478bd9Sstevel@tonic-gate static void 38807c478bd9Sstevel@tonic-gate ohci_insert_ctrl_ed( 38817c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 38827c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 38837c478bd9Sstevel@tonic-gate { 38847c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 38857c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; 38867c478bd9Sstevel@tonic-gate 38877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 38887c478bd9Sstevel@tonic-gate "ohci_insert_ctrl_ed:"); 38897c478bd9Sstevel@tonic-gate 38907c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 38917c478bd9Sstevel@tonic-gate 38927c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the list */ 38937c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_ctrl_head)) { 38947c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, 38957c478bd9Sstevel@tonic-gate Get_OpReg(hcr_ctrl_head)); 38967c478bd9Sstevel@tonic-gate 38977c478bd9Sstevel@tonic-gate /* Set up the backwards pointer */ 38987c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, ept)); 38997c478bd9Sstevel@tonic-gate } 39007c478bd9Sstevel@tonic-gate 39017c478bd9Sstevel@tonic-gate /* The new endpoint points to the head of the list */ 39027c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_OpReg(hcr_ctrl_head)); 39037c478bd9Sstevel@tonic-gate 39047c478bd9Sstevel@tonic-gate /* Set the head ptr to the new endpoint */ 39057c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, ohci_ed_cpu_to_iommu(ohcip, ept)); 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate /* 39087c478bd9Sstevel@tonic-gate * Enable Control list processing if control open 39097c478bd9Sstevel@tonic-gate * pipe count is zero. 39107c478bd9Sstevel@tonic-gate */ 39117c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_ctrl_pipe_count) { 39127c478bd9Sstevel@tonic-gate /* Start Control list processing */ 39137c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 39147c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_CLE)); 39157c478bd9Sstevel@tonic-gate } 39167c478bd9Sstevel@tonic-gate 39177c478bd9Sstevel@tonic-gate ohcip->ohci_open_ctrl_pipe_count++; 39187c478bd9Sstevel@tonic-gate } 39197c478bd9Sstevel@tonic-gate 39207c478bd9Sstevel@tonic-gate 39217c478bd9Sstevel@tonic-gate /* 39227c478bd9Sstevel@tonic-gate * ohci_insert_bulk_ed: 39237c478bd9Sstevel@tonic-gate * 39247c478bd9Sstevel@tonic-gate * Insert a bulk endpoint into the Host Controller's (HC) bulk endpoint list. 39257c478bd9Sstevel@tonic-gate */ 39267c478bd9Sstevel@tonic-gate static void 39277c478bd9Sstevel@tonic-gate ohci_insert_bulk_ed( 39287c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 39297c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 39307c478bd9Sstevel@tonic-gate { 39317c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 39327c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; 39337c478bd9Sstevel@tonic-gate 39347c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 39357c478bd9Sstevel@tonic-gate "ohci_insert_bulk_ed:"); 39367c478bd9Sstevel@tonic-gate 39377c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 39387c478bd9Sstevel@tonic-gate 39397c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the Bulk list */ 39407c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_bulk_head)) { 39417c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, 39427c478bd9Sstevel@tonic-gate Get_OpReg(hcr_bulk_head)); 39437c478bd9Sstevel@tonic-gate 39447c478bd9Sstevel@tonic-gate /* Set up the backwards pointer */ 39457c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, ept)); 39467c478bd9Sstevel@tonic-gate } 39477c478bd9Sstevel@tonic-gate 39487c478bd9Sstevel@tonic-gate /* The new endpoint points to the head of the Bulk list */ 39497c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_OpReg(hcr_bulk_head)); 39507c478bd9Sstevel@tonic-gate 39517c478bd9Sstevel@tonic-gate /* Set the Bulk head ptr to the new endpoint */ 39527c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, ohci_ed_cpu_to_iommu(ohcip, ept)); 39537c478bd9Sstevel@tonic-gate 39547c478bd9Sstevel@tonic-gate /* 39557c478bd9Sstevel@tonic-gate * Enable Bulk list processing if bulk open pipe 39567c478bd9Sstevel@tonic-gate * count is zero. 39577c478bd9Sstevel@tonic-gate */ 39587c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_bulk_pipe_count) { 39597c478bd9Sstevel@tonic-gate /* Start Bulk list processing */ 39607c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 39617c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_BLE)); 39627c478bd9Sstevel@tonic-gate } 39637c478bd9Sstevel@tonic-gate 39647c478bd9Sstevel@tonic-gate ohcip->ohci_open_bulk_pipe_count++; 39657c478bd9Sstevel@tonic-gate } 39667c478bd9Sstevel@tonic-gate 39677c478bd9Sstevel@tonic-gate 39687c478bd9Sstevel@tonic-gate /* 39697c478bd9Sstevel@tonic-gate * ohci_insert_intr_ed: 39707c478bd9Sstevel@tonic-gate * 39717c478bd9Sstevel@tonic-gate * Insert a interrupt endpoint into the Host Controller's (HC) interrupt 39727c478bd9Sstevel@tonic-gate * lattice tree. 39737c478bd9Sstevel@tonic-gate */ 39747c478bd9Sstevel@tonic-gate static void 39757c478bd9Sstevel@tonic-gate ohci_insert_intr_ed( 39767c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 39777c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 39787c478bd9Sstevel@tonic-gate { 39797c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 39807c478bd9Sstevel@tonic-gate ohci_ed_t *next_lattice_ept, *lattice_ept; 39817c478bd9Sstevel@tonic-gate uint_t node; 39827c478bd9Sstevel@tonic-gate 39837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 39867c478bd9Sstevel@tonic-gate "ohci_insert_intr_ed:"); 39877c478bd9Sstevel@tonic-gate 39887c478bd9Sstevel@tonic-gate /* 39897c478bd9Sstevel@tonic-gate * The appropriate node was found 39907c478bd9Sstevel@tonic-gate * during the opening of the pipe. 39917c478bd9Sstevel@tonic-gate */ 39927c478bd9Sstevel@tonic-gate node = pp->pp_node; 39937c478bd9Sstevel@tonic-gate 39947c478bd9Sstevel@tonic-gate if (node >= NUM_STATIC_NODES) { 39957c478bd9Sstevel@tonic-gate /* Get the hcca interrupt table index */ 39967c478bd9Sstevel@tonic-gate node = ohci_hcca_intr_index(node); 39977c478bd9Sstevel@tonic-gate 39987c478bd9Sstevel@tonic-gate /* Get the first endpoint on the list */ 39997c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu(ohcip, 40007c478bd9Sstevel@tonic-gate Get_HCCA(ohcip->ohci_hccap->HccaIntTble[node])); 40017c478bd9Sstevel@tonic-gate 40027c478bd9Sstevel@tonic-gate /* Update this endpoint to point to it */ 40037c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, 40047c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, next_lattice_ept)); 40057c478bd9Sstevel@tonic-gate 40067c478bd9Sstevel@tonic-gate /* Put this endpoint at the head of the list */ 40077c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaIntTble[node], 40087c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate /* The previous pointer is NULL */ 40117c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, NULL); 40127c478bd9Sstevel@tonic-gate 40137c478bd9Sstevel@tonic-gate /* Update the previous pointer of ept->hced_next */ 40147c478bd9Sstevel@tonic-gate if (Get_ED(next_lattice_ept->hced_state) != HC_EPT_STATIC) { 40157c478bd9Sstevel@tonic-gate Set_ED(next_lattice_ept->hced_prev, 40167c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 40177c478bd9Sstevel@tonic-gate } 40187c478bd9Sstevel@tonic-gate } else { 40197c478bd9Sstevel@tonic-gate /* Find the lattice endpoint */ 40207c478bd9Sstevel@tonic-gate lattice_ept = &ohcip->ohci_ed_pool_addr[node]; 40217c478bd9Sstevel@tonic-gate 40227c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 40237c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu( 40247c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next)); 40257c478bd9Sstevel@tonic-gate 40267c478bd9Sstevel@tonic-gate /* 40277c478bd9Sstevel@tonic-gate * Update this endpoint to point to the next one in the 40287c478bd9Sstevel@tonic-gate * lattice. 40297c478bd9Sstevel@tonic-gate */ 40307c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_ED(lattice_ept->hced_next)); 40317c478bd9Sstevel@tonic-gate 40327c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */ 40337c478bd9Sstevel@tonic-gate Set_ED(lattice_ept->hced_next, 40347c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 40357c478bd9Sstevel@tonic-gate 40367c478bd9Sstevel@tonic-gate /* Update the previous pointer */ 40377c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, 40387c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, lattice_ept)); 40397c478bd9Sstevel@tonic-gate 40407c478bd9Sstevel@tonic-gate /* Update the previous pointer of ept->hced_next */ 40417c478bd9Sstevel@tonic-gate if ((next_lattice_ept) && 40427c478bd9Sstevel@tonic-gate (Get_ED(next_lattice_ept->hced_state) != HC_EPT_STATIC)) { 40437c478bd9Sstevel@tonic-gate 40447c478bd9Sstevel@tonic-gate Set_ED(next_lattice_ept->hced_prev, 40457c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 40467c478bd9Sstevel@tonic-gate } 40477c478bd9Sstevel@tonic-gate } 40487c478bd9Sstevel@tonic-gate 40497c478bd9Sstevel@tonic-gate /* 40507c478bd9Sstevel@tonic-gate * Enable periodic list processing if periodic (interrupt 40517c478bd9Sstevel@tonic-gate * and isochronous) open pipe count is zero. 40527c478bd9Sstevel@tonic-gate */ 40537c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_periodic_pipe_count) { 40547c478bd9Sstevel@tonic-gate ASSERT(!ohcip->ohci_open_isoch_pipe_count); 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 40577c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_PLE)); 40587c478bd9Sstevel@tonic-gate } 40597c478bd9Sstevel@tonic-gate 40607c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count++; 40617c478bd9Sstevel@tonic-gate } 40627c478bd9Sstevel@tonic-gate 40637c478bd9Sstevel@tonic-gate 40647c478bd9Sstevel@tonic-gate /* 40657c478bd9Sstevel@tonic-gate * ohci_insert_isoc_ed: 40667c478bd9Sstevel@tonic-gate * 40677c478bd9Sstevel@tonic-gate * Insert a isochronous endpoint into the Host Controller's (HC) interrupt 40687c478bd9Sstevel@tonic-gate * lattice tree. A isochronous endpoint will be inserted at the end of the 40697c478bd9Sstevel@tonic-gate * 1ms interrupt endpoint list. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate static void 40727c478bd9Sstevel@tonic-gate ohci_insert_isoc_ed( 40737c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 40747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 40757c478bd9Sstevel@tonic-gate { 40767c478bd9Sstevel@tonic-gate ohci_ed_t *next_lattice_ept, *lattice_ept; 40777c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 40787c478bd9Sstevel@tonic-gate uint_t node; 40797c478bd9Sstevel@tonic-gate 40807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 40837c478bd9Sstevel@tonic-gate "ohci_insert_isoc_ed:"); 40847c478bd9Sstevel@tonic-gate 40857c478bd9Sstevel@tonic-gate /* 40867c478bd9Sstevel@tonic-gate * The appropriate node was found during the opening of the pipe. 40877c478bd9Sstevel@tonic-gate * This node must be root of the interrupt lattice tree. 40887c478bd9Sstevel@tonic-gate */ 40897c478bd9Sstevel@tonic-gate node = pp->pp_node; 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate ASSERT(node == 0); 40927c478bd9Sstevel@tonic-gate 40937c478bd9Sstevel@tonic-gate /* Find the 1ms interrupt lattice endpoint */ 40947c478bd9Sstevel@tonic-gate lattice_ept = &ohcip->ohci_ed_pool_addr[node]; 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 40977c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu( 40987c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next)); 40997c478bd9Sstevel@tonic-gate 41007c478bd9Sstevel@tonic-gate while (next_lattice_ept) { 41017c478bd9Sstevel@tonic-gate lattice_ept = next_lattice_ept; 41027c478bd9Sstevel@tonic-gate 41037c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 41047c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu( 41057c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next)); 41067c478bd9Sstevel@tonic-gate } 41077c478bd9Sstevel@tonic-gate 41087c478bd9Sstevel@tonic-gate /* The next pointer is NULL */ 41097c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, NULL); 41107c478bd9Sstevel@tonic-gate 41117c478bd9Sstevel@tonic-gate /* Update the previous pointer */ 41127c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, lattice_ept)); 41137c478bd9Sstevel@tonic-gate 41147c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */ 41157c478bd9Sstevel@tonic-gate Set_ED(lattice_ept->hced_next, ohci_ed_cpu_to_iommu(ohcip, ept)); 41167c478bd9Sstevel@tonic-gate 41177c478bd9Sstevel@tonic-gate /* 41187c478bd9Sstevel@tonic-gate * Enable periodic and isoch lists processing if isoch 41197c478bd9Sstevel@tonic-gate * open pipe count is zero. 41207c478bd9Sstevel@tonic-gate */ 41217c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_isoch_pipe_count) { 41227c478bd9Sstevel@tonic-gate 41237c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) | 41247c478bd9Sstevel@tonic-gate HCR_CONTROL_PLE | HCR_CONTROL_IE)); 41257c478bd9Sstevel@tonic-gate } 41267c478bd9Sstevel@tonic-gate 41277c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count++; 41287c478bd9Sstevel@tonic-gate ohcip->ohci_open_isoch_pipe_count++; 41297c478bd9Sstevel@tonic-gate } 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate 41327c478bd9Sstevel@tonic-gate /* 41337c478bd9Sstevel@tonic-gate * ohci_modify_sKip_bit: 41347c478bd9Sstevel@tonic-gate * 41357c478bd9Sstevel@tonic-gate * Modify the sKip bit on the Host Controller (HC) Endpoint Descriptor (ED). 41367c478bd9Sstevel@tonic-gate */ 41377c478bd9Sstevel@tonic-gate static void 41387c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit( 41397c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 41407c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 41417c478bd9Sstevel@tonic-gate skip_bit_t action, 41427c478bd9Sstevel@tonic-gate usb_flags_t flag) 41437c478bd9Sstevel@tonic-gate { 41447c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 41457c478bd9Sstevel@tonic-gate 41467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 41477c478bd9Sstevel@tonic-gate "ohci_modify_sKip_bit: action = 0x%x flag = 0x%x", 41487c478bd9Sstevel@tonic-gate action, flag); 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 41517c478bd9Sstevel@tonic-gate 41527c478bd9Sstevel@tonic-gate if (action == CLEAR_sKip) { 41537c478bd9Sstevel@tonic-gate /* 41547c478bd9Sstevel@tonic-gate * If the skip bit is to be cleared, just clear it. 41557c478bd9Sstevel@tonic-gate * there shouldn't be any race condition problems. 41567c478bd9Sstevel@tonic-gate * If the host controller reads the bit before the 41577c478bd9Sstevel@tonic-gate * driver has a chance to set the bit, the bit will 41587c478bd9Sstevel@tonic-gate * be reread on the next frame. 41597c478bd9Sstevel@tonic-gate */ 41607c478bd9Sstevel@tonic-gate Set_ED(ept->hced_ctrl, (Get_ED(ept->hced_ctrl) & ~HC_EPT_sKip)); 41617c478bd9Sstevel@tonic-gate } else { 41627c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 41637c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_DMA_SYNC) { 41647c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 41657c478bd9Sstevel@tonic-gate } 41667c478bd9Sstevel@tonic-gate 41677c478bd9Sstevel@tonic-gate /* Check Halt or Skip bit is already set */ 41687c478bd9Sstevel@tonic-gate if ((Get_ED(ept->hced_headp) & HC_EPT_Halt) || 41697c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_ctrl) & HC_EPT_sKip)) { 41707c478bd9Sstevel@tonic-gate 41717c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 41727c478bd9Sstevel@tonic-gate "ohci_modify_sKip_bit: " 41737c478bd9Sstevel@tonic-gate "Halt or Skip bit is already set"); 41747c478bd9Sstevel@tonic-gate } else { 41757c478bd9Sstevel@tonic-gate /* 41767c478bd9Sstevel@tonic-gate * The action is to set the skip bit. In order to 41777c478bd9Sstevel@tonic-gate * be sure that the HCD has seen the sKip bit, wait 41787c478bd9Sstevel@tonic-gate * for the next start of frame. 41797c478bd9Sstevel@tonic-gate */ 41807c478bd9Sstevel@tonic-gate Set_ED(ept->hced_ctrl, 41817c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_ctrl) | HC_EPT_sKip)); 41827c478bd9Sstevel@tonic-gate 41837c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_SLEEP) { 41847c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 41857c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip); 41867c478bd9Sstevel@tonic-gate 41877c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 41887c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_DMA_SYNC) { 41897c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 41907c478bd9Sstevel@tonic-gate } 41917c478bd9Sstevel@tonic-gate } 41927c478bd9Sstevel@tonic-gate } 41937c478bd9Sstevel@tonic-gate } 41947c478bd9Sstevel@tonic-gate } 41957c478bd9Sstevel@tonic-gate 41967c478bd9Sstevel@tonic-gate 41977c478bd9Sstevel@tonic-gate /* 41987c478bd9Sstevel@tonic-gate * ohci_remove_ed: 41997c478bd9Sstevel@tonic-gate * 42007c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (ED) from the Host Controller's appropriate 42017c478bd9Sstevel@tonic-gate * endpoint list. 42027c478bd9Sstevel@tonic-gate */ 42037c478bd9Sstevel@tonic-gate static void 42047c478bd9Sstevel@tonic-gate ohci_remove_ed( 42057c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 42067c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 42077c478bd9Sstevel@tonic-gate { 42087c478bd9Sstevel@tonic-gate uchar_t attributes; 42097c478bd9Sstevel@tonic-gate 42107c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 42117c478bd9Sstevel@tonic-gate 42127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 42137c478bd9Sstevel@tonic-gate "ohci_remove_ed:"); 42147c478bd9Sstevel@tonic-gate 42157c478bd9Sstevel@tonic-gate attributes = pp->pp_pipe_handle->p_ep.bmAttributes & USB_EP_ATTR_MASK; 42167c478bd9Sstevel@tonic-gate 42177c478bd9Sstevel@tonic-gate switch (attributes) { 42187c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 42197c478bd9Sstevel@tonic-gate ohci_remove_ctrl_ed(ohcip, pp); 42207c478bd9Sstevel@tonic-gate break; 42217c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 42227c478bd9Sstevel@tonic-gate ohci_remove_bulk_ed(ohcip, pp); 42237c478bd9Sstevel@tonic-gate break; 42247c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 42257c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 42267c478bd9Sstevel@tonic-gate ohci_remove_periodic_ed(ohcip, pp); 42277c478bd9Sstevel@tonic-gate break; 42287c478bd9Sstevel@tonic-gate } 42297c478bd9Sstevel@tonic-gate } 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate 42327c478bd9Sstevel@tonic-gate /* 42337c478bd9Sstevel@tonic-gate * ohci_remove_ctrl_ed: 42347c478bd9Sstevel@tonic-gate * 42357c478bd9Sstevel@tonic-gate * Remove a control Endpoint Descriptor (ED) from the Host Controller's (HC) 42367c478bd9Sstevel@tonic-gate * control endpoint list. 42377c478bd9Sstevel@tonic-gate */ 42387c478bd9Sstevel@tonic-gate static void 42397c478bd9Sstevel@tonic-gate ohci_remove_ctrl_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 42457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 42467c478bd9Sstevel@tonic-gate "ohci_remove_ctrl_ed:"); 42477c478bd9Sstevel@tonic-gate 42487c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 42497c478bd9Sstevel@tonic-gate 42507c478bd9Sstevel@tonic-gate /* The control list should already be stopped */ 42517c478bd9Sstevel@tonic-gate ASSERT(!(Get_OpReg(hcr_control) & HCR_CONTROL_CLE)); 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate ohcip->ohci_open_ctrl_pipe_count--; 42547c478bd9Sstevel@tonic-gate 42557c478bd9Sstevel@tonic-gate /* Detach the endpoint from the list that it's on */ 42567c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, USB_EP_ATTR_CONTROL); 42577c478bd9Sstevel@tonic-gate 42587c478bd9Sstevel@tonic-gate /* 42597c478bd9Sstevel@tonic-gate * If next endpoint pointed by endpoint to be removed is not NULL 42607c478bd9Sstevel@tonic-gate * then set current control pointer to the next endpoint pointed by 42617c478bd9Sstevel@tonic-gate * endpoint to be removed. Otherwise set current control pointer to 42627c478bd9Sstevel@tonic-gate * the beginning of the control list. 42637c478bd9Sstevel@tonic-gate */ 42647c478bd9Sstevel@tonic-gate if (Get_ED(ept->hced_next)) { 42657c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, Get_ED(ept->hced_next)); 42667c478bd9Sstevel@tonic-gate } else { 42677c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, Get_OpReg(hcr_ctrl_head)); 42687c478bd9Sstevel@tonic-gate } 42697c478bd9Sstevel@tonic-gate 42707c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_ctrl_pipe_count) { 42717c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_ctrl_head)); 42727c478bd9Sstevel@tonic-gate 42737c478bd9Sstevel@tonic-gate /* Reenable the control list */ 42747c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 42757c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_CLE)); 42767c478bd9Sstevel@tonic-gate } 42777c478bd9Sstevel@tonic-gate 42787c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp); 42797c478bd9Sstevel@tonic-gate } 42807c478bd9Sstevel@tonic-gate 42817c478bd9Sstevel@tonic-gate 42827c478bd9Sstevel@tonic-gate /* 42837c478bd9Sstevel@tonic-gate * ohci_remove_bulk_ed: 42847c478bd9Sstevel@tonic-gate * 42857c478bd9Sstevel@tonic-gate * Remove free the bulk Endpoint Descriptor (ED) from the Host Controller's 42867c478bd9Sstevel@tonic-gate * (HC) bulk endpoint list. 42877c478bd9Sstevel@tonic-gate */ 42887c478bd9Sstevel@tonic-gate static void 42897c478bd9Sstevel@tonic-gate ohci_remove_bulk_ed( 42907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 42917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 42927c478bd9Sstevel@tonic-gate { 42937c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 42947c478bd9Sstevel@tonic-gate 42957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 42967c478bd9Sstevel@tonic-gate "ohci_remove_bulk_ed:"); 42977c478bd9Sstevel@tonic-gate 42987c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 42997c478bd9Sstevel@tonic-gate 43007c478bd9Sstevel@tonic-gate /* The bulk list should already be stopped */ 43017c478bd9Sstevel@tonic-gate ASSERT(!(Get_OpReg(hcr_control) & HCR_CONTROL_BLE)); 43027c478bd9Sstevel@tonic-gate 43037c478bd9Sstevel@tonic-gate ohcip->ohci_open_bulk_pipe_count--; 43047c478bd9Sstevel@tonic-gate 43057c478bd9Sstevel@tonic-gate /* Detach the endpoint from the bulk list */ 43067c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, USB_EP_ATTR_BULK); 43077c478bd9Sstevel@tonic-gate 43087c478bd9Sstevel@tonic-gate /* 43097c478bd9Sstevel@tonic-gate * If next endpoint pointed by endpoint to be removed is not NULL 43107c478bd9Sstevel@tonic-gate * then set current bulk pointer to the next endpoint pointed by 43117c478bd9Sstevel@tonic-gate * endpoint to be removed. Otherwise set current bulk pointer to 43127c478bd9Sstevel@tonic-gate * the beginning of the bulk list. 43137c478bd9Sstevel@tonic-gate */ 43147c478bd9Sstevel@tonic-gate if (Get_ED(ept->hced_next)) { 43157c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, Get_ED(ept->hced_next)); 43167c478bd9Sstevel@tonic-gate } else { 43177c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, Get_OpReg(hcr_bulk_head)); 43187c478bd9Sstevel@tonic-gate } 43197c478bd9Sstevel@tonic-gate 43207c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_bulk_pipe_count) { 43217c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_bulk_head)); 43227c478bd9Sstevel@tonic-gate 43237c478bd9Sstevel@tonic-gate /* Re-enable the bulk list */ 43247c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 43257c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_BLE)); 43267c478bd9Sstevel@tonic-gate } 43277c478bd9Sstevel@tonic-gate 43287c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp); 43297c478bd9Sstevel@tonic-gate } 43307c478bd9Sstevel@tonic-gate 43317c478bd9Sstevel@tonic-gate 43327c478bd9Sstevel@tonic-gate /* 43337c478bd9Sstevel@tonic-gate * ohci_remove_periodic_ed: 43347c478bd9Sstevel@tonic-gate * 43357c478bd9Sstevel@tonic-gate * Set up an periodic endpoint to be removed from the Host Controller's (HC) 43367c478bd9Sstevel@tonic-gate * interrupt lattice tree. The Endpoint Descriptor (ED) will be freed in the 43377c478bd9Sstevel@tonic-gate * interrupt handler. 43387c478bd9Sstevel@tonic-gate */ 43397c478bd9Sstevel@tonic-gate static void 43407c478bd9Sstevel@tonic-gate ohci_remove_periodic_ed( 43417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 43427c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 43437c478bd9Sstevel@tonic-gate { 43447c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 43457c478bd9Sstevel@tonic-gate uint_t ept_type; 43467c478bd9Sstevel@tonic-gate 43477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 43487c478bd9Sstevel@tonic-gate "ohci_remove_periodic_ed:"); 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 43517c478bd9Sstevel@tonic-gate 43527c478bd9Sstevel@tonic-gate ASSERT((Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL) == 43537c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD)); 43547c478bd9Sstevel@tonic-gate 43557c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count--; 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate ept_type = pp->pp_pipe_handle-> 4358*29aca3ebSlc p_ep.bmAttributes & USB_EP_ATTR_MASK; 43597c478bd9Sstevel@tonic-gate 43607c478bd9Sstevel@tonic-gate if (ept_type == USB_EP_ATTR_ISOCH) { 43617c478bd9Sstevel@tonic-gate ohcip->ohci_open_isoch_pipe_count--; 43627c478bd9Sstevel@tonic-gate } 43637c478bd9Sstevel@tonic-gate 43647c478bd9Sstevel@tonic-gate /* Store the node number */ 43657c478bd9Sstevel@tonic-gate Set_ED(ept->hced_node, pp->pp_node); 43667c478bd9Sstevel@tonic-gate 43677c478bd9Sstevel@tonic-gate /* Remove the endpoint from interrupt lattice tree */ 43687c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, ept_type); 43697c478bd9Sstevel@tonic-gate 43707c478bd9Sstevel@tonic-gate /* 43717c478bd9Sstevel@tonic-gate * Disable isoch list processing if isoch open pipe count 43727c478bd9Sstevel@tonic-gate * is zero. 43737c478bd9Sstevel@tonic-gate */ 43747c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_isoch_pipe_count) { 43757c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 43767c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_IE))); 43777c478bd9Sstevel@tonic-gate } 43787c478bd9Sstevel@tonic-gate 43797c478bd9Sstevel@tonic-gate /* 43807c478bd9Sstevel@tonic-gate * Disable periodic list processing if periodic (interrupt 43817c478bd9Sstevel@tonic-gate * and isochrous) open pipe count is zero. 43827c478bd9Sstevel@tonic-gate */ 43837c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_periodic_pipe_count) { 43847c478bd9Sstevel@tonic-gate ASSERT(!ohcip->ohci_open_isoch_pipe_count); 43857c478bd9Sstevel@tonic-gate 43867c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 43877c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_PLE))); 43887c478bd9Sstevel@tonic-gate } 43897c478bd9Sstevel@tonic-gate 43907c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp); 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate 43937c478bd9Sstevel@tonic-gate 43947c478bd9Sstevel@tonic-gate /* 43957c478bd9Sstevel@tonic-gate * ohci_detach_ed_from_list: 43967c478bd9Sstevel@tonic-gate * 43977c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (ED) from the appropriate Host Controller's 43987c478bd9Sstevel@tonic-gate * (HC) endpoint list. 43997c478bd9Sstevel@tonic-gate */ 44007c478bd9Sstevel@tonic-gate static void 44017c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list( 44027c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 44037c478bd9Sstevel@tonic-gate ohci_ed_t *ept, 44047c478bd9Sstevel@tonic-gate uint_t ept_type) 44057c478bd9Sstevel@tonic-gate { 44067c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; /* Previous endpoint */ 44077c478bd9Sstevel@tonic-gate ohci_ed_t *next_ept; /* Endpoint after one to be removed */ 44087c478bd9Sstevel@tonic-gate uint_t node; 44097c478bd9Sstevel@tonic-gate 44107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 44117c478bd9Sstevel@tonic-gate "ohci_detach_ed_from_list:"); 44127c478bd9Sstevel@tonic-gate 44137c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 44147c478bd9Sstevel@tonic-gate 44157c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, Get_ED(ept->hced_prev)); 44167c478bd9Sstevel@tonic-gate next_ept = ohci_ed_iommu_to_cpu(ohcip, Get_ED(ept->hced_next)); 44177c478bd9Sstevel@tonic-gate 44187c478bd9Sstevel@tonic-gate /* 44197c478bd9Sstevel@tonic-gate * If there is no previous endpoint, then this 44207c478bd9Sstevel@tonic-gate * endpoint is at the head of the endpoint list. 44217c478bd9Sstevel@tonic-gate */ 44227c478bd9Sstevel@tonic-gate if (prev_ept == NULL) { 44237c478bd9Sstevel@tonic-gate if (next_ept) { 44247c478bd9Sstevel@tonic-gate /* 44257c478bd9Sstevel@tonic-gate * If this endpoint is the first element of the 44267c478bd9Sstevel@tonic-gate * list and there is more than one endpoint on 44277c478bd9Sstevel@tonic-gate * the list then perform specific actions based 44287c478bd9Sstevel@tonic-gate * on the type of endpoint list. 44297c478bd9Sstevel@tonic-gate */ 44307c478bd9Sstevel@tonic-gate switch (ept_type) { 44317c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 44327c478bd9Sstevel@tonic-gate /* Set the head of list to next ept */ 44337c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, 44347c478bd9Sstevel@tonic-gate Get_ED(ept->hced_next)); 44357c478bd9Sstevel@tonic-gate 44367c478bd9Sstevel@tonic-gate /* Clear prev ptr of next endpoint */ 44377c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, NULL); 44387c478bd9Sstevel@tonic-gate break; 44397c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 44407c478bd9Sstevel@tonic-gate /* Set the head of list to next ept */ 44417c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, 44427c478bd9Sstevel@tonic-gate Get_ED(ept->hced_next)); 44437c478bd9Sstevel@tonic-gate 44447c478bd9Sstevel@tonic-gate /* Clear prev ptr of next endpoint */ 44457c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, NULL); 44467c478bd9Sstevel@tonic-gate break; 44477c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 44487c478bd9Sstevel@tonic-gate /* 44497c478bd9Sstevel@tonic-gate * HCCA area should point 44507c478bd9Sstevel@tonic-gate * directly to this ept. 44517c478bd9Sstevel@tonic-gate */ 44527c478bd9Sstevel@tonic-gate ASSERT(Get_ED(ept->hced_node) >= 44537c478bd9Sstevel@tonic-gate NUM_STATIC_NODES); 44547c478bd9Sstevel@tonic-gate 44557c478bd9Sstevel@tonic-gate /* Get the hcca interrupt table index */ 44567c478bd9Sstevel@tonic-gate node = ohci_hcca_intr_index( 44577c478bd9Sstevel@tonic-gate Get_ED(ept->hced_node)); 44587c478bd9Sstevel@tonic-gate 44597c478bd9Sstevel@tonic-gate /* 44607c478bd9Sstevel@tonic-gate * Delete the ept from the 44617c478bd9Sstevel@tonic-gate * bottom of the tree. 44627c478bd9Sstevel@tonic-gate */ 44637c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap-> 44647c478bd9Sstevel@tonic-gate HccaIntTble[node], Get_ED(ept->hced_next)); 44657c478bd9Sstevel@tonic-gate 44667c478bd9Sstevel@tonic-gate /* 44677c478bd9Sstevel@tonic-gate * Update the previous pointer 44687c478bd9Sstevel@tonic-gate * of ept->hced_next 44697c478bd9Sstevel@tonic-gate */ 44707c478bd9Sstevel@tonic-gate if (Get_ED(next_ept->hced_state) != 44717c478bd9Sstevel@tonic-gate HC_EPT_STATIC) { 44727c478bd9Sstevel@tonic-gate 44737c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, NULL); 44747c478bd9Sstevel@tonic-gate } 44757c478bd9Sstevel@tonic-gate 44767c478bd9Sstevel@tonic-gate break; 44777c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 44787c478bd9Sstevel@tonic-gate default: 44797c478bd9Sstevel@tonic-gate break; 44807c478bd9Sstevel@tonic-gate } 44817c478bd9Sstevel@tonic-gate } else { 44827c478bd9Sstevel@tonic-gate /* 44837c478bd9Sstevel@tonic-gate * If there was only one element on the list 44847c478bd9Sstevel@tonic-gate * perform specific actions based on the type 44857c478bd9Sstevel@tonic-gate * of the list. 44867c478bd9Sstevel@tonic-gate */ 44877c478bd9Sstevel@tonic-gate switch (ept_type) { 44887c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 44897c478bd9Sstevel@tonic-gate /* Set the head to NULL */ 44907c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, NULL); 44917c478bd9Sstevel@tonic-gate break; 44927c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 44937c478bd9Sstevel@tonic-gate /* Set the head to NULL */ 44947c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, NULL); 44957c478bd9Sstevel@tonic-gate break; 44967c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 44977c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 44987c478bd9Sstevel@tonic-gate default: 44997c478bd9Sstevel@tonic-gate break; 45007c478bd9Sstevel@tonic-gate } 45017c478bd9Sstevel@tonic-gate } 45027c478bd9Sstevel@tonic-gate } else { 45037c478bd9Sstevel@tonic-gate /* The previous ept points to the next one */ 45047c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_next, Get_ED(ept->hced_next)); 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate /* 45077c478bd9Sstevel@tonic-gate * Set the previous ptr of the next_ept to prev_ept 45087c478bd9Sstevel@tonic-gate * if this isn't the last endpoint on the list 45097c478bd9Sstevel@tonic-gate */ 45107c478bd9Sstevel@tonic-gate if ((next_ept) && 45117c478bd9Sstevel@tonic-gate (Get_ED(next_ept->hced_state) != HC_EPT_STATIC)) { 45127c478bd9Sstevel@tonic-gate 45137c478bd9Sstevel@tonic-gate /* Set the previous ptr of the next one */ 45147c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, Get_ED(ept->hced_prev)); 45157c478bd9Sstevel@tonic-gate } 45167c478bd9Sstevel@tonic-gate } 45177c478bd9Sstevel@tonic-gate } 45187c478bd9Sstevel@tonic-gate 45197c478bd9Sstevel@tonic-gate 45207c478bd9Sstevel@tonic-gate /* 45217c478bd9Sstevel@tonic-gate * ohci_insert_ed_on_reclaim_list: 45227c478bd9Sstevel@tonic-gate * 45237c478bd9Sstevel@tonic-gate * Insert Endpoint onto the reclaim list 45247c478bd9Sstevel@tonic-gate */ 45257c478bd9Sstevel@tonic-gate static void 45267c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list( 45277c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 45287c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 45297c478bd9Sstevel@tonic-gate { 45307c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */ 45317c478bd9Sstevel@tonic-gate ohci_ed_t *next_ept, *prev_ept; 45327c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number; 45337c478bd9Sstevel@tonic-gate 45347c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 45357c478bd9Sstevel@tonic-gate 45367c478bd9Sstevel@tonic-gate /* 45377c478bd9Sstevel@tonic-gate * Read current usb frame number and add appropriate number of 45387c478bd9Sstevel@tonic-gate * usb frames needs to wait before reclaiming current endpoint. 45397c478bd9Sstevel@tonic-gate */ 45407c478bd9Sstevel@tonic-gate frame_number = 45417c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohcip) + MAX_SOF_WAIT_COUNT; 45427c478bd9Sstevel@tonic-gate 45437c478bd9Sstevel@tonic-gate /* Store 32bit ID */ 45447c478bd9Sstevel@tonic-gate Set_ED(ept->hced_reclaim_frame, 45457c478bd9Sstevel@tonic-gate ((uint32_t)(OHCI_GET_ID((void *)(uintptr_t)frame_number)))); 45467c478bd9Sstevel@tonic-gate 45477c478bd9Sstevel@tonic-gate /* Insert the endpoint onto the reclaimation list */ 45487c478bd9Sstevel@tonic-gate if (ohcip->ohci_reclaim_list) { 45497c478bd9Sstevel@tonic-gate next_ept = ohcip->ohci_reclaim_list; 45507c478bd9Sstevel@tonic-gate 45517c478bd9Sstevel@tonic-gate while (next_ept) { 45527c478bd9Sstevel@tonic-gate prev_ept = next_ept; 45537c478bd9Sstevel@tonic-gate next_ept = ohci_ed_iommu_to_cpu(ohcip, 45547c478bd9Sstevel@tonic-gate Get_ED(next_ept->hced_reclaim_next)); 45557c478bd9Sstevel@tonic-gate } 45567c478bd9Sstevel@tonic-gate 45577c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_reclaim_next, 45587c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept)); 45597c478bd9Sstevel@tonic-gate } else { 45607c478bd9Sstevel@tonic-gate ohcip->ohci_reclaim_list = ept; 45617c478bd9Sstevel@tonic-gate } 45627c478bd9Sstevel@tonic-gate 45637c478bd9Sstevel@tonic-gate ASSERT(Get_ED(ept->hced_reclaim_next) == NULL); 45647c478bd9Sstevel@tonic-gate 45657c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */ 45667c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF); 45677c478bd9Sstevel@tonic-gate } 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate 45707c478bd9Sstevel@tonic-gate /* 45717c478bd9Sstevel@tonic-gate * ohci_deallocate_ed: 45727c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 45737c478bd9Sstevel@tonic-gate * 45747c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Endpoint Descriptor (ED). 45757c478bd9Sstevel@tonic-gate */ 45767c478bd9Sstevel@tonic-gate void 45777c478bd9Sstevel@tonic-gate ohci_deallocate_ed( 45787c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 45797c478bd9Sstevel@tonic-gate ohci_ed_t *old_ed) 45807c478bd9Sstevel@tonic-gate { 45817c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td; 45827c478bd9Sstevel@tonic-gate 45837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 45847c478bd9Sstevel@tonic-gate "ohci_deallocate_ed:"); 45857c478bd9Sstevel@tonic-gate 45867c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 45877c478bd9Sstevel@tonic-gate 45887c478bd9Sstevel@tonic-gate dummy_td = ohci_td_iommu_to_cpu(ohcip, Get_ED(old_ed->hced_headp)); 45897c478bd9Sstevel@tonic-gate 45907c478bd9Sstevel@tonic-gate if (dummy_td) { 45917c478bd9Sstevel@tonic-gate 45927c478bd9Sstevel@tonic-gate ASSERT(Get_TD(dummy_td->hctd_state) == HC_TD_DUMMY); 45937c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, dummy_td); 45947c478bd9Sstevel@tonic-gate } 45957c478bd9Sstevel@tonic-gate 45967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 45977c478bd9Sstevel@tonic-gate "ohci_deallocate_ed: Deallocated 0x%p", (void *)old_ed); 45987c478bd9Sstevel@tonic-gate 45997c478bd9Sstevel@tonic-gate bzero((void *)old_ed, sizeof (ohci_ed_t)); 46007c478bd9Sstevel@tonic-gate Set_ED(old_ed->hced_state, HC_EPT_FREE); 46017c478bd9Sstevel@tonic-gate } 46027c478bd9Sstevel@tonic-gate 46037c478bd9Sstevel@tonic-gate 46047c478bd9Sstevel@tonic-gate /* 46057c478bd9Sstevel@tonic-gate * ohci_ed_cpu_to_iommu: 46067c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 46077c478bd9Sstevel@tonic-gate * 46087c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (ED) CPU address 46097c478bd9Sstevel@tonic-gate * to IO address. 46107c478bd9Sstevel@tonic-gate */ 46117c478bd9Sstevel@tonic-gate uint32_t 46127c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu( 46137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 46147c478bd9Sstevel@tonic-gate ohci_ed_t *addr) 46157c478bd9Sstevel@tonic-gate { 46167c478bd9Sstevel@tonic-gate uint32_t ed; 46177c478bd9Sstevel@tonic-gate 46187c478bd9Sstevel@tonic-gate ed = (uint32_t)ohcip->ohci_ed_pool_cookie.dmac_address + 46197c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ohcip->ohci_ed_pool_addr)); 46207c478bd9Sstevel@tonic-gate 46217c478bd9Sstevel@tonic-gate ASSERT(ed >= ohcip->ohci_ed_pool_cookie.dmac_address); 46227c478bd9Sstevel@tonic-gate ASSERT(ed <= ohcip->ohci_ed_pool_cookie.dmac_address + 46237c478bd9Sstevel@tonic-gate sizeof (ohci_ed_t) * ohci_ed_pool_size); 46247c478bd9Sstevel@tonic-gate 46257c478bd9Sstevel@tonic-gate return (ed); 46267c478bd9Sstevel@tonic-gate } 46277c478bd9Sstevel@tonic-gate 46287c478bd9Sstevel@tonic-gate 46297c478bd9Sstevel@tonic-gate /* 46307c478bd9Sstevel@tonic-gate * ohci_ed_iommu_to_cpu: 46317c478bd9Sstevel@tonic-gate * 46327c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (ED) IO address 46337c478bd9Sstevel@tonic-gate * to CPU address. 46347c478bd9Sstevel@tonic-gate */ 46357c478bd9Sstevel@tonic-gate static ohci_ed_t * 46367c478bd9Sstevel@tonic-gate ohci_ed_iommu_to_cpu( 46377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 46387c478bd9Sstevel@tonic-gate uintptr_t addr) 46397c478bd9Sstevel@tonic-gate { 46407c478bd9Sstevel@tonic-gate ohci_ed_t *ed; 46417c478bd9Sstevel@tonic-gate 46427c478bd9Sstevel@tonic-gate if (addr == NULL) { 46437c478bd9Sstevel@tonic-gate 46447c478bd9Sstevel@tonic-gate return (NULL); 46457c478bd9Sstevel@tonic-gate } 46467c478bd9Sstevel@tonic-gate 46477c478bd9Sstevel@tonic-gate ed = (ohci_ed_t *)((uintptr_t) 46487c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_ed_pool_cookie.dmac_address) + 46497c478bd9Sstevel@tonic-gate (uintptr_t)ohcip->ohci_ed_pool_addr); 46507c478bd9Sstevel@tonic-gate 46517c478bd9Sstevel@tonic-gate ASSERT(ed >= ohcip->ohci_ed_pool_addr); 46527c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)ed <= (uintptr_t)ohcip->ohci_ed_pool_addr + 46537c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ohci_ed_t) * ohci_ed_pool_size)); 46547c478bd9Sstevel@tonic-gate 46557c478bd9Sstevel@tonic-gate return (ed); 46567c478bd9Sstevel@tonic-gate } 46577c478bd9Sstevel@tonic-gate 46587c478bd9Sstevel@tonic-gate 46597c478bd9Sstevel@tonic-gate /* 46607c478bd9Sstevel@tonic-gate * Transfer Descriptor manipulations functions 46617c478bd9Sstevel@tonic-gate */ 46627c478bd9Sstevel@tonic-gate 46637c478bd9Sstevel@tonic-gate /* 46647c478bd9Sstevel@tonic-gate * ohci_initialize_dummy: 46657c478bd9Sstevel@tonic-gate * 46667c478bd9Sstevel@tonic-gate * An Endpoint Descriptor (ED) has a dummy Transfer Descriptor (TD) on the 46677c478bd9Sstevel@tonic-gate * end of its TD list. Initially, both the head and tail pointers of the ED 46687c478bd9Sstevel@tonic-gate * point to the dummy TD. 46697c478bd9Sstevel@tonic-gate */ 46707c478bd9Sstevel@tonic-gate static int 46717c478bd9Sstevel@tonic-gate ohci_initialize_dummy( 46727c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 46737c478bd9Sstevel@tonic-gate ohci_ed_t *ept) 46747c478bd9Sstevel@tonic-gate { 46757c478bd9Sstevel@tonic-gate ohci_td_t *dummy; 46767c478bd9Sstevel@tonic-gate 46777c478bd9Sstevel@tonic-gate /* Obtain a dummy TD */ 46787c478bd9Sstevel@tonic-gate dummy = ohci_allocate_td_from_pool(ohcip); 46797c478bd9Sstevel@tonic-gate 46807c478bd9Sstevel@tonic-gate if (dummy == NULL) { 46817c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 46827c478bd9Sstevel@tonic-gate } 46837c478bd9Sstevel@tonic-gate 46847c478bd9Sstevel@tonic-gate /* 46857c478bd9Sstevel@tonic-gate * Both the head and tail pointers of an ED point 46867c478bd9Sstevel@tonic-gate * to this new dummy TD. 46877c478bd9Sstevel@tonic-gate */ 46887c478bd9Sstevel@tonic-gate Set_ED(ept->hced_headp, (ohci_td_cpu_to_iommu(ohcip, dummy))); 46897c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, dummy))); 46907c478bd9Sstevel@tonic-gate 46917c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 46927c478bd9Sstevel@tonic-gate } 46937c478bd9Sstevel@tonic-gate 46947c478bd9Sstevel@tonic-gate /* 46957c478bd9Sstevel@tonic-gate * ohci_allocate_ctrl_resources: 46967c478bd9Sstevel@tonic-gate * 46977c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates 46987c478bd9Sstevel@tonic-gate * all the resources necessary. 46997c478bd9Sstevel@tonic-gate * 47007c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 47017c478bd9Sstevel@tonic-gate */ 47027c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 47037c478bd9Sstevel@tonic-gate ohci_allocate_ctrl_resources( 4704*29aca3ebSlc ohci_state_t *ohcip, 47057c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 47067c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 47077c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 47087c478bd9Sstevel@tonic-gate { 4709*29aca3ebSlc size_t td_count = 2; 471002acac7eSsl size_t ctrl_buf_size; 47117c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 47127c478bd9Sstevel@tonic-gate 47137c478bd9Sstevel@tonic-gate /* Add one more td for data phase */ 47147c478bd9Sstevel@tonic-gate if (ctrl_reqp->ctrl_wLength) { 47157c478bd9Sstevel@tonic-gate td_count++; 47167c478bd9Sstevel@tonic-gate } 47177c478bd9Sstevel@tonic-gate 471802acac7eSsl /* 471902acac7eSsl * If we have a control data phase, the data buffer starts 472002acac7eSsl * on the next 4K page boundary. So the TW buffer is allocated 472102acac7eSsl * to be larger than required. The buffer in the range of 472202acac7eSsl * [SETUP_SIZE, OHCI_MAX_TD_BUF_SIZE) is just for padding 472302acac7eSsl * and not to be transferred. 472402acac7eSsl */ 472502acac7eSsl if (ctrl_reqp->ctrl_wLength) { 472602acac7eSsl ctrl_buf_size = OHCI_MAX_TD_BUF_SIZE + 472702acac7eSsl ctrl_reqp->ctrl_wLength; 472802acac7eSsl } else { 472902acac7eSsl ctrl_buf_size = SETUP_SIZE; 473002acac7eSsl } 473102acac7eSsl 473202acac7eSsl tw = ohci_allocate_tw_resources(ohcip, pp, ctrl_buf_size, 47337c478bd9Sstevel@tonic-gate usb_flags, td_count); 47347c478bd9Sstevel@tonic-gate 47357c478bd9Sstevel@tonic-gate return (tw); 47367c478bd9Sstevel@tonic-gate } 47377c478bd9Sstevel@tonic-gate 47387c478bd9Sstevel@tonic-gate /* 47397c478bd9Sstevel@tonic-gate * ohci_insert_ctrl_req: 47407c478bd9Sstevel@tonic-gate * 47417c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (TD) and a data buffer for a control endpoint. 47427c478bd9Sstevel@tonic-gate */ 47437c478bd9Sstevel@tonic-gate /* ARGSUSED */ 47447c478bd9Sstevel@tonic-gate static void 47457c478bd9Sstevel@tonic-gate ohci_insert_ctrl_req( 47467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 47477c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 47487c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 47497c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 47507c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 47517c478bd9Sstevel@tonic-gate { 47527c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 47537c478bd9Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType; 47547c478bd9Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest; 47557c478bd9Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue; 47567c478bd9Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex; 47577c478bd9Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength; 47587c478bd9Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data; 47597c478bd9Sstevel@tonic-gate uint32_t ctrl = 0; 47607c478bd9Sstevel@tonic-gate int sdata; 47617c478bd9Sstevel@tonic-gate 47627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 47637c478bd9Sstevel@tonic-gate "ohci_insert_ctrl_req:"); 47647c478bd9Sstevel@tonic-gate 47657c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 47667c478bd9Sstevel@tonic-gate 47677c478bd9Sstevel@tonic-gate /* 47687c478bd9Sstevel@tonic-gate * Save current control request pointer and timeout values 47697c478bd9Sstevel@tonic-gate * in transfer wrapper. 47707c478bd9Sstevel@tonic-gate */ 47717c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)ctrl_reqp; 47727c478bd9Sstevel@tonic-gate tw->tw_timeout = ctrl_reqp->ctrl_timeout ? 47737c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_timeout : OHCI_DEFAULT_XFER_TIMEOUT; 47747c478bd9Sstevel@tonic-gate 47757c478bd9Sstevel@tonic-gate /* 47767c478bd9Sstevel@tonic-gate * Initialize the callback and any callback data for when 47777c478bd9Sstevel@tonic-gate * the td completes. 47787c478bd9Sstevel@tonic-gate */ 47797c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_ctrl_td; 47807c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 47817c478bd9Sstevel@tonic-gate 47827c478bd9Sstevel@tonic-gate /* Create the first four bytes of the setup packet */ 47837c478bd9Sstevel@tonic-gate sdata = (bmRequestType << 24) | (bRequest << 16) | 47847c478bd9Sstevel@tonic-gate (((wValue >> 8) | (wValue << 8)) & 0x0000FFFF); 47857c478bd9Sstevel@tonic-gate 47867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 47877c478bd9Sstevel@tonic-gate "ohci_create_setup_pkt: sdata = 0x%x", sdata); 47887c478bd9Sstevel@tonic-gate 47897c478bd9Sstevel@tonic-gate ddi_put32(tw->tw_accesshandle, (uint_t *)tw->tw_buf, sdata); 47907c478bd9Sstevel@tonic-gate 47917c478bd9Sstevel@tonic-gate /* Create the second four bytes */ 47927c478bd9Sstevel@tonic-gate sdata = (uint32_t)(((((wIndex >> 8) | 47937c478bd9Sstevel@tonic-gate (wIndex << 8)) << 16) & 0xFFFF0000) | 47947c478bd9Sstevel@tonic-gate (((wLength >> 8) | (wLength << 8)) & 0x0000FFFF)); 47957c478bd9Sstevel@tonic-gate 47967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 47977c478bd9Sstevel@tonic-gate "ohci_create_setup_pkt: sdata = 0x%x", sdata); 47987c478bd9Sstevel@tonic-gate 47997c478bd9Sstevel@tonic-gate ddi_put32(tw->tw_accesshandle, 48007c478bd9Sstevel@tonic-gate (uint_t *)(tw->tw_buf + sizeof (uint_t)), sdata); 48017c478bd9Sstevel@tonic-gate 48027c478bd9Sstevel@tonic-gate ctrl = HC_TD_SETUP|HC_TD_MS_DT|HC_TD_DT_0|HC_TD_6I; 48037c478bd9Sstevel@tonic-gate 48047c478bd9Sstevel@tonic-gate /* 48057c478bd9Sstevel@tonic-gate * The TD's are placed on the ED one at a time. 48067c478bd9Sstevel@tonic-gate * Once this TD is placed on the done list, the 48077c478bd9Sstevel@tonic-gate * data or status phase TD will be enqueued. 48087c478bd9Sstevel@tonic-gate */ 480902acac7eSsl (void) ohci_insert_hc_td(ohcip, ctrl, 0, SETUP_SIZE, 48107c478bd9Sstevel@tonic-gate OHCI_CTRL_SETUP_PHASE, pp, tw); 48117c478bd9Sstevel@tonic-gate 48127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 48137c478bd9Sstevel@tonic-gate "Create_setup: pp 0x%p", (void *)pp); 48147c478bd9Sstevel@tonic-gate 48157c478bd9Sstevel@tonic-gate /* 48167c478bd9Sstevel@tonic-gate * If this control transfer has a data phase, record the 48177c478bd9Sstevel@tonic-gate * direction. If the data phase is an OUT transaction, 48187c478bd9Sstevel@tonic-gate * copy the data into the buffer of the transfer wrapper. 48197c478bd9Sstevel@tonic-gate */ 48207c478bd9Sstevel@tonic-gate if (wLength != 0) { 48217c478bd9Sstevel@tonic-gate /* There is a data stage. Find the direction */ 48227c478bd9Sstevel@tonic-gate if (bmRequestType & USB_DEV_REQ_DEV_TO_HOST) { 48237c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN; 48247c478bd9Sstevel@tonic-gate } else { 48257c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT; 48267c478bd9Sstevel@tonic-gate 48277c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 48287c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, data->b_rptr, 482902acac7eSsl (uint8_t *)(tw->tw_buf + OHCI_MAX_TD_BUF_SIZE), 48307c478bd9Sstevel@tonic-gate wLength, DDI_DEV_AUTOINCR); 48317c478bd9Sstevel@tonic-gate 48327c478bd9Sstevel@tonic-gate } 48337c478bd9Sstevel@tonic-gate 48347c478bd9Sstevel@tonic-gate ctrl = (ctrl_reqp->ctrl_attributes & USB_ATTRS_SHORT_XFER_OK) ? 4835*29aca3ebSlc HC_TD_R : 0; 48367c478bd9Sstevel@tonic-gate 48377c478bd9Sstevel@tonic-gate /* 48387c478bd9Sstevel@tonic-gate * There is a data stage. 48397c478bd9Sstevel@tonic-gate * Find the direction. 48407c478bd9Sstevel@tonic-gate */ 48417c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) { 48427c478bd9Sstevel@tonic-gate ctrl = ctrl|HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_6I; 48437c478bd9Sstevel@tonic-gate } else { 48447c478bd9Sstevel@tonic-gate ctrl = ctrl|HC_TD_OUT|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_6I; 48457c478bd9Sstevel@tonic-gate } 48467c478bd9Sstevel@tonic-gate 48477c478bd9Sstevel@tonic-gate /* 48487c478bd9Sstevel@tonic-gate * Create the TD. If this is an OUT transaction, 48497c478bd9Sstevel@tonic-gate * the data is already in the buffer of the TW. 48507c478bd9Sstevel@tonic-gate */ 485102acac7eSsl (void) ohci_insert_hc_td(ohcip, ctrl, OHCI_MAX_TD_BUF_SIZE, 485202acac7eSsl wLength, OHCI_CTRL_DATA_PHASE, pp, tw); 48537c478bd9Sstevel@tonic-gate 48547c478bd9Sstevel@tonic-gate /* 48557c478bd9Sstevel@tonic-gate * The direction of the STATUS TD depends on 48567c478bd9Sstevel@tonic-gate * the direction of the transfer. 48577c478bd9Sstevel@tonic-gate */ 48587c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) { 48597c478bd9Sstevel@tonic-gate ctrl = HC_TD_OUT|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I; 48607c478bd9Sstevel@tonic-gate } else { 48617c478bd9Sstevel@tonic-gate ctrl = HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I; 48627c478bd9Sstevel@tonic-gate } 48637c478bd9Sstevel@tonic-gate } else { 48647c478bd9Sstevel@tonic-gate ctrl = HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I; 48657c478bd9Sstevel@tonic-gate } 48667c478bd9Sstevel@tonic-gate 48677c478bd9Sstevel@tonic-gate /* Status stage */ 486802acac7eSsl (void) ohci_insert_hc_td(ohcip, ctrl, 0, 48697c478bd9Sstevel@tonic-gate 0, OHCI_CTRL_STATUS_PHASE, pp, tw); 48707c478bd9Sstevel@tonic-gate 48717c478bd9Sstevel@tonic-gate /* Indicate that the control list is filled */ 48727c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_CLF); 48737c478bd9Sstevel@tonic-gate 48747c478bd9Sstevel@tonic-gate /* Start the timer for this control transfer */ 48757c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw); 48767c478bd9Sstevel@tonic-gate } 48777c478bd9Sstevel@tonic-gate 48787c478bd9Sstevel@tonic-gate /* 48797c478bd9Sstevel@tonic-gate * ohci_allocate_bulk_resources: 48807c478bd9Sstevel@tonic-gate * 48817c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates 48827c478bd9Sstevel@tonic-gate * all the resources necessary. 48837c478bd9Sstevel@tonic-gate * 48847c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 48857c478bd9Sstevel@tonic-gate */ 48867c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 48877c478bd9Sstevel@tonic-gate ohci_allocate_bulk_resources( 4888*29aca3ebSlc ohci_state_t *ohcip, 48897c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 48907c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 48917c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 48927c478bd9Sstevel@tonic-gate { 4893*29aca3ebSlc size_t td_count = 0; 48947c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 48957c478bd9Sstevel@tonic-gate 48967c478bd9Sstevel@tonic-gate /* Check the size of bulk request */ 48977c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_len > OHCI_MAX_BULK_XFER_SIZE) { 48987c478bd9Sstevel@tonic-gate 48997c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49007c478bd9Sstevel@tonic-gate "ohci_allocate_bulk_resources: Bulk request size 0x%x is " 49017c478bd9Sstevel@tonic-gate "more than 0x%x", bulk_reqp->bulk_len, 49027c478bd9Sstevel@tonic-gate OHCI_MAX_BULK_XFER_SIZE); 49037c478bd9Sstevel@tonic-gate 49047c478bd9Sstevel@tonic-gate return (NULL); 49057c478bd9Sstevel@tonic-gate } 49067c478bd9Sstevel@tonic-gate 49077c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */ 49087c478bd9Sstevel@tonic-gate td_count = bulk_reqp->bulk_len / OHCI_MAX_TD_XFER_SIZE; 4909688b07c5Sgc if (bulk_reqp->bulk_len % OHCI_MAX_TD_XFER_SIZE || 4910*29aca3ebSlc bulk_reqp->bulk_len == 0) { 49117c478bd9Sstevel@tonic-gate td_count++; 49127c478bd9Sstevel@tonic-gate } 49137c478bd9Sstevel@tonic-gate 49147c478bd9Sstevel@tonic-gate tw = ohci_allocate_tw_resources(ohcip, pp, bulk_reqp->bulk_len, 49157c478bd9Sstevel@tonic-gate usb_flags, td_count); 49167c478bd9Sstevel@tonic-gate 49177c478bd9Sstevel@tonic-gate return (tw); 49187c478bd9Sstevel@tonic-gate } 49197c478bd9Sstevel@tonic-gate 49207c478bd9Sstevel@tonic-gate /* 49217c478bd9Sstevel@tonic-gate * ohci_insert_bulk_req: 49227c478bd9Sstevel@tonic-gate * 49237c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (TD) and a data buffer for a bulk 49247c478bd9Sstevel@tonic-gate * endpoint. 49257c478bd9Sstevel@tonic-gate */ 49267c478bd9Sstevel@tonic-gate /* ARGSUSED */ 49277c478bd9Sstevel@tonic-gate static void 49287c478bd9Sstevel@tonic-gate ohci_insert_bulk_req( 49297c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 49307c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 49317c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 49327c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 49337c478bd9Sstevel@tonic-gate usb_flags_t flags) 49347c478bd9Sstevel@tonic-gate { 49357c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 49367c478bd9Sstevel@tonic-gate uint_t bulk_pkt_size, count; 49377c478bd9Sstevel@tonic-gate size_t residue = 0, len = 0; 49387c478bd9Sstevel@tonic-gate uint32_t ctrl = 0; 49397c478bd9Sstevel@tonic-gate int pipe_dir; 49407c478bd9Sstevel@tonic-gate 49417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49427c478bd9Sstevel@tonic-gate "ohci_insert_bulk_req: bulk_reqp = 0x%p flags = 0x%x", 49437c478bd9Sstevel@tonic-gate bulk_reqp, flags); 49447c478bd9Sstevel@tonic-gate 49457c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 49467c478bd9Sstevel@tonic-gate 49477c478bd9Sstevel@tonic-gate /* Get the bulk pipe direction */ 49487c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 49497c478bd9Sstevel@tonic-gate 49507c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */ 49517c478bd9Sstevel@tonic-gate bulk_pkt_size = min(bulk_reqp->bulk_len, OHCI_MAX_TD_XFER_SIZE); 49527c478bd9Sstevel@tonic-gate 4953688b07c5Sgc if (bulk_pkt_size) 4954688b07c5Sgc residue = tw->tw_length % bulk_pkt_size; 49557c478bd9Sstevel@tonic-gate 49567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 49577c478bd9Sstevel@tonic-gate "ohci_insert_bulk_req: bulk_pkt_size = %d", bulk_pkt_size); 49587c478bd9Sstevel@tonic-gate 49597c478bd9Sstevel@tonic-gate /* 49607c478bd9Sstevel@tonic-gate * Save current bulk request pointer and timeout values 49617c478bd9Sstevel@tonic-gate * in transfer wrapper. 49627c478bd9Sstevel@tonic-gate */ 49637c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)bulk_reqp; 49647c478bd9Sstevel@tonic-gate tw->tw_timeout = bulk_reqp->bulk_timeout; 49657c478bd9Sstevel@tonic-gate 49667c478bd9Sstevel@tonic-gate /* 49677c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 49687c478bd9Sstevel@tonic-gate * data required when the td completes. 49697c478bd9Sstevel@tonic-gate */ 49707c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_bulk_td; 49717c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 49727c478bd9Sstevel@tonic-gate 49737c478bd9Sstevel@tonic-gate tw->tw_direction = 49747c478bd9Sstevel@tonic-gate (pipe_dir == USB_EP_DIR_OUT) ? HC_TD_OUT : HC_TD_IN; 49757c478bd9Sstevel@tonic-gate 4976688b07c5Sgc if (tw->tw_direction == HC_TD_OUT && bulk_reqp->bulk_len) { 49777c478bd9Sstevel@tonic-gate 49787c478bd9Sstevel@tonic-gate ASSERT(bulk_reqp->bulk_data != NULL); 49797c478bd9Sstevel@tonic-gate 49807c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 49817c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, 49827c478bd9Sstevel@tonic-gate bulk_reqp->bulk_data->b_rptr, (uint8_t *)tw->tw_buf, 49837c478bd9Sstevel@tonic-gate bulk_reqp->bulk_len, DDI_DEV_AUTOINCR); 49847c478bd9Sstevel@tonic-gate } 49857c478bd9Sstevel@tonic-gate 49867c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction|HC_TD_DT_0|HC_TD_6I; 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate /* Insert all the bulk TDs */ 49897c478bd9Sstevel@tonic-gate for (count = 0; count < tw->tw_num_tds; count++) { 49907c478bd9Sstevel@tonic-gate 49917c478bd9Sstevel@tonic-gate /* Check for last td */ 49927c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_tds - 1)) { 49937c478bd9Sstevel@tonic-gate 49947c478bd9Sstevel@tonic-gate ctrl = ((ctrl & ~HC_TD_DI) | HC_TD_1I); 49957c478bd9Sstevel@tonic-gate 49967c478bd9Sstevel@tonic-gate /* Check for inserting residue data */ 49977c478bd9Sstevel@tonic-gate if (residue) { 49987c478bd9Sstevel@tonic-gate bulk_pkt_size = residue; 49997c478bd9Sstevel@tonic-gate } 50007c478bd9Sstevel@tonic-gate 50017c478bd9Sstevel@tonic-gate /* 50027c478bd9Sstevel@tonic-gate * Only set the round bit on the last TD, to ensure 50037c478bd9Sstevel@tonic-gate * the controller will always HALT the ED in case of 50047c478bd9Sstevel@tonic-gate * a short transfer. 50057c478bd9Sstevel@tonic-gate */ 50067c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_attributes & 50077c478bd9Sstevel@tonic-gate USB_ATTRS_SHORT_XFER_OK) { 50087c478bd9Sstevel@tonic-gate ctrl |= HC_TD_R; 50097c478bd9Sstevel@tonic-gate } 50107c478bd9Sstevel@tonic-gate } 50117c478bd9Sstevel@tonic-gate 50127c478bd9Sstevel@tonic-gate /* Insert the TD onto the endpoint */ 501302acac7eSsl (void) ohci_insert_hc_td(ohcip, ctrl, len, 50147c478bd9Sstevel@tonic-gate bulk_pkt_size, 0, pp, tw); 50157c478bd9Sstevel@tonic-gate 50167c478bd9Sstevel@tonic-gate len = len + bulk_pkt_size; 50177c478bd9Sstevel@tonic-gate } 50187c478bd9Sstevel@tonic-gate 50197c478bd9Sstevel@tonic-gate /* Indicate that the bulk list is filled */ 50207c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_BLF); 50217c478bd9Sstevel@tonic-gate 50227c478bd9Sstevel@tonic-gate /* Start the timer for this bulk transfer */ 50237c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw); 50247c478bd9Sstevel@tonic-gate } 50257c478bd9Sstevel@tonic-gate 50267c478bd9Sstevel@tonic-gate 50277c478bd9Sstevel@tonic-gate /* 50287c478bd9Sstevel@tonic-gate * ohci_start_periodic_pipe_polling: 50297c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 50307c478bd9Sstevel@tonic-gate */ 50317c478bd9Sstevel@tonic-gate int 50327c478bd9Sstevel@tonic-gate ohci_start_periodic_pipe_polling( 50337c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 50347c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 50357c478bd9Sstevel@tonic-gate usb_opaque_t periodic_in_reqp, 50367c478bd9Sstevel@tonic-gate usb_flags_t flags) 50377c478bd9Sstevel@tonic-gate { 50387c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 50397c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 50407c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 50417c478bd9Sstevel@tonic-gate 50427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 50437c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: ep%d", 50447c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK); 50457c478bd9Sstevel@tonic-gate 50467c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 50477c478bd9Sstevel@tonic-gate 50487c478bd9Sstevel@tonic-gate /* 50497c478bd9Sstevel@tonic-gate * Check and handle start polling on root hub interrupt pipe. 50507c478bd9Sstevel@tonic-gate */ 50517c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) && 50527c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 50537c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) { 50547c478bd9Sstevel@tonic-gate 50557c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_start_intr_polling(ph, 50567c478bd9Sstevel@tonic-gate (usb_intr_req_t *)periodic_in_reqp, flags); 50577c478bd9Sstevel@tonic-gate 50587c478bd9Sstevel@tonic-gate return (error); 50597c478bd9Sstevel@tonic-gate } 50607c478bd9Sstevel@tonic-gate 50617c478bd9Sstevel@tonic-gate switch (pp->pp_state) { 50627c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_IDLE: 50637c478bd9Sstevel@tonic-gate /* Save the Original client's Periodic IN request */ 50647c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = periodic_in_reqp; 50657c478bd9Sstevel@tonic-gate 50667c478bd9Sstevel@tonic-gate /* 50677c478bd9Sstevel@tonic-gate * This pipe is uninitialized or if a valid TD is 50687c478bd9Sstevel@tonic-gate * not found then insert a TD on the interrupt or 50697c478bd9Sstevel@tonic-gate * isochronous IN endpoint. 50707c478bd9Sstevel@tonic-gate */ 50717c478bd9Sstevel@tonic-gate error = ohci_start_pipe_polling(ohcip, ph, flags); 50727c478bd9Sstevel@tonic-gate 50737c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 50747c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 50757c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: " 50767c478bd9Sstevel@tonic-gate "Start polling failed"); 50777c478bd9Sstevel@tonic-gate 50787c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 50797c478bd9Sstevel@tonic-gate 50807c478bd9Sstevel@tonic-gate return (error); 50817c478bd9Sstevel@tonic-gate } 50827c478bd9Sstevel@tonic-gate 50837c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 50847c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: PP = 0x%p", pp); 50857c478bd9Sstevel@tonic-gate 50867c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head != NULL) && (pp->pp_tw_tail != NULL)); 50877c478bd9Sstevel@tonic-gate 50887c478bd9Sstevel@tonic-gate break; 50897c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_ACTIVE: 50907c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 50917c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: " 50927c478bd9Sstevel@tonic-gate "Polling is already in progress"); 50937c478bd9Sstevel@tonic-gate 50947c478bd9Sstevel@tonic-gate error = USB_FAILURE; 50957c478bd9Sstevel@tonic-gate break; 50967c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_ERROR: 50977c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 50987c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: " 50997c478bd9Sstevel@tonic-gate "Pipe is halted and perform reset before restart polling"); 51007c478bd9Sstevel@tonic-gate 51017c478bd9Sstevel@tonic-gate error = USB_FAILURE; 51027c478bd9Sstevel@tonic-gate break; 51037c478bd9Sstevel@tonic-gate default: 51047c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 51057c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: Undefined state"); 51067c478bd9Sstevel@tonic-gate 51077c478bd9Sstevel@tonic-gate error = USB_FAILURE; 51087c478bd9Sstevel@tonic-gate break; 51097c478bd9Sstevel@tonic-gate } 51107c478bd9Sstevel@tonic-gate 51117c478bd9Sstevel@tonic-gate return (error); 51127c478bd9Sstevel@tonic-gate } 51137c478bd9Sstevel@tonic-gate 51147c478bd9Sstevel@tonic-gate 51157c478bd9Sstevel@tonic-gate /* 51167c478bd9Sstevel@tonic-gate * ohci_start_pipe_polling: 51177c478bd9Sstevel@tonic-gate * 51187c478bd9Sstevel@tonic-gate * Insert the number of periodic requests corresponding to polling 51197c478bd9Sstevel@tonic-gate * interval as calculated during pipe open. 51207c478bd9Sstevel@tonic-gate */ 51217c478bd9Sstevel@tonic-gate static int 51227c478bd9Sstevel@tonic-gate ohci_start_pipe_polling( 51237c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 51247c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 51257c478bd9Sstevel@tonic-gate usb_flags_t flags) 51267c478bd9Sstevel@tonic-gate { 51277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 51287c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 51297c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw_list, *tw; 51307c478bd9Sstevel@tonic-gate int i, total_tws; 51317c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 51327c478bd9Sstevel@tonic-gate 51337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 51347c478bd9Sstevel@tonic-gate "ohci_start_pipe_polling:"); 51357c478bd9Sstevel@tonic-gate 51367c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 51377c478bd9Sstevel@tonic-gate 51387c478bd9Sstevel@tonic-gate /* 51397c478bd9Sstevel@tonic-gate * For the start polling, pp_max_periodic_req_cnt will be zero 51407c478bd9Sstevel@tonic-gate * and for the restart polling request, it will be non zero. 51417c478bd9Sstevel@tonic-gate * 51427c478bd9Sstevel@tonic-gate * In case of start polling request, find out number of requests 51437c478bd9Sstevel@tonic-gate * required for the Interrupt IN endpoints corresponding to the 51447c478bd9Sstevel@tonic-gate * endpoint polling interval. For Isochronous IN endpoints, it is 51457c478bd9Sstevel@tonic-gate * always fixed since its polling interval will be one ms. 51467c478bd9Sstevel@tonic-gate */ 51477c478bd9Sstevel@tonic-gate if (pp->pp_max_periodic_req_cnt == 0) { 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate ohci_set_periodic_pipe_polling(ohcip, ph); 51507c478bd9Sstevel@tonic-gate } 51517c478bd9Sstevel@tonic-gate 51527c478bd9Sstevel@tonic-gate ASSERT(pp->pp_max_periodic_req_cnt != 0); 51537c478bd9Sstevel@tonic-gate 51547c478bd9Sstevel@tonic-gate /* Allocate all the necessary resources for the IN transfer */ 51557c478bd9Sstevel@tonic-gate tw_list = NULL; 51567c478bd9Sstevel@tonic-gate total_tws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt; 51577c478bd9Sstevel@tonic-gate for (i = 0; i < total_tws; i++) { 51587c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 51597c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 51607c478bd9Sstevel@tonic-gate tw = ohci_allocate_intr_resources( 5161*29aca3ebSlc ohcip, ph, NULL, flags); 51627c478bd9Sstevel@tonic-gate break; 51637c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 51647c478bd9Sstevel@tonic-gate tw = ohci_allocate_isoc_resources( 5165*29aca3ebSlc ohcip, ph, NULL, flags); 51667c478bd9Sstevel@tonic-gate break; 51677c478bd9Sstevel@tonic-gate } 51687c478bd9Sstevel@tonic-gate if (tw == NULL) { 51697c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 51707c478bd9Sstevel@tonic-gate /* There are not enough resources, deallocate the TWs */ 51717c478bd9Sstevel@tonic-gate tw = tw_list; 51727c478bd9Sstevel@tonic-gate while (tw != NULL) { 51737c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 51747c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 5175*29aca3ebSlc ohcip, pp, tw); 51767c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 51777c478bd9Sstevel@tonic-gate tw = tw_list; 51787c478bd9Sstevel@tonic-gate } 51797c478bd9Sstevel@tonic-gate return (error); 51807c478bd9Sstevel@tonic-gate } else { 51817c478bd9Sstevel@tonic-gate if (tw_list == NULL) { 51827c478bd9Sstevel@tonic-gate tw_list = tw; 51837c478bd9Sstevel@tonic-gate } 51847c478bd9Sstevel@tonic-gate } 51857c478bd9Sstevel@tonic-gate } 51867c478bd9Sstevel@tonic-gate 51877c478bd9Sstevel@tonic-gate i = 0; 51887c478bd9Sstevel@tonic-gate while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) { 51897c478bd9Sstevel@tonic-gate 51907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 51917c478bd9Sstevel@tonic-gate "ohci_start_pipe_polling: max = %d curr = %d tw = %p:", 51927c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt, 51937c478bd9Sstevel@tonic-gate tw_list); 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate tw = tw_list; 51967c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 51977c478bd9Sstevel@tonic-gate 51987c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 51997c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 52007c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, pp, tw, flags); 52017c478bd9Sstevel@tonic-gate break; 52027c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 52037c478bd9Sstevel@tonic-gate error = ohci_insert_isoc_req(ohcip, pp, tw, flags); 52047c478bd9Sstevel@tonic-gate break; 52057c478bd9Sstevel@tonic-gate } 52067c478bd9Sstevel@tonic-gate if (error == USB_SUCCESS) { 52077c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 52087c478bd9Sstevel@tonic-gate } else { 52097c478bd9Sstevel@tonic-gate /* 52107c478bd9Sstevel@tonic-gate * Deallocate the remaining tw 52117c478bd9Sstevel@tonic-gate * The current tw should have already been deallocated 52127c478bd9Sstevel@tonic-gate */ 52137c478bd9Sstevel@tonic-gate tw = tw_list; 52147c478bd9Sstevel@tonic-gate while (tw != NULL) { 52157c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 52167c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 5217*29aca3ebSlc ohcip, pp, tw); 52187c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 52197c478bd9Sstevel@tonic-gate tw = tw_list; 52207c478bd9Sstevel@tonic-gate } 52217c478bd9Sstevel@tonic-gate /* 52227c478bd9Sstevel@tonic-gate * If this is the first req return an error. 52237c478bd9Sstevel@tonic-gate * Otherwise return success. 52247c478bd9Sstevel@tonic-gate */ 52257c478bd9Sstevel@tonic-gate if (i != 0) { 52267c478bd9Sstevel@tonic-gate error = USB_SUCCESS; 52277c478bd9Sstevel@tonic-gate } 52287c478bd9Sstevel@tonic-gate 52297c478bd9Sstevel@tonic-gate break; 52307c478bd9Sstevel@tonic-gate } 52317c478bd9Sstevel@tonic-gate i++; 52327c478bd9Sstevel@tonic-gate } 52337c478bd9Sstevel@tonic-gate 52347c478bd9Sstevel@tonic-gate return (error); 52357c478bd9Sstevel@tonic-gate } 52367c478bd9Sstevel@tonic-gate 52377c478bd9Sstevel@tonic-gate 52387c478bd9Sstevel@tonic-gate /* 52397c478bd9Sstevel@tonic-gate * ohci_set_periodic_pipe_polling: 52407c478bd9Sstevel@tonic-gate * 52417c478bd9Sstevel@tonic-gate * Calculate the number of periodic requests needed corresponding to the 52427c478bd9Sstevel@tonic-gate * interrupt/isochronous IN endpoints polling interval. Table below gives 52437c478bd9Sstevel@tonic-gate * the number of periodic requests needed for the interrupt/isochronous 52447c478bd9Sstevel@tonic-gate * IN endpoints according to endpoint polling interval. 52457c478bd9Sstevel@tonic-gate * 52467c478bd9Sstevel@tonic-gate * Polling interval Number of periodic requests 52477c478bd9Sstevel@tonic-gate * 52487c478bd9Sstevel@tonic-gate * 1ms 4 52497c478bd9Sstevel@tonic-gate * 2ms 2 52507c478bd9Sstevel@tonic-gate * 4ms to 32ms 1 52517c478bd9Sstevel@tonic-gate */ 52527c478bd9Sstevel@tonic-gate static void 52537c478bd9Sstevel@tonic-gate ohci_set_periodic_pipe_polling( 52547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 52557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 52567c478bd9Sstevel@tonic-gate { 52577c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 52587c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 52597c478bd9Sstevel@tonic-gate uchar_t ep_attr = endpoint->bmAttributes; 52607c478bd9Sstevel@tonic-gate uint_t interval; 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 52637c478bd9Sstevel@tonic-gate "ohci_set_periodic_pipe_polling:"); 52647c478bd9Sstevel@tonic-gate 52657c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 52667c478bd9Sstevel@tonic-gate 52677c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt = 0; 52687c478bd9Sstevel@tonic-gate 52697c478bd9Sstevel@tonic-gate /* 52707c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_TIME_POLL flag is 52717c478bd9Sstevel@tonic-gate * set and if so, set pp->pp_max_periodic_req_cnt to one. 52727c478bd9Sstevel@tonic-gate */ 52737c478bd9Sstevel@tonic-gate if (((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) && 52747c478bd9Sstevel@tonic-gate (pp->pp_client_periodic_in_reqp)) { 52757c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp = 52767c478bd9Sstevel@tonic-gate (usb_intr_req_t *)pp->pp_client_periodic_in_reqp; 52777c478bd9Sstevel@tonic-gate 52787c478bd9Sstevel@tonic-gate if (intr_reqp->intr_attributes & 52797c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 52807c478bd9Sstevel@tonic-gate 52817c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_XMS_REQS; 52827c478bd9Sstevel@tonic-gate 52837c478bd9Sstevel@tonic-gate return; 52847c478bd9Sstevel@tonic-gate } 52857c478bd9Sstevel@tonic-gate } 52867c478bd9Sstevel@tonic-gate 52877c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 52887c478bd9Sstevel@tonic-gate 52897c478bd9Sstevel@tonic-gate /* 52907c478bd9Sstevel@tonic-gate * The ohci_adjust_polling_interval function will not fail 52917c478bd9Sstevel@tonic-gate * at this instance since bandwidth allocation is already 52927c478bd9Sstevel@tonic-gate * done. Here we are getting only the periodic interval. 52937c478bd9Sstevel@tonic-gate */ 52947c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, endpoint, 5295*29aca3ebSlc ph->p_usba_device->usb_port_status); 52967c478bd9Sstevel@tonic-gate 52977c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 52987c478bd9Sstevel@tonic-gate 52997c478bd9Sstevel@tonic-gate switch (interval) { 53007c478bd9Sstevel@tonic-gate case INTR_1MS_POLL: 53017c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_1MS_REQS; 53027c478bd9Sstevel@tonic-gate break; 53037c478bd9Sstevel@tonic-gate case INTR_2MS_POLL: 53047c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_2MS_REQS; 53057c478bd9Sstevel@tonic-gate break; 53067c478bd9Sstevel@tonic-gate default: 53077c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_XMS_REQS; 53087c478bd9Sstevel@tonic-gate break; 53097c478bd9Sstevel@tonic-gate } 53107c478bd9Sstevel@tonic-gate 53117c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 53127c478bd9Sstevel@tonic-gate "ohci_set_periodic_pipe_polling: Max periodic requests = %d", 53137c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 53147c478bd9Sstevel@tonic-gate } 53157c478bd9Sstevel@tonic-gate 53167c478bd9Sstevel@tonic-gate /* 53177c478bd9Sstevel@tonic-gate * ohci_allocate_intr_resources: 53187c478bd9Sstevel@tonic-gate * 53197c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates 53207c478bd9Sstevel@tonic-gate * all the necessary resources. 53217c478bd9Sstevel@tonic-gate * 53227c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 53237c478bd9Sstevel@tonic-gate */ 53247c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 53257c478bd9Sstevel@tonic-gate ohci_allocate_intr_resources( 53267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 53277c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 53287c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 53297c478bd9Sstevel@tonic-gate usb_flags_t flags) 53307c478bd9Sstevel@tonic-gate { 53317c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 53327c478bd9Sstevel@tonic-gate int pipe_dir; 5333*29aca3ebSlc size_t td_count = 1; 53347c478bd9Sstevel@tonic-gate size_t tw_length; 53357c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 53367c478bd9Sstevel@tonic-gate 53377c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 53387c478bd9Sstevel@tonic-gate "ohci_allocate_intr_resources:"); 53397c478bd9Sstevel@tonic-gate 53407c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 53417c478bd9Sstevel@tonic-gate 53427c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 53437c478bd9Sstevel@tonic-gate 53447c478bd9Sstevel@tonic-gate /* Get the length of interrupt transfer & alloc data */ 53457c478bd9Sstevel@tonic-gate if (intr_reqp) { 53467c478bd9Sstevel@tonic-gate tw_length = intr_reqp->intr_len; 53477c478bd9Sstevel@tonic-gate } else { 53487c478bd9Sstevel@tonic-gate ASSERT(pipe_dir == USB_EP_DIR_IN); 53497c478bd9Sstevel@tonic-gate tw_length = (pp->pp_client_periodic_in_reqp) ? 53507c478bd9Sstevel@tonic-gate (((usb_intr_req_t *)pp-> 53517c478bd9Sstevel@tonic-gate pp_client_periodic_in_reqp)->intr_len) : 53527c478bd9Sstevel@tonic-gate ph->p_ep.wMaxPacketSize; 53537c478bd9Sstevel@tonic-gate } 53547c478bd9Sstevel@tonic-gate 53557c478bd9Sstevel@tonic-gate /* Check the size of interrupt request */ 53567c478bd9Sstevel@tonic-gate if (tw_length > OHCI_MAX_TD_XFER_SIZE) { 53577c478bd9Sstevel@tonic-gate 53587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 53597c478bd9Sstevel@tonic-gate "ohci_allocate_intr_resources: Intr request size 0x%lx is " 53607c478bd9Sstevel@tonic-gate "more than 0x%x", tw_length, OHCI_MAX_TD_XFER_SIZE); 53617c478bd9Sstevel@tonic-gate 53627c478bd9Sstevel@tonic-gate return (NULL); 53637c478bd9Sstevel@tonic-gate } 53647c478bd9Sstevel@tonic-gate 53657c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_tw_resources(ohcip, pp, tw_length, 53667c478bd9Sstevel@tonic-gate flags, td_count)) == NULL) { 53677c478bd9Sstevel@tonic-gate 53687c478bd9Sstevel@tonic-gate return (NULL); 53697c478bd9Sstevel@tonic-gate } 53707c478bd9Sstevel@tonic-gate 53717c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 53727c478bd9Sstevel@tonic-gate if (ohci_allocate_periodic_in_resource(ohcip, pp, tw, flags) != 53737c478bd9Sstevel@tonic-gate USB_SUCCESS) { 53747c478bd9Sstevel@tonic-gate 53757c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 53767c478bd9Sstevel@tonic-gate return (NULL); 53777c478bd9Sstevel@tonic-gate } 53787c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN; 53797c478bd9Sstevel@tonic-gate } else { 5380688b07c5Sgc if (tw_length) { 5381688b07c5Sgc ASSERT(intr_reqp->intr_data != NULL); 53827c478bd9Sstevel@tonic-gate 5383688b07c5Sgc /* Copy the data into the message */ 5384688b07c5Sgc ddi_rep_put8(tw->tw_accesshandle, 5385688b07c5Sgc intr_reqp->intr_data->b_rptr, (uint8_t *)tw->tw_buf, 5386688b07c5Sgc intr_reqp->intr_len, DDI_DEV_AUTOINCR); 5387688b07c5Sgc } 53887c478bd9Sstevel@tonic-gate 53897c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)intr_reqp; 53907c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT; 53917c478bd9Sstevel@tonic-gate } 53927c478bd9Sstevel@tonic-gate 53937c478bd9Sstevel@tonic-gate if (intr_reqp) { 53947c478bd9Sstevel@tonic-gate tw->tw_timeout = intr_reqp->intr_timeout; 53957c478bd9Sstevel@tonic-gate } 53967c478bd9Sstevel@tonic-gate 53977c478bd9Sstevel@tonic-gate /* 53987c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 53997c478bd9Sstevel@tonic-gate * data required when the td completes. 54007c478bd9Sstevel@tonic-gate */ 54017c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_intr_td; 54027c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 54037c478bd9Sstevel@tonic-gate 54047c478bd9Sstevel@tonic-gate return (tw); 54057c478bd9Sstevel@tonic-gate } 54067c478bd9Sstevel@tonic-gate 54077c478bd9Sstevel@tonic-gate /* 54087c478bd9Sstevel@tonic-gate * ohci_insert_intr_req: 54097c478bd9Sstevel@tonic-gate * 54107c478bd9Sstevel@tonic-gate * Insert an Interrupt request into the Host Controller's periodic list. 54117c478bd9Sstevel@tonic-gate */ 54127c478bd9Sstevel@tonic-gate /* ARGSUSED */ 54137c478bd9Sstevel@tonic-gate static void 54147c478bd9Sstevel@tonic-gate ohci_insert_intr_req( 54157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 54167c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 54177c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 54187c478bd9Sstevel@tonic-gate usb_flags_t flags) 54197c478bd9Sstevel@tonic-gate { 54207c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = NULL; 54217c478bd9Sstevel@tonic-gate uint_t ctrl = 0; 54227c478bd9Sstevel@tonic-gate 54237c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 54247c478bd9Sstevel@tonic-gate 54257c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp != NULL); 54267c478bd9Sstevel@tonic-gate 54277c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */ 54287c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction | HC_TD_DT_0 | HC_TD_1I; 54317c478bd9Sstevel@tonic-gate 54327c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & USB_ATTRS_SHORT_XFER_OK) { 54337c478bd9Sstevel@tonic-gate ctrl |= HC_TD_R; 54347c478bd9Sstevel@tonic-gate } 54357c478bd9Sstevel@tonic-gate 54367c478bd9Sstevel@tonic-gate /* Insert another interrupt TD */ 543702acac7eSsl (void) ohci_insert_hc_td(ohcip, ctrl, 0, tw->tw_length, 0, pp, tw); 54387c478bd9Sstevel@tonic-gate 54397c478bd9Sstevel@tonic-gate /* Start the timer for this Interrupt transfer */ 54407c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw); 54417c478bd9Sstevel@tonic-gate } 54427c478bd9Sstevel@tonic-gate 54437c478bd9Sstevel@tonic-gate 54447c478bd9Sstevel@tonic-gate /* 54457c478bd9Sstevel@tonic-gate * ohci_stop_periodic_pipe_polling: 54467c478bd9Sstevel@tonic-gate */ 54477c478bd9Sstevel@tonic-gate /* ARGSUSED */ 54487c478bd9Sstevel@tonic-gate static int 54497c478bd9Sstevel@tonic-gate ohci_stop_periodic_pipe_polling( 54507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 54517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 54527c478bd9Sstevel@tonic-gate usb_flags_t flags) 54537c478bd9Sstevel@tonic-gate { 54547c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 54557c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 54567c478bd9Sstevel@tonic-gate 54577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 54587c478bd9Sstevel@tonic-gate "ohci_stop_periodic_pipe_polling: Flags = 0x%x", flags); 54597c478bd9Sstevel@tonic-gate 54607c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 54617c478bd9Sstevel@tonic-gate 54627c478bd9Sstevel@tonic-gate /* 54637c478bd9Sstevel@tonic-gate * Check and handle stop polling on root hub interrupt pipe. 54647c478bd9Sstevel@tonic-gate */ 54657c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) && 54667c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 54677c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) { 54687c478bd9Sstevel@tonic-gate 54697c478bd9Sstevel@tonic-gate ohci_handle_root_hub_pipe_stop_intr_polling( 5470*29aca3ebSlc ph, flags); 54717c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 54727c478bd9Sstevel@tonic-gate } 54737c478bd9Sstevel@tonic-gate 54747c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) { 54757c478bd9Sstevel@tonic-gate 54767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 54777c478bd9Sstevel@tonic-gate "ohci_stop_periodic_pipe_polling: Polling already stopped"); 54787c478bd9Sstevel@tonic-gate 54797c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 54807c478bd9Sstevel@tonic-gate } 54817c478bd9Sstevel@tonic-gate 54827c478bd9Sstevel@tonic-gate /* Set pipe state to pipe stop polling */ 54837c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 54847c478bd9Sstevel@tonic-gate 54857c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph); 54867c478bd9Sstevel@tonic-gate 54877c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 54887c478bd9Sstevel@tonic-gate } 54897c478bd9Sstevel@tonic-gate 54907c478bd9Sstevel@tonic-gate /* 54917c478bd9Sstevel@tonic-gate * ohci_allocate_isoc_resources: 54927c478bd9Sstevel@tonic-gate * 54937c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates 54947c478bd9Sstevel@tonic-gate * all the necessary resources. 54957c478bd9Sstevel@tonic-gate * 54967c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 54977c478bd9Sstevel@tonic-gate */ 54987c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 54997c478bd9Sstevel@tonic-gate ohci_allocate_isoc_resources( 55007c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 55017c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 55027c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 55037c478bd9Sstevel@tonic-gate usb_flags_t flags) 55047c478bd9Sstevel@tonic-gate { 55057c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 55067c478bd9Sstevel@tonic-gate int pipe_dir; 55077c478bd9Sstevel@tonic-gate uint_t max_pkt_size = ph->p_ep.wMaxPacketSize; 55087c478bd9Sstevel@tonic-gate uint_t max_isoc_xfer_size; 550902acac7eSsl usb_isoc_pkt_descr_t *isoc_pkt_descr, *start_isoc_pkt_descr; 55107c478bd9Sstevel@tonic-gate ushort_t isoc_pkt_count; 5511*29aca3ebSlc size_t count, td_count; 55127c478bd9Sstevel@tonic-gate size_t tw_length; 5513b3001defSlg size_t isoc_pkts_length; 55147c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 55157c478bd9Sstevel@tonic-gate 55167c478bd9Sstevel@tonic-gate 55177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 55187c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: flags = ox%x", flags); 55197c478bd9Sstevel@tonic-gate 55207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 55217c478bd9Sstevel@tonic-gate 55227c478bd9Sstevel@tonic-gate /* 55237c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 55247c478bd9Sstevel@tonic-gate */ 55257c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) { 55267c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 55277c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources:" 55287c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 55297c478bd9Sstevel@tonic-gate 55307c478bd9Sstevel@tonic-gate return (NULL); 55317c478bd9Sstevel@tonic-gate } 55327c478bd9Sstevel@tonic-gate 55337c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 55347c478bd9Sstevel@tonic-gate 55357c478bd9Sstevel@tonic-gate /* Calculate the maximum isochronous transfer size */ 55367c478bd9Sstevel@tonic-gate max_isoc_xfer_size = OHCI_MAX_ISOC_PKTS_PER_XFER * max_pkt_size; 55377c478bd9Sstevel@tonic-gate 55387c478bd9Sstevel@tonic-gate if (isoc_reqp) { 55397c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr; 55407c478bd9Sstevel@tonic-gate isoc_pkt_count = isoc_reqp->isoc_pkts_count; 5541b3001defSlg isoc_pkts_length = isoc_reqp->isoc_pkts_length; 55427c478bd9Sstevel@tonic-gate } else { 55437c478bd9Sstevel@tonic-gate isoc_pkt_descr = ((usb_isoc_req_t *) 55447c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkt_descr; 55457c478bd9Sstevel@tonic-gate 55467c478bd9Sstevel@tonic-gate isoc_pkt_count = ((usb_isoc_req_t *) 55477c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_count; 5548b3001defSlg 5549b3001defSlg isoc_pkts_length = ((usb_isoc_req_t *) 5550b3001defSlg pp->pp_client_periodic_in_reqp)->isoc_pkts_length; 55517c478bd9Sstevel@tonic-gate } 55527c478bd9Sstevel@tonic-gate 555302acac7eSsl start_isoc_pkt_descr = isoc_pkt_descr; 555402acac7eSsl 55557c478bd9Sstevel@tonic-gate /* 55567c478bd9Sstevel@tonic-gate * For isochronous IN pipe, get value of number of isochronous 55577c478bd9Sstevel@tonic-gate * packets per usb isochronous request 55587c478bd9Sstevel@tonic-gate */ 55597c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 55607c478bd9Sstevel@tonic-gate for (count = 0, tw_length = 0; 55617c478bd9Sstevel@tonic-gate count < isoc_pkt_count; count++) { 55627c478bd9Sstevel@tonic-gate tw_length += isoc_pkt_descr->isoc_pkt_length; 55637c478bd9Sstevel@tonic-gate isoc_pkt_descr++; 55647c478bd9Sstevel@tonic-gate } 5565b3001defSlg 5566b3001defSlg if ((isoc_pkts_length) && (isoc_pkts_length != tw_length)) { 5567b3001defSlg 5568b3001defSlg USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 5569b3001defSlg "ohci_allocate_isoc_resources: " 5570b3001defSlg "isoc_pkts_length 0x%x is not equal to the sum of " 5571b3001defSlg "all pkt lengths 0x%x in an isoc request", 5572b3001defSlg isoc_pkts_length, tw_length); 5573b3001defSlg 5574b3001defSlg return (NULL); 5575b3001defSlg } 5576b3001defSlg 55777c478bd9Sstevel@tonic-gate } else { 55787c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp != NULL); 55797c478bd9Sstevel@tonic-gate tw_length = isoc_reqp->isoc_data->b_wptr - 55807c478bd9Sstevel@tonic-gate isoc_reqp->isoc_data->b_rptr; 55817c478bd9Sstevel@tonic-gate } 55827c478bd9Sstevel@tonic-gate 55837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 55847c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: length = 0x%lx", tw_length); 55857c478bd9Sstevel@tonic-gate 55867c478bd9Sstevel@tonic-gate /* Check the size of isochronous request */ 55877c478bd9Sstevel@tonic-gate if (tw_length > max_isoc_xfer_size) { 55887c478bd9Sstevel@tonic-gate 55897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 55907c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: Maximum isoc request" 55917c478bd9Sstevel@tonic-gate "size 0x%x Given isoc request size 0x%lx", 55927c478bd9Sstevel@tonic-gate max_isoc_xfer_size, tw_length); 55937c478bd9Sstevel@tonic-gate 55947c478bd9Sstevel@tonic-gate return (NULL); 55957c478bd9Sstevel@tonic-gate } 55967c478bd9Sstevel@tonic-gate 55977c478bd9Sstevel@tonic-gate /* 55987c478bd9Sstevel@tonic-gate * Each isochronous TD can hold data upto eight isochronous 55997c478bd9Sstevel@tonic-gate * data packets. Calculate the number of isochronous TDs needs 56007c478bd9Sstevel@tonic-gate * to be insert to complete current isochronous request. 56017c478bd9Sstevel@tonic-gate */ 56027c478bd9Sstevel@tonic-gate td_count = isoc_pkt_count / OHCI_ISOC_PKTS_PER_TD; 56037c478bd9Sstevel@tonic-gate 56047c478bd9Sstevel@tonic-gate if (isoc_pkt_count % OHCI_ISOC_PKTS_PER_TD) { 56057c478bd9Sstevel@tonic-gate td_count++; 56067c478bd9Sstevel@tonic-gate } 56077c478bd9Sstevel@tonic-gate 560802acac7eSsl tw = ohci_create_isoc_transfer_wrapper(ohcip, pp, tw_length, 560902acac7eSsl start_isoc_pkt_descr, isoc_pkt_count, td_count, flags); 561002acac7eSsl 561102acac7eSsl if (tw == NULL) { 561202acac7eSsl USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 561302acac7eSsl "ohci_create_isoc_transfer_wrapper: " 561402acac7eSsl "Unable to allocate TW"); 561502acac7eSsl 561602acac7eSsl return (NULL); 561702acac7eSsl } 561802acac7eSsl 561902acac7eSsl if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) == 562002acac7eSsl USB_SUCCESS) { 562102acac7eSsl tw->tw_num_tds = td_count; 562202acac7eSsl } else { 562302acac7eSsl ohci_deallocate_tw_resources(ohcip, pp, tw); 562402acac7eSsl 56257c478bd9Sstevel@tonic-gate return (NULL); 56267c478bd9Sstevel@tonic-gate } 56277c478bd9Sstevel@tonic-gate 56287c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 56297c478bd9Sstevel@tonic-gate if (ohci_allocate_periodic_in_resource(ohcip, pp, tw, flags) != 56307c478bd9Sstevel@tonic-gate USB_SUCCESS) { 56317c478bd9Sstevel@tonic-gate 56327c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 56337c478bd9Sstevel@tonic-gate return (NULL); 56347c478bd9Sstevel@tonic-gate } 56357c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN; 56367c478bd9Sstevel@tonic-gate } else { 56377c478bd9Sstevel@tonic-gate if (tw->tw_length) { 563802acac7eSsl uchar_t *p; 563902acac7eSsl int i; 564002acac7eSsl 56417c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp->isoc_data != NULL); 564202acac7eSsl p = isoc_reqp->isoc_data->b_rptr; 56437c478bd9Sstevel@tonic-gate 56447c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 564502acac7eSsl for (i = 0; i < td_count; i++) { 564602acac7eSsl ddi_rep_put8( 564702acac7eSsl tw->tw_isoc_bufs[i].mem_handle, p, 564802acac7eSsl (uint8_t *)tw->tw_isoc_bufs[i].buf_addr, 564902acac7eSsl tw->tw_isoc_bufs[i].length, 565002acac7eSsl DDI_DEV_AUTOINCR); 565102acac7eSsl p += tw->tw_isoc_bufs[i].length; 565202acac7eSsl } 56537c478bd9Sstevel@tonic-gate } 56547c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)isoc_reqp; 56557c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT; 56567c478bd9Sstevel@tonic-gate } 56577c478bd9Sstevel@tonic-gate 56587c478bd9Sstevel@tonic-gate /* 56597c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 56607c478bd9Sstevel@tonic-gate * data required when the td completes. 56617c478bd9Sstevel@tonic-gate */ 56627c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_isoc_td; 56637c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 56647c478bd9Sstevel@tonic-gate 56657c478bd9Sstevel@tonic-gate return (tw); 56667c478bd9Sstevel@tonic-gate } 56677c478bd9Sstevel@tonic-gate 56687c478bd9Sstevel@tonic-gate /* 56697c478bd9Sstevel@tonic-gate * ohci_insert_isoc_req: 56707c478bd9Sstevel@tonic-gate * 56717c478bd9Sstevel@tonic-gate * Insert an isochronous request into the Host Controller's 56727c478bd9Sstevel@tonic-gate * isochronous list. If there is an error is will appropriately 56737c478bd9Sstevel@tonic-gate * deallocate the unused resources. 56747c478bd9Sstevel@tonic-gate */ 56757c478bd9Sstevel@tonic-gate static int 56767c478bd9Sstevel@tonic-gate ohci_insert_isoc_req( 56777c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 56787c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 56797c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 56807c478bd9Sstevel@tonic-gate uint_t flags) 56817c478bd9Sstevel@tonic-gate { 56827c478bd9Sstevel@tonic-gate size_t curr_isoc_xfer_offset, curr_isoc_xfer_len; 56837c478bd9Sstevel@tonic-gate uint_t isoc_pkts, residue, count; 56847c478bd9Sstevel@tonic-gate uint_t i, ctrl, frame_count; 56857c478bd9Sstevel@tonic-gate uint_t error = USB_SUCCESS; 56867c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp; 56877c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *curr_isoc_pkt_descr; 56887c478bd9Sstevel@tonic-gate 56897c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 56907c478bd9Sstevel@tonic-gate "ohci_insert_isoc_req: flags = 0x%x", flags); 56917c478bd9Sstevel@tonic-gate 56927c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 56937c478bd9Sstevel@tonic-gate 56947c478bd9Sstevel@tonic-gate /* 56957c478bd9Sstevel@tonic-gate * Get the current isochronous request and packet 56967c478bd9Sstevel@tonic-gate * descriptor pointers. 56977c478bd9Sstevel@tonic-gate */ 56987c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 56997c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = curr_isoc_reqp->isoc_pkt_descr; 57007c478bd9Sstevel@tonic-gate 57017c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL); 57027c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp->isoc_pkt_descr != NULL); 57037c478bd9Sstevel@tonic-gate 57047c478bd9Sstevel@tonic-gate /* 57057c478bd9Sstevel@tonic-gate * Save address of first usb isochronous packet descriptor. 57067c478bd9Sstevel@tonic-gate */ 57077c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr; 57087c478bd9Sstevel@tonic-gate 57097c478bd9Sstevel@tonic-gate /* Insert all the isochronous TDs */ 57107c478bd9Sstevel@tonic-gate for (count = 0, curr_isoc_xfer_offset = 0, 57117c478bd9Sstevel@tonic-gate isoc_pkts = 0; count < tw->tw_num_tds; count++) { 57127c478bd9Sstevel@tonic-gate 57137c478bd9Sstevel@tonic-gate residue = curr_isoc_reqp->isoc_pkts_count - isoc_pkts; 57147c478bd9Sstevel@tonic-gate 57157c478bd9Sstevel@tonic-gate /* Check for inserting residue data */ 57167c478bd9Sstevel@tonic-gate if ((count == (tw->tw_num_tds - 1)) && 57177c478bd9Sstevel@tonic-gate (residue < OHCI_ISOC_PKTS_PER_TD)) { 57187c478bd9Sstevel@tonic-gate frame_count = residue; 57197c478bd9Sstevel@tonic-gate } else { 57207c478bd9Sstevel@tonic-gate frame_count = OHCI_ISOC_PKTS_PER_TD; 57217c478bd9Sstevel@tonic-gate } 57227c478bd9Sstevel@tonic-gate 57237c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = tw->tw_curr_isoc_pktp; 57247c478bd9Sstevel@tonic-gate 57257c478bd9Sstevel@tonic-gate /* 57267c478bd9Sstevel@tonic-gate * Calculate length of isochronous transfer 57277c478bd9Sstevel@tonic-gate * for the current TD. 57287c478bd9Sstevel@tonic-gate */ 57297c478bd9Sstevel@tonic-gate for (i = 0, curr_isoc_xfer_len = 0; 57307c478bd9Sstevel@tonic-gate i < frame_count; i++, curr_isoc_pkt_descr++) { 57317c478bd9Sstevel@tonic-gate curr_isoc_xfer_len += 57327c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr->isoc_pkt_length; 57337c478bd9Sstevel@tonic-gate } 57347c478bd9Sstevel@tonic-gate 57357c478bd9Sstevel@tonic-gate /* 57367c478bd9Sstevel@tonic-gate * Programm td control field by checking whether this 57377c478bd9Sstevel@tonic-gate * is last td. 57387c478bd9Sstevel@tonic-gate */ 57397c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_tds - 1)) { 57407c478bd9Sstevel@tonic-gate ctrl = ((((frame_count - 1) << HC_ITD_FC_SHIFT) & 57417c478bd9Sstevel@tonic-gate HC_ITD_FC) | HC_TD_DT_0 | HC_TD_0I); 57427c478bd9Sstevel@tonic-gate } else { 57437c478bd9Sstevel@tonic-gate ctrl = ((((frame_count - 1) << HC_ITD_FC_SHIFT) & 57447c478bd9Sstevel@tonic-gate HC_ITD_FC) | HC_TD_DT_0 | HC_TD_6I); 57457c478bd9Sstevel@tonic-gate } 57467c478bd9Sstevel@tonic-gate 57477c478bd9Sstevel@tonic-gate /* Insert the TD into the endpoint */ 574802acac7eSsl if ((error = ohci_insert_hc_td(ohcip, ctrl, count, 57497c478bd9Sstevel@tonic-gate curr_isoc_xfer_len, 0, pp, tw)) != 57507c478bd9Sstevel@tonic-gate USB_SUCCESS) { 57517c478bd9Sstevel@tonic-gate tw->tw_num_tds = count; 57527c478bd9Sstevel@tonic-gate tw->tw_length = curr_isoc_xfer_offset; 57537c478bd9Sstevel@tonic-gate break; 57547c478bd9Sstevel@tonic-gate } 57557c478bd9Sstevel@tonic-gate 57567c478bd9Sstevel@tonic-gate isoc_pkts += frame_count; 57577c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp += frame_count; 57587c478bd9Sstevel@tonic-gate curr_isoc_xfer_offset += curr_isoc_xfer_len; 57597c478bd9Sstevel@tonic-gate } 57607c478bd9Sstevel@tonic-gate 57617c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 57627c478bd9Sstevel@tonic-gate /* Free periodic in resources */ 57637c478bd9Sstevel@tonic-gate if (tw->tw_direction == USB_EP_DIR_IN) { 57647c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 57657c478bd9Sstevel@tonic-gate } 57667c478bd9Sstevel@tonic-gate 57677c478bd9Sstevel@tonic-gate /* Free all resources if IN or if count == 0(for both IN/OUT) */ 57687c478bd9Sstevel@tonic-gate if (tw->tw_direction == USB_EP_DIR_IN || count == 0) { 57697c478bd9Sstevel@tonic-gate 57707c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 57717c478bd9Sstevel@tonic-gate 57727c478bd9Sstevel@tonic-gate if (pp->pp_cur_periodic_req_cnt) { 57737c478bd9Sstevel@tonic-gate /* 57747c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and 57757c478bd9Sstevel@tonic-gate * error to no resource. Don't insert 57767c478bd9Sstevel@tonic-gate * any more isochronous polling requests. 57777c478bd9Sstevel@tonic-gate */ 57787c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 57797c478bd9Sstevel@tonic-gate pp->pp_error = error; 57807c478bd9Sstevel@tonic-gate } else { 57817c478bd9Sstevel@tonic-gate /* Set periodic in pipe state to idle */ 57827c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 57837c478bd9Sstevel@tonic-gate } 57847c478bd9Sstevel@tonic-gate } 57857c478bd9Sstevel@tonic-gate } else { 57867c478bd9Sstevel@tonic-gate 57877c478bd9Sstevel@tonic-gate /* 57887c478bd9Sstevel@tonic-gate * Reset back to the address of first usb isochronous 57897c478bd9Sstevel@tonic-gate * packet descriptor. 57907c478bd9Sstevel@tonic-gate */ 57917c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr; 57927c478bd9Sstevel@tonic-gate 57937c478bd9Sstevel@tonic-gate /* Reset the CONTINUE flag */ 57947c478bd9Sstevel@tonic-gate pp->pp_flag &= ~OHCI_ISOC_XFER_CONTINUE; 57957c478bd9Sstevel@tonic-gate } 57967c478bd9Sstevel@tonic-gate 57977c478bd9Sstevel@tonic-gate return (error); 57987c478bd9Sstevel@tonic-gate } 57997c478bd9Sstevel@tonic-gate 58007c478bd9Sstevel@tonic-gate 58017c478bd9Sstevel@tonic-gate /* 58027c478bd9Sstevel@tonic-gate * ohci_insert_hc_td: 58037c478bd9Sstevel@tonic-gate * 58047c478bd9Sstevel@tonic-gate * Insert a Transfer Descriptor (TD) on an Endpoint Descriptor (ED). 58057c478bd9Sstevel@tonic-gate * Always returns USB_SUCCESS, except for ISOCH. 58067c478bd9Sstevel@tonic-gate */ 58077c478bd9Sstevel@tonic-gate static int 58087c478bd9Sstevel@tonic-gate ohci_insert_hc_td( 58097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 58107c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 581102acac7eSsl uint32_t hctd_dma_offs, 58127c478bd9Sstevel@tonic-gate size_t hctd_length, 58137c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 58147c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 58157c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 58167c478bd9Sstevel@tonic-gate { 58177c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy; 58187c478bd9Sstevel@tonic-gate ohci_td_t *cpu_current_dummy; 58197c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 58207c478bd9Sstevel@tonic-gate int error; 58217c478bd9Sstevel@tonic-gate 58227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 58237c478bd9Sstevel@tonic-gate 58247c478bd9Sstevel@tonic-gate /* Retrieve preallocated td from the TW */ 58257c478bd9Sstevel@tonic-gate new_dummy = tw->tw_hctd_free_list; 58267c478bd9Sstevel@tonic-gate 58277c478bd9Sstevel@tonic-gate ASSERT(new_dummy != NULL); 58287c478bd9Sstevel@tonic-gate 58297c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = ohci_td_iommu_to_cpu(ohcip, 58307c478bd9Sstevel@tonic-gate Get_TD(new_dummy->hctd_tw_next_td)); 58317c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_tw_next_td, NULL); 58327c478bd9Sstevel@tonic-gate 58337c478bd9Sstevel@tonic-gate /* Fill in the current dummy */ 58347c478bd9Sstevel@tonic-gate cpu_current_dummy = (ohci_td_t *) 58357c478bd9Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip, Get_ED(ept->hced_tailp))); 58367c478bd9Sstevel@tonic-gate 58377c478bd9Sstevel@tonic-gate /* 58387c478bd9Sstevel@tonic-gate * Fill in the current dummy td and 58397c478bd9Sstevel@tonic-gate * add the new dummy to the end. 58407c478bd9Sstevel@tonic-gate */ 58417c478bd9Sstevel@tonic-gate ohci_fill_in_td(ohcip, cpu_current_dummy, new_dummy, 584202acac7eSsl hctd_ctrl, hctd_dma_offs, hctd_length, hctd_ctrl_phase, pp, tw); 58437c478bd9Sstevel@tonic-gate 58447c478bd9Sstevel@tonic-gate /* 58457c478bd9Sstevel@tonic-gate * If this is an isochronous TD, first write proper 58467c478bd9Sstevel@tonic-gate * starting usb frame number in which this TD must 58477c478bd9Sstevel@tonic-gate * can be processed. After writing the frame number 58487c478bd9Sstevel@tonic-gate * insert this TD into the ED's list. 58497c478bd9Sstevel@tonic-gate */ 58507c478bd9Sstevel@tonic-gate if ((pp->pp_pipe_handle->p_ep.bmAttributes & 58517c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 58527c478bd9Sstevel@tonic-gate 58537c478bd9Sstevel@tonic-gate error = ohci_insert_td_with_frame_number( 58547c478bd9Sstevel@tonic-gate ohcip, pp, tw, cpu_current_dummy, new_dummy); 58557c478bd9Sstevel@tonic-gate 58567c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 58577c478bd9Sstevel@tonic-gate /* Reset the current dummy back to a dummy */ 58587c478bd9Sstevel@tonic-gate bzero((char *)cpu_current_dummy, sizeof (ohci_td_t)); 58597c478bd9Sstevel@tonic-gate Set_TD(cpu_current_dummy->hctd_state, HC_TD_DUMMY); 58607c478bd9Sstevel@tonic-gate 58617c478bd9Sstevel@tonic-gate /* return the new dummy back to the free list */ 58627c478bd9Sstevel@tonic-gate bzero((char *)new_dummy, sizeof (ohci_td_t)); 58637c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_state, HC_TD_DUMMY); 58647c478bd9Sstevel@tonic-gate if (tw->tw_hctd_free_list != NULL) { 58657c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_tw_next_td, 58667c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, 5867*29aca3ebSlc tw->tw_hctd_free_list)); 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = new_dummy; 58707c478bd9Sstevel@tonic-gate 58717c478bd9Sstevel@tonic-gate return (error); 58727c478bd9Sstevel@tonic-gate } 58737c478bd9Sstevel@tonic-gate } else { 58747c478bd9Sstevel@tonic-gate /* 58757c478bd9Sstevel@tonic-gate * For control, bulk and interrupt TD, just 58767c478bd9Sstevel@tonic-gate * add the new dummy to the ED's list. When 58777c478bd9Sstevel@tonic-gate * this occurs, the Host Controller ill see 58787c478bd9Sstevel@tonic-gate * the newly filled in dummy TD. 58797c478bd9Sstevel@tonic-gate */ 58807c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, 58817c478bd9Sstevel@tonic-gate (ohci_td_cpu_to_iommu(ohcip, new_dummy))); 58827c478bd9Sstevel@tonic-gate } 58837c478bd9Sstevel@tonic-gate 58847c478bd9Sstevel@tonic-gate /* Insert this td onto the tw */ 58857c478bd9Sstevel@tonic-gate ohci_insert_td_on_tw(ohcip, tw, cpu_current_dummy); 58867c478bd9Sstevel@tonic-gate 58877c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 58887c478bd9Sstevel@tonic-gate } 58897c478bd9Sstevel@tonic-gate 58907c478bd9Sstevel@tonic-gate 58917c478bd9Sstevel@tonic-gate /* 58927c478bd9Sstevel@tonic-gate * ohci_allocate_td_from_pool: 58937c478bd9Sstevel@tonic-gate * 58947c478bd9Sstevel@tonic-gate * Allocate a Transfer Descriptor (TD) from the TD buffer pool. 58957c478bd9Sstevel@tonic-gate */ 58967c478bd9Sstevel@tonic-gate static ohci_td_t * 58977c478bd9Sstevel@tonic-gate ohci_allocate_td_from_pool(ohci_state_t *ohcip) 58987c478bd9Sstevel@tonic-gate { 58997c478bd9Sstevel@tonic-gate int i, state; 59007c478bd9Sstevel@tonic-gate ohci_td_t *td; 59017c478bd9Sstevel@tonic-gate 59027c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 59037c478bd9Sstevel@tonic-gate 59047c478bd9Sstevel@tonic-gate /* 59057c478bd9Sstevel@tonic-gate * Search for a blank Transfer Descriptor (TD) 59067c478bd9Sstevel@tonic-gate * in the TD buffer pool. 59077c478bd9Sstevel@tonic-gate */ 59087c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) { 59097c478bd9Sstevel@tonic-gate state = Get_TD(ohcip->ohci_td_pool_addr[i].hctd_state); 59107c478bd9Sstevel@tonic-gate if (state == HC_TD_FREE) { 59117c478bd9Sstevel@tonic-gate break; 59127c478bd9Sstevel@tonic-gate } 59137c478bd9Sstevel@tonic-gate } 59147c478bd9Sstevel@tonic-gate 59157c478bd9Sstevel@tonic-gate if (i >= ohci_td_pool_size) { 59167c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 59177c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: TD exhausted"); 59187c478bd9Sstevel@tonic-gate 59197c478bd9Sstevel@tonic-gate return (NULL); 59207c478bd9Sstevel@tonic-gate } 59217c478bd9Sstevel@tonic-gate 59227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 59237c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: Allocated %d", i); 59247c478bd9Sstevel@tonic-gate 59257c478bd9Sstevel@tonic-gate /* Create a new dummy for the end of the TD list */ 59267c478bd9Sstevel@tonic-gate td = &ohcip->ohci_td_pool_addr[i]; 59277c478bd9Sstevel@tonic-gate 59287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 59297c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: td 0x%p", (void *)td); 59307c478bd9Sstevel@tonic-gate 59317c478bd9Sstevel@tonic-gate /* Mark the newly allocated TD as a dummy */ 59327c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_DUMMY); 59337c478bd9Sstevel@tonic-gate 59347c478bd9Sstevel@tonic-gate return (td); 59357c478bd9Sstevel@tonic-gate } 59367c478bd9Sstevel@tonic-gate 59377c478bd9Sstevel@tonic-gate /* 59387c478bd9Sstevel@tonic-gate * ohci_fill_in_td: 59397c478bd9Sstevel@tonic-gate * 59407c478bd9Sstevel@tonic-gate * Fill in the fields of a Transfer Descriptor (TD). 594102acac7eSsl * 594202acac7eSsl * hctd_dma_offs - different meanings for non-isoc and isoc TDs: 5943*29aca3ebSlc * starting offset into the TW buffer for a non-isoc TD 5944*29aca3ebSlc * and the index into the isoc TD list for an isoc TD. 5945*29aca3ebSlc * For non-isoc TDs, the starting offset should be 4k 5946*29aca3ebSlc * aligned and the TDs in one transfer must be filled in 5947*29aca3ebSlc * increasing order. 59487c478bd9Sstevel@tonic-gate */ 59497c478bd9Sstevel@tonic-gate static void 59507c478bd9Sstevel@tonic-gate ohci_fill_in_td( 59517c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 59527c478bd9Sstevel@tonic-gate ohci_td_t *td, 59537c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy, 59547c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 595502acac7eSsl uint32_t hctd_dma_offs, 59567c478bd9Sstevel@tonic-gate size_t hctd_length, 59577c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase, 59587c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 59597c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 59607c478bd9Sstevel@tonic-gate { 596102acac7eSsl USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 596202acac7eSsl "ohci_fill_in_td: td 0x%p bufoffs 0x%x len 0x%lx", 596302acac7eSsl td, hctd_dma_offs, hctd_length); 596402acac7eSsl 59657c478bd9Sstevel@tonic-gate /* Assert that the td to be filled in is a dummy */ 59667c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) == HC_TD_DUMMY); 59677c478bd9Sstevel@tonic-gate 59687c478bd9Sstevel@tonic-gate /* Change TD's state Active */ 59697c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_ACTIVE); 59707c478bd9Sstevel@tonic-gate 597102acac7eSsl /* Update the TD special fields */ 59727c478bd9Sstevel@tonic-gate if ((pp->pp_pipe_handle->p_ep.bmAttributes & 5973*29aca3ebSlc USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 597402acac7eSsl ohci_init_itd(ohcip, tw, hctd_ctrl, hctd_dma_offs, td); 59757c478bd9Sstevel@tonic-gate } else { 59767c478bd9Sstevel@tonic-gate /* Update the dummy with control information */ 59777c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA)); 59787c478bd9Sstevel@tonic-gate 597902acac7eSsl ohci_init_td(ohcip, tw, hctd_dma_offs, hctd_length, td); 59807c478bd9Sstevel@tonic-gate } 59817c478bd9Sstevel@tonic-gate 59827c478bd9Sstevel@tonic-gate /* The current dummy now points to the new dummy */ 59837c478bd9Sstevel@tonic-gate Set_TD(td->hctd_next_td, (ohci_td_cpu_to_iommu(ohcip, new_dummy))); 59847c478bd9Sstevel@tonic-gate 59857c478bd9Sstevel@tonic-gate /* 59867c478bd9Sstevel@tonic-gate * For Control transfer, hctd_ctrl_phase is a valid field. 59877c478bd9Sstevel@tonic-gate */ 59887c478bd9Sstevel@tonic-gate if (hctd_ctrl_phase) { 59897c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl_phase, hctd_ctrl_phase); 59907c478bd9Sstevel@tonic-gate } 59917c478bd9Sstevel@tonic-gate 59927c478bd9Sstevel@tonic-gate /* Print the td */ 59937c478bd9Sstevel@tonic-gate ohci_print_td(ohcip, td); 59947c478bd9Sstevel@tonic-gate 59957c478bd9Sstevel@tonic-gate /* Fill in the wrapper portion of the TD */ 59967c478bd9Sstevel@tonic-gate 59977c478bd9Sstevel@tonic-gate /* Set the transfer wrapper */ 59987c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 59997c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 60007c478bd9Sstevel@tonic-gate 60017c478bd9Sstevel@tonic-gate Set_TD(td->hctd_trans_wrapper, (uint32_t)tw->tw_id); 60027c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL); 60037c478bd9Sstevel@tonic-gate } 60047c478bd9Sstevel@tonic-gate 60057c478bd9Sstevel@tonic-gate 600602acac7eSsl /* 600702acac7eSsl * ohci_init_td: 600802acac7eSsl * 600902acac7eSsl * Initialize the buffer address portion of non-isoc Transfer 601002acac7eSsl * Descriptor (TD). 601102acac7eSsl */ 601202acac7eSsl void 601302acac7eSsl ohci_init_td( 601402acac7eSsl ohci_state_t *ohcip, 601502acac7eSsl ohci_trans_wrapper_t *tw, 601602acac7eSsl uint32_t hctd_dma_offs, 601702acac7eSsl size_t hctd_length, 601802acac7eSsl ohci_td_t *td) 601902acac7eSsl { 602002acac7eSsl uint32_t page_addr, start_addr = 0, end_addr = 0; 602102acac7eSsl size_t buf_len = hctd_length; 602202acac7eSsl int rem_len, i; 602302acac7eSsl 602402acac7eSsl /* 602502acac7eSsl * TDs must be filled in increasing DMA offset order. 602602acac7eSsl * tw_dma_offs is initialized to be 0 at TW creation and 602702acac7eSsl * is only increased in this function. 602802acac7eSsl */ 602902acac7eSsl ASSERT(buf_len == 0 || hctd_dma_offs >= tw->tw_dma_offs); 603002acac7eSsl 603102acac7eSsl Set_TD(td->hctd_xfer_offs, hctd_dma_offs); 603202acac7eSsl Set_TD(td->hctd_xfer_len, buf_len); 603302acac7eSsl 603402acac7eSsl /* Computing the starting buffer address and end buffer address */ 603502acac7eSsl for (i = 0; (i < 2) && (buf_len > 0); i++) { 603602acac7eSsl /* Advance to the next DMA cookie if necessary */ 603702acac7eSsl if ((tw->tw_dma_offs + tw->tw_cookie.dmac_size) <= 603802acac7eSsl hctd_dma_offs) { 603902acac7eSsl /* 604002acac7eSsl * tw_dma_offs always points to the starting offset 604102acac7eSsl * of a cookie 604202acac7eSsl */ 604302acac7eSsl tw->tw_dma_offs += tw->tw_cookie.dmac_size; 604402acac7eSsl ddi_dma_nextcookie(tw->tw_dmahandle, &tw->tw_cookie); 604502acac7eSsl tw->tw_cookie_idx++; 604602acac7eSsl ASSERT(tw->tw_cookie_idx < tw->tw_ncookies); 604702acac7eSsl } 604802acac7eSsl 604902acac7eSsl ASSERT((tw->tw_dma_offs + tw->tw_cookie.dmac_size) > 605002acac7eSsl hctd_dma_offs); 605102acac7eSsl 605202acac7eSsl /* 605302acac7eSsl * Counting the remained buffer length to be filled in 605402acac7eSsl * the TD for current DMA cookie 605502acac7eSsl */ 605602acac7eSsl rem_len = (tw->tw_dma_offs + tw->tw_cookie.dmac_size) - 605702acac7eSsl hctd_dma_offs; 605802acac7eSsl 605902acac7eSsl /* Get the beginning address of the buffer */ 606002acac7eSsl page_addr = (hctd_dma_offs - tw->tw_dma_offs) + 606102acac7eSsl tw->tw_cookie.dmac_address; 606202acac7eSsl ASSERT((page_addr % OHCI_4K_ALIGN) == 0); 606302acac7eSsl 606402acac7eSsl if (i == 0) { 606502acac7eSsl start_addr = page_addr; 606602acac7eSsl } 606702acac7eSsl 606802acac7eSsl USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 606902acac7eSsl "ohci_init_td: page_addr 0x%p dmac_size " 607002acac7eSsl "0x%lx idx %d", page_addr, tw->tw_cookie.dmac_size, 607102acac7eSsl tw->tw_cookie_idx); 607202acac7eSsl 607302acac7eSsl if (buf_len <= OHCI_MAX_TD_BUF_SIZE) { 607402acac7eSsl ASSERT(buf_len <= rem_len); 607502acac7eSsl end_addr = page_addr + buf_len - 1; 607602acac7eSsl buf_len = 0; 607702acac7eSsl break; 607802acac7eSsl } else { 607902acac7eSsl ASSERT(rem_len >= OHCI_MAX_TD_BUF_SIZE); 608002acac7eSsl buf_len -= OHCI_MAX_TD_BUF_SIZE; 608102acac7eSsl hctd_dma_offs += OHCI_MAX_TD_BUF_SIZE; 608202acac7eSsl } 608302acac7eSsl } 608402acac7eSsl 608502acac7eSsl ASSERT(buf_len == 0); 608602acac7eSsl 608702acac7eSsl Set_TD(td->hctd_cbp, start_addr); 608802acac7eSsl Set_TD(td->hctd_buf_end, end_addr); 608902acac7eSsl } 609002acac7eSsl 609102acac7eSsl 60927c478bd9Sstevel@tonic-gate /* 60937c478bd9Sstevel@tonic-gate * ohci_init_itd: 60947c478bd9Sstevel@tonic-gate * 609502acac7eSsl * Initialize the buffer address portion of isoc Transfer Descriptor (TD). 60967c478bd9Sstevel@tonic-gate */ 60977c478bd9Sstevel@tonic-gate static void 60987c478bd9Sstevel@tonic-gate ohci_init_itd( 60997c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 61007c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 61017c478bd9Sstevel@tonic-gate uint_t hctd_ctrl, 610202acac7eSsl uint32_t index, 61037c478bd9Sstevel@tonic-gate ohci_td_t *td) 61047c478bd9Sstevel@tonic-gate { 610502acac7eSsl uint32_t start_addr, end_addr, offset, offset_addr; 610602acac7eSsl ohci_isoc_buf_t *bufp; 610702acac7eSsl size_t buf_len; 61087c478bd9Sstevel@tonic-gate uint_t buf, fc, toggle, flag; 61097c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *temp_pkt_descr; 61107c478bd9Sstevel@tonic-gate int i; 61117c478bd9Sstevel@tonic-gate 61127c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 61137c478bd9Sstevel@tonic-gate 61147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 61157c478bd9Sstevel@tonic-gate "ohci_init_itd: ctrl = 0x%x", hctd_ctrl); 61167c478bd9Sstevel@tonic-gate 61177c478bd9Sstevel@tonic-gate /* 61187c478bd9Sstevel@tonic-gate * Write control information except starting 61197c478bd9Sstevel@tonic-gate * usb frame number. 61207c478bd9Sstevel@tonic-gate */ 61217c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA)); 61227c478bd9Sstevel@tonic-gate 612302acac7eSsl bufp = &tw->tw_isoc_bufs[index]; 612402acac7eSsl Set_TD(td->hctd_xfer_offs, index); 612502acac7eSsl Set_TD(td->hctd_xfer_len, bufp->length); 612602acac7eSsl 612702acac7eSsl start_addr = bufp->cookie.dmac_address; 612802acac7eSsl ASSERT((start_addr % OHCI_4K_ALIGN) == 0); 612902acac7eSsl 613002acac7eSsl buf_len = bufp->length; 613102acac7eSsl if (bufp->ncookies == OHCI_DMA_ATTR_TD_SGLLEN) { 613202acac7eSsl buf_len = bufp->length - bufp->cookie.dmac_size; 613302acac7eSsl ddi_dma_nextcookie(bufp->dma_handle, &bufp->cookie); 613402acac7eSsl } 613502acac7eSsl end_addr = bufp->cookie.dmac_address + buf_len - 1; 613602acac7eSsl 61377c478bd9Sstevel@tonic-gate /* 61387c478bd9Sstevel@tonic-gate * For an isochronous transfer, the hctd_cbp contains, 61397c478bd9Sstevel@tonic-gate * the 4k page, and not the actual start of the buffer. 61407c478bd9Sstevel@tonic-gate */ 614102acac7eSsl Set_TD(td->hctd_cbp, ((uint32_t)start_addr & HC_ITD_PAGE_MASK)); 614202acac7eSsl Set_TD(td->hctd_buf_end, end_addr); 61437c478bd9Sstevel@tonic-gate 61447c478bd9Sstevel@tonic-gate fc = (hctd_ctrl & HC_ITD_FC) >> HC_ITD_FC_SHIFT; 61457c478bd9Sstevel@tonic-gate toggle = 0; 614602acac7eSsl buf = start_addr; 61477c478bd9Sstevel@tonic-gate 61487c478bd9Sstevel@tonic-gate /* 61497c478bd9Sstevel@tonic-gate * Get the address of first isochronous data packet 61507c478bd9Sstevel@tonic-gate * for the current isochronous TD. 61517c478bd9Sstevel@tonic-gate */ 61527c478bd9Sstevel@tonic-gate temp_pkt_descr = tw->tw_curr_isoc_pktp; 61537c478bd9Sstevel@tonic-gate 61547c478bd9Sstevel@tonic-gate /* The offsets are actually offsets into the page */ 61557c478bd9Sstevel@tonic-gate for (i = 0; i <= fc; i++) { 61567c478bd9Sstevel@tonic-gate offset_addr = (uint32_t)((buf & 6157b3001defSlg HC_ITD_OFFSET_ADDR) | (HC_ITD_OFFSET_CC)); 61587c478bd9Sstevel@tonic-gate 615902acac7eSsl flag = ((start_addr & 61607c478bd9Sstevel@tonic-gate HC_ITD_PAGE_MASK) ^ (buf & HC_ITD_PAGE_MASK)); 61617c478bd9Sstevel@tonic-gate 61627c478bd9Sstevel@tonic-gate if (flag) { 61637c478bd9Sstevel@tonic-gate offset_addr |= HC_ITD_4KBOUNDARY_CROSS; 61647c478bd9Sstevel@tonic-gate } 61657c478bd9Sstevel@tonic-gate 61667c478bd9Sstevel@tonic-gate if (toggle) { 61677c478bd9Sstevel@tonic-gate offset = (uint32_t)((offset_addr << 61687c478bd9Sstevel@tonic-gate HC_ITD_OFFSET_SHIFT) & HC_ITD_ODD_OFFSET); 61697c478bd9Sstevel@tonic-gate 61707c478bd9Sstevel@tonic-gate Set_TD(td->hctd_offsets[i / 2], 61717c478bd9Sstevel@tonic-gate Get_TD(td->hctd_offsets[i / 2]) | offset); 61727c478bd9Sstevel@tonic-gate toggle = 0; 61737c478bd9Sstevel@tonic-gate } else { 61747c478bd9Sstevel@tonic-gate offset = (uint32_t)(offset_addr & HC_ITD_EVEN_OFFSET); 61757c478bd9Sstevel@tonic-gate 61767c478bd9Sstevel@tonic-gate Set_TD(td->hctd_offsets[i / 2], 61777c478bd9Sstevel@tonic-gate Get_TD(td->hctd_offsets[i / 2]) | offset); 61787c478bd9Sstevel@tonic-gate toggle = 1; 61797c478bd9Sstevel@tonic-gate } 61807c478bd9Sstevel@tonic-gate 61817c478bd9Sstevel@tonic-gate buf = (uint32_t)(buf + temp_pkt_descr->isoc_pkt_length); 61827c478bd9Sstevel@tonic-gate temp_pkt_descr++; 61837c478bd9Sstevel@tonic-gate } 61847c478bd9Sstevel@tonic-gate } 61857c478bd9Sstevel@tonic-gate 61867c478bd9Sstevel@tonic-gate 61877c478bd9Sstevel@tonic-gate /* 61887c478bd9Sstevel@tonic-gate * ohci_insert_td_with_frame_number: 61897c478bd9Sstevel@tonic-gate * 61907c478bd9Sstevel@tonic-gate * Insert current isochronous TD into the ED's list. with proper 61917c478bd9Sstevel@tonic-gate * usb frame number in which this TD can be processed. 61927c478bd9Sstevel@tonic-gate */ 61937c478bd9Sstevel@tonic-gate static int 61947c478bd9Sstevel@tonic-gate ohci_insert_td_with_frame_number( 61957c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 61967c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 61977c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 61987c478bd9Sstevel@tonic-gate ohci_td_t *current_td, 61997c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td) 62007c478bd9Sstevel@tonic-gate { 62017c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp = 6202*29aca3ebSlc (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 62037c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number, start_frame_number; 62047c478bd9Sstevel@tonic-gate uint_t ddic, ctrl, isoc_pkts; 62057c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 62067c478bd9Sstevel@tonic-gate 62077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 62087c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:" 62097c478bd9Sstevel@tonic-gate "isoc flags 0x%x", isoc_reqp->isoc_attributes); 62107c478bd9Sstevel@tonic-gate 62117c478bd9Sstevel@tonic-gate /* Get the TD ctrl information */ 62127c478bd9Sstevel@tonic-gate isoc_pkts = ((Get_TD(current_td->hctd_ctrl) & 62137c478bd9Sstevel@tonic-gate HC_ITD_FC) >> HC_ITD_FC_SHIFT) + 1; 62147c478bd9Sstevel@tonic-gate 62157c478bd9Sstevel@tonic-gate /* 62167c478bd9Sstevel@tonic-gate * Enter critical, while programming the usb frame number 62177c478bd9Sstevel@tonic-gate * and inserting current isochronous TD into the ED's list. 62187c478bd9Sstevel@tonic-gate */ 62197c478bd9Sstevel@tonic-gate ddic = ddi_enter_critical(); 62207c478bd9Sstevel@tonic-gate 62217c478bd9Sstevel@tonic-gate /* Get the current frame number */ 62227c478bd9Sstevel@tonic-gate current_frame_number = ohci_get_current_frame_number(ohcip); 62237c478bd9Sstevel@tonic-gate 62247c478bd9Sstevel@tonic-gate /* Check the given isochronous flags */ 62257c478bd9Sstevel@tonic-gate switch (isoc_reqp->isoc_attributes & 62267c478bd9Sstevel@tonic-gate (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) { 62277c478bd9Sstevel@tonic-gate case USB_ATTRS_ISOC_START_FRAME: 62287c478bd9Sstevel@tonic-gate /* Starting frame number is specified */ 62297c478bd9Sstevel@tonic-gate if (pp->pp_flag & OHCI_ISOC_XFER_CONTINUE) { 62307c478bd9Sstevel@tonic-gate /* Get the starting usb frame number */ 62317c478bd9Sstevel@tonic-gate start_frame_number = pp->pp_next_frame_number; 62327c478bd9Sstevel@tonic-gate } else { 62337c478bd9Sstevel@tonic-gate /* Check for the Starting usb frame number */ 62347c478bd9Sstevel@tonic-gate if ((isoc_reqp->isoc_frame_no == 0) || 62357c478bd9Sstevel@tonic-gate ((isoc_reqp->isoc_frame_no + 62367c478bd9Sstevel@tonic-gate isoc_reqp->isoc_pkts_count) < 62377c478bd9Sstevel@tonic-gate current_frame_number)) { 62387c478bd9Sstevel@tonic-gate 62397c478bd9Sstevel@tonic-gate /* Exit the critical */ 62407c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 62417c478bd9Sstevel@tonic-gate 62427c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, 62437c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, 62447c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:" 62457c478bd9Sstevel@tonic-gate "Invalid starting frame number"); 62467c478bd9Sstevel@tonic-gate 62477c478bd9Sstevel@tonic-gate return (USB_INVALID_START_FRAME); 62487c478bd9Sstevel@tonic-gate } 62497c478bd9Sstevel@tonic-gate 62507c478bd9Sstevel@tonic-gate /* Get the starting usb frame number */ 62517c478bd9Sstevel@tonic-gate start_frame_number = isoc_reqp->isoc_frame_no; 62527c478bd9Sstevel@tonic-gate 62537c478bd9Sstevel@tonic-gate pp->pp_next_frame_number = 0; 62547c478bd9Sstevel@tonic-gate } 62557c478bd9Sstevel@tonic-gate break; 62567c478bd9Sstevel@tonic-gate case USB_ATTRS_ISOC_XFER_ASAP: 62577c478bd9Sstevel@tonic-gate /* ohci has to specify starting frame number */ 62587c478bd9Sstevel@tonic-gate if ((pp->pp_next_frame_number) && 62597c478bd9Sstevel@tonic-gate (pp->pp_next_frame_number > current_frame_number)) { 62607c478bd9Sstevel@tonic-gate /* 62617c478bd9Sstevel@tonic-gate * Get the next usb frame number. 62627c478bd9Sstevel@tonic-gate */ 62637c478bd9Sstevel@tonic-gate start_frame_number = pp->pp_next_frame_number; 62647c478bd9Sstevel@tonic-gate } else { 62657c478bd9Sstevel@tonic-gate /* 62667c478bd9Sstevel@tonic-gate * Add appropriate offset to the current usb 62677c478bd9Sstevel@tonic-gate * frame number and use it as a starting frame 62687c478bd9Sstevel@tonic-gate * number. 62697c478bd9Sstevel@tonic-gate */ 62707c478bd9Sstevel@tonic-gate start_frame_number = 62717c478bd9Sstevel@tonic-gate current_frame_number + OHCI_FRAME_OFFSET; 62727c478bd9Sstevel@tonic-gate } 62737c478bd9Sstevel@tonic-gate 62747c478bd9Sstevel@tonic-gate if (!(pp->pp_flag & OHCI_ISOC_XFER_CONTINUE)) { 62757c478bd9Sstevel@tonic-gate isoc_reqp->isoc_frame_no = start_frame_number; 62767c478bd9Sstevel@tonic-gate } 62777c478bd9Sstevel@tonic-gate break; 62787c478bd9Sstevel@tonic-gate default: 62797c478bd9Sstevel@tonic-gate /* Exit the critical */ 62807c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 62817c478bd9Sstevel@tonic-gate 62827c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 62837c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number: Either starting " 62847c478bd9Sstevel@tonic-gate "frame number or ASAP flags are not set, attrs = 0x%x", 62857c478bd9Sstevel@tonic-gate isoc_reqp->isoc_attributes); 62867c478bd9Sstevel@tonic-gate 62877c478bd9Sstevel@tonic-gate return (USB_NO_FRAME_NUMBER); 62887c478bd9Sstevel@tonic-gate } 62897c478bd9Sstevel@tonic-gate 62907c478bd9Sstevel@tonic-gate /* Get the TD ctrl information */ 62917c478bd9Sstevel@tonic-gate ctrl = Get_TD(current_td->hctd_ctrl) & (~(HC_ITD_SF)); 62927c478bd9Sstevel@tonic-gate 62937c478bd9Sstevel@tonic-gate /* Set the frame number field */ 62947c478bd9Sstevel@tonic-gate Set_TD(current_td->hctd_ctrl, ctrl | (start_frame_number & HC_ITD_SF)); 62957c478bd9Sstevel@tonic-gate 62967c478bd9Sstevel@tonic-gate /* 62977c478bd9Sstevel@tonic-gate * Add the new dummy to the ED's list. When this occurs, 62987c478bd9Sstevel@tonic-gate * the Host Controller will see newly filled in dummy TD. 62997c478bd9Sstevel@tonic-gate */ 63007c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, dummy_td))); 63017c478bd9Sstevel@tonic-gate 63027c478bd9Sstevel@tonic-gate /* Exit the critical */ 63037c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic); 63047c478bd9Sstevel@tonic-gate 63057c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 63067c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:" 63077c478bd9Sstevel@tonic-gate "current frame number 0x%llx start frame number 0x%llx", 63087c478bd9Sstevel@tonic-gate current_frame_number, start_frame_number); 63097c478bd9Sstevel@tonic-gate 63107c478bd9Sstevel@tonic-gate /* 63117c478bd9Sstevel@tonic-gate * Increment this saved frame number by current number 63127c478bd9Sstevel@tonic-gate * of data packets needs to be transfer. 63137c478bd9Sstevel@tonic-gate */ 63147c478bd9Sstevel@tonic-gate pp->pp_next_frame_number = start_frame_number + isoc_pkts; 63157c478bd9Sstevel@tonic-gate 63167c478bd9Sstevel@tonic-gate /* 63177c478bd9Sstevel@tonic-gate * Set OHCI_ISOC_XFER_CONTINUE flag in order to send other 63187c478bd9Sstevel@tonic-gate * isochronous packets, part of the current isoch request 63197c478bd9Sstevel@tonic-gate * in the subsequent frames. 63207c478bd9Sstevel@tonic-gate */ 63217c478bd9Sstevel@tonic-gate pp->pp_flag |= OHCI_ISOC_XFER_CONTINUE; 63227c478bd9Sstevel@tonic-gate 63237c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 63247c478bd9Sstevel@tonic-gate } 63257c478bd9Sstevel@tonic-gate 63267c478bd9Sstevel@tonic-gate 63277c478bd9Sstevel@tonic-gate /* 63287c478bd9Sstevel@tonic-gate * ohci_insert_td_on_tw: 63297c478bd9Sstevel@tonic-gate * 63307c478bd9Sstevel@tonic-gate * The transfer wrapper keeps a list of all Transfer Descriptors (TD) that 63317c478bd9Sstevel@tonic-gate * are allocated for this transfer. Insert a TD onto this list. The list 63327c478bd9Sstevel@tonic-gate * of TD's does not include the dummy TD that is at the end of the list of 63337c478bd9Sstevel@tonic-gate * TD's for the endpoint. 63347c478bd9Sstevel@tonic-gate */ 63357c478bd9Sstevel@tonic-gate static void 63367c478bd9Sstevel@tonic-gate ohci_insert_td_on_tw( 63377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 63387c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 63397c478bd9Sstevel@tonic-gate ohci_td_t *td) 63407c478bd9Sstevel@tonic-gate { 63417c478bd9Sstevel@tonic-gate /* 63427c478bd9Sstevel@tonic-gate * Set the next pointer to NULL because 63437c478bd9Sstevel@tonic-gate * this is the last TD on list. 63447c478bd9Sstevel@tonic-gate */ 63457c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL); 63467c478bd9Sstevel@tonic-gate 63477c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head == NULL) { 63487c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL); 63497c478bd9Sstevel@tonic-gate tw->tw_hctd_head = td; 63507c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td; 63517c478bd9Sstevel@tonic-gate } else { 63527c478bd9Sstevel@tonic-gate ohci_td_t *dummy = (ohci_td_t *)tw->tw_hctd_tail; 63537c478bd9Sstevel@tonic-gate 63547c478bd9Sstevel@tonic-gate ASSERT(dummy != NULL); 63557c478bd9Sstevel@tonic-gate ASSERT(dummy != td); 63567c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) != HC_TD_DUMMY); 63577c478bd9Sstevel@tonic-gate 63587c478bd9Sstevel@tonic-gate /* Add the td to the end of the list */ 63597c478bd9Sstevel@tonic-gate Set_TD(dummy->hctd_tw_next_td, 63607c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, td)); 63617c478bd9Sstevel@tonic-gate 63627c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td; 63637c478bd9Sstevel@tonic-gate 63647c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_tw_next_td) == NULL); 63657c478bd9Sstevel@tonic-gate } 63667c478bd9Sstevel@tonic-gate } 63677c478bd9Sstevel@tonic-gate 63687c478bd9Sstevel@tonic-gate 63697c478bd9Sstevel@tonic-gate /* 63707c478bd9Sstevel@tonic-gate * ohci_traverse_tds: 63717c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 63727c478bd9Sstevel@tonic-gate * 63737c478bd9Sstevel@tonic-gate * Traverse the list of TD's for an endpoint. Since the endpoint is marked 63747c478bd9Sstevel@tonic-gate * as sKipped, the Host Controller (HC) is no longer accessing these TD's. 63757c478bd9Sstevel@tonic-gate * Remove all the TD's that are attached to the endpoint. 63767c478bd9Sstevel@tonic-gate */ 63777c478bd9Sstevel@tonic-gate void 63787c478bd9Sstevel@tonic-gate ohci_traverse_tds( 63797c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 63807c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 63817c478bd9Sstevel@tonic-gate { 63827c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 63837c478bd9Sstevel@tonic-gate ohci_ed_t *ept; 63847c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 63857c478bd9Sstevel@tonic-gate uint32_t addr; 63867c478bd9Sstevel@tonic-gate ohci_td_t *tailp, *headp, *next; 63877c478bd9Sstevel@tonic-gate 63887c478bd9Sstevel@tonic-gate pp = (ohci_pipe_private_t *)ph->p_hcd_private; 63897c478bd9Sstevel@tonic-gate ept = pp->pp_ept; 63907c478bd9Sstevel@tonic-gate 63917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 63927c478bd9Sstevel@tonic-gate "ohci_traverse_tds: ph = 0x%p ept = 0x%p", 63937c478bd9Sstevel@tonic-gate (void *)ph, (void *)ept); 63947c478bd9Sstevel@tonic-gate 63957c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 63967c478bd9Sstevel@tonic-gate 63977c478bd9Sstevel@tonic-gate addr = Get_ED(ept->hced_headp) & (uint32_t)HC_EPT_TD_HEAD; 63987c478bd9Sstevel@tonic-gate 63997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64007c478bd9Sstevel@tonic-gate "ohci_traverse_tds: addr (head) = 0x%x", addr); 64017c478bd9Sstevel@tonic-gate 64027c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, addr)); 64037c478bd9Sstevel@tonic-gate 64047c478bd9Sstevel@tonic-gate addr = Get_ED(ept->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL; 64057c478bd9Sstevel@tonic-gate 64067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64077c478bd9Sstevel@tonic-gate "ohci_traverse_tds: addr (tail) = 0x%x", addr); 64087c478bd9Sstevel@tonic-gate 64097c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, addr)); 64107c478bd9Sstevel@tonic-gate 64117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64127c478bd9Sstevel@tonic-gate "ohci_traverse_tds: cpu head = 0x%p cpu tail = 0x%p", 64137c478bd9Sstevel@tonic-gate (void *)headp, (void *)tailp); 64147c478bd9Sstevel@tonic-gate 64157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64167c478bd9Sstevel@tonic-gate "ohci_traverse_tds: iommu head = 0x%x iommu tail = 0x%x", 64177c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, headp), 64187c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, tailp)); 64197c478bd9Sstevel@tonic-gate 64207c478bd9Sstevel@tonic-gate /* 64217c478bd9Sstevel@tonic-gate * Traverse the list of TD's that are currently on the endpoint. 64227c478bd9Sstevel@tonic-gate * These TD's have not been processed and will not be processed 64237c478bd9Sstevel@tonic-gate * because the endpoint processing is stopped. 64247c478bd9Sstevel@tonic-gate */ 64257c478bd9Sstevel@tonic-gate while (headp != tailp) { 64267c478bd9Sstevel@tonic-gate next = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 64277c478bd9Sstevel@tonic-gate (Get_TD(headp->hctd_next_td) & HC_EPT_TD_TAIL))); 64287c478bd9Sstevel@tonic-gate 64297c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID( 64307c478bd9Sstevel@tonic-gate (uint32_t)Get_TD(headp->hctd_trans_wrapper)); 64317c478bd9Sstevel@tonic-gate 64327c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 64337c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, OHCI_REMOVE_XFER_ALWAYS); 64347c478bd9Sstevel@tonic-gate 64357c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, headp); 64367c478bd9Sstevel@tonic-gate headp = next; 64377c478bd9Sstevel@tonic-gate } 64387c478bd9Sstevel@tonic-gate 64397c478bd9Sstevel@tonic-gate /* Both head and tail pointers must be same */ 64407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64417c478bd9Sstevel@tonic-gate "ohci_traverse_tds: head = 0x%p tail = 0x%p", 64427c478bd9Sstevel@tonic-gate (void *)headp, (void *)tailp); 64437c478bd9Sstevel@tonic-gate 64447c478bd9Sstevel@tonic-gate /* Update the pointer in the endpoint descriptor */ 64457c478bd9Sstevel@tonic-gate Set_ED(ept->hced_headp, (ohci_td_cpu_to_iommu(ohcip, headp))); 64467c478bd9Sstevel@tonic-gate 64477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64487c478bd9Sstevel@tonic-gate "ohci_traverse_tds: new head = 0x%x", 64497c478bd9Sstevel@tonic-gate (ohci_td_cpu_to_iommu(ohcip, headp))); 64507c478bd9Sstevel@tonic-gate 64517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64527c478bd9Sstevel@tonic-gate "ohci_traverse_tds: tailp = 0x%x headp = 0x%x", 64537c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL), 64547c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD)); 64557c478bd9Sstevel@tonic-gate 64567c478bd9Sstevel@tonic-gate ASSERT((Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL) == 64577c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD)); 64587c478bd9Sstevel@tonic-gate } 64597c478bd9Sstevel@tonic-gate 64607c478bd9Sstevel@tonic-gate 64617c478bd9Sstevel@tonic-gate /* 64627c478bd9Sstevel@tonic-gate * ohci_done_list_tds: 64637c478bd9Sstevel@tonic-gate * 64647c478bd9Sstevel@tonic-gate * There may be TD's on the done list that have not been processed yet. Walk 64657c478bd9Sstevel@tonic-gate * through these TD's and mark them as RECLAIM. All the mappings for the TD 64667c478bd9Sstevel@tonic-gate * will be torn down, so the interrupt handle is alerted of this fact through 64677c478bd9Sstevel@tonic-gate * the RECLAIM flag. 64687c478bd9Sstevel@tonic-gate */ 64697c478bd9Sstevel@tonic-gate static void 64707c478bd9Sstevel@tonic-gate ohci_done_list_tds( 64717c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 64727c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 64737c478bd9Sstevel@tonic-gate { 64747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 64757c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head; 64767c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw; 64777c478bd9Sstevel@tonic-gate ohci_td_t *head_td, *next_td; 64787c478bd9Sstevel@tonic-gate 64797c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 64807c478bd9Sstevel@tonic-gate 64817c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 64827c478bd9Sstevel@tonic-gate "ohci_done_list_tds:"); 64837c478bd9Sstevel@tonic-gate 64847c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */ 64857c478bd9Sstevel@tonic-gate next_tw = head_tw; 64867c478bd9Sstevel@tonic-gate while (next_tw) { 64877c478bd9Sstevel@tonic-gate head_td = (ohci_td_t *)next_tw->tw_hctd_head; 64887c478bd9Sstevel@tonic-gate next_td = head_td; 64897c478bd9Sstevel@tonic-gate 64907c478bd9Sstevel@tonic-gate if (head_td) { 64917c478bd9Sstevel@tonic-gate /* 64927c478bd9Sstevel@tonic-gate * Walk through each TD for this transfer 64937c478bd9Sstevel@tonic-gate * wrapper. If a TD still exists, then it 64947c478bd9Sstevel@tonic-gate * is currently on the done list. 64957c478bd9Sstevel@tonic-gate */ 64967c478bd9Sstevel@tonic-gate while (next_td) { 64977c478bd9Sstevel@tonic-gate 64987c478bd9Sstevel@tonic-gate /* To free TD, set TD state to RECLAIM */ 64997c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_state, HC_TD_RECLAIM); 65007c478bd9Sstevel@tonic-gate 65017c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_trans_wrapper, NULL); 65027c478bd9Sstevel@tonic-gate 65037c478bd9Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip, 65047c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td)); 65057c478bd9Sstevel@tonic-gate } 65067c478bd9Sstevel@tonic-gate } 65077c478bd9Sstevel@tonic-gate 65087c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 65097c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, next_tw, OHCI_REMOVE_XFER_ALWAYS); 65107c478bd9Sstevel@tonic-gate 65117c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next; 65127c478bd9Sstevel@tonic-gate } 65137c478bd9Sstevel@tonic-gate } 65147c478bd9Sstevel@tonic-gate 65157c478bd9Sstevel@tonic-gate 6516277d02f6Sgc /* 6517277d02f6Sgc * Remove old_td from tw and update the links. 6518277d02f6Sgc */ 6519277d02f6Sgc void 6520277d02f6Sgc ohci_unlink_td_from_tw( 6521277d02f6Sgc ohci_state_t *ohcip, 6522277d02f6Sgc ohci_td_t *old_td, 6523277d02f6Sgc ohci_trans_wrapper_t *tw) 6524277d02f6Sgc { 6525277d02f6Sgc ohci_td_t *next, *head, *tail; 6526277d02f6Sgc 6527277d02f6Sgc USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 6528277d02f6Sgc "ohci_unlink_td_from_tw: ohcip = 0x%p, old_td = 0x%p, tw = 0x%p", 6529277d02f6Sgc (void *)ohcip, (void *)old_td, (void *)tw); 6530277d02f6Sgc 6531277d02f6Sgc if (old_td == NULL || tw == NULL) { 6532277d02f6Sgc 6533277d02f6Sgc return; 6534277d02f6Sgc } 6535277d02f6Sgc 6536277d02f6Sgc head = tw->tw_hctd_head; 6537277d02f6Sgc tail = tw->tw_hctd_tail; 6538277d02f6Sgc 6539277d02f6Sgc if (head == NULL) { 6540277d02f6Sgc 6541277d02f6Sgc return; 6542277d02f6Sgc } 6543277d02f6Sgc 6544277d02f6Sgc /* if this old_td is on head */ 6545277d02f6Sgc if (old_td == head) { 6546277d02f6Sgc if (old_td == tail) { 6547277d02f6Sgc tw->tw_hctd_head = NULL; 6548277d02f6Sgc tw->tw_hctd_tail = NULL; 6549277d02f6Sgc } else { 6550277d02f6Sgc tw->tw_hctd_head = ohci_td_iommu_to_cpu(ohcip, 6551*29aca3ebSlc Get_TD(head->hctd_tw_next_td)); 6552277d02f6Sgc } 6553277d02f6Sgc 6554277d02f6Sgc return; 6555277d02f6Sgc } 6556277d02f6Sgc 6557277d02f6Sgc /* find this old_td's position in the tw */ 6558277d02f6Sgc next = ohci_td_iommu_to_cpu(ohcip, Get_TD(head->hctd_tw_next_td)); 6559277d02f6Sgc while (next && (old_td != next)) { 6560277d02f6Sgc head = next; 6561277d02f6Sgc next = ohci_td_iommu_to_cpu(ohcip, 6562*29aca3ebSlc Get_TD(next->hctd_tw_next_td)); 6563277d02f6Sgc } 6564277d02f6Sgc 6565277d02f6Sgc /* unlink the found old_td from the tw */ 6566277d02f6Sgc if (old_td == next) { 6567277d02f6Sgc Set_TD(head->hctd_tw_next_td, Get_TD(next->hctd_tw_next_td)); 6568277d02f6Sgc if (old_td == tail) { 6569277d02f6Sgc tw->tw_hctd_tail = head; 6570277d02f6Sgc } 6571277d02f6Sgc } 6572277d02f6Sgc } 6573277d02f6Sgc 6574277d02f6Sgc 65757c478bd9Sstevel@tonic-gate /* 65767c478bd9Sstevel@tonic-gate * ohci_deallocate_td: 65777c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 65787c478bd9Sstevel@tonic-gate * 65797c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Transfer Descriptor (TD). 65807c478bd9Sstevel@tonic-gate */ 65817c478bd9Sstevel@tonic-gate void 65827c478bd9Sstevel@tonic-gate ohci_deallocate_td( 65837c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 65847c478bd9Sstevel@tonic-gate ohci_td_t *old_td) 65857c478bd9Sstevel@tonic-gate { 65867c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 65877c478bd9Sstevel@tonic-gate 65887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 65897c478bd9Sstevel@tonic-gate "ohci_deallocate_td: old_td = 0x%p", (void *)old_td); 65907c478bd9Sstevel@tonic-gate 65917c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 65927c478bd9Sstevel@tonic-gate 65937c478bd9Sstevel@tonic-gate /* 65947c478bd9Sstevel@tonic-gate * Obtain the transaction wrapper and tw will be 65957c478bd9Sstevel@tonic-gate * NULL for the dummy and for the reclaim TD's. 65967c478bd9Sstevel@tonic-gate */ 65977c478bd9Sstevel@tonic-gate if ((Get_TD(old_td->hctd_state) == HC_TD_DUMMY) || 6598*29aca3ebSlc (Get_TD(old_td->hctd_state) == HC_TD_RECLAIM)) { 65997c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)((uintptr_t) 6600*29aca3ebSlc Get_TD(old_td->hctd_trans_wrapper)); 66017c478bd9Sstevel@tonic-gate ASSERT(tw == NULL); 66027c478bd9Sstevel@tonic-gate } else { 66037c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 6604*29aca3ebSlc OHCI_LOOKUP_ID((uint32_t) 6605*29aca3ebSlc Get_TD(old_td->hctd_trans_wrapper)); 66067c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 66077c478bd9Sstevel@tonic-gate } 66087c478bd9Sstevel@tonic-gate 66097c478bd9Sstevel@tonic-gate /* 66107c478bd9Sstevel@tonic-gate * If this TD should be reclaimed, don't try to access its 66117c478bd9Sstevel@tonic-gate * transfer wrapper. 66127c478bd9Sstevel@tonic-gate */ 66137c478bd9Sstevel@tonic-gate if ((Get_TD(old_td->hctd_state) != HC_TD_RECLAIM) && tw) { 66147c478bd9Sstevel@tonic-gate 6615277d02f6Sgc ohci_unlink_td_from_tw(ohcip, old_td, tw); 66167c478bd9Sstevel@tonic-gate } 66177c478bd9Sstevel@tonic-gate 66187c478bd9Sstevel@tonic-gate bzero((void *)old_td, sizeof (ohci_td_t)); 66197c478bd9Sstevel@tonic-gate Set_TD(old_td->hctd_state, HC_TD_FREE); 66207c478bd9Sstevel@tonic-gate 66217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 66227c478bd9Sstevel@tonic-gate "ohci_deallocate_td: td 0x%p", (void *)old_td); 66237c478bd9Sstevel@tonic-gate } 66247c478bd9Sstevel@tonic-gate 66257c478bd9Sstevel@tonic-gate 66267c478bd9Sstevel@tonic-gate /* 66277c478bd9Sstevel@tonic-gate * ohci_td_cpu_to_iommu: 66287c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 66297c478bd9Sstevel@tonic-gate * 66307c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (TD) CPU address 66317c478bd9Sstevel@tonic-gate * to IO address. 66327c478bd9Sstevel@tonic-gate */ 66337c478bd9Sstevel@tonic-gate uint32_t 66347c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu( 66357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 66367c478bd9Sstevel@tonic-gate ohci_td_t *addr) 66377c478bd9Sstevel@tonic-gate { 66387c478bd9Sstevel@tonic-gate uint32_t td; 66397c478bd9Sstevel@tonic-gate 66407c478bd9Sstevel@tonic-gate td = (uint32_t)ohcip->ohci_td_pool_cookie.dmac_address + 66417c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ohcip->ohci_td_pool_addr)); 66427c478bd9Sstevel@tonic-gate 66437c478bd9Sstevel@tonic-gate ASSERT((ohcip->ohci_td_pool_cookie.dmac_address + 66447c478bd9Sstevel@tonic-gate (uint32_t) (sizeof (ohci_td_t) * 66457c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_td_pool_addr))) == 66467c478bd9Sstevel@tonic-gate (ohcip->ohci_td_pool_cookie.dmac_address + 66477c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t) 66487c478bd9Sstevel@tonic-gate (ohcip->ohci_td_pool_addr)))); 66497c478bd9Sstevel@tonic-gate 66507c478bd9Sstevel@tonic-gate ASSERT(td >= ohcip->ohci_td_pool_cookie.dmac_address); 66517c478bd9Sstevel@tonic-gate ASSERT(td <= ohcip->ohci_td_pool_cookie.dmac_address + 66527c478bd9Sstevel@tonic-gate sizeof (ohci_td_t) * ohci_td_pool_size); 66537c478bd9Sstevel@tonic-gate 66547c478bd9Sstevel@tonic-gate return (td); 66557c478bd9Sstevel@tonic-gate } 66567c478bd9Sstevel@tonic-gate 66577c478bd9Sstevel@tonic-gate 66587c478bd9Sstevel@tonic-gate /* 66597c478bd9Sstevel@tonic-gate * ohci_td_iommu_to_cpu: 66607c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 66617c478bd9Sstevel@tonic-gate * 66627c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (TD) IO address 66637c478bd9Sstevel@tonic-gate * to CPU address. 66647c478bd9Sstevel@tonic-gate */ 66657c478bd9Sstevel@tonic-gate ohci_td_t * 66667c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu( 66677c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 66687c478bd9Sstevel@tonic-gate uintptr_t addr) 66697c478bd9Sstevel@tonic-gate { 66707c478bd9Sstevel@tonic-gate ohci_td_t *td; 66717c478bd9Sstevel@tonic-gate 66727c478bd9Sstevel@tonic-gate if (addr == NULL) { 66737c478bd9Sstevel@tonic-gate 66747c478bd9Sstevel@tonic-gate return (NULL); 66757c478bd9Sstevel@tonic-gate } 66767c478bd9Sstevel@tonic-gate 66777c478bd9Sstevel@tonic-gate td = (ohci_td_t *)((uintptr_t) 66787c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_td_pool_cookie.dmac_address) + 66797c478bd9Sstevel@tonic-gate (uintptr_t)ohcip->ohci_td_pool_addr); 66807c478bd9Sstevel@tonic-gate 66817c478bd9Sstevel@tonic-gate ASSERT(td >= ohcip->ohci_td_pool_addr); 66827c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)td <= (uintptr_t)ohcip->ohci_td_pool_addr + 66837c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ohci_td_t) * ohci_td_pool_size)); 66847c478bd9Sstevel@tonic-gate 66857c478bd9Sstevel@tonic-gate return (td); 66867c478bd9Sstevel@tonic-gate } 66877c478bd9Sstevel@tonic-gate 66887c478bd9Sstevel@tonic-gate /* 66897c478bd9Sstevel@tonic-gate * ohci_allocate_tds_for_tw: 66907c478bd9Sstevel@tonic-gate * 66917c478bd9Sstevel@tonic-gate * Allocate n Transfer Descriptors (TD) from the TD buffer pool and places it 66927c478bd9Sstevel@tonic-gate * into the TW. 66937c478bd9Sstevel@tonic-gate * 66947c478bd9Sstevel@tonic-gate * Returns USB_NO_RESOURCES if it was not able to allocate all the requested TD 66957c478bd9Sstevel@tonic-gate * otherwise USB_SUCCESS. 66967c478bd9Sstevel@tonic-gate */ 66977c478bd9Sstevel@tonic-gate static int 66987c478bd9Sstevel@tonic-gate ohci_allocate_tds_for_tw( 66997c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 67007c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 67017c478bd9Sstevel@tonic-gate size_t td_count) 67027c478bd9Sstevel@tonic-gate { 67037c478bd9Sstevel@tonic-gate ohci_td_t *td; 67047c478bd9Sstevel@tonic-gate uint32_t td_addr; 67057c478bd9Sstevel@tonic-gate int i; 67067c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 67077c478bd9Sstevel@tonic-gate 67087c478bd9Sstevel@tonic-gate for (i = 0; i < td_count; i++) { 67097c478bd9Sstevel@tonic-gate td = ohci_allocate_td_from_pool(ohcip); 67107c478bd9Sstevel@tonic-gate if (td == NULL) { 67117c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 67127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 67137c478bd9Sstevel@tonic-gate "ohci_allocate_tds_for_tw: " 67147c478bd9Sstevel@tonic-gate "Unable to allocate %lu TDs", 67157c478bd9Sstevel@tonic-gate td_count); 67167c478bd9Sstevel@tonic-gate break; 67177c478bd9Sstevel@tonic-gate } 67187c478bd9Sstevel@tonic-gate if (tw->tw_hctd_free_list != NULL) { 67197c478bd9Sstevel@tonic-gate td_addr = ohci_td_cpu_to_iommu(ohcip, 67207c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list); 67217c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, td_addr); 67227c478bd9Sstevel@tonic-gate } 67237c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = td; 67247c478bd9Sstevel@tonic-gate } 67257c478bd9Sstevel@tonic-gate 67267c478bd9Sstevel@tonic-gate return (error); 67277c478bd9Sstevel@tonic-gate } 67287c478bd9Sstevel@tonic-gate 67297c478bd9Sstevel@tonic-gate /* 67307c478bd9Sstevel@tonic-gate * ohci_allocate_tw_resources: 67317c478bd9Sstevel@tonic-gate * 67327c478bd9Sstevel@tonic-gate * Allocate a Transaction Wrapper (TW) and n Transfer Descriptors (TD) 67337c478bd9Sstevel@tonic-gate * from the TD buffer pool and places it into the TW. It does an all 67347c478bd9Sstevel@tonic-gate * or nothing transaction. 67357c478bd9Sstevel@tonic-gate * 67367c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 67377c478bd9Sstevel@tonic-gate */ 67387c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 67397c478bd9Sstevel@tonic-gate ohci_allocate_tw_resources( 6740*29aca3ebSlc ohci_state_t *ohcip, 67417c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 67427c478bd9Sstevel@tonic-gate size_t tw_length, 67437c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 6744*29aca3ebSlc size_t td_count) 67457c478bd9Sstevel@tonic-gate { 67467c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 67477c478bd9Sstevel@tonic-gate 67487c478bd9Sstevel@tonic-gate tw = ohci_create_transfer_wrapper(ohcip, pp, tw_length, usb_flags); 67497c478bd9Sstevel@tonic-gate 67507c478bd9Sstevel@tonic-gate if (tw == NULL) { 67517c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 67527c478bd9Sstevel@tonic-gate "ohci_allocate_tw_resources: Unable to allocate TW"); 67537c478bd9Sstevel@tonic-gate } else { 67547c478bd9Sstevel@tonic-gate if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) == 67557c478bd9Sstevel@tonic-gate USB_SUCCESS) { 67567c478bd9Sstevel@tonic-gate tw->tw_num_tds = td_count; 67577c478bd9Sstevel@tonic-gate } else { 67587c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 67597c478bd9Sstevel@tonic-gate tw = NULL; 67607c478bd9Sstevel@tonic-gate } 67617c478bd9Sstevel@tonic-gate } 67627c478bd9Sstevel@tonic-gate 67637c478bd9Sstevel@tonic-gate return (tw); 67647c478bd9Sstevel@tonic-gate } 67657c478bd9Sstevel@tonic-gate 67667c478bd9Sstevel@tonic-gate /* 67677c478bd9Sstevel@tonic-gate * ohci_free_tw_tds_resources: 67687c478bd9Sstevel@tonic-gate * 67697c478bd9Sstevel@tonic-gate * Free all allocated resources for Transaction Wrapper (TW). 67707c478bd9Sstevel@tonic-gate * Does not free the TW itself. 67717c478bd9Sstevel@tonic-gate */ 67727c478bd9Sstevel@tonic-gate static void 67737c478bd9Sstevel@tonic-gate ohci_free_tw_tds_resources( 67747c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 67757c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 67767c478bd9Sstevel@tonic-gate { 67777c478bd9Sstevel@tonic-gate ohci_td_t *td; 67787c478bd9Sstevel@tonic-gate ohci_td_t *temp_td; 67797c478bd9Sstevel@tonic-gate 67807c478bd9Sstevel@tonic-gate td = tw->tw_hctd_free_list; 67817c478bd9Sstevel@tonic-gate while (td != NULL) { 67827c478bd9Sstevel@tonic-gate /* Save the pointer to the next td before destroying it */ 67837c478bd9Sstevel@tonic-gate temp_td = ohci_td_iommu_to_cpu(ohcip, 67847c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td)); 67857c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, td); 67867c478bd9Sstevel@tonic-gate td = temp_td; 67877c478bd9Sstevel@tonic-gate } 67887c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = NULL; 67897c478bd9Sstevel@tonic-gate } 67907c478bd9Sstevel@tonic-gate 67917c478bd9Sstevel@tonic-gate 67927c478bd9Sstevel@tonic-gate /* 67937c478bd9Sstevel@tonic-gate * Transfer Wrapper functions 67947c478bd9Sstevel@tonic-gate * 67957c478bd9Sstevel@tonic-gate * ohci_create_transfer_wrapper: 67967c478bd9Sstevel@tonic-gate * 679702acac7eSsl * Create a Transaction Wrapper (TW) for non-isoc transfer types 679802acac7eSsl * and this involves the allocating of DMA resources. 67997c478bd9Sstevel@tonic-gate */ 68007c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t * 68017c478bd9Sstevel@tonic-gate ohci_create_transfer_wrapper( 68027c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 68037c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 68047c478bd9Sstevel@tonic-gate size_t length, 68057c478bd9Sstevel@tonic-gate uint_t usb_flags) 68067c478bd9Sstevel@tonic-gate { 68077c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 68087c478bd9Sstevel@tonic-gate int result; 68097c478bd9Sstevel@tonic-gate size_t real_length; 68107c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 681102acac7eSsl ddi_dma_attr_t dma_attr; 681202acac7eSsl int kmem_flag; 681302acac7eSsl int (*dmamem_wait)(caddr_t); 681402acac7eSsl usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 68157c478bd9Sstevel@tonic-gate 68167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 68177c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: length = 0x%lx flags = 0x%x", 68187c478bd9Sstevel@tonic-gate length, usb_flags); 68197c478bd9Sstevel@tonic-gate 68207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 68217c478bd9Sstevel@tonic-gate 682202acac7eSsl /* isochronous pipe should not call into this function */ 682302acac7eSsl if ((ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) == 682402acac7eSsl USB_EP_ATTR_ISOCH) { 682502acac7eSsl 682602acac7eSsl return (NULL); 682702acac7eSsl } 682802acac7eSsl 682902acac7eSsl /* SLEEP flag should not be used in interrupt context */ 683002acac7eSsl if (servicing_interrupt()) { 683102acac7eSsl kmem_flag = KM_NOSLEEP; 683202acac7eSsl dmamem_wait = DDI_DMA_DONTWAIT; 683302acac7eSsl } else { 683402acac7eSsl kmem_flag = KM_SLEEP; 683502acac7eSsl dmamem_wait = DDI_DMA_SLEEP; 683602acac7eSsl } 683702acac7eSsl 68387c478bd9Sstevel@tonic-gate /* Allocate space for the transfer wrapper */ 683902acac7eSsl tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t), kmem_flag); 68407c478bd9Sstevel@tonic-gate 68417c478bd9Sstevel@tonic-gate if (tw == NULL) { 68427c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 68437c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: kmem_zalloc failed"); 68447c478bd9Sstevel@tonic-gate 68457c478bd9Sstevel@tonic-gate return (NULL); 68467c478bd9Sstevel@tonic-gate } 68477c478bd9Sstevel@tonic-gate 6848688b07c5Sgc /* zero-length packet doesn't need to allocate dma memory */ 6849688b07c5Sgc if (length == 0) { 6850688b07c5Sgc 6851688b07c5Sgc goto dmadone; 6852688b07c5Sgc } 6853688b07c5Sgc 685402acac7eSsl /* allow sg lists for transfer wrapper dma memory */ 685502acac7eSsl bcopy(&ohcip->ohci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t)); 685602acac7eSsl dma_attr.dma_attr_sgllen = OHCI_DMA_ATTR_TW_SGLLEN; 685702acac7eSsl dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT; 68587c478bd9Sstevel@tonic-gate 68597c478bd9Sstevel@tonic-gate /* Allocate the DMA handle */ 68607c478bd9Sstevel@tonic-gate result = ddi_dma_alloc_handle(ohcip->ohci_dip, 686102acac7eSsl &dma_attr, dmamem_wait, 0, &tw->tw_dmahandle); 68627c478bd9Sstevel@tonic-gate 68637c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 68647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 68657c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: Alloc handle failed"); 68667c478bd9Sstevel@tonic-gate 68677c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 68687c478bd9Sstevel@tonic-gate 68697c478bd9Sstevel@tonic-gate return (NULL); 68707c478bd9Sstevel@tonic-gate } 68717c478bd9Sstevel@tonic-gate 68727c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 68737c478bd9Sstevel@tonic-gate 68747c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 68757c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 68767c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 68777c478bd9Sstevel@tonic-gate 68787c478bd9Sstevel@tonic-gate /* Allocate the memory */ 68797c478bd9Sstevel@tonic-gate result = ddi_dma_mem_alloc(tw->tw_dmahandle, length, 688002acac7eSsl &dev_attr, DDI_DMA_CONSISTENT, dmamem_wait, NULL, 68817c478bd9Sstevel@tonic-gate (caddr_t *)&tw->tw_buf, &real_length, &tw->tw_accesshandle); 68827c478bd9Sstevel@tonic-gate 68837c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 68847c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 68857c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: dma_mem_alloc fail"); 68867c478bd9Sstevel@tonic-gate 68877c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 68887c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 68897c478bd9Sstevel@tonic-gate 68907c478bd9Sstevel@tonic-gate return (NULL); 68917c478bd9Sstevel@tonic-gate } 68927c478bd9Sstevel@tonic-gate 68937c478bd9Sstevel@tonic-gate ASSERT(real_length >= length); 68947c478bd9Sstevel@tonic-gate 68957c478bd9Sstevel@tonic-gate /* Bind the handle */ 68967c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL, 68977c478bd9Sstevel@tonic-gate (caddr_t)tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT, 689802acac7eSsl dmamem_wait, NULL, &tw->tw_cookie, &tw->tw_ncookies); 68997c478bd9Sstevel@tonic-gate 690002acac7eSsl if (result != DDI_DMA_MAPPED) { 690102acac7eSsl ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result); 690202acac7eSsl 690302acac7eSsl ddi_dma_mem_free(&tw->tw_accesshandle); 690402acac7eSsl ddi_dma_free_handle(&tw->tw_dmahandle); 690502acac7eSsl kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 690602acac7eSsl 690702acac7eSsl return (NULL); 690802acac7eSsl } 690902acac7eSsl 691002acac7eSsl tw->tw_cookie_idx = 0; 691102acac7eSsl tw->tw_dma_offs = 0; 691202acac7eSsl 6913688b07c5Sgc dmadone: 691402acac7eSsl /* 691502acac7eSsl * Only allow one wrapper to be added at a time. Insert the 691602acac7eSsl * new transaction wrapper into the list for this pipe. 691702acac7eSsl */ 691802acac7eSsl if (pp->pp_tw_head == NULL) { 691902acac7eSsl pp->pp_tw_head = tw; 692002acac7eSsl pp->pp_tw_tail = tw; 692102acac7eSsl } else { 692202acac7eSsl pp->pp_tw_tail->tw_next = tw; 692302acac7eSsl pp->pp_tw_tail = tw; 692402acac7eSsl } 692502acac7eSsl 692602acac7eSsl /* Store the transfer length */ 692702acac7eSsl tw->tw_length = length; 692802acac7eSsl 692902acac7eSsl /* Store a back pointer to the pipe private structure */ 693002acac7eSsl tw->tw_pipe_private = pp; 693102acac7eSsl 693202acac7eSsl /* Store the transfer type - synchronous or asynchronous */ 693302acac7eSsl tw->tw_flags = usb_flags; 693402acac7eSsl 693502acac7eSsl /* Get and Store 32bit ID */ 693602acac7eSsl tw->tw_id = OHCI_GET_ID((void *)tw); 693702acac7eSsl 693802acac7eSsl ASSERT(tw->tw_id != NULL); 693902acac7eSsl 694002acac7eSsl USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 694102acac7eSsl "ohci_create_transfer_wrapper: tw = 0x%p, ncookies = %u", 694202acac7eSsl tw, tw->tw_ncookies); 694302acac7eSsl 694402acac7eSsl return (tw); 694502acac7eSsl } 694602acac7eSsl 694702acac7eSsl 694802acac7eSsl /* 694902acac7eSsl * Transfer Wrapper functions 695002acac7eSsl * 695102acac7eSsl * ohci_create_isoc_transfer_wrapper: 695202acac7eSsl * 695302acac7eSsl * Create a Transaction Wrapper (TW) for isoc transfer 695402acac7eSsl * and this involves the allocating of DMA resources. 695502acac7eSsl */ 695602acac7eSsl static ohci_trans_wrapper_t * 695702acac7eSsl ohci_create_isoc_transfer_wrapper( 695802acac7eSsl ohci_state_t *ohcip, 695902acac7eSsl ohci_pipe_private_t *pp, 696002acac7eSsl size_t length, 696102acac7eSsl usb_isoc_pkt_descr_t *descr, 696202acac7eSsl ushort_t pkt_count, 6963*29aca3ebSlc size_t td_count, 696402acac7eSsl uint_t usb_flags) 696502acac7eSsl { 696602acac7eSsl ddi_device_acc_attr_t dev_attr; 696702acac7eSsl int result; 696802acac7eSsl size_t real_length, xfer_size; 696902acac7eSsl uint_t ccount; 697002acac7eSsl ohci_trans_wrapper_t *tw; 697102acac7eSsl ddi_dma_attr_t dma_attr; 697202acac7eSsl int kmem_flag; 697302acac7eSsl uint_t i, j, frame_count, residue; 697402acac7eSsl int (*dmamem_wait)(caddr_t); 697502acac7eSsl usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 697602acac7eSsl usb_isoc_pkt_descr_t *isoc_pkt_descr = descr; 697702acac7eSsl 697802acac7eSsl USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 697902acac7eSsl "ohci_create_isoc_transfer_wrapper: length = 0x%lx flags = 0x%x", 698002acac7eSsl length, usb_flags); 698102acac7eSsl 698202acac7eSsl ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 698302acac7eSsl 698402acac7eSsl /* non-isochronous pipe should not call into this function */ 698502acac7eSsl if ((ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) != 698602acac7eSsl USB_EP_ATTR_ISOCH) { 698702acac7eSsl 698802acac7eSsl return (NULL); 698902acac7eSsl } 699002acac7eSsl 699102acac7eSsl /* SLEEP flag should not be used in interrupt context */ 699202acac7eSsl if (servicing_interrupt()) { 699302acac7eSsl kmem_flag = KM_NOSLEEP; 699402acac7eSsl dmamem_wait = DDI_DMA_DONTWAIT; 699502acac7eSsl } else { 699602acac7eSsl kmem_flag = KM_SLEEP; 699702acac7eSsl dmamem_wait = DDI_DMA_SLEEP; 699802acac7eSsl } 699902acac7eSsl 700002acac7eSsl /* Allocate space for the transfer wrapper */ 700102acac7eSsl tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t), kmem_flag); 700202acac7eSsl 700302acac7eSsl if (tw == NULL) { 700402acac7eSsl USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 700502acac7eSsl "ohci_create_transfer_wrapper: kmem_zalloc failed"); 700602acac7eSsl 700702acac7eSsl return (NULL); 700802acac7eSsl } 700902acac7eSsl 701002acac7eSsl /* Allocate space for the isoc buffer handles */ 701102acac7eSsl tw->tw_isoc_strtlen = sizeof (ohci_isoc_buf_t) * td_count; 701202acac7eSsl if ((tw->tw_isoc_bufs = kmem_zalloc(tw->tw_isoc_strtlen, 701302acac7eSsl kmem_flag)) == NULL) { 701402acac7eSsl USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 701502acac7eSsl "ohci_create_isoc_transfer_wrapper: kmem_alloc " 701602acac7eSsl "isoc buffer failed"); 701702acac7eSsl kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 701802acac7eSsl 701902acac7eSsl return (NULL); 702002acac7eSsl } 702102acac7eSsl 702202acac7eSsl /* allow sg lists for transfer wrapper dma memory */ 702302acac7eSsl bcopy(&ohcip->ohci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t)); 702402acac7eSsl dma_attr.dma_attr_sgllen = OHCI_DMA_ATTR_TD_SGLLEN; 702502acac7eSsl dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT; 702602acac7eSsl 702702acac7eSsl dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 702802acac7eSsl 702902acac7eSsl /* The host controller will be little endian */ 703002acac7eSsl dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 703102acac7eSsl dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 703202acac7eSsl 703302acac7eSsl residue = pkt_count % OHCI_ISOC_PKTS_PER_TD; 703402acac7eSsl 703502acac7eSsl for (i = 0; i < td_count; i++) { 703602acac7eSsl tw->tw_isoc_bufs[i].index = i; 703702acac7eSsl 703802acac7eSsl if ((i == (td_count - 1)) && (residue != 0)) { 703902acac7eSsl frame_count = residue; 704002acac7eSsl } else { 704102acac7eSsl frame_count = OHCI_ISOC_PKTS_PER_TD; 704202acac7eSsl } 704302acac7eSsl 704402acac7eSsl /* Allocate the DMA handle */ 704502acac7eSsl result = ddi_dma_alloc_handle(ohcip->ohci_dip, &dma_attr, 704602acac7eSsl dmamem_wait, 0, &tw->tw_isoc_bufs[i].dma_handle); 704702acac7eSsl 704802acac7eSsl if (result != DDI_SUCCESS) { 70497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 705002acac7eSsl "ohci_create_isoc_transfer_wrapper: " 705102acac7eSsl "Alloc handle failed"); 705202acac7eSsl 705302acac7eSsl for (j = 0; j < i; j++) { 705402acac7eSsl result = ddi_dma_unbind_handle( 705502acac7eSsl tw->tw_isoc_bufs[j].dma_handle); 705602acac7eSsl ASSERT(result == USB_SUCCESS); 705702acac7eSsl ddi_dma_mem_free(&tw->tw_isoc_bufs[j]. 705802acac7eSsl mem_handle); 705902acac7eSsl ddi_dma_free_handle(&tw->tw_isoc_bufs[j]. 706002acac7eSsl dma_handle); 706102acac7eSsl } 706202acac7eSsl kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen); 706302acac7eSsl kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 70647c478bd9Sstevel@tonic-gate 706502acac7eSsl return (NULL); 706602acac7eSsl } 70677c478bd9Sstevel@tonic-gate 706802acac7eSsl /* Compute the memory length */ 706902acac7eSsl for (xfer_size = 0, j = 0; j < frame_count; j++) { 707002acac7eSsl ASSERT(isoc_pkt_descr != NULL); 707102acac7eSsl xfer_size += isoc_pkt_descr->isoc_pkt_length; 707202acac7eSsl isoc_pkt_descr++; 707302acac7eSsl } 707402acac7eSsl 707502acac7eSsl /* Allocate the memory */ 707602acac7eSsl result = ddi_dma_mem_alloc(tw->tw_isoc_bufs[i].dma_handle, 707702acac7eSsl xfer_size, &dev_attr, DDI_DMA_CONSISTENT, dmamem_wait, 707802acac7eSsl NULL, (caddr_t *)&tw->tw_isoc_bufs[i].buf_addr, 707902acac7eSsl &real_length, &tw->tw_isoc_bufs[i].mem_handle); 708002acac7eSsl 708102acac7eSsl if (result != DDI_SUCCESS) { 708202acac7eSsl USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 708302acac7eSsl "ohci_create_isoc_transfer_wrapper: " 708402acac7eSsl "dma_mem_alloc %d fail", i); 708502acac7eSsl ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle); 708602acac7eSsl 708702acac7eSsl for (j = 0; j < i; j++) { 708802acac7eSsl result = ddi_dma_unbind_handle( 708902acac7eSsl tw->tw_isoc_bufs[j].dma_handle); 709002acac7eSsl ASSERT(result == USB_SUCCESS); 709102acac7eSsl ddi_dma_mem_free(&tw->tw_isoc_bufs[j]. 709202acac7eSsl mem_handle); 709302acac7eSsl ddi_dma_free_handle(&tw->tw_isoc_bufs[j]. 709402acac7eSsl dma_handle); 709502acac7eSsl } 709602acac7eSsl kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen); 70977c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 70987c478bd9Sstevel@tonic-gate 70997c478bd9Sstevel@tonic-gate return (NULL); 71007c478bd9Sstevel@tonic-gate } 71017c478bd9Sstevel@tonic-gate 710202acac7eSsl ASSERT(real_length >= xfer_size); 71037c478bd9Sstevel@tonic-gate 710402acac7eSsl /* Bind the handle */ 710502acac7eSsl result = ddi_dma_addr_bind_handle( 710602acac7eSsl tw->tw_isoc_bufs[i].dma_handle, NULL, 710702acac7eSsl (caddr_t)tw->tw_isoc_bufs[i].buf_addr, real_length, 710802acac7eSsl DDI_DMA_RDWR|DDI_DMA_CONSISTENT, dmamem_wait, NULL, 710902acac7eSsl &tw->tw_isoc_bufs[i].cookie, &ccount); 711002acac7eSsl 711102acac7eSsl if ((result == DDI_DMA_MAPPED) && 711202acac7eSsl (ccount <= OHCI_DMA_ATTR_TD_SGLLEN)) { 711302acac7eSsl tw->tw_isoc_bufs[i].length = xfer_size; 711402acac7eSsl tw->tw_isoc_bufs[i].ncookies = ccount; 711502acac7eSsl 711602acac7eSsl continue; 711702acac7eSsl } else { 711802acac7eSsl USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 711902acac7eSsl "ohci_create_isoc_transfer_wrapper: " 712002acac7eSsl "Bind handle %d failed", i); 712102acac7eSsl if (result == DDI_DMA_MAPPED) { 712202acac7eSsl result = ddi_dma_unbind_handle( 712302acac7eSsl tw->tw_isoc_bufs[i].dma_handle); 712402acac7eSsl ASSERT(result == USB_SUCCESS); 712502acac7eSsl } 712602acac7eSsl ddi_dma_mem_free(&tw->tw_isoc_bufs[i].mem_handle); 712702acac7eSsl ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle); 712802acac7eSsl 712902acac7eSsl for (j = 0; j < i; j++) { 713002acac7eSsl result = ddi_dma_unbind_handle( 713102acac7eSsl tw->tw_isoc_bufs[j].dma_handle); 713202acac7eSsl ASSERT(result == USB_SUCCESS); 713302acac7eSsl ddi_dma_mem_free(&tw->tw_isoc_bufs[j]. 713402acac7eSsl mem_handle); 713502acac7eSsl ddi_dma_free_handle(&tw->tw_isoc_bufs[j]. 713602acac7eSsl dma_handle); 713702acac7eSsl } 713802acac7eSsl kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen); 713902acac7eSsl kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 714002acac7eSsl 714102acac7eSsl return (NULL); 714202acac7eSsl } 71437c478bd9Sstevel@tonic-gate } 71447c478bd9Sstevel@tonic-gate 71457c478bd9Sstevel@tonic-gate /* 71467c478bd9Sstevel@tonic-gate * Only allow one wrapper to be added at a time. Insert the 71477c478bd9Sstevel@tonic-gate * new transaction wrapper into the list for this pipe. 71487c478bd9Sstevel@tonic-gate */ 71497c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == NULL) { 71507c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw; 71517c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw; 71527c478bd9Sstevel@tonic-gate } else { 71537c478bd9Sstevel@tonic-gate pp->pp_tw_tail->tw_next = tw; 71547c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw; 71557c478bd9Sstevel@tonic-gate } 71567c478bd9Sstevel@tonic-gate 71577c478bd9Sstevel@tonic-gate /* Store the transfer length */ 71587c478bd9Sstevel@tonic-gate tw->tw_length = length; 71597c478bd9Sstevel@tonic-gate 716002acac7eSsl /* Store the td numbers */ 716102acac7eSsl tw->tw_ncookies = td_count; 716202acac7eSsl 71637c478bd9Sstevel@tonic-gate /* Store a back pointer to the pipe private structure */ 71647c478bd9Sstevel@tonic-gate tw->tw_pipe_private = pp; 71657c478bd9Sstevel@tonic-gate 71667c478bd9Sstevel@tonic-gate /* Store the transfer type - synchronous or asynchronous */ 71677c478bd9Sstevel@tonic-gate tw->tw_flags = usb_flags; 71687c478bd9Sstevel@tonic-gate 71697c478bd9Sstevel@tonic-gate /* Get and Store 32bit ID */ 71707c478bd9Sstevel@tonic-gate tw->tw_id = OHCI_GET_ID((void *)tw); 71717c478bd9Sstevel@tonic-gate 71727c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 71737c478bd9Sstevel@tonic-gate 71747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 717502acac7eSsl "ohci_create_isoc_transfer_wrapper: tw = 0x%p", tw); 71767c478bd9Sstevel@tonic-gate 71777c478bd9Sstevel@tonic-gate return (tw); 71787c478bd9Sstevel@tonic-gate } 71797c478bd9Sstevel@tonic-gate 71807c478bd9Sstevel@tonic-gate 71817c478bd9Sstevel@tonic-gate /* 71827c478bd9Sstevel@tonic-gate * ohci_start_xfer_timer: 71837c478bd9Sstevel@tonic-gate * 71847c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt 71857c478bd9Sstevel@tonic-gate * transfers. 71867c478bd9Sstevel@tonic-gate */ 71877c478bd9Sstevel@tonic-gate /* ARGSUSED */ 71887c478bd9Sstevel@tonic-gate static void 71897c478bd9Sstevel@tonic-gate ohci_start_xfer_timer( 71907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 71917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 71927c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 71937c478bd9Sstevel@tonic-gate { 71947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 71957c478bd9Sstevel@tonic-gate "ohci_start_xfer_timer: tw = 0x%p", tw); 71967c478bd9Sstevel@tonic-gate 71977c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 71987c478bd9Sstevel@tonic-gate 71997c478bd9Sstevel@tonic-gate /* 72007c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk and for 72017c478bd9Sstevel@tonic-gate * one time Interrupt transfers. 72027c478bd9Sstevel@tonic-gate * 72037c478bd9Sstevel@tonic-gate * NOTE: If timeout is zero; Assume infinite timeout and don't 72047c478bd9Sstevel@tonic-gate * insert this transfer on the timeout list. 72057c478bd9Sstevel@tonic-gate */ 72067c478bd9Sstevel@tonic-gate if (tw->tw_timeout) { 72077c478bd9Sstevel@tonic-gate /* 72087c478bd9Sstevel@tonic-gate * Increase timeout value by one second and this extra one 72097c478bd9Sstevel@tonic-gate * second is used to halt the endpoint if given transfer 72107c478bd9Sstevel@tonic-gate * times out. 72117c478bd9Sstevel@tonic-gate */ 72127c478bd9Sstevel@tonic-gate tw->tw_timeout++; 72137c478bd9Sstevel@tonic-gate 72147c478bd9Sstevel@tonic-gate /* 72157c478bd9Sstevel@tonic-gate * Add this transfer wrapper into the transfer timeout list. 72167c478bd9Sstevel@tonic-gate */ 72177c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list) { 72187c478bd9Sstevel@tonic-gate tw->tw_timeout_next = ohcip->ohci_timeout_list; 72197c478bd9Sstevel@tonic-gate } 72207c478bd9Sstevel@tonic-gate 72217c478bd9Sstevel@tonic-gate ohcip->ohci_timeout_list = tw; 72227c478bd9Sstevel@tonic-gate ohci_start_timer(ohcip); 72237c478bd9Sstevel@tonic-gate } 72247c478bd9Sstevel@tonic-gate } 72257c478bd9Sstevel@tonic-gate 72267c478bd9Sstevel@tonic-gate 72277c478bd9Sstevel@tonic-gate /* 72287c478bd9Sstevel@tonic-gate * ohci_stop_xfer_timer: 72297c478bd9Sstevel@tonic-gate * 72307c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt 72317c478bd9Sstevel@tonic-gate * transfers. 72327c478bd9Sstevel@tonic-gate */ 72337c478bd9Sstevel@tonic-gate void 72347c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer( 72357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 72367c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 72377c478bd9Sstevel@tonic-gate uint_t flag) 72387c478bd9Sstevel@tonic-gate { 72397c478bd9Sstevel@tonic-gate timeout_id_t timer_id; 72407c478bd9Sstevel@tonic-gate 72417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 72427c478bd9Sstevel@tonic-gate "ohci_stop_xfer_timer: tw = 0x%p", tw); 72437c478bd9Sstevel@tonic-gate 72447c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 72457c478bd9Sstevel@tonic-gate 72467c478bd9Sstevel@tonic-gate /* 72477c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk 72487c478bd9Sstevel@tonic-gate * and for one time Interrupt transfers. 72497c478bd9Sstevel@tonic-gate */ 72507c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list == NULL) { 72517c478bd9Sstevel@tonic-gate return; 72527c478bd9Sstevel@tonic-gate } 72537c478bd9Sstevel@tonic-gate 72547c478bd9Sstevel@tonic-gate switch (flag) { 72557c478bd9Sstevel@tonic-gate case OHCI_REMOVE_XFER_IFLAST: 72567c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head != tw->tw_hctd_tail) { 72577c478bd9Sstevel@tonic-gate break; 72587c478bd9Sstevel@tonic-gate } 72597c478bd9Sstevel@tonic-gate /* FALLTHRU */ 72607c478bd9Sstevel@tonic-gate case OHCI_REMOVE_XFER_ALWAYS: 72617c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(ohcip, tw); 72627c478bd9Sstevel@tonic-gate 72637c478bd9Sstevel@tonic-gate if ((ohcip->ohci_timeout_list == NULL) && 72647c478bd9Sstevel@tonic-gate (ohcip->ohci_timer_id)) { 72657c478bd9Sstevel@tonic-gate 72667c478bd9Sstevel@tonic-gate timer_id = ohcip->ohci_timer_id; 72677c478bd9Sstevel@tonic-gate 72687c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */ 72697c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0; 72707c478bd9Sstevel@tonic-gate 72717c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 72727c478bd9Sstevel@tonic-gate 72737c478bd9Sstevel@tonic-gate (void) untimeout(timer_id); 72747c478bd9Sstevel@tonic-gate 72757c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 72767c478bd9Sstevel@tonic-gate } 72777c478bd9Sstevel@tonic-gate break; 72787c478bd9Sstevel@tonic-gate default: 72797c478bd9Sstevel@tonic-gate break; 72807c478bd9Sstevel@tonic-gate } 72817c478bd9Sstevel@tonic-gate } 72827c478bd9Sstevel@tonic-gate 72837c478bd9Sstevel@tonic-gate 72847c478bd9Sstevel@tonic-gate /* 72857c478bd9Sstevel@tonic-gate * ohci_xfer_timeout_handler: 72867c478bd9Sstevel@tonic-gate * 72877c478bd9Sstevel@tonic-gate * Control or bulk transfer timeout handler. 72887c478bd9Sstevel@tonic-gate */ 72897c478bd9Sstevel@tonic-gate static void 72907c478bd9Sstevel@tonic-gate ohci_xfer_timeout_handler(void *arg) 72917c478bd9Sstevel@tonic-gate { 72927c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = (ohci_state_t *)arg; 72937c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *exp_xfer_list_head = NULL; 72947c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *exp_xfer_list_tail = NULL; 72957c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, *next; 72967c478bd9Sstevel@tonic-gate ohci_td_t *td; 72977c478bd9Sstevel@tonic-gate usb_flags_t flags; 72987c478bd9Sstevel@tonic-gate 72997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 73007c478bd9Sstevel@tonic-gate "ohci_xfer_timeout_handler: ohcip = 0x%p", ohcip); 73017c478bd9Sstevel@tonic-gate 73027c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 73037c478bd9Sstevel@tonic-gate 73047c478bd9Sstevel@tonic-gate /* Set the required flags */ 73057c478bd9Sstevel@tonic-gate flags = OHCI_FLAGS_NOSLEEP | OHCI_FLAGS_DMA_SYNC; 73067c478bd9Sstevel@tonic-gate 73077c478bd9Sstevel@tonic-gate /* 73087c478bd9Sstevel@tonic-gate * Check whether still timeout handler is valid. 73097c478bd9Sstevel@tonic-gate */ 73107c478bd9Sstevel@tonic-gate if (ohcip->ohci_timer_id) { 73117c478bd9Sstevel@tonic-gate 73127c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */ 73137c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0; 73147c478bd9Sstevel@tonic-gate } else { 73157c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 73167c478bd9Sstevel@tonic-gate 73177c478bd9Sstevel@tonic-gate return; 73187c478bd9Sstevel@tonic-gate } 73197c478bd9Sstevel@tonic-gate 73207c478bd9Sstevel@tonic-gate /* Get the transfer timeout list head */ 73217c478bd9Sstevel@tonic-gate tw = ohcip->ohci_timeout_list; 73227c478bd9Sstevel@tonic-gate 73237c478bd9Sstevel@tonic-gate /* 73247c478bd9Sstevel@tonic-gate * Process ohci timeout list and look whether the timer 73257c478bd9Sstevel@tonic-gate * has expired for any transfers. Create a temporary list 73267c478bd9Sstevel@tonic-gate * of expired transfers and process them later. 73277c478bd9Sstevel@tonic-gate */ 73287c478bd9Sstevel@tonic-gate while (tw) { 73297c478bd9Sstevel@tonic-gate /* Get the transfer on the timeout list */ 73307c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next; 73317c478bd9Sstevel@tonic-gate 73327c478bd9Sstevel@tonic-gate tw->tw_timeout--; 73337c478bd9Sstevel@tonic-gate 73347c478bd9Sstevel@tonic-gate /* 73357c478bd9Sstevel@tonic-gate * Set the sKip bit to stop all transactions on 73367c478bd9Sstevel@tonic-gate * this pipe 73377c478bd9Sstevel@tonic-gate */ 73387c478bd9Sstevel@tonic-gate if (tw->tw_timeout == 1) { 73397c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, 73407c478bd9Sstevel@tonic-gate tw->tw_pipe_private, SET_sKip, flags); 73417c478bd9Sstevel@tonic-gate 73427c478bd9Sstevel@tonic-gate /* Reset dma sync flag */ 73437c478bd9Sstevel@tonic-gate flags &= ~OHCI_FLAGS_DMA_SYNC; 73447c478bd9Sstevel@tonic-gate } 73457c478bd9Sstevel@tonic-gate 73467c478bd9Sstevel@tonic-gate /* Remove tw from the timeout list */ 73477c478bd9Sstevel@tonic-gate if (tw->tw_timeout <= 0) { 73487c478bd9Sstevel@tonic-gate 73497c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(ohcip, tw); 73507c478bd9Sstevel@tonic-gate 73517c478bd9Sstevel@tonic-gate /* Add tw to the end of expire list */ 73527c478bd9Sstevel@tonic-gate if (exp_xfer_list_head) { 73537c478bd9Sstevel@tonic-gate exp_xfer_list_tail->tw_timeout_next = tw; 73547c478bd9Sstevel@tonic-gate } else { 73557c478bd9Sstevel@tonic-gate exp_xfer_list_head = tw; 73567c478bd9Sstevel@tonic-gate } 73577c478bd9Sstevel@tonic-gate exp_xfer_list_tail = tw; 73587c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL; 73597c478bd9Sstevel@tonic-gate } 73607c478bd9Sstevel@tonic-gate 73617c478bd9Sstevel@tonic-gate tw = next; 73627c478bd9Sstevel@tonic-gate } 73637c478bd9Sstevel@tonic-gate 73647c478bd9Sstevel@tonic-gate /* Get the expired transfer timeout list head */ 73657c478bd9Sstevel@tonic-gate tw = exp_xfer_list_head; 73667c478bd9Sstevel@tonic-gate 73677c478bd9Sstevel@tonic-gate if (tw && (flags & OHCI_FLAGS_DMA_SYNC)) { 73687c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 73697c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 73707c478bd9Sstevel@tonic-gate } 73717c478bd9Sstevel@tonic-gate 73727c478bd9Sstevel@tonic-gate /* 73737c478bd9Sstevel@tonic-gate * Process the expired transfers by notifing the corrsponding 73747c478bd9Sstevel@tonic-gate * client driver through the exception callback. 73757c478bd9Sstevel@tonic-gate */ 73767c478bd9Sstevel@tonic-gate while (tw) { 73777c478bd9Sstevel@tonic-gate /* Get the transfer on the expired transfer timeout list */ 73787c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next; 73797c478bd9Sstevel@tonic-gate 73807c478bd9Sstevel@tonic-gate td = tw->tw_hctd_head; 73817c478bd9Sstevel@tonic-gate 73827c478bd9Sstevel@tonic-gate while (td) { 73837c478bd9Sstevel@tonic-gate /* Set TD state to TIMEOUT */ 73847c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_TIMEOUT); 73857c478bd9Sstevel@tonic-gate 73867c478bd9Sstevel@tonic-gate /* Get the next TD from the wrapper */ 73877c478bd9Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip, 73887c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td)); 73897c478bd9Sstevel@tonic-gate } 73907c478bd9Sstevel@tonic-gate 73917c478bd9Sstevel@tonic-gate ohci_handle_error(ohcip, tw->tw_hctd_head, USB_CR_TIMEOUT); 73927c478bd9Sstevel@tonic-gate 73937c478bd9Sstevel@tonic-gate tw = next; 73947c478bd9Sstevel@tonic-gate } 73957c478bd9Sstevel@tonic-gate 73967c478bd9Sstevel@tonic-gate ohci_start_timer(ohcip); 73977c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 73987c478bd9Sstevel@tonic-gate } 73997c478bd9Sstevel@tonic-gate 74007c478bd9Sstevel@tonic-gate 74017c478bd9Sstevel@tonic-gate /* 74027c478bd9Sstevel@tonic-gate * ohci_remove_tw_from_timeout_list: 74037c478bd9Sstevel@tonic-gate * 74047c478bd9Sstevel@tonic-gate * Remove Control or bulk transfer from the timeout list. 74057c478bd9Sstevel@tonic-gate */ 74067c478bd9Sstevel@tonic-gate static void 74077c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list( 74087c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 74097c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 74107c478bd9Sstevel@tonic-gate { 74117c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *prev, *next; 74127c478bd9Sstevel@tonic-gate 74137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 74147c478bd9Sstevel@tonic-gate "ohci_remove_tw_from_timeout_list: tw = 0x%p", tw); 74157c478bd9Sstevel@tonic-gate 74167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 74177c478bd9Sstevel@tonic-gate 74187c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list == tw) { 74197c478bd9Sstevel@tonic-gate ohcip->ohci_timeout_list = tw->tw_timeout_next; 74207c478bd9Sstevel@tonic-gate } else { 74217c478bd9Sstevel@tonic-gate prev = ohcip->ohci_timeout_list; 74227c478bd9Sstevel@tonic-gate next = prev->tw_timeout_next; 74237c478bd9Sstevel@tonic-gate 74247c478bd9Sstevel@tonic-gate while (next && (next != tw)) { 74257c478bd9Sstevel@tonic-gate prev = next; 74267c478bd9Sstevel@tonic-gate next = next->tw_timeout_next; 74277c478bd9Sstevel@tonic-gate } 74287c478bd9Sstevel@tonic-gate 74297c478bd9Sstevel@tonic-gate if (next == tw) { 74307c478bd9Sstevel@tonic-gate prev->tw_timeout_next = next->tw_timeout_next; 74317c478bd9Sstevel@tonic-gate } 74327c478bd9Sstevel@tonic-gate } 74337c478bd9Sstevel@tonic-gate 74347c478bd9Sstevel@tonic-gate /* Reset the xfer timeout */ 74357c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL; 74367c478bd9Sstevel@tonic-gate } 74377c478bd9Sstevel@tonic-gate 74387c478bd9Sstevel@tonic-gate 74397c478bd9Sstevel@tonic-gate /* 74407c478bd9Sstevel@tonic-gate * ohci_start_timer: 74417c478bd9Sstevel@tonic-gate * 74427c478bd9Sstevel@tonic-gate * Start the ohci timer 74437c478bd9Sstevel@tonic-gate */ 74447c478bd9Sstevel@tonic-gate static void 74457c478bd9Sstevel@tonic-gate ohci_start_timer(ohci_state_t *ohcip) 74467c478bd9Sstevel@tonic-gate { 74477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 74487c478bd9Sstevel@tonic-gate "ohci_start_timer: ohcip = 0x%p", ohcip); 74497c478bd9Sstevel@tonic-gate 74507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 74517c478bd9Sstevel@tonic-gate 74527c478bd9Sstevel@tonic-gate /* 74537c478bd9Sstevel@tonic-gate * Start the global timer only if currently timer is not 74547c478bd9Sstevel@tonic-gate * running and if there are any transfers on the timeout 74557c478bd9Sstevel@tonic-gate * list. This timer will be per USB Host Controller. 74567c478bd9Sstevel@tonic-gate */ 74577c478bd9Sstevel@tonic-gate if ((!ohcip->ohci_timer_id) && (ohcip->ohci_timeout_list)) { 74587c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = timeout(ohci_xfer_timeout_handler, 74597c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(1000000)); 74607c478bd9Sstevel@tonic-gate } 74617c478bd9Sstevel@tonic-gate } 74627c478bd9Sstevel@tonic-gate 74637c478bd9Sstevel@tonic-gate 74647c478bd9Sstevel@tonic-gate /* 74657c478bd9Sstevel@tonic-gate * ohci_deallocate_tw_resources: 74667c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 74677c478bd9Sstevel@tonic-gate * 74687c478bd9Sstevel@tonic-gate * Deallocate of a Transaction Wrapper (TW) and this involves the freeing of 74697c478bd9Sstevel@tonic-gate * of DMA resources. 74707c478bd9Sstevel@tonic-gate */ 74717c478bd9Sstevel@tonic-gate void 74727c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources( 74737c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 74747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 74757c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 74767c478bd9Sstevel@tonic-gate { 74777c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *prev, *next; 74787c478bd9Sstevel@tonic-gate 74797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 74807c478bd9Sstevel@tonic-gate "ohci_deallocate_tw_resources: tw = 0x%p", tw); 74817c478bd9Sstevel@tonic-gate 74827c478bd9Sstevel@tonic-gate /* 74837c478bd9Sstevel@tonic-gate * If the transfer wrapper has no Host Controller (HC) 74847c478bd9Sstevel@tonic-gate * Transfer Descriptors (TD) associated with it, then 74857c478bd9Sstevel@tonic-gate * remove the transfer wrapper. 74867c478bd9Sstevel@tonic-gate */ 74877c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head) { 74887c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail != NULL); 74897c478bd9Sstevel@tonic-gate 74907c478bd9Sstevel@tonic-gate return; 74917c478bd9Sstevel@tonic-gate } 74927c478bd9Sstevel@tonic-gate 74937c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL); 74947c478bd9Sstevel@tonic-gate 74957c478bd9Sstevel@tonic-gate /* Make sure we return all the unused td's to the pool as well */ 74967c478bd9Sstevel@tonic-gate ohci_free_tw_tds_resources(ohcip, tw); 74977c478bd9Sstevel@tonic-gate 74987c478bd9Sstevel@tonic-gate /* 74997c478bd9Sstevel@tonic-gate * If pp->pp_tw_head and pp->pp_tw_tail are pointing to 75007c478bd9Sstevel@tonic-gate * given TW then set the head and tail equal to NULL. 75017c478bd9Sstevel@tonic-gate * Otherwise search for this TW in the linked TW's list 75027c478bd9Sstevel@tonic-gate * and then remove this TW from the list. 75037c478bd9Sstevel@tonic-gate */ 75047c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == tw) { 75057c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) { 75067c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL; 75077c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL; 75087c478bd9Sstevel@tonic-gate } else { 75097c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw->tw_next; 75107c478bd9Sstevel@tonic-gate } 75117c478bd9Sstevel@tonic-gate } else { 75127c478bd9Sstevel@tonic-gate prev = pp->pp_tw_head; 75137c478bd9Sstevel@tonic-gate next = prev->tw_next; 75147c478bd9Sstevel@tonic-gate 75157c478bd9Sstevel@tonic-gate while (next && (next != tw)) { 75167c478bd9Sstevel@tonic-gate prev = next; 75177c478bd9Sstevel@tonic-gate next = next->tw_next; 75187c478bd9Sstevel@tonic-gate } 75197c478bd9Sstevel@tonic-gate 75207c478bd9Sstevel@tonic-gate if (next == tw) { 75217c478bd9Sstevel@tonic-gate prev->tw_next = next->tw_next; 75227c478bd9Sstevel@tonic-gate 75237c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) { 75247c478bd9Sstevel@tonic-gate pp->pp_tw_tail = prev; 75257c478bd9Sstevel@tonic-gate } 75267c478bd9Sstevel@tonic-gate } 75277c478bd9Sstevel@tonic-gate } 75287c478bd9Sstevel@tonic-gate 75297c478bd9Sstevel@tonic-gate ohci_free_tw(ohcip, tw); 75307c478bd9Sstevel@tonic-gate } 75317c478bd9Sstevel@tonic-gate 75327c478bd9Sstevel@tonic-gate 75337c478bd9Sstevel@tonic-gate /* 75347c478bd9Sstevel@tonic-gate * ohci_free_dma_resources: 75357c478bd9Sstevel@tonic-gate * 75367c478bd9Sstevel@tonic-gate * Free dma resources of a Transfer Wrapper (TW) and also free the TW. 75377c478bd9Sstevel@tonic-gate */ 75387c478bd9Sstevel@tonic-gate static void 75397c478bd9Sstevel@tonic-gate ohci_free_dma_resources( 75407c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 75417c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 75427c478bd9Sstevel@tonic-gate { 75437c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 75447c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head; 75457c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw, *tw; 75467c478bd9Sstevel@tonic-gate 75477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 75487c478bd9Sstevel@tonic-gate "ohci_free_dma_resources: ph = 0x%p", (void *)ph); 75497c478bd9Sstevel@tonic-gate 75507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 75517c478bd9Sstevel@tonic-gate 75527c478bd9Sstevel@tonic-gate /* Process the Transfer Wrappers */ 75537c478bd9Sstevel@tonic-gate next_tw = head_tw; 75547c478bd9Sstevel@tonic-gate while (next_tw) { 75557c478bd9Sstevel@tonic-gate tw = next_tw; 75567c478bd9Sstevel@tonic-gate next_tw = tw->tw_next; 75577c478bd9Sstevel@tonic-gate 75587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 75597c478bd9Sstevel@tonic-gate "ohci_free_dma_resources: Free TW = 0x%p", (void *)tw); 75607c478bd9Sstevel@tonic-gate 75617c478bd9Sstevel@tonic-gate ohci_free_tw(ohcip, tw); 75627c478bd9Sstevel@tonic-gate } 75637c478bd9Sstevel@tonic-gate 75647c478bd9Sstevel@tonic-gate /* Adjust the head and tail pointers */ 75657c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL; 75667c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL; 75677c478bd9Sstevel@tonic-gate } 75687c478bd9Sstevel@tonic-gate 75697c478bd9Sstevel@tonic-gate 75707c478bd9Sstevel@tonic-gate /* 75717c478bd9Sstevel@tonic-gate * ohci_free_tw: 75727c478bd9Sstevel@tonic-gate * 75737c478bd9Sstevel@tonic-gate * Free the Transfer Wrapper (TW). 75747c478bd9Sstevel@tonic-gate */ 75757c478bd9Sstevel@tonic-gate static void 75767c478bd9Sstevel@tonic-gate ohci_free_tw( 75777c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 75787c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 75797c478bd9Sstevel@tonic-gate { 758002acac7eSsl int rval, i; 75817c478bd9Sstevel@tonic-gate 75827c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl, 75837c478bd9Sstevel@tonic-gate "ohci_free_tw: tw = 0x%p", tw); 75847c478bd9Sstevel@tonic-gate 75857c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 75867c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 75877c478bd9Sstevel@tonic-gate 75887c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 75897c478bd9Sstevel@tonic-gate OHCI_FREE_ID((uint32_t)tw->tw_id); 75907c478bd9Sstevel@tonic-gate 759102acac7eSsl if (tw->tw_isoc_strtlen > 0) { 759202acac7eSsl ASSERT(tw->tw_isoc_bufs != NULL); 759302acac7eSsl for (i = 0; i < tw->tw_ncookies; i++) { 759402acac7eSsl if (tw->tw_isoc_bufs[i].ncookies > 0) { 759502acac7eSsl rval = ddi_dma_unbind_handle( 759602acac7eSsl tw->tw_isoc_bufs[i].dma_handle); 759702acac7eSsl ASSERT(rval == USB_SUCCESS); 759802acac7eSsl } 759902acac7eSsl ddi_dma_mem_free(&tw->tw_isoc_bufs[i].mem_handle); 760002acac7eSsl ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle); 760102acac7eSsl } 760202acac7eSsl kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen); 760302acac7eSsl } else if (tw->tw_dmahandle != NULL) { 760402acac7eSsl if (tw->tw_ncookies > 0) { 760502acac7eSsl rval = ddi_dma_unbind_handle(tw->tw_dmahandle); 760602acac7eSsl ASSERT(rval == DDI_SUCCESS); 760702acac7eSsl } 760802acac7eSsl ddi_dma_mem_free(&tw->tw_accesshandle); 760902acac7eSsl ddi_dma_free_handle(&tw->tw_dmahandle); 761002acac7eSsl } 76117c478bd9Sstevel@tonic-gate 76127c478bd9Sstevel@tonic-gate /* Free transfer wrapper */ 76137c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t)); 76147c478bd9Sstevel@tonic-gate } 76157c478bd9Sstevel@tonic-gate 76167c478bd9Sstevel@tonic-gate 76177c478bd9Sstevel@tonic-gate /* 76187c478bd9Sstevel@tonic-gate * Interrupt Handling functions 76197c478bd9Sstevel@tonic-gate */ 76207c478bd9Sstevel@tonic-gate 76217c478bd9Sstevel@tonic-gate /* 76227c478bd9Sstevel@tonic-gate * ohci_intr: 76237c478bd9Sstevel@tonic-gate * 76247c478bd9Sstevel@tonic-gate * OpenHCI (OHCI) interrupt handling routine. 76257c478bd9Sstevel@tonic-gate */ 76267c478bd9Sstevel@tonic-gate static uint_t 76279c75c6bfSgovinda ohci_intr(caddr_t arg1, caddr_t arg2) 76287c478bd9Sstevel@tonic-gate { 76299c75c6bfSgovinda ohci_state_t *ohcip = (ohci_state_t *)arg1; 76307c478bd9Sstevel@tonic-gate uint_t intr; 76317c478bd9Sstevel@tonic-gate ohci_td_t *done_head = NULL; 76327c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = &ohcip->ohci_save_intr_sts; 76337c478bd9Sstevel@tonic-gate 76347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 76359c75c6bfSgovinda "ohci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2); 76367c478bd9Sstevel@tonic-gate 76377c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 76387c478bd9Sstevel@tonic-gate 76397c478bd9Sstevel@tonic-gate /* 76407c478bd9Sstevel@tonic-gate * Suppose if we switched to the polled mode from the normal 76417c478bd9Sstevel@tonic-gate * mode when interrupt handler is executing then we need to 76427c478bd9Sstevel@tonic-gate * save the interrupt status information in the polled mode 76437c478bd9Sstevel@tonic-gate * to avoid race conditions. The following flag will be set 76447c478bd9Sstevel@tonic-gate * and reset on entering & exiting of ohci interrupt handler 76457c478bd9Sstevel@tonic-gate * respectively. This flag will be used in the polled mode 76467c478bd9Sstevel@tonic-gate * to check whether the interrupt handler was running when we 76477c478bd9Sstevel@tonic-gate * switched to the polled mode from the normal mode. 76487c478bd9Sstevel@tonic-gate */ 76497c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag = OHCI_INTR_HANDLING; 76507c478bd9Sstevel@tonic-gate 76517c478bd9Sstevel@tonic-gate /* Temporarily turn off interrupts */ 76527c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE); 76537c478bd9Sstevel@tonic-gate 76547c478bd9Sstevel@tonic-gate /* 76557c478bd9Sstevel@tonic-gate * Handle any missed ohci interrupt especially WriteDoneHead 76567c478bd9Sstevel@tonic-gate * and SOF interrupts because of previous polled mode switch. 76577c478bd9Sstevel@tonic-gate */ 76587c478bd9Sstevel@tonic-gate ohci_handle_missed_intr(ohcip); 76597c478bd9Sstevel@tonic-gate 76607c478bd9Sstevel@tonic-gate /* 76617c478bd9Sstevel@tonic-gate * Now process the actual ohci interrupt events that caused 76627c478bd9Sstevel@tonic-gate * invocation of this ohci interrupt handler. 76637c478bd9Sstevel@tonic-gate */ 76647c478bd9Sstevel@tonic-gate 76657c478bd9Sstevel@tonic-gate /* 76667c478bd9Sstevel@tonic-gate * Updating the WriteDoneHead interrupt: 76677c478bd9Sstevel@tonic-gate * 76687c478bd9Sstevel@tonic-gate * (a) Host Controller 76697c478bd9Sstevel@tonic-gate * 76707c478bd9Sstevel@tonic-gate * - First Host controller (HC) checks whether WDH bit 76717c478bd9Sstevel@tonic-gate * in the interrupt status register is cleared. 76727c478bd9Sstevel@tonic-gate * 76737c478bd9Sstevel@tonic-gate * - If WDH bit is cleared then HC writes new done head 76747c478bd9Sstevel@tonic-gate * list information into the HCCA done head field. 76757c478bd9Sstevel@tonic-gate * 76767c478bd9Sstevel@tonic-gate * - Set WDH bit in the interrupt status register. 76777c478bd9Sstevel@tonic-gate * 76787c478bd9Sstevel@tonic-gate * (b) Host Controller Driver (HCD) 76797c478bd9Sstevel@tonic-gate * 76807c478bd9Sstevel@tonic-gate * - First read the interrupt status register. The HCCA 76817c478bd9Sstevel@tonic-gate * done head and WDH bit may be set or may not be set 76827c478bd9Sstevel@tonic-gate * while reading the interrupt status register. 76837c478bd9Sstevel@tonic-gate * 76847c478bd9Sstevel@tonic-gate * - Read the HCCA done head list. By this time may be 76857c478bd9Sstevel@tonic-gate * HC has updated HCCA done head and WDH bit in ohci 76867c478bd9Sstevel@tonic-gate * interrupt status register. 76877c478bd9Sstevel@tonic-gate * 76887c478bd9Sstevel@tonic-gate * - If done head is non-null and if WDH bit is not set 76897c478bd9Sstevel@tonic-gate * then Host Controller has updated HCCA done head & 76907c478bd9Sstevel@tonic-gate * WDH bit in the interrupt stats register in between 76917c478bd9Sstevel@tonic-gate * reading the interrupt status register & HCCA done 76927c478bd9Sstevel@tonic-gate * head. In that case, definitely WDH bit will be set 76937c478bd9Sstevel@tonic-gate * in the interrupt status register & driver can take 76947c478bd9Sstevel@tonic-gate * it for granted. 76957c478bd9Sstevel@tonic-gate * 76967c478bd9Sstevel@tonic-gate * Now read the Interrupt Status & Interrupt enable register 76977c478bd9Sstevel@tonic-gate * to determine the exact interrupt events. 76987c478bd9Sstevel@tonic-gate */ 76997c478bd9Sstevel@tonic-gate intr = ohci_intr_sts->ohci_curr_intr_sts = 77007c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_intr_status) & Get_OpReg(hcr_intr_enable)); 77017c478bd9Sstevel@tonic-gate 77027c478bd9Sstevel@tonic-gate if (ohcip->ohci_hccap) { 77037c478bd9Sstevel@tonic-gate /* Sync HCCA area */ 77047c478bd9Sstevel@tonic-gate Sync_HCCA(ohcip); 77057c478bd9Sstevel@tonic-gate 77067c478bd9Sstevel@tonic-gate /* Read and Save the HCCA DoneHead value */ 77077c478bd9Sstevel@tonic-gate done_head = ohci_intr_sts->ohci_curr_done_lst = 77087c478bd9Sstevel@tonic-gate (ohci_td_t *)(uintptr_t) 7709e026ab87Sgc (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & 7710e026ab87Sgc HCCA_DONE_HEAD_MASK); 77117c478bd9Sstevel@tonic-gate 77127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77137c478bd9Sstevel@tonic-gate "ohci_intr: Done head! 0x%p", (void *)done_head); 77147c478bd9Sstevel@tonic-gate } 77157c478bd9Sstevel@tonic-gate 77167c478bd9Sstevel@tonic-gate /* Update kstat values */ 77177c478bd9Sstevel@tonic-gate ohci_do_intrs_stats(ohcip, intr); 77187c478bd9Sstevel@tonic-gate 77197c478bd9Sstevel@tonic-gate /* 7720e026ab87Sgc * Look at the HccaDoneHead, if it is a non-zero valid address, 7721e026ab87Sgc * a done list update interrupt is indicated. Otherwise, this 7722e026ab87Sgc * intr bit is cleared. 77237c478bd9Sstevel@tonic-gate */ 7724688b07c5Sgc if (ohci_check_done_head(ohcip, done_head) == USB_SUCCESS) { 77257c478bd9Sstevel@tonic-gate 7726688b07c5Sgc /* Set the WriteDoneHead bit in the interrupt events */ 7727e026ab87Sgc intr |= HCR_INTR_WDH; 7728688b07c5Sgc } else { 7729688b07c5Sgc 7730688b07c5Sgc /* Clear the WriteDoneHead bit */ 7731688b07c5Sgc intr &= ~HCR_INTR_WDH; 77327c478bd9Sstevel@tonic-gate } 77337c478bd9Sstevel@tonic-gate 77347c478bd9Sstevel@tonic-gate /* 77357c478bd9Sstevel@tonic-gate * We could have gotten a spurious interrupts. If so, do not 77367c478bd9Sstevel@tonic-gate * claim it. This is quite possible on some architectures 77377c478bd9Sstevel@tonic-gate * where more than one PCI slots share the IRQs. If so, the 77387c478bd9Sstevel@tonic-gate * associated driver's interrupt routine may get called even 77397c478bd9Sstevel@tonic-gate * if the interrupt is not meant for them. 77407c478bd9Sstevel@tonic-gate * 77417c478bd9Sstevel@tonic-gate * By unclaiming the interrupt, the other driver gets chance 77427c478bd9Sstevel@tonic-gate * to service its interrupt. 77437c478bd9Sstevel@tonic-gate */ 77447c478bd9Sstevel@tonic-gate if (!intr) { 77457c478bd9Sstevel@tonic-gate 77467c478bd9Sstevel@tonic-gate /* Reset the interrupt handler flag */ 77477c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_HANDLING; 77487c478bd9Sstevel@tonic-gate 77497c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_MIE); 77507c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 77517c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 77527c478bd9Sstevel@tonic-gate } 77537c478bd9Sstevel@tonic-gate 77547c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77557c478bd9Sstevel@tonic-gate "Interrupt status 0x%x", intr); 77567c478bd9Sstevel@tonic-gate 77577c478bd9Sstevel@tonic-gate /* 77587c478bd9Sstevel@tonic-gate * Check for Frame Number Overflow. 77597c478bd9Sstevel@tonic-gate */ 77607c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_FNO) { 77617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77627c478bd9Sstevel@tonic-gate "ohci_intr: Frame Number Overflow"); 77637c478bd9Sstevel@tonic-gate 77647c478bd9Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohcip); 77657c478bd9Sstevel@tonic-gate } 77667c478bd9Sstevel@tonic-gate 77677c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SOF) { 77687c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77697c478bd9Sstevel@tonic-gate "ohci_intr: Start of Frame"); 77707c478bd9Sstevel@tonic-gate 77717c478bd9Sstevel@tonic-gate /* Set ohci_sof_flag indicating SOF interrupt occurred */ 77727c478bd9Sstevel@tonic-gate ohcip->ohci_sof_flag = B_TRUE; 77737c478bd9Sstevel@tonic-gate 77747c478bd9Sstevel@tonic-gate /* Disabel SOF interrupt */ 77757c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SOF); 77767c478bd9Sstevel@tonic-gate 77777c478bd9Sstevel@tonic-gate /* 77787c478bd9Sstevel@tonic-gate * Call cv_broadcast on every SOF interrupt to wakeup 77797c478bd9Sstevel@tonic-gate * all the threads that are waiting the SOF. Calling 77807c478bd9Sstevel@tonic-gate * cv_broadcast on every SOF has no effect even if no 77817c478bd9Sstevel@tonic-gate * threads are waiting for the SOF. 77827c478bd9Sstevel@tonic-gate */ 77837c478bd9Sstevel@tonic-gate cv_broadcast(&ohcip->ohci_SOF_cv); 77847c478bd9Sstevel@tonic-gate } 77857c478bd9Sstevel@tonic-gate 77867c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SO) { 77877c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77887c478bd9Sstevel@tonic-gate "ohci_intr: Schedule overrun"); 77897c478bd9Sstevel@tonic-gate 77907c478bd9Sstevel@tonic-gate ohcip->ohci_so_error++; 77917c478bd9Sstevel@tonic-gate } 77927c478bd9Sstevel@tonic-gate 77937c478bd9Sstevel@tonic-gate if ((intr & HCR_INTR_WDH) && (done_head)) { 77947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 77957c478bd9Sstevel@tonic-gate "ohci_intr: Done Head"); 77967c478bd9Sstevel@tonic-gate 77977c478bd9Sstevel@tonic-gate /* 77987c478bd9Sstevel@tonic-gate * Currently if we are processing one WriteDoneHead 77997c478bd9Sstevel@tonic-gate * interrupt and also if we switched to the polled 78007c478bd9Sstevel@tonic-gate * mode at least once during this time, then there 78017c478bd9Sstevel@tonic-gate * may be chance that Host Controller generates one 78027c478bd9Sstevel@tonic-gate * more Write DoneHead or Start of Frame interrupts 78037c478bd9Sstevel@tonic-gate * for the normal since the polled code clears WDH & 78047c478bd9Sstevel@tonic-gate * SOF interrupt bits before returning to the normal 78057c478bd9Sstevel@tonic-gate * mode. Under this condition, we must not clear the 78067c478bd9Sstevel@tonic-gate * HCCA done head field & also we must not clear WDH 78077c478bd9Sstevel@tonic-gate * interrupt bit in the interrupt status register. 78087c478bd9Sstevel@tonic-gate */ 78097c478bd9Sstevel@tonic-gate if (done_head == (ohci_td_t *)(uintptr_t) 7810e026ab87Sgc (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & 7811e026ab87Sgc HCCA_DONE_HEAD_MASK)) { 78127c478bd9Sstevel@tonic-gate 78137c478bd9Sstevel@tonic-gate /* Reset the done head to NULL */ 78147c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL); 78157c478bd9Sstevel@tonic-gate } else { 78167c478bd9Sstevel@tonic-gate intr &= ~HCR_INTR_WDH; 78177c478bd9Sstevel@tonic-gate } 78187c478bd9Sstevel@tonic-gate 78197c478bd9Sstevel@tonic-gate /* Clear the current done head field */ 78207c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_curr_done_lst = NULL; 78217c478bd9Sstevel@tonic-gate 78227c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head); 78237c478bd9Sstevel@tonic-gate } 78247c478bd9Sstevel@tonic-gate 78257c478bd9Sstevel@tonic-gate /* Process endpoint reclaimation list */ 78267c478bd9Sstevel@tonic-gate if (ohcip->ohci_reclaim_list) { 78277c478bd9Sstevel@tonic-gate ohci_handle_endpoint_reclaimation(ohcip); 78287c478bd9Sstevel@tonic-gate } 78297c478bd9Sstevel@tonic-gate 78307c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_RD) { 78317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78327c478bd9Sstevel@tonic-gate "ohci_intr: Resume Detected"); 78337c478bd9Sstevel@tonic-gate } 78347c478bd9Sstevel@tonic-gate 78357c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_RHSC) { 78367c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78377c478bd9Sstevel@tonic-gate "ohci_intr: Root hub status change"); 78387c478bd9Sstevel@tonic-gate } 78397c478bd9Sstevel@tonic-gate 78407c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_OC) { 78417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78427c478bd9Sstevel@tonic-gate "ohci_intr: Change ownership"); 78437c478bd9Sstevel@tonic-gate 78447c478bd9Sstevel@tonic-gate } 78457c478bd9Sstevel@tonic-gate 78467c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_UE) { 78477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78487c478bd9Sstevel@tonic-gate "ohci_intr: Unrecoverable error"); 78497c478bd9Sstevel@tonic-gate 78507c478bd9Sstevel@tonic-gate ohci_handle_ue(ohcip); 78517c478bd9Sstevel@tonic-gate } 78527c478bd9Sstevel@tonic-gate 78537c478bd9Sstevel@tonic-gate /* Acknowledge the interrupt */ 78547c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_status, intr); 78557c478bd9Sstevel@tonic-gate 78567c478bd9Sstevel@tonic-gate /* Clear the current interrupt event field */ 78577c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_curr_intr_sts = 0; 78587c478bd9Sstevel@tonic-gate 78597c478bd9Sstevel@tonic-gate /* 78607c478bd9Sstevel@tonic-gate * Reset the following flag indicating exiting the interrupt 78617c478bd9Sstevel@tonic-gate * handler and this flag will be used in the polled mode to 78627c478bd9Sstevel@tonic-gate * do some extra processing. 78637c478bd9Sstevel@tonic-gate */ 78647c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_HANDLING; 78657c478bd9Sstevel@tonic-gate 78667c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_MIE); 78677c478bd9Sstevel@tonic-gate 78687c478bd9Sstevel@tonic-gate /* 78697c478bd9Sstevel@tonic-gate * Read interrupt status register to make sure that any PIO 78707c478bd9Sstevel@tonic-gate * store to clear the ISR has made it on the PCI bus before 78717c478bd9Sstevel@tonic-gate * returning from its interrupt handler. 78727c478bd9Sstevel@tonic-gate */ 78737c478bd9Sstevel@tonic-gate (void) Get_OpReg(hcr_intr_status); 78747c478bd9Sstevel@tonic-gate 78757c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 78767c478bd9Sstevel@tonic-gate 78777c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 78787c478bd9Sstevel@tonic-gate "Interrupt handling completed"); 78797c478bd9Sstevel@tonic-gate 78807c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 78817c478bd9Sstevel@tonic-gate } 78827c478bd9Sstevel@tonic-gate 7883688b07c5Sgc /* 7884688b07c5Sgc * Check whether done_head is a valid td point address. 7885e026ab87Sgc * It should be non-zero, 16-byte aligned, and fall in ohci_td_pool. 7886688b07c5Sgc */ 7887688b07c5Sgc static int 7888688b07c5Sgc ohci_check_done_head(ohci_state_t *ohcip, ohci_td_t *done_head) 7889688b07c5Sgc { 7890688b07c5Sgc uintptr_t lower, upper, headp; 7891688b07c5Sgc lower = ohcip->ohci_td_pool_cookie.dmac_address; 7892688b07c5Sgc upper = lower + ohcip->ohci_td_pool_cookie.dmac_size; 7893688b07c5Sgc headp = (uintptr_t)done_head; 7894688b07c5Sgc 7895688b07c5Sgc if (headp && !(headp & ~HCCA_DONE_HEAD_MASK) && 7896*29aca3ebSlc (headp >= lower) && (headp < upper)) { 7897688b07c5Sgc 7898688b07c5Sgc return (USB_SUCCESS); 7899688b07c5Sgc } else { 7900688b07c5Sgc 7901688b07c5Sgc return (USB_FAILURE); 7902688b07c5Sgc } 7903688b07c5Sgc } 79047c478bd9Sstevel@tonic-gate 79057c478bd9Sstevel@tonic-gate /* 79067c478bd9Sstevel@tonic-gate * ohci_handle_missed_intr: 79077c478bd9Sstevel@tonic-gate * 79087c478bd9Sstevel@tonic-gate * Handle any ohci missed interrupts because of polled mode switch. 79097c478bd9Sstevel@tonic-gate */ 79107c478bd9Sstevel@tonic-gate static void 79117c478bd9Sstevel@tonic-gate ohci_handle_missed_intr(ohci_state_t *ohcip) 79127c478bd9Sstevel@tonic-gate { 79137c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = 7914*29aca3ebSlc &ohcip->ohci_save_intr_sts; 79157c478bd9Sstevel@tonic-gate ohci_td_t *done_head; 79167c478bd9Sstevel@tonic-gate uint_t intr; 79177c478bd9Sstevel@tonic-gate 79187c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 79197c478bd9Sstevel@tonic-gate 79207c478bd9Sstevel@tonic-gate /* 79217c478bd9Sstevel@tonic-gate * Check whether we have missed any ohci interrupts because 79227c478bd9Sstevel@tonic-gate * of the polled mode switch during previous ohci interrupt 79237c478bd9Sstevel@tonic-gate * handler execution. Only Write Done Head & SOF interrupts 79247c478bd9Sstevel@tonic-gate * saved in the polled mode. First process these interrupts 79257c478bd9Sstevel@tonic-gate * before processing actual interrupts that caused invocation 79267c478bd9Sstevel@tonic-gate * of ohci interrupt handler. 79277c478bd9Sstevel@tonic-gate */ 79287c478bd9Sstevel@tonic-gate if (!ohci_intr_sts->ohci_missed_intr_sts) { 79297c478bd9Sstevel@tonic-gate /* No interrupts are missed, simply return */ 79307c478bd9Sstevel@tonic-gate 79317c478bd9Sstevel@tonic-gate return; 79327c478bd9Sstevel@tonic-gate } 79337c478bd9Sstevel@tonic-gate 79347c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 79357c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Handle ohci missed interrupts"); 79367c478bd9Sstevel@tonic-gate 79377c478bd9Sstevel@tonic-gate /* 79387c478bd9Sstevel@tonic-gate * The functionality and importance of critical code section 79397c478bd9Sstevel@tonic-gate * in the normal mode ohci interrupt handler & its usage in 79407c478bd9Sstevel@tonic-gate * the polled mode is explained below. 79417c478bd9Sstevel@tonic-gate * 79427c478bd9Sstevel@tonic-gate * (a) Normal mode: 79437c478bd9Sstevel@tonic-gate * 79447c478bd9Sstevel@tonic-gate * - Set the flag indicating that processing critical 79457c478bd9Sstevel@tonic-gate * code in ohci interrupt handler. 79467c478bd9Sstevel@tonic-gate * 79477c478bd9Sstevel@tonic-gate * - Process the missed ohci interrupts by copying the 79487c478bd9Sstevel@tonic-gate * miised interrupt events and done head list fields 79497c478bd9Sstevel@tonic-gate * information to the critical interrupt event & done 79507c478bd9Sstevel@tonic-gate * list fields. 79517c478bd9Sstevel@tonic-gate * 79527c478bd9Sstevel@tonic-gate * - Reset the missed ohci interrupt events & done head 79537c478bd9Sstevel@tonic-gate * list fields so that the new missed interrupt event 79547c478bd9Sstevel@tonic-gate * and done head list information can be saved. 79557c478bd9Sstevel@tonic-gate * 79567c478bd9Sstevel@tonic-gate * - All above steps will be executed with in critical 79577c478bd9Sstevel@tonic-gate * section of the interrupt handler.Then ohci missed 79587c478bd9Sstevel@tonic-gate * interrupt handler will be called to service missed 79597c478bd9Sstevel@tonic-gate * ohci interrupts. 79607c478bd9Sstevel@tonic-gate * 79617c478bd9Sstevel@tonic-gate * (b) Polled mode: 79627c478bd9Sstevel@tonic-gate * 79637c478bd9Sstevel@tonic-gate * - On entering the polled code,it checks for critical 79647c478bd9Sstevel@tonic-gate * section code execution within the normal mode ohci 79657c478bd9Sstevel@tonic-gate * interrupt handler. 79667c478bd9Sstevel@tonic-gate * 79677c478bd9Sstevel@tonic-gate * - If the critical section code is executing in normal 79687c478bd9Sstevel@tonic-gate * mode ohci interrupt handler and if copying of ohci 79697c478bd9Sstevel@tonic-gate * missed interrupt events & done head list fields to 79707c478bd9Sstevel@tonic-gate * the critical fields is finished then save the "any 79717c478bd9Sstevel@tonic-gate * missed interrupt events & done head list" because 79727c478bd9Sstevel@tonic-gate * of current polled mode switch into "critical missed 79737c478bd9Sstevel@tonic-gate * interrupt events & done list fields" instead actual 79747c478bd9Sstevel@tonic-gate * missed events and done list fields. 79757c478bd9Sstevel@tonic-gate * 79767c478bd9Sstevel@tonic-gate * - Otherwise save "any missed interrupt events & done 79777c478bd9Sstevel@tonic-gate * list" because of this current polled mode switch 79787c478bd9Sstevel@tonic-gate * in the actual missed interrupt events & done head 79797c478bd9Sstevel@tonic-gate * list fields. 79807c478bd9Sstevel@tonic-gate */ 79817c478bd9Sstevel@tonic-gate 79827c478bd9Sstevel@tonic-gate /* 79837c478bd9Sstevel@tonic-gate * Set flag indicating that interrupt handler is processing 79847c478bd9Sstevel@tonic-gate * critical interrupt code, so that polled mode code checks 79857c478bd9Sstevel@tonic-gate * for this condition & will do extra processing as explained 79867c478bd9Sstevel@tonic-gate * above in order to aviod the race conditions. 79877c478bd9Sstevel@tonic-gate */ 79887c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag |= OHCI_INTR_CRITICAL; 79897c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts |= 79907c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts; 79917c478bd9Sstevel@tonic-gate 79927c478bd9Sstevel@tonic-gate if (ohci_intr_sts->ohci_missed_done_lst) { 79937c478bd9Sstevel@tonic-gate 79947c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_done_lst = 79957c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_done_lst; 79967c478bd9Sstevel@tonic-gate } 79977c478bd9Sstevel@tonic-gate 79987c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts = 0; 79997c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_done_lst = NULL; 80007c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_CRITICAL; 80017c478bd9Sstevel@tonic-gate 80027c478bd9Sstevel@tonic-gate intr = ohci_intr_sts->ohci_critical_intr_sts; 80037c478bd9Sstevel@tonic-gate done_head = ohci_intr_sts->ohci_critical_done_lst; 80047c478bd9Sstevel@tonic-gate 80057c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SOF) { 80067c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80077c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Start of Frame"); 80087c478bd9Sstevel@tonic-gate 80097c478bd9Sstevel@tonic-gate /* 80107c478bd9Sstevel@tonic-gate * Call cv_broadcast on every SOF interrupt to wakeup 80117c478bd9Sstevel@tonic-gate * all the threads that are waiting the SOF. Calling 80127c478bd9Sstevel@tonic-gate * cv_broadcast on every SOF has no effect even if no 80137c478bd9Sstevel@tonic-gate * threads are waiting for the SOF. 80147c478bd9Sstevel@tonic-gate */ 80157c478bd9Sstevel@tonic-gate cv_broadcast(&ohcip->ohci_SOF_cv); 80167c478bd9Sstevel@tonic-gate } 80177c478bd9Sstevel@tonic-gate 80187c478bd9Sstevel@tonic-gate if ((intr & HCR_INTR_WDH) && (done_head)) { 80197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80207c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Done Head"); 80217c478bd9Sstevel@tonic-gate 80227c478bd9Sstevel@tonic-gate /* Clear the critical done head field */ 80237c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_done_lst = NULL; 80247c478bd9Sstevel@tonic-gate 80257c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head); 80267c478bd9Sstevel@tonic-gate } 80277c478bd9Sstevel@tonic-gate 80287c478bd9Sstevel@tonic-gate /* Clear the critical interrupt event field */ 80297c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts = 0; 80307c478bd9Sstevel@tonic-gate } 80317c478bd9Sstevel@tonic-gate 80327c478bd9Sstevel@tonic-gate 80337c478bd9Sstevel@tonic-gate /* 80347c478bd9Sstevel@tonic-gate * ohci_handle_ue: 80357c478bd9Sstevel@tonic-gate * 80367c478bd9Sstevel@tonic-gate * Handling of Unrecoverable Error interrupt (UE). 80377c478bd9Sstevel@tonic-gate */ 80387c478bd9Sstevel@tonic-gate static void 80397c478bd9Sstevel@tonic-gate ohci_handle_ue(ohci_state_t *ohcip) 80407c478bd9Sstevel@tonic-gate { 80417c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 80427c478bd9Sstevel@tonic-gate 80437c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 80447c478bd9Sstevel@tonic-gate 80457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80467c478bd9Sstevel@tonic-gate "ohci_handle_ue: Handling of UE interrupt"); 80477c478bd9Sstevel@tonic-gate 80487c478bd9Sstevel@tonic-gate /* 80497c478bd9Sstevel@tonic-gate * First check whether current UE error occured due to USB or 80507c478bd9Sstevel@tonic-gate * due to some other subsystem. This can be verified by reading 80517c478bd9Sstevel@tonic-gate * usb frame numbers before & after a delay of few milliseconds. 80527c478bd9Sstevel@tonic-gate * If usb frame number read after delay is greater than the one 80537c478bd9Sstevel@tonic-gate * read before delay, then, USB subsystem is fine. In this case, 80547c478bd9Sstevel@tonic-gate * disable UE error interrupt and return without shutdowning the 80557c478bd9Sstevel@tonic-gate * USB subsystem. 80567c478bd9Sstevel@tonic-gate * 80577c478bd9Sstevel@tonic-gate * Otherwise, if usb frame number read after delay is less than 80587c478bd9Sstevel@tonic-gate * or equal to one read before the delay, then, current UE error 80597c478bd9Sstevel@tonic-gate * occured from USB susbsystem. In this case,go ahead with actual 80607c478bd9Sstevel@tonic-gate * UE error recovery procedure. 80617c478bd9Sstevel@tonic-gate * 80627c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few 80637c478bd9Sstevel@tonic-gate * milliseconds. 80647c478bd9Sstevel@tonic-gate */ 80657c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip); 80667c478bd9Sstevel@tonic-gate 80677c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 80687c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 80697c478bd9Sstevel@tonic-gate 80707c478bd9Sstevel@tonic-gate /* 80717c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 80727c478bd9Sstevel@tonic-gate * milliseconds. 80737c478bd9Sstevel@tonic-gate */ 80747c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip); 80757c478bd9Sstevel@tonic-gate 80767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80777c478bd9Sstevel@tonic-gate "ohci_handle_ue: Before Frm No 0x%llx After Frm No 0x%llx", 80787c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 80797c478bd9Sstevel@tonic-gate 80807c478bd9Sstevel@tonic-gate if (after_frame_number > before_frame_number) { 80817c478bd9Sstevel@tonic-gate 80827c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 80837c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_UE); 80847c478bd9Sstevel@tonic-gate 80857c478bd9Sstevel@tonic-gate return; 80867c478bd9Sstevel@tonic-gate } 80877c478bd9Sstevel@tonic-gate 80887c478bd9Sstevel@tonic-gate /* 80897c478bd9Sstevel@tonic-gate * This UE is due to USB hardware error. Reset ohci controller 80907c478bd9Sstevel@tonic-gate * and reprogram to bring it back to functional state. 80917c478bd9Sstevel@tonic-gate */ 80927c478bd9Sstevel@tonic-gate if ((ohci_do_soft_reset(ohcip)) != USB_SUCCESS) { 80937c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 80947c478bd9Sstevel@tonic-gate "Unrecoverable USB Hardware Error"); 80957c478bd9Sstevel@tonic-gate 80967c478bd9Sstevel@tonic-gate /* Disable UE interrupt */ 80977c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_UE); 80987c478bd9Sstevel@tonic-gate 80997c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 81007c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_ERROR_STATE; 81017c478bd9Sstevel@tonic-gate } 81027c478bd9Sstevel@tonic-gate } 81037c478bd9Sstevel@tonic-gate 81047c478bd9Sstevel@tonic-gate 81057c478bd9Sstevel@tonic-gate /* 81067c478bd9Sstevel@tonic-gate * ohci_handle_frame_number_overflow: 81077c478bd9Sstevel@tonic-gate * 81087c478bd9Sstevel@tonic-gate * Update software based usb frame number part on every frame number 81097c478bd9Sstevel@tonic-gate * overflow interrupt. 81107c478bd9Sstevel@tonic-gate * 81117c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 81127c478bd9Sstevel@tonic-gate * 81137c478bd9Sstevel@tonic-gate * Refer ohci spec 1.0a, section 5.3, page 81 for more details. 81147c478bd9Sstevel@tonic-gate */ 81157c478bd9Sstevel@tonic-gate void 81167c478bd9Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohci_state_t *ohcip) 81177c478bd9Sstevel@tonic-gate { 81187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 81197c478bd9Sstevel@tonic-gate "ohci_handle_frame_number_overflow:"); 81207c478bd9Sstevel@tonic-gate 81217c478bd9Sstevel@tonic-gate ohcip->ohci_fno += (0x10000 - 81227c478bd9Sstevel@tonic-gate (((Get_HCCA(ohcip->ohci_hccap->HccaFrameNo) & 81237c478bd9Sstevel@tonic-gate 0xFFFF) ^ ohcip->ohci_fno) & 0x8000)); 81247c478bd9Sstevel@tonic-gate 81257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 81267c478bd9Sstevel@tonic-gate "ohci_handle_frame_number_overflow:" 81277c478bd9Sstevel@tonic-gate "Frame Number Higher Part 0x%llx\n", ohcip->ohci_fno); 81287c478bd9Sstevel@tonic-gate } 81297c478bd9Sstevel@tonic-gate 81307c478bd9Sstevel@tonic-gate 81317c478bd9Sstevel@tonic-gate /* 81327c478bd9Sstevel@tonic-gate * ohci_handle_endpoint_reclaimation: 81337c478bd9Sstevel@tonic-gate * 81347c478bd9Sstevel@tonic-gate * Reclamation of Host Controller (HC) Endpoint Descriptors (ED). 81357c478bd9Sstevel@tonic-gate */ 81367c478bd9Sstevel@tonic-gate static void 81377c478bd9Sstevel@tonic-gate ohci_handle_endpoint_reclaimation(ohci_state_t *ohcip) 81387c478bd9Sstevel@tonic-gate { 81397c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number; 81407c478bd9Sstevel@tonic-gate usb_frame_number_t endpoint_frame_number; 81417c478bd9Sstevel@tonic-gate ohci_ed_t *reclaim_ed; 81427c478bd9Sstevel@tonic-gate 81437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 81447c478bd9Sstevel@tonic-gate "ohci_handle_endpoint_reclaimation:"); 81457c478bd9Sstevel@tonic-gate 81467c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 81477c478bd9Sstevel@tonic-gate 81487c478bd9Sstevel@tonic-gate current_frame_number = ohci_get_current_frame_number(ohcip); 81497c478bd9Sstevel@tonic-gate 81507c478bd9Sstevel@tonic-gate /* 81517c478bd9Sstevel@tonic-gate * Deallocate all Endpoint Descriptors (ED) which are on the 81527c478bd9Sstevel@tonic-gate * reclaimation list. These ED's are already removed from the 81537c478bd9Sstevel@tonic-gate * interrupt lattice tree. 81547c478bd9Sstevel@tonic-gate */ 81557c478bd9Sstevel@tonic-gate while (ohcip->ohci_reclaim_list) { 81567c478bd9Sstevel@tonic-gate reclaim_ed = ohcip->ohci_reclaim_list; 81577c478bd9Sstevel@tonic-gate 81587c478bd9Sstevel@tonic-gate endpoint_frame_number = (usb_frame_number_t)(uintptr_t) 81597c478bd9Sstevel@tonic-gate (OHCI_LOOKUP_ID(Get_ED(reclaim_ed->hced_reclaim_frame))); 81607c478bd9Sstevel@tonic-gate 81617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 81627c478bd9Sstevel@tonic-gate "ohci_handle_endpoint_reclaimation:" 81637c478bd9Sstevel@tonic-gate "current frame number 0x%llx endpoint frame number 0x%llx", 81647c478bd9Sstevel@tonic-gate current_frame_number, endpoint_frame_number); 81657c478bd9Sstevel@tonic-gate 81667c478bd9Sstevel@tonic-gate /* 81677c478bd9Sstevel@tonic-gate * Deallocate current endpoint only if endpoint's usb frame 81687c478bd9Sstevel@tonic-gate * number is less than or equal to current usb frame number. 81697c478bd9Sstevel@tonic-gate * 81707c478bd9Sstevel@tonic-gate * If endpoint's usb frame number is greater than the current 81717c478bd9Sstevel@tonic-gate * usb frame number, ignore rest of the endpoints in the list 81727c478bd9Sstevel@tonic-gate * since rest of the endpoints are inserted into the reclaim 81737c478bd9Sstevel@tonic-gate * list later than the current reclaim endpoint. 81747c478bd9Sstevel@tonic-gate */ 81757c478bd9Sstevel@tonic-gate if (endpoint_frame_number > current_frame_number) { 81767c478bd9Sstevel@tonic-gate break; 81777c478bd9Sstevel@tonic-gate } 81787c478bd9Sstevel@tonic-gate 81797c478bd9Sstevel@tonic-gate /* Get the next endpoint from the rec. list */ 81807c478bd9Sstevel@tonic-gate ohcip->ohci_reclaim_list = ohci_ed_iommu_to_cpu(ohcip, 81817c478bd9Sstevel@tonic-gate Get_ED(reclaim_ed->hced_reclaim_next)); 81827c478bd9Sstevel@tonic-gate 81837c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 81847c478bd9Sstevel@tonic-gate OHCI_FREE_ID((uint32_t)Get_ED(reclaim_ed->hced_reclaim_frame)); 81857c478bd9Sstevel@tonic-gate 81867c478bd9Sstevel@tonic-gate /* Deallocate the endpoint */ 81877c478bd9Sstevel@tonic-gate ohci_deallocate_ed(ohcip, reclaim_ed); 81887c478bd9Sstevel@tonic-gate } 81897c478bd9Sstevel@tonic-gate } 81907c478bd9Sstevel@tonic-gate 81917c478bd9Sstevel@tonic-gate 81927c478bd9Sstevel@tonic-gate /* 81937c478bd9Sstevel@tonic-gate * ohci_traverse_done_list: 81947c478bd9Sstevel@tonic-gate */ 81957c478bd9Sstevel@tonic-gate static void 81967c478bd9Sstevel@tonic-gate ohci_traverse_done_list( 81977c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 81987c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list) 81997c478bd9Sstevel@tonic-gate { 82007c478bd9Sstevel@tonic-gate uint_t state; /* TD state */ 82017c478bd9Sstevel@tonic-gate ohci_td_t *td, *old_td; /* TD pointers */ 82027c478bd9Sstevel@tonic-gate usb_cr_t error; /* Error from TD */ 82037c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw = NULL; /* Transfer wrapper */ 82047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = NULL; /* Pipe private field */ 82057c478bd9Sstevel@tonic-gate 82067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 82077c478bd9Sstevel@tonic-gate "ohci_traverse_done_list:"); 82087c478bd9Sstevel@tonic-gate 82097c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 82107c478bd9Sstevel@tonic-gate 82117c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */ 82127c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip); 82137c478bd9Sstevel@tonic-gate 82147c478bd9Sstevel@tonic-gate /* Reverse the done list */ 82157c478bd9Sstevel@tonic-gate td = ohci_reverse_done_list(ohcip, head_done_list); 82167c478bd9Sstevel@tonic-gate 82177c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */ 82187c478bd9Sstevel@tonic-gate while (td) { 82197c478bd9Sstevel@tonic-gate /* Check for TD state */ 82207c478bd9Sstevel@tonic-gate state = Get_TD(td->hctd_state); 82217c478bd9Sstevel@tonic-gate 82227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 82237c478bd9Sstevel@tonic-gate "ohci_traverse_done_list:\n\t" 82247c478bd9Sstevel@tonic-gate "td = 0x%p state = 0x%x", (void *)td, state); 82257c478bd9Sstevel@tonic-gate 82267c478bd9Sstevel@tonic-gate /* 82277c478bd9Sstevel@tonic-gate * Obtain the transfer wrapper only if the TD is 82287c478bd9Sstevel@tonic-gate * not marked as RECLAIM. 82297c478bd9Sstevel@tonic-gate * 82307c478bd9Sstevel@tonic-gate * A TD that is marked as RECLAIM has had its DMA 82317c478bd9Sstevel@tonic-gate * mappings, ED, TD and pipe private structure are 82327c478bd9Sstevel@tonic-gate * ripped down. Just deallocate this TD. 82337c478bd9Sstevel@tonic-gate */ 82347c478bd9Sstevel@tonic-gate if (state != HC_TD_RECLAIM) { 82357c478bd9Sstevel@tonic-gate 82367c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID( 82377c478bd9Sstevel@tonic-gate (uint32_t)Get_TD(td->hctd_trans_wrapper)); 82387c478bd9Sstevel@tonic-gate 82397c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 82407c478bd9Sstevel@tonic-gate 82417c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 82427c478bd9Sstevel@tonic-gate 82437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 82447c478bd9Sstevel@tonic-gate "ohci_traverse_done_list: PP = 0x%p TW = 0x%p", 82457c478bd9Sstevel@tonic-gate pp, tw); 82467c478bd9Sstevel@tonic-gate } 82477c478bd9Sstevel@tonic-gate 82487c478bd9Sstevel@tonic-gate /* 82497c478bd9Sstevel@tonic-gate * Don't process the TD if its state is marked as 82507c478bd9Sstevel@tonic-gate * either RECLAIM or TIMEOUT. 82517c478bd9Sstevel@tonic-gate * 82527c478bd9Sstevel@tonic-gate * A TD that is marked as TIMEOUT has already been 82537c478bd9Sstevel@tonic-gate * processed by TD timeout handler & client driver 82547c478bd9Sstevel@tonic-gate * has been informed through exception callback. 82557c478bd9Sstevel@tonic-gate */ 82567c478bd9Sstevel@tonic-gate if ((state != HC_TD_RECLAIM) && (state != HC_TD_TIMEOUT)) { 82577c478bd9Sstevel@tonic-gate 82587c478bd9Sstevel@tonic-gate /* Look at the error status */ 82597c478bd9Sstevel@tonic-gate error = ohci_parse_error(ohcip, td); 82607c478bd9Sstevel@tonic-gate 82617c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) { 82627c478bd9Sstevel@tonic-gate ohci_handle_normal_td(ohcip, td, tw); 82637c478bd9Sstevel@tonic-gate } else { 82647c478bd9Sstevel@tonic-gate /* handle the error condition */ 82657c478bd9Sstevel@tonic-gate ohci_handle_error(ohcip, td, error); 82667c478bd9Sstevel@tonic-gate } 82677c478bd9Sstevel@tonic-gate } else { 82687c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 82697c478bd9Sstevel@tonic-gate "ohci_traverse_done_list: TD State = %d", state); 82707c478bd9Sstevel@tonic-gate } 82717c478bd9Sstevel@tonic-gate 82727c478bd9Sstevel@tonic-gate /* 82737c478bd9Sstevel@tonic-gate * Save a pointer to the current transfer descriptor 82747c478bd9Sstevel@tonic-gate */ 82757c478bd9Sstevel@tonic-gate old_td = td; 82767c478bd9Sstevel@tonic-gate 82777c478bd9Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_next_td)); 82787c478bd9Sstevel@tonic-gate 82797c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 82807c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, old_td); 82817c478bd9Sstevel@tonic-gate 82827c478bd9Sstevel@tonic-gate /* 82837c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more 82847c478bd9Sstevel@tonic-gate * TD's for the transfer wrapper. ohci_deallocate_tw_resources() 82857c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic endpoint 82867c478bd9Sstevel@tonic-gate * since it will always have a TD attached to it. 82877c478bd9Sstevel@tonic-gate * 82887c478bd9Sstevel@tonic-gate * Do not deallocate the TW if it is a isoc or intr pipe in. 82897c478bd9Sstevel@tonic-gate * The tw's are reused. 82907c478bd9Sstevel@tonic-gate * 82917c478bd9Sstevel@tonic-gate * An TD that is marked as reclaim doesn't have a pipe 82927c478bd9Sstevel@tonic-gate * or a TW associated with it anymore so don't call this 82937c478bd9Sstevel@tonic-gate * function. 82947c478bd9Sstevel@tonic-gate */ 82957c478bd9Sstevel@tonic-gate if (state != HC_TD_RECLAIM) { 82967c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 82977c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw); 82987c478bd9Sstevel@tonic-gate } 82997c478bd9Sstevel@tonic-gate } 83007c478bd9Sstevel@tonic-gate } 83017c478bd9Sstevel@tonic-gate 83027c478bd9Sstevel@tonic-gate 83037c478bd9Sstevel@tonic-gate /* 83047c478bd9Sstevel@tonic-gate * ohci_reverse_done_list: 83057c478bd9Sstevel@tonic-gate * 83067c478bd9Sstevel@tonic-gate * Reverse the order of the Transfer Descriptor (TD) Done List. 83077c478bd9Sstevel@tonic-gate */ 83087c478bd9Sstevel@tonic-gate static ohci_td_t * 83097c478bd9Sstevel@tonic-gate ohci_reverse_done_list( 83107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 83117c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list) 83127c478bd9Sstevel@tonic-gate { 83137c478bd9Sstevel@tonic-gate ohci_td_t *cpu_new_tail, *cpu_new_head, *cpu_save; 83147c478bd9Sstevel@tonic-gate 83157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83167c478bd9Sstevel@tonic-gate "ohci_reverse_done_list:"); 83177c478bd9Sstevel@tonic-gate 83187c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 83197c478bd9Sstevel@tonic-gate ASSERT(head_done_list != NULL); 83207c478bd9Sstevel@tonic-gate 83217c478bd9Sstevel@tonic-gate /* At first, both the tail and head pointers point to the same elem */ 83227c478bd9Sstevel@tonic-gate cpu_new_tail = cpu_new_head = 83237c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, (uintptr_t)head_done_list); 83247c478bd9Sstevel@tonic-gate 83257c478bd9Sstevel@tonic-gate /* See if the list has only one element */ 83267c478bd9Sstevel@tonic-gate if (Get_TD(cpu_new_head->hctd_next_td) == NULL) { 83277c478bd9Sstevel@tonic-gate 83287c478bd9Sstevel@tonic-gate return (cpu_new_head); 83297c478bd9Sstevel@tonic-gate } 83307c478bd9Sstevel@tonic-gate 83317c478bd9Sstevel@tonic-gate /* Advance the head pointer */ 83327c478bd9Sstevel@tonic-gate cpu_new_head = (ohci_td_t *) 83337c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(cpu_new_head->hctd_next_td)); 83347c478bd9Sstevel@tonic-gate 83357c478bd9Sstevel@tonic-gate /* The new tail now points to nothing */ 83367c478bd9Sstevel@tonic-gate Set_TD(cpu_new_tail->hctd_next_td, NULL); 83377c478bd9Sstevel@tonic-gate 83387c478bd9Sstevel@tonic-gate cpu_save = (ohci_td_t *) 83397c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(cpu_new_head->hctd_next_td)); 83407c478bd9Sstevel@tonic-gate 83417c478bd9Sstevel@tonic-gate /* Reverse the list and store the pointers as CPU addresses */ 83427c478bd9Sstevel@tonic-gate while (cpu_save) { 83437c478bd9Sstevel@tonic-gate Set_TD(cpu_new_head->hctd_next_td, 83447c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, cpu_new_tail)); 83457c478bd9Sstevel@tonic-gate 83467c478bd9Sstevel@tonic-gate cpu_new_tail = cpu_new_head; 83477c478bd9Sstevel@tonic-gate cpu_new_head = cpu_save; 83487c478bd9Sstevel@tonic-gate 83497c478bd9Sstevel@tonic-gate cpu_save = (ohci_td_t *) 83507c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, 83517c478bd9Sstevel@tonic-gate Get_TD(cpu_new_head->hctd_next_td)); 83527c478bd9Sstevel@tonic-gate } 83537c478bd9Sstevel@tonic-gate 83547c478bd9Sstevel@tonic-gate Set_TD(cpu_new_head->hctd_next_td, 83557c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, cpu_new_tail)); 83567c478bd9Sstevel@tonic-gate 83577c478bd9Sstevel@tonic-gate return (cpu_new_head); 83587c478bd9Sstevel@tonic-gate } 83597c478bd9Sstevel@tonic-gate 83607c478bd9Sstevel@tonic-gate 83617c478bd9Sstevel@tonic-gate /* 83627c478bd9Sstevel@tonic-gate * ohci_parse_error: 83637c478bd9Sstevel@tonic-gate * 83647c478bd9Sstevel@tonic-gate * Parse the result for any errors. 83657c478bd9Sstevel@tonic-gate */ 83667c478bd9Sstevel@tonic-gate static usb_cr_t 83677c478bd9Sstevel@tonic-gate ohci_parse_error( 83687c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 83697c478bd9Sstevel@tonic-gate ohci_td_t *td) 83707c478bd9Sstevel@tonic-gate { 83717c478bd9Sstevel@tonic-gate uint_t ctrl; 83727c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd; 83737c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 83747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 83757c478bd9Sstevel@tonic-gate uint_t flag; 83767c478bd9Sstevel@tonic-gate usb_cr_t error; 83777c478bd9Sstevel@tonic-gate 83787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83797c478bd9Sstevel@tonic-gate "ohci_parse_error:"); 83807c478bd9Sstevel@tonic-gate 83817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 83827c478bd9Sstevel@tonic-gate 83837c478bd9Sstevel@tonic-gate ASSERT(td != NULL); 83847c478bd9Sstevel@tonic-gate 83857c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */ 83867c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 83877c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)Get_TD(td->hctd_trans_wrapper)); 83887c478bd9Sstevel@tonic-gate 83897c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 83907c478bd9Sstevel@tonic-gate 83917c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 83927c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 83937c478bd9Sstevel@tonic-gate 83947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 83957c478bd9Sstevel@tonic-gate "ohci_parse_error: PP 0x%p TW 0x%p", pp, tw); 83967c478bd9Sstevel@tonic-gate 83977c478bd9Sstevel@tonic-gate eptd = &pp->pp_pipe_handle->p_ep; 83987c478bd9Sstevel@tonic-gate 83997c478bd9Sstevel@tonic-gate ctrl = (uint_t)Get_TD(td->hctd_ctrl) & (uint32_t)HC_TD_CC; 84007c478bd9Sstevel@tonic-gate 84017c478bd9Sstevel@tonic-gate /* 84027c478bd9Sstevel@tonic-gate * Check the condition code of completed TD and report errors 84037c478bd9Sstevel@tonic-gate * if any. This checking will be done both for the general and 84047c478bd9Sstevel@tonic-gate * the isochronous TDs. 84057c478bd9Sstevel@tonic-gate */ 84067c478bd9Sstevel@tonic-gate if ((error = ohci_check_for_error(ohcip, pp, tw, td, ctrl)) != 84077c478bd9Sstevel@tonic-gate USB_CR_OK) { 84087c478bd9Sstevel@tonic-gate flag = OHCI_REMOVE_XFER_ALWAYS; 84097c478bd9Sstevel@tonic-gate } else { 84107c478bd9Sstevel@tonic-gate flag = OHCI_REMOVE_XFER_IFLAST; 84117c478bd9Sstevel@tonic-gate } 84127c478bd9Sstevel@tonic-gate 84137c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 84147c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, flag); 84157c478bd9Sstevel@tonic-gate 84167c478bd9Sstevel@tonic-gate /* 84177c478bd9Sstevel@tonic-gate * The isochronous endpoint needs additional error checking 84187c478bd9Sstevel@tonic-gate * and special processing. 84197c478bd9Sstevel@tonic-gate */ 84207c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 84217c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) { 84227c478bd9Sstevel@tonic-gate 84237c478bd9Sstevel@tonic-gate ohci_parse_isoc_error(ohcip, pp, tw, td); 84247c478bd9Sstevel@tonic-gate 84257c478bd9Sstevel@tonic-gate /* always reset error */ 84267c478bd9Sstevel@tonic-gate error = USB_CR_OK; 84277c478bd9Sstevel@tonic-gate } 84287c478bd9Sstevel@tonic-gate 84297c478bd9Sstevel@tonic-gate return (error); 84307c478bd9Sstevel@tonic-gate } 84317c478bd9Sstevel@tonic-gate 84327c478bd9Sstevel@tonic-gate 84337c478bd9Sstevel@tonic-gate /* 84347c478bd9Sstevel@tonic-gate * ohci_parse_isoc_error: 84357c478bd9Sstevel@tonic-gate * 84367c478bd9Sstevel@tonic-gate * Check for any errors in the isochronous data packets. Also fillup 84377c478bd9Sstevel@tonic-gate * the status for each of the isochrnous data packets. 84387c478bd9Sstevel@tonic-gate */ 84397c478bd9Sstevel@tonic-gate void 84407c478bd9Sstevel@tonic-gate ohci_parse_isoc_error( 84417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 84427c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 84437c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 84447c478bd9Sstevel@tonic-gate ohci_td_t *td) 84457c478bd9Sstevel@tonic-gate { 84467c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp; 84477c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *isoc_pkt_descr; 84487c478bd9Sstevel@tonic-gate uint_t toggle = 0, fc, ctrl, psw; 84497c478bd9Sstevel@tonic-gate int i; 84507c478bd9Sstevel@tonic-gate 84517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 84527c478bd9Sstevel@tonic-gate "ohci_parse_isoc_error: td 0x%p", td); 84537c478bd9Sstevel@tonic-gate 84547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 84557c478bd9Sstevel@tonic-gate 84567c478bd9Sstevel@tonic-gate fc = ((uint_t)Get_TD(td->hctd_ctrl) & 84577c478bd9Sstevel@tonic-gate HC_ITD_FC) >> HC_ITD_FC_SHIFT; 84587c478bd9Sstevel@tonic-gate 84597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 84607c478bd9Sstevel@tonic-gate "ohci_parse_isoc_error: frame count %d", fc); 84617c478bd9Sstevel@tonic-gate 84627c478bd9Sstevel@tonic-gate /* 84637c478bd9Sstevel@tonic-gate * Get the address of current usb isochronous request 84647c478bd9Sstevel@tonic-gate * and array of packet descriptors. 84657c478bd9Sstevel@tonic-gate */ 84667c478bd9Sstevel@tonic-gate isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 84677c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr; 8468b3001defSlg isoc_pkt_descr += tw->tw_pkt_idx; 84697c478bd9Sstevel@tonic-gate 84707c478bd9Sstevel@tonic-gate for (i = 0; i <= fc; i++) { 84717c478bd9Sstevel@tonic-gate 84727c478bd9Sstevel@tonic-gate psw = Get_TD(td->hctd_offsets[i / 2]); 84737c478bd9Sstevel@tonic-gate 84747c478bd9Sstevel@tonic-gate if (toggle) { 84757c478bd9Sstevel@tonic-gate ctrl = psw & HC_ITD_ODD_OFFSET; 84767c478bd9Sstevel@tonic-gate toggle = 0; 84777c478bd9Sstevel@tonic-gate } else { 84787c478bd9Sstevel@tonic-gate ctrl = (psw & HC_ITD_EVEN_OFFSET) << 8479*29aca3ebSlc HC_ITD_OFFSET_SHIFT; 84807c478bd9Sstevel@tonic-gate toggle = 1; 84817c478bd9Sstevel@tonic-gate } 84827c478bd9Sstevel@tonic-gate 84837c478bd9Sstevel@tonic-gate isoc_pkt_descr->isoc_pkt_actual_length = 84847c478bd9Sstevel@tonic-gate (ctrl >> HC_ITD_OFFSET_SHIFT) & HC_ITD_OFFSET_ADDR; 84857c478bd9Sstevel@tonic-gate 84867c478bd9Sstevel@tonic-gate ctrl = (uint_t)(ctrl & (uint32_t)HC_TD_CC); 84877c478bd9Sstevel@tonic-gate 84887c478bd9Sstevel@tonic-gate /* Write the status of isoc data packet */ 84897c478bd9Sstevel@tonic-gate isoc_pkt_descr->isoc_pkt_status = 84907c478bd9Sstevel@tonic-gate ohci_check_for_error(ohcip, pp, tw, td, ctrl); 84917c478bd9Sstevel@tonic-gate 84927c478bd9Sstevel@tonic-gate if (isoc_pkt_descr->isoc_pkt_status) { 84937c478bd9Sstevel@tonic-gate /* Increment isoc data packet error count */ 84947c478bd9Sstevel@tonic-gate isoc_reqp->isoc_error_count++; 84957c478bd9Sstevel@tonic-gate } 84967c478bd9Sstevel@tonic-gate 84977c478bd9Sstevel@tonic-gate /* 84987c478bd9Sstevel@tonic-gate * Get the address of next isoc data packet descriptor. 84997c478bd9Sstevel@tonic-gate */ 85007c478bd9Sstevel@tonic-gate isoc_pkt_descr++; 85017c478bd9Sstevel@tonic-gate } 8502b3001defSlg tw->tw_pkt_idx = tw->tw_pkt_idx + fc + 1; 8503b3001defSlg 8504b3001defSlg USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 8505b3001defSlg "ohci_parse_isoc_error: tw_pkt_idx %d", tw->tw_pkt_idx); 8506b3001defSlg 85077c478bd9Sstevel@tonic-gate } 85087c478bd9Sstevel@tonic-gate 85097c478bd9Sstevel@tonic-gate 85107c478bd9Sstevel@tonic-gate /* 85117c478bd9Sstevel@tonic-gate * ohci_check_for_error: 85127c478bd9Sstevel@tonic-gate * 85137c478bd9Sstevel@tonic-gate * Check for any errors. 85147c478bd9Sstevel@tonic-gate */ 85157c478bd9Sstevel@tonic-gate static usb_cr_t 85167c478bd9Sstevel@tonic-gate ohci_check_for_error( 85177c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 85187c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 85197c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 85207c478bd9Sstevel@tonic-gate ohci_td_t *td, 85217c478bd9Sstevel@tonic-gate uint_t ctrl) 85227c478bd9Sstevel@tonic-gate { 85237c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 85247c478bd9Sstevel@tonic-gate uchar_t ep_attrs = ph->p_ep.bmAttributes; 85257c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK; 85267c478bd9Sstevel@tonic-gate usb_req_attrs_t xfer_attrs; 85277c478bd9Sstevel@tonic-gate 85287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85297c478bd9Sstevel@tonic-gate "ohci_check_for_error: td = 0x%p ctrl = 0x%x", 85307c478bd9Sstevel@tonic-gate td, ctrl); 85317c478bd9Sstevel@tonic-gate 85327c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 85337c478bd9Sstevel@tonic-gate 85347c478bd9Sstevel@tonic-gate switch (ctrl) { 85357c478bd9Sstevel@tonic-gate case HC_TD_CC_NO_E: 85367c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85377c478bd9Sstevel@tonic-gate "ohci_check_for_error: No Error"); 85387c478bd9Sstevel@tonic-gate error = USB_CR_OK; 85397c478bd9Sstevel@tonic-gate break; 85407c478bd9Sstevel@tonic-gate case HC_TD_CC_CRC: 85417c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85427c478bd9Sstevel@tonic-gate "ohci_check_for_error: CRC error"); 85437c478bd9Sstevel@tonic-gate error = USB_CR_CRC; 85447c478bd9Sstevel@tonic-gate break; 85457c478bd9Sstevel@tonic-gate case HC_TD_CC_BS: 85467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85477c478bd9Sstevel@tonic-gate "ohci_check_for_error: Bit stuffing"); 85487c478bd9Sstevel@tonic-gate error = USB_CR_BITSTUFFING; 85497c478bd9Sstevel@tonic-gate break; 85507c478bd9Sstevel@tonic-gate case HC_TD_CC_DTM: 85517c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85527c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data Toggle Mismatch"); 85537c478bd9Sstevel@tonic-gate error = USB_CR_DATA_TOGGLE_MM; 85547c478bd9Sstevel@tonic-gate break; 85557c478bd9Sstevel@tonic-gate case HC_TD_CC_STALL: 85567c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85577c478bd9Sstevel@tonic-gate "ohci_check_for_error: Stall"); 85587c478bd9Sstevel@tonic-gate error = USB_CR_STALL; 85597c478bd9Sstevel@tonic-gate break; 85607c478bd9Sstevel@tonic-gate case HC_TD_CC_DNR: 85617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85627c478bd9Sstevel@tonic-gate "ohci_check_for_error: Device not responding"); 85637c478bd9Sstevel@tonic-gate error = USB_CR_DEV_NOT_RESP; 85647c478bd9Sstevel@tonic-gate break; 85657c478bd9Sstevel@tonic-gate case HC_TD_CC_PCF: 85667c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85677c478bd9Sstevel@tonic-gate "ohci_check_for_error: PID check failure"); 85687c478bd9Sstevel@tonic-gate error = USB_CR_PID_CHECKFAILURE; 85697c478bd9Sstevel@tonic-gate break; 85707c478bd9Sstevel@tonic-gate case HC_TD_CC_UPID: 85717c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85727c478bd9Sstevel@tonic-gate "ohci_check_for_error: Unexpected PID"); 85737c478bd9Sstevel@tonic-gate error = USB_CR_UNEXP_PID; 85747c478bd9Sstevel@tonic-gate break; 85757c478bd9Sstevel@tonic-gate case HC_TD_CC_DO: 85767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 85777c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data overrrun"); 85787c478bd9Sstevel@tonic-gate error = USB_CR_DATA_OVERRUN; 85797c478bd9Sstevel@tonic-gate break; 85807c478bd9Sstevel@tonic-gate case HC_TD_CC_DU: 85817c478bd9Sstevel@tonic-gate /* 85827c478bd9Sstevel@tonic-gate * Check whether short packets are acceptable. 85837c478bd9Sstevel@tonic-gate * If so don't report error to client drivers 85847c478bd9Sstevel@tonic-gate * and restart the endpoint. Otherwise report 85857c478bd9Sstevel@tonic-gate * data underrun error to client driver. 85867c478bd9Sstevel@tonic-gate */ 85877c478bd9Sstevel@tonic-gate xfer_attrs = ohci_get_xfer_attrs(ohcip, pp, tw); 85887c478bd9Sstevel@tonic-gate 85897c478bd9Sstevel@tonic-gate if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) { 85907c478bd9Sstevel@tonic-gate error = USB_CR_OK; 85917c478bd9Sstevel@tonic-gate if ((ep_attrs & USB_EP_ATTR_MASK) != 85927c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) { 85937c478bd9Sstevel@tonic-gate /* 85947c478bd9Sstevel@tonic-gate * Cleanup the remaining resources that may have 85957c478bd9Sstevel@tonic-gate * been allocated for this transfer. 85967c478bd9Sstevel@tonic-gate */ 85977c478bd9Sstevel@tonic-gate if (ohci_cleanup_data_underrun(ohcip, pp, tw, 85987c478bd9Sstevel@tonic-gate td) == USB_SUCCESS) { 85997c478bd9Sstevel@tonic-gate /* Clear the halt bit */ 86007c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 86017c478bd9Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) & 8602*29aca3ebSlc ~HC_EPT_Halt)); 86037c478bd9Sstevel@tonic-gate } else { 86047c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR; 86057c478bd9Sstevel@tonic-gate } 86067c478bd9Sstevel@tonic-gate } 86077c478bd9Sstevel@tonic-gate } else { 86087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86097c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data underrun"); 86107c478bd9Sstevel@tonic-gate 86117c478bd9Sstevel@tonic-gate error = USB_CR_DATA_UNDERRUN; 86127c478bd9Sstevel@tonic-gate } 86137c478bd9Sstevel@tonic-gate 86147c478bd9Sstevel@tonic-gate break; 86157c478bd9Sstevel@tonic-gate case HC_TD_CC_BO: 86167c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86177c478bd9Sstevel@tonic-gate "ohci_check_for_error: Buffer overrun"); 86187c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_OVERRUN; 86197c478bd9Sstevel@tonic-gate break; 86207c478bd9Sstevel@tonic-gate case HC_TD_CC_BU: 86217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86227c478bd9Sstevel@tonic-gate "ohci_check_for_error: Buffer underrun"); 86237c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_UNDERRUN; 86247c478bd9Sstevel@tonic-gate break; 86257c478bd9Sstevel@tonic-gate case HC_TD_CC_NA: 86267c478bd9Sstevel@tonic-gate default: 86277c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86287c478bd9Sstevel@tonic-gate "ohci_check_for_error: Not accessed"); 86297c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED; 86307c478bd9Sstevel@tonic-gate break; 86317c478bd9Sstevel@tonic-gate } 86327c478bd9Sstevel@tonic-gate 86337c478bd9Sstevel@tonic-gate if (error) { 86347c478bd9Sstevel@tonic-gate uint_t hced_ctrl = Get_ED(pp->pp_ept->hced_ctrl); 86357c478bd9Sstevel@tonic-gate 86367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86377c478bd9Sstevel@tonic-gate "ohci_check_for_error: Error %d Device address %d " 86387c478bd9Sstevel@tonic-gate "Endpoint number %d", error, (hced_ctrl & HC_EPT_FUNC), 86397c478bd9Sstevel@tonic-gate ((hced_ctrl & HC_EPT_EP) >> HC_EPT_EP_SHFT)); 86407c478bd9Sstevel@tonic-gate } 86417c478bd9Sstevel@tonic-gate 86427c478bd9Sstevel@tonic-gate return (error); 86437c478bd9Sstevel@tonic-gate } 86447c478bd9Sstevel@tonic-gate 86457c478bd9Sstevel@tonic-gate 86467c478bd9Sstevel@tonic-gate /* 86477c478bd9Sstevel@tonic-gate * ohci_handle_error: 86487c478bd9Sstevel@tonic-gate * 86497c478bd9Sstevel@tonic-gate * Inform USBA about occured transaction errors by calling the USBA callback 86507c478bd9Sstevel@tonic-gate * routine. 86517c478bd9Sstevel@tonic-gate */ 86527c478bd9Sstevel@tonic-gate static void 86537c478bd9Sstevel@tonic-gate ohci_handle_error( 86547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 86557c478bd9Sstevel@tonic-gate ohci_td_t *td, 86567c478bd9Sstevel@tonic-gate usb_cr_t error) 86577c478bd9Sstevel@tonic-gate { 86587c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw; 86597c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph; 86607c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; 86617c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 86627c478bd9Sstevel@tonic-gate size_t length = 0; 86637c478bd9Sstevel@tonic-gate uchar_t attributes; 86647c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 86657c478bd9Sstevel@tonic-gate 86667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 86677c478bd9Sstevel@tonic-gate "ohci_handle_error: error = 0x%x", error); 86687c478bd9Sstevel@tonic-gate 86697c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 86707c478bd9Sstevel@tonic-gate 86717c478bd9Sstevel@tonic-gate ASSERT(td != NULL); 86727c478bd9Sstevel@tonic-gate 86737c478bd9Sstevel@tonic-gate /* Print the values in the td */ 86747c478bd9Sstevel@tonic-gate ohci_print_td(ohcip, td); 86757c478bd9Sstevel@tonic-gate 86767c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */ 86777c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *) 86787c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)Get_TD(td->hctd_trans_wrapper)); 86797c478bd9Sstevel@tonic-gate 86807c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 86817c478bd9Sstevel@tonic-gate 86827c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 86837c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 86847c478bd9Sstevel@tonic-gate 86857c478bd9Sstevel@tonic-gate ph = tw->tw_pipe_private->pp_pipe_handle; 86867c478bd9Sstevel@tonic-gate attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK; 86877c478bd9Sstevel@tonic-gate 86887c478bd9Sstevel@tonic-gate /* 86897c478bd9Sstevel@tonic-gate * Special error handling 86907c478bd9Sstevel@tonic-gate */ 86917c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) { 86927c478bd9Sstevel@tonic-gate 86937c478bd9Sstevel@tonic-gate switch (attributes) { 86947c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 86957c478bd9Sstevel@tonic-gate if (((ph->p_ep.bmAttributes & 86967c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == 86977c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) && 86987c478bd9Sstevel@tonic-gate (Get_TD(td->hctd_ctrl_phase) == 86997c478bd9Sstevel@tonic-gate OHCI_CTRL_SETUP_PHASE)) { 87007c478bd9Sstevel@tonic-gate 87017c478bd9Sstevel@tonic-gate break; 87027c478bd9Sstevel@tonic-gate } 87037c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 87047c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 87057c478bd9Sstevel@tonic-gate /* 87067c478bd9Sstevel@tonic-gate * Call ohci_sendup_td_message 87077c478bd9Sstevel@tonic-gate * to send message to upstream. 87087c478bd9Sstevel@tonic-gate */ 87097c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, error); 87107c478bd9Sstevel@tonic-gate 87117c478bd9Sstevel@tonic-gate return; 87127c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 87137c478bd9Sstevel@tonic-gate curr_intr_reqp = 87147c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 87157c478bd9Sstevel@tonic-gate 87167c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & 87177c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 87187c478bd9Sstevel@tonic-gate 87197c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(ohcip, tw); 87207c478bd9Sstevel@tonic-gate } 87217c478bd9Sstevel@tonic-gate 87227c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 87237c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 87247c478bd9Sstevel@tonic-gate break; 87257c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 87267c478bd9Sstevel@tonic-gate default: 87277c478bd9Sstevel@tonic-gate break; 87287c478bd9Sstevel@tonic-gate } 87297c478bd9Sstevel@tonic-gate } else { 87307c478bd9Sstevel@tonic-gate switch (attributes) { 87317c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 87327c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 87337c478bd9Sstevel@tonic-gate /* 87347c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer 87357c478bd9Sstevel@tonic-gate * Descriptor (TD) is not equal to zero, 87367c478bd9Sstevel@tonic-gate * then we sent less data to the device 87377c478bd9Sstevel@tonic-gate * than requested by client. In that case, 87387c478bd9Sstevel@tonic-gate * return the mblk after updating the 87397c478bd9Sstevel@tonic-gate * data->r_ptr. 87407c478bd9Sstevel@tonic-gate */ 87417c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) { 87427c478bd9Sstevel@tonic-gate usb_opaque_t xfer_reqp = tw->tw_curr_xfer_reqp; 874302acac7eSsl size_t residue; 87447c478bd9Sstevel@tonic-gate 874502acac7eSsl residue = ohci_get_td_residue(ohcip, td); 874602acac7eSsl length = Get_TD(td->hctd_xfer_offs) + 874702acac7eSsl Get_TD(td->hctd_xfer_len) - residue; 87487c478bd9Sstevel@tonic-gate 87497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 87507c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, 87517c478bd9Sstevel@tonic-gate "ohci_handle_error: requested data %lu " 87527c478bd9Sstevel@tonic-gate "sent data %lu", tw->tw_length, length); 87537c478bd9Sstevel@tonic-gate 87547c478bd9Sstevel@tonic-gate if (attributes == USB_EP_ATTR_BULK) { 87557c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_bulk_req_t *) 87567c478bd9Sstevel@tonic-gate (xfer_reqp))->bulk_data; 87577c478bd9Sstevel@tonic-gate } else { 87587c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_intr_req_t *) 87597c478bd9Sstevel@tonic-gate (xfer_reqp))->intr_data; 87607c478bd9Sstevel@tonic-gate } 87617c478bd9Sstevel@tonic-gate 87627c478bd9Sstevel@tonic-gate /* Increment the read pointer */ 87637c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length; 87647c478bd9Sstevel@tonic-gate } 87657c478bd9Sstevel@tonic-gate break; 87667c478bd9Sstevel@tonic-gate default: 87677c478bd9Sstevel@tonic-gate break; 87687c478bd9Sstevel@tonic-gate } 87697c478bd9Sstevel@tonic-gate } 87707c478bd9Sstevel@tonic-gate 87717c478bd9Sstevel@tonic-gate /* 87727c478bd9Sstevel@tonic-gate * Callback the client with the 87737c478bd9Sstevel@tonic-gate * failure reason. 87747c478bd9Sstevel@tonic-gate */ 87757c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, error); 87767c478bd9Sstevel@tonic-gate 87777c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 87787c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(ohcip, pp); 87797c478bd9Sstevel@tonic-gate } 87807c478bd9Sstevel@tonic-gate 87817c478bd9Sstevel@tonic-gate /* 87827c478bd9Sstevel@tonic-gate * ohci_cleanup_data_underrun: 87837c478bd9Sstevel@tonic-gate * 87847c478bd9Sstevel@tonic-gate * Cleans up resources when a short xfer occurs 87857c478bd9Sstevel@tonic-gate */ 87867c478bd9Sstevel@tonic-gate static int 87877c478bd9Sstevel@tonic-gate ohci_cleanup_data_underrun( 87887c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 87897c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 87907c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 87917c478bd9Sstevel@tonic-gate ohci_td_t *td) 87927c478bd9Sstevel@tonic-gate { 87937c478bd9Sstevel@tonic-gate ohci_td_t *next_td; 87947c478bd9Sstevel@tonic-gate ohci_td_t *last_td; 87957c478bd9Sstevel@tonic-gate ohci_td_t *temp_td; 87967c478bd9Sstevel@tonic-gate uint32_t last_td_addr; 87977c478bd9Sstevel@tonic-gate uint_t hced_head; 87987c478bd9Sstevel@tonic-gate 87997c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 88007c478bd9Sstevel@tonic-gate "ohci_cleanup_data_underrun: td 0x%p, tw 0x%p", td, tw); 88017c478bd9Sstevel@tonic-gate 88027c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 88037c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_head == td); 88047c478bd9Sstevel@tonic-gate 88057c478bd9Sstevel@tonic-gate /* Check if this TD is the last td in the tw */ 88067c478bd9Sstevel@tonic-gate last_td = tw->tw_hctd_tail; 88077c478bd9Sstevel@tonic-gate if (td == last_td) { 88087c478bd9Sstevel@tonic-gate /* There is no need for cleanup */ 88097c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 88107c478bd9Sstevel@tonic-gate } 88117c478bd9Sstevel@tonic-gate 88127c478bd9Sstevel@tonic-gate /* 88137c478bd9Sstevel@tonic-gate * Make sure the ED is halted before we change any td's. 88147c478bd9Sstevel@tonic-gate * If for some reason it is not halted, return error to client 88157c478bd9Sstevel@tonic-gate * driver so they can reset the port. 88167c478bd9Sstevel@tonic-gate */ 88177c478bd9Sstevel@tonic-gate hced_head = Get_ED(pp->pp_ept->hced_headp); 88187c478bd9Sstevel@tonic-gate if (!(hced_head & HC_EPT_Halt)) { 88197c478bd9Sstevel@tonic-gate uint_t hced_ctrl = Get_ED(pp->pp_ept->hced_ctrl); 88207c478bd9Sstevel@tonic-gate 8821d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 88227c478bd9Sstevel@tonic-gate "ohci_cleanup_data_underrun: Unable to clean up a short " 88237c478bd9Sstevel@tonic-gate "xfer error. Client might send/receive irrelevant data." 88247c478bd9Sstevel@tonic-gate " Device address %d Endpoint number %d", 88257c478bd9Sstevel@tonic-gate (hced_ctrl & HC_EPT_FUNC), 88267c478bd9Sstevel@tonic-gate ((hced_ctrl & HC_EPT_EP) >> HC_EPT_EP_SHFT)); 88277c478bd9Sstevel@tonic-gate 88287c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, hced_head | HC_EPT_Halt); 88297c478bd9Sstevel@tonic-gate 88307c478bd9Sstevel@tonic-gate return (USB_FAILURE); 88317c478bd9Sstevel@tonic-gate } 88327c478bd9Sstevel@tonic-gate 88337c478bd9Sstevel@tonic-gate /* 88347c478bd9Sstevel@tonic-gate * Get the address of the first td of the next transfer (tw). 88357c478bd9Sstevel@tonic-gate * This td, may currently be a dummy td, but when a new request 88367c478bd9Sstevel@tonic-gate * arrives, it will be transformed into a regular td. 88377c478bd9Sstevel@tonic-gate */ 88387c478bd9Sstevel@tonic-gate last_td_addr = Get_TD(last_td->hctd_next_td); 88397c478bd9Sstevel@tonic-gate /* Set ED head to this last td */ 88407c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 88417c478bd9Sstevel@tonic-gate (last_td_addr & HC_EPT_TD_HEAD) | 88427c478bd9Sstevel@tonic-gate (hced_head & ~HC_EPT_TD_HEAD)); 88437c478bd9Sstevel@tonic-gate 88447c478bd9Sstevel@tonic-gate /* 88457c478bd9Sstevel@tonic-gate * Start removing all the unused TD's from the TW, 88467c478bd9Sstevel@tonic-gate * but keep the first one. 88477c478bd9Sstevel@tonic-gate */ 88487c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td; 88497c478bd9Sstevel@tonic-gate 88507c478bd9Sstevel@tonic-gate /* 88517c478bd9Sstevel@tonic-gate * Get the last_td, the next td in the tw list. 88527c478bd9Sstevel@tonic-gate * Afterwards completely disassociate the current td from other tds 88537c478bd9Sstevel@tonic-gate */ 88547c478bd9Sstevel@tonic-gate next_td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip, 88557c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td)); 88567c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL); 88577c478bd9Sstevel@tonic-gate 88587c478bd9Sstevel@tonic-gate /* 88597c478bd9Sstevel@tonic-gate * Iterate down the tw list and deallocate them 88607c478bd9Sstevel@tonic-gate */ 88617c478bd9Sstevel@tonic-gate while (next_td != NULL) { 88627c478bd9Sstevel@tonic-gate tw->tw_num_tds--; 88637c478bd9Sstevel@tonic-gate /* Disassociate this td from it's TW and set to RECLAIM */ 88647c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_trans_wrapper, NULL); 88657c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_state, HC_TD_RECLAIM); 88667c478bd9Sstevel@tonic-gate 88677c478bd9Sstevel@tonic-gate temp_td = next_td; 88687c478bd9Sstevel@tonic-gate 88697c478bd9Sstevel@tonic-gate next_td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip, 88707c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td)); 88717c478bd9Sstevel@tonic-gate 88727c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, temp_td); 88737c478bd9Sstevel@tonic-gate } 88747c478bd9Sstevel@tonic-gate 88757c478bd9Sstevel@tonic-gate ASSERT(tw->tw_num_tds == 1); 88767c478bd9Sstevel@tonic-gate 88777c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 88787c478bd9Sstevel@tonic-gate } 88797c478bd9Sstevel@tonic-gate 88807c478bd9Sstevel@tonic-gate /* 88817c478bd9Sstevel@tonic-gate * ohci_handle_normal_td: 88827c478bd9Sstevel@tonic-gate */ 88837c478bd9Sstevel@tonic-gate static void 88847c478bd9Sstevel@tonic-gate ohci_handle_normal_td( 88857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 88867c478bd9Sstevel@tonic-gate ohci_td_t *td, 88877c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 88887c478bd9Sstevel@tonic-gate { 88897c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; /* Pipe private field */ 88907c478bd9Sstevel@tonic-gate 88917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 88927c478bd9Sstevel@tonic-gate "ohci_handle_normal_td:"); 88937c478bd9Sstevel@tonic-gate 88947c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 88957c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 88967c478bd9Sstevel@tonic-gate 88977c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 88987c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 88997c478bd9Sstevel@tonic-gate 89007c478bd9Sstevel@tonic-gate (*tw->tw_handle_td)(ohcip, pp, tw, 89017c478bd9Sstevel@tonic-gate td, tw->tw_handle_callback_value); 89027c478bd9Sstevel@tonic-gate 89037c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */ 89047c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(ohcip, pp); 89057c478bd9Sstevel@tonic-gate } 89067c478bd9Sstevel@tonic-gate 89077c478bd9Sstevel@tonic-gate 89087c478bd9Sstevel@tonic-gate /* 89097c478bd9Sstevel@tonic-gate * ohci_handle_ctrl_td: 89107c478bd9Sstevel@tonic-gate * 89117c478bd9Sstevel@tonic-gate * Handle a control Transfer Descriptor (TD). 89127c478bd9Sstevel@tonic-gate */ 89137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 89147c478bd9Sstevel@tonic-gate static void 89157c478bd9Sstevel@tonic-gate ohci_handle_ctrl_td( 89167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 89177c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 89187c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 89197c478bd9Sstevel@tonic-gate ohci_td_t *td, 89207c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 89217c478bd9Sstevel@tonic-gate { 89227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 89237c478bd9Sstevel@tonic-gate 89247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89257c478bd9Sstevel@tonic-gate "ohci_handle_ctrl_td: pp = 0x%p tw = 0x%p td = 0x%p state = 0x%x", 89267c478bd9Sstevel@tonic-gate (void *)pp, (void *)tw, (void *)td, Get_TD(td->hctd_ctrl_phase)); 89277c478bd9Sstevel@tonic-gate 89287c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 89297c478bd9Sstevel@tonic-gate 89307c478bd9Sstevel@tonic-gate /* 89317c478bd9Sstevel@tonic-gate * Check which control transfer phase got completed. 89327c478bd9Sstevel@tonic-gate */ 89337c478bd9Sstevel@tonic-gate tw->tw_num_tds--; 89347c478bd9Sstevel@tonic-gate switch (Get_TD(td->hctd_ctrl_phase)) { 89357c478bd9Sstevel@tonic-gate case OHCI_CTRL_SETUP_PHASE: 89367c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89377c478bd9Sstevel@tonic-gate "Setup complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 89387c478bd9Sstevel@tonic-gate 89397c478bd9Sstevel@tonic-gate break; 89407c478bd9Sstevel@tonic-gate case OHCI_CTRL_DATA_PHASE: 89417c478bd9Sstevel@tonic-gate /* 89427c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor (TD) 89437c478bd9Sstevel@tonic-gate * is not equal to zero, then we received less data from 89447c478bd9Sstevel@tonic-gate * the device than requested by us. In that case, get the 89457c478bd9Sstevel@tonic-gate * actual received data size. 89467c478bd9Sstevel@tonic-gate */ 89477c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) { 894802acac7eSsl size_t length, residue; 89497c478bd9Sstevel@tonic-gate 895002acac7eSsl residue = ohci_get_td_residue(ohcip, td); 895102acac7eSsl length = Get_TD(td->hctd_xfer_offs) + 895202acac7eSsl Get_TD(td->hctd_xfer_len) - residue; 89537c478bd9Sstevel@tonic-gate 89547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89557c478bd9Sstevel@tonic-gate "ohci_handle_ctrl_qtd: requested data %lu " 89567c478bd9Sstevel@tonic-gate "received data %lu", tw->tw_length, length); 89577c478bd9Sstevel@tonic-gate 89587c478bd9Sstevel@tonic-gate /* Save actual received data length */ 89597c478bd9Sstevel@tonic-gate tw->tw_length = length; 89607c478bd9Sstevel@tonic-gate } 89617c478bd9Sstevel@tonic-gate 89627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89637c478bd9Sstevel@tonic-gate "Data complete: pp 0x%p td 0x%p", 89647c478bd9Sstevel@tonic-gate (void *)pp, (void *)td); 89657c478bd9Sstevel@tonic-gate 89667c478bd9Sstevel@tonic-gate break; 89677c478bd9Sstevel@tonic-gate case OHCI_CTRL_STATUS_PHASE: 89687c478bd9Sstevel@tonic-gate if ((tw->tw_length != 0) && 89697c478bd9Sstevel@tonic-gate (tw->tw_direction == HC_TD_IN)) { 89707c478bd9Sstevel@tonic-gate 89717c478bd9Sstevel@tonic-gate /* 89727c478bd9Sstevel@tonic-gate * Call ohci_sendup_td_message 89737c478bd9Sstevel@tonic-gate * to send message to upstream. 89747c478bd9Sstevel@tonic-gate */ 89757c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, 89767c478bd9Sstevel@tonic-gate pp, tw, td, USB_CR_OK); 89777c478bd9Sstevel@tonic-gate } else { 89787c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, 897902acac7eSsl tw->tw_length - OHCI_MAX_TD_BUF_SIZE, 89807c478bd9Sstevel@tonic-gate ph->p_ep.bmAttributes, 89817c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress); 89827c478bd9Sstevel@tonic-gate 89837c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 89847c478bd9Sstevel@tonic-gate } 89857c478bd9Sstevel@tonic-gate 89867c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 89877c478bd9Sstevel@tonic-gate "Status complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 89887c478bd9Sstevel@tonic-gate 89897c478bd9Sstevel@tonic-gate break; 89907c478bd9Sstevel@tonic-gate } 89917c478bd9Sstevel@tonic-gate } 89927c478bd9Sstevel@tonic-gate 89937c478bd9Sstevel@tonic-gate 89947c478bd9Sstevel@tonic-gate /* 89957c478bd9Sstevel@tonic-gate * ohci_handle_bulk_td: 89967c478bd9Sstevel@tonic-gate * 89977c478bd9Sstevel@tonic-gate * Handle a bulk Transfer Descriptor (TD). 89987c478bd9Sstevel@tonic-gate */ 89997c478bd9Sstevel@tonic-gate /* ARGSUSED */ 90007c478bd9Sstevel@tonic-gate static void 90017c478bd9Sstevel@tonic-gate ohci_handle_bulk_td( 90027c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 90037c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 90047c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 90057c478bd9Sstevel@tonic-gate ohci_td_t *td, 90067c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 90077c478bd9Sstevel@tonic-gate { 90087c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 90097c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 90107c478bd9Sstevel@tonic-gate 90117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 90127c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td:"); 90137c478bd9Sstevel@tonic-gate 90147c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 90157c478bd9Sstevel@tonic-gate 90167c478bd9Sstevel@tonic-gate /* 90177c478bd9Sstevel@tonic-gate * Decrement the TDs counter and check whether all the bulk 90187c478bd9Sstevel@tonic-gate * data has been send or received. If TDs counter reaches 90197c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 90207c478bd9Sstevel@tonic-gate * bulk request. Other wise wait for completion of other bulk 90217c478bd9Sstevel@tonic-gate * TDs or transactions on this pipe. 90227c478bd9Sstevel@tonic-gate */ 90237c478bd9Sstevel@tonic-gate if (--tw->tw_num_tds != 0) { 90247c478bd9Sstevel@tonic-gate 90257c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 90267c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td: Number of TDs %d", tw->tw_num_tds); 90277c478bd9Sstevel@tonic-gate 90287c478bd9Sstevel@tonic-gate return; 90297c478bd9Sstevel@tonic-gate } 90307c478bd9Sstevel@tonic-gate 90317c478bd9Sstevel@tonic-gate /* 90327c478bd9Sstevel@tonic-gate * If this is a bulk in pipe, return the data to the client. 90337c478bd9Sstevel@tonic-gate * For a bulk out pipe, there is no need to do anything. 90347c478bd9Sstevel@tonic-gate */ 90357c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & 90367c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 90377c478bd9Sstevel@tonic-gate 90387c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 90397c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td: Bulk out pipe"); 90407c478bd9Sstevel@tonic-gate 90417c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length, 90427c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 90437c478bd9Sstevel@tonic-gate 90447c478bd9Sstevel@tonic-gate /* Do the callback */ 90457c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 90467c478bd9Sstevel@tonic-gate 90477c478bd9Sstevel@tonic-gate return; 90487c478bd9Sstevel@tonic-gate } 90497c478bd9Sstevel@tonic-gate 90507c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to send message to upstream */ 90517c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK); 90527c478bd9Sstevel@tonic-gate } 90537c478bd9Sstevel@tonic-gate 90547c478bd9Sstevel@tonic-gate 90557c478bd9Sstevel@tonic-gate /* 90567c478bd9Sstevel@tonic-gate * ohci_handle_intr_td: 90577c478bd9Sstevel@tonic-gate * 90587c478bd9Sstevel@tonic-gate * Handle a interrupt Transfer Descriptor (TD). 90597c478bd9Sstevel@tonic-gate */ 90607c478bd9Sstevel@tonic-gate /* ARGSUSED */ 90617c478bd9Sstevel@tonic-gate static void 90627c478bd9Sstevel@tonic-gate ohci_handle_intr_td( 90637c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 90647c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 90657c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 90667c478bd9Sstevel@tonic-gate ohci_td_t *td, 90677c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 90687c478bd9Sstevel@tonic-gate { 90697c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 9070*29aca3ebSlc (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 90717c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 90727c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 90737c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs; 90747c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 90757c478bd9Sstevel@tonic-gate 90767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 90777c478bd9Sstevel@tonic-gate "ohci_handle_intr_td: pp=0x%p tw=0x%p td=0x%p" 90787c478bd9Sstevel@tonic-gate "intr_reqp=0%p data=0x%p", pp, tw, td, curr_intr_reqp, 90797c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_data); 90807c478bd9Sstevel@tonic-gate 90817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 90827c478bd9Sstevel@tonic-gate 90837c478bd9Sstevel@tonic-gate /* Get the interrupt xfer attributes */ 90847c478bd9Sstevel@tonic-gate attrs = curr_intr_reqp->intr_attributes; 90857c478bd9Sstevel@tonic-gate 90867c478bd9Sstevel@tonic-gate /* 90877c478bd9Sstevel@tonic-gate * For a Interrupt OUT pipe, we just callback and we are done 90887c478bd9Sstevel@tonic-gate */ 90897c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 90907c478bd9Sstevel@tonic-gate 90917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 90927c478bd9Sstevel@tonic-gate "ohci_handle_intr_td: Intr out pipe, intr_reqp=0x%p," 90937c478bd9Sstevel@tonic-gate "data=0x%p", curr_intr_reqp, curr_intr_reqp->intr_data); 90947c478bd9Sstevel@tonic-gate 90957c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length, 90967c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 90977c478bd9Sstevel@tonic-gate 90987c478bd9Sstevel@tonic-gate /* Do the callback */ 90997c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 91007c478bd9Sstevel@tonic-gate 91017c478bd9Sstevel@tonic-gate return; 91027c478bd9Sstevel@tonic-gate } 91037c478bd9Sstevel@tonic-gate 91047c478bd9Sstevel@tonic-gate /* Decrement number of interrupt request count */ 91057c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 91067c478bd9Sstevel@tonic-gate 91077c478bd9Sstevel@tonic-gate /* 91087c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_XFER flag is set 91097c478bd9Sstevel@tonic-gate * and if so, free duplicate request. 91107c478bd9Sstevel@tonic-gate */ 91117c478bd9Sstevel@tonic-gate if (attrs & USB_ATTRS_ONE_XFER) { 91127c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(ohcip, tw); 91137c478bd9Sstevel@tonic-gate } 91147c478bd9Sstevel@tonic-gate 91157c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to callback into client */ 91167c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK); 91177c478bd9Sstevel@tonic-gate 91187c478bd9Sstevel@tonic-gate /* 91197c478bd9Sstevel@tonic-gate * If interrupt pipe state is still active, insert next Interrupt 91207c478bd9Sstevel@tonic-gate * request into the Host Controller's Interrupt list. Otherwise 91217c478bd9Sstevel@tonic-gate * you are done. 91227c478bd9Sstevel@tonic-gate */ 91237c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) { 91247c478bd9Sstevel@tonic-gate return; 91257c478bd9Sstevel@tonic-gate } 91267c478bd9Sstevel@tonic-gate 91277c478bd9Sstevel@tonic-gate if ((error = ohci_allocate_periodic_in_resource(ohcip, pp, tw, 0)) == 91287c478bd9Sstevel@tonic-gate USB_SUCCESS) { 91297c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 91307c478bd9Sstevel@tonic-gate 91317c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp != NULL); 91327c478bd9Sstevel@tonic-gate 91337c478bd9Sstevel@tonic-gate tw->tw_num_tds = 1; 91347c478bd9Sstevel@tonic-gate 913502acac7eSsl if (ohci_tw_rebind_cookie(ohcip, pp, tw) != USB_SUCCESS) { 913602acac7eSsl ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 913702acac7eSsl error = USB_FAILURE; 913802acac7eSsl } else if (ohci_allocate_tds_for_tw(ohcip, tw, 913902acac7eSsl tw->tw_num_tds) != USB_SUCCESS) { 91407c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 91417c478bd9Sstevel@tonic-gate error = USB_FAILURE; 91427c478bd9Sstevel@tonic-gate } 91437c478bd9Sstevel@tonic-gate } 91447c478bd9Sstevel@tonic-gate 91457c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 91467c478bd9Sstevel@tonic-gate /* 91477c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 91487c478bd9Sstevel@tonic-gate * resource. Don't insert any more interrupt polling 91497c478bd9Sstevel@tonic-gate * requests. 91507c478bd9Sstevel@tonic-gate */ 91517c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 91527c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 91537c478bd9Sstevel@tonic-gate } else { 91547c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, pp, tw, 0); 91557c478bd9Sstevel@tonic-gate 91567c478bd9Sstevel@tonic-gate /* Increment number of interrupt request count */ 91577c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 91587c478bd9Sstevel@tonic-gate 91597c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 91607c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 91617c478bd9Sstevel@tonic-gate } 91627c478bd9Sstevel@tonic-gate } 91637c478bd9Sstevel@tonic-gate 91647c478bd9Sstevel@tonic-gate 91657c478bd9Sstevel@tonic-gate /* 91667c478bd9Sstevel@tonic-gate * ohci_handle_one_xfer_completion: 91677c478bd9Sstevel@tonic-gate */ 91687c478bd9Sstevel@tonic-gate static void 91697c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion( 91707c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 91717c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 91727c478bd9Sstevel@tonic-gate { 91737c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = tw->tw_pipe_private->pp_pipe_handle; 91747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = tw->tw_pipe_private; 91757c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = 9176*29aca3ebSlc (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 91777c478bd9Sstevel@tonic-gate 91787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 91797c478bd9Sstevel@tonic-gate "ohci_handle_one_xfer_completion: tw = 0x%p", tw); 91807c478bd9Sstevel@tonic-gate 91817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 91827c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER); 91837c478bd9Sstevel@tonic-gate 91847c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 91857c478bd9Sstevel@tonic-gate 91867c478bd9Sstevel@tonic-gate /* 91877c478bd9Sstevel@tonic-gate * For one xfer, we need to copy back data ptr 91887c478bd9Sstevel@tonic-gate * and free current request 91897c478bd9Sstevel@tonic-gate */ 91907c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))-> 91917c478bd9Sstevel@tonic-gate intr_data = ((usb_intr_req_t *) 91927c478bd9Sstevel@tonic-gate (tw->tw_curr_xfer_reqp))->intr_data; 91937c478bd9Sstevel@tonic-gate 91947c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL; 91957c478bd9Sstevel@tonic-gate 91967c478bd9Sstevel@tonic-gate /* Now free duplicate current request */ 91977c478bd9Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp); 91987c478bd9Sstevel@tonic-gate 91997c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 92007c478bd9Sstevel@tonic-gate ph->p_req_count--; 92017c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 92027c478bd9Sstevel@tonic-gate 92037c478bd9Sstevel@tonic-gate /* Make client's request the current request */ 92047c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 92057c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 92067c478bd9Sstevel@tonic-gate } 92077c478bd9Sstevel@tonic-gate 92087c478bd9Sstevel@tonic-gate 92097c478bd9Sstevel@tonic-gate /* 92107c478bd9Sstevel@tonic-gate * ohci_handle_isoc_td: 92117c478bd9Sstevel@tonic-gate * 92127c478bd9Sstevel@tonic-gate * Handle an isochronous Transfer Descriptor (TD). 92137c478bd9Sstevel@tonic-gate */ 92147c478bd9Sstevel@tonic-gate /* ARGSUSED */ 92157c478bd9Sstevel@tonic-gate static void 92167c478bd9Sstevel@tonic-gate ohci_handle_isoc_td( 92177c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 92187c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 92197c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 92207c478bd9Sstevel@tonic-gate ohci_td_t *td, 92217c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 92227c478bd9Sstevel@tonic-gate { 92237c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 92247c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 92257c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp = 9226*29aca3ebSlc (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 92277c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 92287c478bd9Sstevel@tonic-gate 92297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 92307c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: pp=0x%p tw=0x%p td=0x%p" 92317c478bd9Sstevel@tonic-gate "isoc_reqp=0%p data=0x%p", pp, tw, td, curr_isoc_reqp, 92327c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_data); 92337c478bd9Sstevel@tonic-gate 92347c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 92357c478bd9Sstevel@tonic-gate 92367c478bd9Sstevel@tonic-gate /* 92377c478bd9Sstevel@tonic-gate * Decrement the TDs counter and check whether all the isoc 92387c478bd9Sstevel@tonic-gate * data has been send or received. If TDs counter reaches 92397c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 92407c478bd9Sstevel@tonic-gate * isoc request. Otherwise wait for completion of other isoc 92417c478bd9Sstevel@tonic-gate * TDs or transactions on this pipe. 92427c478bd9Sstevel@tonic-gate */ 92437c478bd9Sstevel@tonic-gate if (--tw->tw_num_tds != 0) { 92447c478bd9Sstevel@tonic-gate 92457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 92467c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: Number of TDs %d", tw->tw_num_tds); 92477c478bd9Sstevel@tonic-gate 92487c478bd9Sstevel@tonic-gate return; 92497c478bd9Sstevel@tonic-gate } 92507c478bd9Sstevel@tonic-gate 92517c478bd9Sstevel@tonic-gate /* 92527c478bd9Sstevel@tonic-gate * If this is a isoc in pipe, return the data to the client. 92537c478bd9Sstevel@tonic-gate * For a isoc out pipe, there is no need to do anything. 92547c478bd9Sstevel@tonic-gate */ 92557c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) { 92567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 92577c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: Isoc out pipe, isoc_reqp=0x%p," 92587c478bd9Sstevel@tonic-gate "data=0x%p", curr_isoc_reqp, curr_isoc_reqp->isoc_data); 92597c478bd9Sstevel@tonic-gate 92607c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length, 92617c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 92627c478bd9Sstevel@tonic-gate 92637c478bd9Sstevel@tonic-gate /* Do the callback */ 92647c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK); 92657c478bd9Sstevel@tonic-gate 92667c478bd9Sstevel@tonic-gate return; 92677c478bd9Sstevel@tonic-gate } 92687c478bd9Sstevel@tonic-gate 92697c478bd9Sstevel@tonic-gate /* Decrement number of IN isochronous request count */ 92707c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 92717c478bd9Sstevel@tonic-gate 92727c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to send message to upstream */ 92737c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK); 92747c478bd9Sstevel@tonic-gate 92757c478bd9Sstevel@tonic-gate /* 92767c478bd9Sstevel@tonic-gate * If isochronous pipe state is still active, insert next isochronous 92777c478bd9Sstevel@tonic-gate * request into the Host Controller's isochronous list. 92787c478bd9Sstevel@tonic-gate */ 92797c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) { 92807c478bd9Sstevel@tonic-gate return; 92817c478bd9Sstevel@tonic-gate } 92827c478bd9Sstevel@tonic-gate 92837c478bd9Sstevel@tonic-gate if ((error = ohci_allocate_periodic_in_resource(ohcip, pp, tw, 0)) == 92847c478bd9Sstevel@tonic-gate USB_SUCCESS) { 92857c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp; 92867c478bd9Sstevel@tonic-gate 92877c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL); 92887c478bd9Sstevel@tonic-gate 92897c478bd9Sstevel@tonic-gate tw->tw_num_tds = 92907c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_pkts_count / OHCI_ISOC_PKTS_PER_TD; 92917c478bd9Sstevel@tonic-gate if (curr_isoc_reqp->isoc_pkts_count % OHCI_ISOC_PKTS_PER_TD) { 92927c478bd9Sstevel@tonic-gate tw->tw_num_tds++; 92937c478bd9Sstevel@tonic-gate } 92947c478bd9Sstevel@tonic-gate 929502acac7eSsl if (ohci_tw_rebind_cookie(ohcip, pp, tw) != USB_SUCCESS) { 929602acac7eSsl ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 929702acac7eSsl error = USB_FAILURE; 929802acac7eSsl } else if (ohci_allocate_tds_for_tw(ohcip, tw, 929902acac7eSsl tw->tw_num_tds) != USB_SUCCESS) { 93007c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw); 93017c478bd9Sstevel@tonic-gate error = USB_FAILURE; 93027c478bd9Sstevel@tonic-gate } 93037c478bd9Sstevel@tonic-gate } 93047c478bd9Sstevel@tonic-gate 93057c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS || 93067c478bd9Sstevel@tonic-gate ohci_insert_isoc_req(ohcip, pp, tw, 0) != USB_SUCCESS) { 93077c478bd9Sstevel@tonic-gate /* 93087c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 93097c478bd9Sstevel@tonic-gate * resource. Don't insert any more isoch polling 93107c478bd9Sstevel@tonic-gate * requests. 93117c478bd9Sstevel@tonic-gate */ 93127c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING; 93137c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 93147c478bd9Sstevel@tonic-gate 93157c478bd9Sstevel@tonic-gate } else { 93167c478bd9Sstevel@tonic-gate /* Increment number of IN isochronous request count */ 93177c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 93187c478bd9Sstevel@tonic-gate 93197c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 93207c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 93217c478bd9Sstevel@tonic-gate } 93227c478bd9Sstevel@tonic-gate } 93237c478bd9Sstevel@tonic-gate 93247c478bd9Sstevel@tonic-gate 932502acac7eSsl /* 932602acac7eSsl * ohci_tw_rebind_cookie: 932702acac7eSsl * 932802acac7eSsl * If the cookie associated with a DMA buffer has been walked, the cookie 932902acac7eSsl * is not usable any longer. To reuse the DMA buffer, the DMA handle needs 933002acac7eSsl * to rebind for cookies. 933102acac7eSsl */ 933202acac7eSsl static int 933302acac7eSsl ohci_tw_rebind_cookie( 933402acac7eSsl ohci_state_t *ohcip, 933502acac7eSsl ohci_pipe_private_t *pp, 933602acac7eSsl ohci_trans_wrapper_t *tw) 933702acac7eSsl { 933802acac7eSsl usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 933902acac7eSsl int rval, i; 934002acac7eSsl uint_t ccount; 934102acac7eSsl 934202acac7eSsl USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 934302acac7eSsl "ohci_tw_rebind_cookie:"); 934402acac7eSsl 934502acac7eSsl ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 934602acac7eSsl 934702acac7eSsl if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 934802acac7eSsl ASSERT(tw->tw_num_tds == tw->tw_ncookies); 934902acac7eSsl 935002acac7eSsl for (i = 0; i < tw->tw_num_tds; i++) { 935102acac7eSsl if (tw->tw_isoc_bufs[i].ncookies == 1) { 935202acac7eSsl 935302acac7eSsl /* 935402acac7eSsl * no need to rebind when there is 935502acac7eSsl * only one cookie in a buffer 935602acac7eSsl */ 935702acac7eSsl continue; 935802acac7eSsl } 935902acac7eSsl 936002acac7eSsl /* unbind the DMA handle before rebinding */ 936102acac7eSsl rval = ddi_dma_unbind_handle( 936202acac7eSsl tw->tw_isoc_bufs[i].dma_handle); 936302acac7eSsl ASSERT(rval == USB_SUCCESS); 936402acac7eSsl tw->tw_isoc_bufs[i].ncookies = 0; 936502acac7eSsl 936602acac7eSsl USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 936702acac7eSsl "rebind dma_handle %d", i); 936802acac7eSsl 936902acac7eSsl /* rebind the handle to get cookies */ 937002acac7eSsl rval = ddi_dma_addr_bind_handle( 937102acac7eSsl tw->tw_isoc_bufs[i].dma_handle, NULL, 937202acac7eSsl (caddr_t)tw->tw_isoc_bufs[i].buf_addr, 937302acac7eSsl tw->tw_isoc_bufs[i].length, 937402acac7eSsl DDI_DMA_RDWR|DDI_DMA_CONSISTENT, 937502acac7eSsl DDI_DMA_DONTWAIT, NULL, 937602acac7eSsl &tw->tw_isoc_bufs[i].cookie, &ccount); 937702acac7eSsl 937802acac7eSsl if ((rval == DDI_DMA_MAPPED) && 937902acac7eSsl (ccount <= OHCI_DMA_ATTR_TD_SGLLEN)) { 938002acac7eSsl tw->tw_isoc_bufs[i].ncookies = ccount; 938102acac7eSsl } else { 938202acac7eSsl 938302acac7eSsl return (USB_NO_RESOURCES); 938402acac7eSsl } 938502acac7eSsl } 938602acac7eSsl } else { 938702acac7eSsl if (tw->tw_cookie_idx != 0) { 938802acac7eSsl /* unbind the DMA handle before rebinding */ 938902acac7eSsl rval = ddi_dma_unbind_handle(tw->tw_dmahandle); 939002acac7eSsl ASSERT(rval == DDI_SUCCESS); 939102acac7eSsl tw->tw_ncookies = 0; 939202acac7eSsl 939302acac7eSsl USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 939402acac7eSsl "rebind dma_handle"); 939502acac7eSsl 939602acac7eSsl /* rebind the handle to get cookies */ 939702acac7eSsl rval = ddi_dma_addr_bind_handle( 939802acac7eSsl tw->tw_dmahandle, NULL, 939902acac7eSsl (caddr_t)tw->tw_buf, tw->tw_length, 940002acac7eSsl DDI_DMA_RDWR|DDI_DMA_CONSISTENT, 940102acac7eSsl DDI_DMA_DONTWAIT, NULL, 940202acac7eSsl &tw->tw_cookie, &ccount); 940302acac7eSsl 940402acac7eSsl if (rval == DDI_DMA_MAPPED) { 940502acac7eSsl tw->tw_ncookies = ccount; 940602acac7eSsl tw->tw_dma_offs = 0; 940702acac7eSsl tw->tw_cookie_idx = 0; 940802acac7eSsl } else { 940902acac7eSsl 941002acac7eSsl return (USB_NO_RESOURCES); 941102acac7eSsl } 941202acac7eSsl } 941302acac7eSsl } 941402acac7eSsl 941502acac7eSsl return (USB_SUCCESS); 941602acac7eSsl } 941702acac7eSsl 941802acac7eSsl 94197c478bd9Sstevel@tonic-gate /* 94207c478bd9Sstevel@tonic-gate * ohci_sendup_td_message: 94217c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback 94227c478bd9Sstevel@tonic-gate */ 94237c478bd9Sstevel@tonic-gate static void 94247c478bd9Sstevel@tonic-gate ohci_sendup_td_message( 94257c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 94267c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 94277c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 94287c478bd9Sstevel@tonic-gate ohci_td_t *td, 94297c478bd9Sstevel@tonic-gate usb_cr_t error) 94307c478bd9Sstevel@tonic-gate { 94317c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 94327c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 943302acac7eSsl size_t length = 0, skip_len = 0, residue; 94347c478bd9Sstevel@tonic-gate mblk_t *mp; 94357c478bd9Sstevel@tonic-gate uchar_t *buf; 94367c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp; 94377c478bd9Sstevel@tonic-gate 94387c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 94397c478bd9Sstevel@tonic-gate 94407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 94417c478bd9Sstevel@tonic-gate "ohci_sendup_td_message:"); 94427c478bd9Sstevel@tonic-gate 94437c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 94447c478bd9Sstevel@tonic-gate 94457c478bd9Sstevel@tonic-gate length = tw->tw_length; 94467c478bd9Sstevel@tonic-gate 94477c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 94487c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 94497c478bd9Sstevel@tonic-gate /* 94507c478bd9Sstevel@tonic-gate * Get the correct length, adjust it for the setup size 94517c478bd9Sstevel@tonic-gate * which is not part of the data length in control end 94527c478bd9Sstevel@tonic-gate * points. Update tw->tw_length for future references. 94537c478bd9Sstevel@tonic-gate */ 945402acac7eSsl if (((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_wLength) { 945502acac7eSsl tw->tw_length = length = length - OHCI_MAX_TD_BUF_SIZE; 945602acac7eSsl } else { 945702acac7eSsl tw->tw_length = length = length - SETUP_SIZE; 945802acac7eSsl } 94597c478bd9Sstevel@tonic-gate 94607c478bd9Sstevel@tonic-gate /* Set the length of the buffer to skip */ 946102acac7eSsl skip_len = OHCI_MAX_TD_BUF_SIZE; 94627c478bd9Sstevel@tonic-gate 94637c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_ctrl_phase) != OHCI_CTRL_DATA_PHASE) { 94647c478bd9Sstevel@tonic-gate break; 94657c478bd9Sstevel@tonic-gate } 94667c478bd9Sstevel@tonic-gate /* FALLTHRU */ 94677c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 94687c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 94697c478bd9Sstevel@tonic-gate /* 94707c478bd9Sstevel@tonic-gate * If error is "data overrun", do not check for the 94717c478bd9Sstevel@tonic-gate * "CurrentBufferPointer" and return whatever data 94727c478bd9Sstevel@tonic-gate * received to the client driver. 94737c478bd9Sstevel@tonic-gate */ 94747c478bd9Sstevel@tonic-gate if (error == USB_CR_DATA_OVERRUN) { 94757c478bd9Sstevel@tonic-gate break; 94767c478bd9Sstevel@tonic-gate } 94777c478bd9Sstevel@tonic-gate 94787c478bd9Sstevel@tonic-gate /* 94797c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor 94807c478bd9Sstevel@tonic-gate * (TD) is not equal to zero, then we received less 94817c478bd9Sstevel@tonic-gate * data from the device than requested by us. In that 94827c478bd9Sstevel@tonic-gate * case, get the actual received data size. 94837c478bd9Sstevel@tonic-gate */ 94847c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) { 948502acac7eSsl residue = ohci_get_td_residue(ohcip, td); 948602acac7eSsl length = Get_TD(td->hctd_xfer_offs) + 948702acac7eSsl Get_TD(td->hctd_xfer_len) - residue - skip_len; 94887c478bd9Sstevel@tonic-gate 94897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 94907c478bd9Sstevel@tonic-gate "ohci_sendup_qtd_message: requested data %lu " 94917c478bd9Sstevel@tonic-gate "received data %lu", tw->tw_length, length); 94927c478bd9Sstevel@tonic-gate } 94937c478bd9Sstevel@tonic-gate 94947c478bd9Sstevel@tonic-gate break; 94957c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 94967c478bd9Sstevel@tonic-gate default: 94977c478bd9Sstevel@tonic-gate break; 94987c478bd9Sstevel@tonic-gate } 94997c478bd9Sstevel@tonic-gate 95007c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */ 95017c478bd9Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf + skip_len; 95027c478bd9Sstevel@tonic-gate 95037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 95047c478bd9Sstevel@tonic-gate "ohci_sendup_qtd_message: length %lu error %d", length, error); 95057c478bd9Sstevel@tonic-gate 95067c478bd9Sstevel@tonic-gate /* Get the message block */ 95077c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 95087c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 95097c478bd9Sstevel@tonic-gate mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data; 95107c478bd9Sstevel@tonic-gate break; 95117c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 95127c478bd9Sstevel@tonic-gate mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data; 95137c478bd9Sstevel@tonic-gate break; 95147c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 95157c478bd9Sstevel@tonic-gate mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data; 95167c478bd9Sstevel@tonic-gate break; 95177c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 95187c478bd9Sstevel@tonic-gate mp = ((usb_isoc_req_t *)curr_xfer_reqp)->isoc_data; 95197c478bd9Sstevel@tonic-gate break; 95207c478bd9Sstevel@tonic-gate } 95217c478bd9Sstevel@tonic-gate 95227c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 95237c478bd9Sstevel@tonic-gate 95247c478bd9Sstevel@tonic-gate if (length) { 952502acac7eSsl int i; 952602acac7eSsl uchar_t *p = mp->b_rptr; 952702acac7eSsl 95287c478bd9Sstevel@tonic-gate /* 95297c478bd9Sstevel@tonic-gate * Update kstat byte counts 95307c478bd9Sstevel@tonic-gate * The control endpoints don't have direction bits so in 95317c478bd9Sstevel@tonic-gate * order for control stats to be counted correctly an in 95327c478bd9Sstevel@tonic-gate * bit must be faked on a control read. 95337c478bd9Sstevel@tonic-gate */ 95347c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 95357c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) { 95367c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, length, 95377c478bd9Sstevel@tonic-gate eptd->bmAttributes, USB_EP_DIR_IN); 95387c478bd9Sstevel@tonic-gate } else { 95397c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, length, 95407c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress); 95417c478bd9Sstevel@tonic-gate } 95427c478bd9Sstevel@tonic-gate 954302acac7eSsl if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 954402acac7eSsl USB_EP_ATTR_ISOCH) { 954502acac7eSsl for (i = 0; i < tw->tw_ncookies; i++) { 954602acac7eSsl Sync_IO_Buffer( 954702acac7eSsl tw->tw_isoc_bufs[i].dma_handle, 954802acac7eSsl tw->tw_isoc_bufs[i].length); 954902acac7eSsl 955002acac7eSsl ddi_rep_get8(tw->tw_isoc_bufs[i].mem_handle, 955102acac7eSsl p, (uint8_t *)tw->tw_isoc_bufs[i].buf_addr, 955202acac7eSsl tw->tw_isoc_bufs[i].length, 955302acac7eSsl DDI_DEV_AUTOINCR); 955402acac7eSsl p += tw->tw_isoc_bufs[i].length; 955502acac7eSsl } 9556b3001defSlg tw->tw_pkt_idx = 0; 955702acac7eSsl } else { 955802acac7eSsl /* Sync IO buffer */ 955902acac7eSsl Sync_IO_Buffer(tw->tw_dmahandle, (skip_len + length)); 95607c478bd9Sstevel@tonic-gate 956102acac7eSsl /* Copy the data into the message */ 956202acac7eSsl ddi_rep_get8(tw->tw_accesshandle, 956302acac7eSsl mp->b_rptr, buf, length, DDI_DEV_AUTOINCR); 956402acac7eSsl } 95657c478bd9Sstevel@tonic-gate 95667c478bd9Sstevel@tonic-gate /* Increment the write pointer */ 95677c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length; 95687c478bd9Sstevel@tonic-gate } else { 95697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 95707c478bd9Sstevel@tonic-gate "ohci_sendup_td_message: Zero length packet"); 95717c478bd9Sstevel@tonic-gate } 95727c478bd9Sstevel@tonic-gate 95737c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, error); 95747c478bd9Sstevel@tonic-gate } 95757c478bd9Sstevel@tonic-gate 95767c478bd9Sstevel@tonic-gate 957702acac7eSsl /* 957802acac7eSsl * ohci_get_td_residue: 957902acac7eSsl * 958002acac7eSsl * Calculate the bytes not transfered by the TD 958102acac7eSsl */ 958202acac7eSsl size_t 958302acac7eSsl ohci_get_td_residue( 958402acac7eSsl ohci_state_t *ohcip, 958502acac7eSsl ohci_td_t *td) 958602acac7eSsl { 958702acac7eSsl uint32_t buf_addr, end_addr; 958802acac7eSsl size_t residue; 958902acac7eSsl 959002acac7eSsl buf_addr = Get_TD(td->hctd_cbp); 959102acac7eSsl end_addr = Get_TD(td->hctd_buf_end); 959202acac7eSsl 959302acac7eSsl if ((buf_addr & 0xfffff000) == 959402acac7eSsl (end_addr & 0xfffff000)) { 959502acac7eSsl residue = end_addr - buf_addr + 1; 959602acac7eSsl } else { 959702acac7eSsl residue = OHCI_MAX_TD_BUF_SIZE - 959802acac7eSsl (buf_addr & 0x00000fff) + 959902acac7eSsl (end_addr & 0x00000fff) + 1; 960002acac7eSsl } 960102acac7eSsl 960202acac7eSsl return (residue); 960302acac7eSsl } 960402acac7eSsl 960502acac7eSsl 96067c478bd9Sstevel@tonic-gate /* 96077c478bd9Sstevel@tonic-gate * Miscellaneous functions 96087c478bd9Sstevel@tonic-gate */ 96097c478bd9Sstevel@tonic-gate 96107c478bd9Sstevel@tonic-gate /* 96117c478bd9Sstevel@tonic-gate * ohci_obtain_state: 96127c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 96137c478bd9Sstevel@tonic-gate */ 96147c478bd9Sstevel@tonic-gate ohci_state_t * 96157c478bd9Sstevel@tonic-gate ohci_obtain_state(dev_info_t *dip) 96167c478bd9Sstevel@tonic-gate { 96177c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 9618*29aca3ebSlc ohci_state_t *state = ddi_get_soft_state( 9619*29aca3ebSlc ohci_statep, instance); 96207c478bd9Sstevel@tonic-gate 96217c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 96227c478bd9Sstevel@tonic-gate 96237c478bd9Sstevel@tonic-gate return (state); 96247c478bd9Sstevel@tonic-gate } 96257c478bd9Sstevel@tonic-gate 96267c478bd9Sstevel@tonic-gate 96277c478bd9Sstevel@tonic-gate /* 96287c478bd9Sstevel@tonic-gate * ohci_state_is_operational: 96297c478bd9Sstevel@tonic-gate * 96307c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 96317c478bd9Sstevel@tonic-gate */ 96327c478bd9Sstevel@tonic-gate int 96337c478bd9Sstevel@tonic-gate ohci_state_is_operational(ohci_state_t *ohcip) 96347c478bd9Sstevel@tonic-gate { 96357c478bd9Sstevel@tonic-gate int val; 96367c478bd9Sstevel@tonic-gate 96377c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 96387c478bd9Sstevel@tonic-gate 96397c478bd9Sstevel@tonic-gate switch (ohcip->ohci_hc_soft_state) { 96407c478bd9Sstevel@tonic-gate case OHCI_CTLR_INIT_STATE: 96417c478bd9Sstevel@tonic-gate case OHCI_CTLR_SUSPEND_STATE: 96427c478bd9Sstevel@tonic-gate val = USB_FAILURE; 96437c478bd9Sstevel@tonic-gate break; 96447c478bd9Sstevel@tonic-gate case OHCI_CTLR_OPERATIONAL_STATE: 96457c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 96467c478bd9Sstevel@tonic-gate break; 96477c478bd9Sstevel@tonic-gate case OHCI_CTLR_ERROR_STATE: 96487c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 96497c478bd9Sstevel@tonic-gate break; 96507c478bd9Sstevel@tonic-gate default: 96517c478bd9Sstevel@tonic-gate val = USB_FAILURE; 96527c478bd9Sstevel@tonic-gate break; 96537c478bd9Sstevel@tonic-gate } 96547c478bd9Sstevel@tonic-gate 96557c478bd9Sstevel@tonic-gate return (val); 96567c478bd9Sstevel@tonic-gate } 96577c478bd9Sstevel@tonic-gate 96587c478bd9Sstevel@tonic-gate 96597c478bd9Sstevel@tonic-gate /* 96607c478bd9Sstevel@tonic-gate * ohci_do_soft_reset 96617c478bd9Sstevel@tonic-gate * 96627c478bd9Sstevel@tonic-gate * Do soft reset of ohci host controller. 96637c478bd9Sstevel@tonic-gate */ 96647c478bd9Sstevel@tonic-gate int 96657c478bd9Sstevel@tonic-gate ohci_do_soft_reset(ohci_state_t *ohcip) 96667c478bd9Sstevel@tonic-gate { 96677c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 96687c478bd9Sstevel@tonic-gate timeout_id_t xfer_timer_id, rh_timer_id; 96697c478bd9Sstevel@tonic-gate ohci_regs_t *ohci_save_regs; 96707c478bd9Sstevel@tonic-gate ohci_td_t *done_head; 96717c478bd9Sstevel@tonic-gate 96727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 96737c478bd9Sstevel@tonic-gate 96747c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 96757c478bd9Sstevel@tonic-gate ohcip->ohci_hc_error++; 96767c478bd9Sstevel@tonic-gate 96777c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 96787c478bd9Sstevel@tonic-gate "ohci_do_soft_reset:" 96797c478bd9Sstevel@tonic-gate "Reset ohci host controller 0x%x", ohcip->ohci_hc_error); 96807c478bd9Sstevel@tonic-gate 96817c478bd9Sstevel@tonic-gate /* 96827c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 96837c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 96847c478bd9Sstevel@tonic-gate * fails. 96857c478bd9Sstevel@tonic-gate */ 96867c478bd9Sstevel@tonic-gate ohci_save_regs = (ohci_regs_t *) 96877c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ohci_regs_t), KM_NOSLEEP); 96887c478bd9Sstevel@tonic-gate 96897c478bd9Sstevel@tonic-gate if (ohci_save_regs == NULL) { 96907c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 96917c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: kmem_zalloc failed"); 96927c478bd9Sstevel@tonic-gate 96937c478bd9Sstevel@tonic-gate return (USB_FAILURE); 96947c478bd9Sstevel@tonic-gate } 96957c478bd9Sstevel@tonic-gate 96967c478bd9Sstevel@tonic-gate /* Save current ohci registers */ 96977c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_control = Get_OpReg(hcr_control); 96987c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_cmd_status = Get_OpReg(hcr_cmd_status); 96997c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_intr_enable = Get_OpReg(hcr_intr_enable); 97007c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_periodic_strt = Get_OpReg(hcr_periodic_strt); 97017c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_frame_interval = Get_OpReg(hcr_frame_interval); 97027c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_HCCA = Get_OpReg(hcr_HCCA); 97037c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_bulk_head = Get_OpReg(hcr_bulk_head); 97047c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_ctrl_head = Get_OpReg(hcr_ctrl_head); 97057c478bd9Sstevel@tonic-gate 97067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 97077c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Save reg = 0x%p", ohci_save_regs); 97087c478bd9Sstevel@tonic-gate 97097c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 97107c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE | 97117c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE))); 97127c478bd9Sstevel@tonic-gate 97137c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SO | 97147c478bd9Sstevel@tonic-gate HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE | 97157c478bd9Sstevel@tonic-gate HCR_INTR_FNO | HCR_INTR_SOF | HCR_INTR_MIE); 97167c478bd9Sstevel@tonic-gate 97177c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 97187c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 97197c478bd9Sstevel@tonic-gate 97207c478bd9Sstevel@tonic-gate /* Root hub interrupt pipe timeout id */ 97217c478bd9Sstevel@tonic-gate rh_timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id; 97227c478bd9Sstevel@tonic-gate 97237c478bd9Sstevel@tonic-gate /* Stop the root hub interrupt timer */ 97247c478bd9Sstevel@tonic-gate if (rh_timer_id) { 97257c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0; 97267c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state = 97277c478bd9Sstevel@tonic-gate OHCI_PIPE_STATE_IDLE; 97287c478bd9Sstevel@tonic-gate 97297c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 97307c478bd9Sstevel@tonic-gate (void) untimeout(rh_timer_id); 97317c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 97327c478bd9Sstevel@tonic-gate } 97337c478bd9Sstevel@tonic-gate 97347c478bd9Sstevel@tonic-gate /* Transfer timeout id */ 97357c478bd9Sstevel@tonic-gate xfer_timer_id = ohcip->ohci_timer_id; 97367c478bd9Sstevel@tonic-gate 97377c478bd9Sstevel@tonic-gate /* Stop the global transfer timer */ 97387c478bd9Sstevel@tonic-gate if (xfer_timer_id) { 97397c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0; 97407c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 97417c478bd9Sstevel@tonic-gate (void) untimeout(xfer_timer_id); 97427c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 97437c478bd9Sstevel@tonic-gate } 97447c478bd9Sstevel@tonic-gate 97457c478bd9Sstevel@tonic-gate /* Process any pending HCCA DoneHead */ 97467c478bd9Sstevel@tonic-gate done_head = (ohci_td_t *)(uintptr_t) 9747e026ab87Sgc (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & HCCA_DONE_HEAD_MASK); 97487c478bd9Sstevel@tonic-gate 9749688b07c5Sgc if (ohci_check_done_head(ohcip, done_head) == USB_SUCCESS) { 97507c478bd9Sstevel@tonic-gate /* Reset the done head to NULL */ 97517c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, NULL); 97527c478bd9Sstevel@tonic-gate 97537c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head); 97547c478bd9Sstevel@tonic-gate } 97557c478bd9Sstevel@tonic-gate 97567c478bd9Sstevel@tonic-gate /* Process any pending hcr_done_head value */ 9757e026ab87Sgc done_head = (ohci_td_t *)(uintptr_t) 9758*29aca3ebSlc (Get_OpReg(hcr_done_head) & HCCA_DONE_HEAD_MASK); 9759688b07c5Sgc if (ohci_check_done_head(ohcip, done_head) == USB_SUCCESS) { 9760688b07c5Sgc 9761688b07c5Sgc ohci_traverse_done_list(ohcip, done_head); 97627c478bd9Sstevel@tonic-gate } 97637c478bd9Sstevel@tonic-gate 97647c478bd9Sstevel@tonic-gate /* Do soft reset of ohci host controller */ 97657c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET); 97667c478bd9Sstevel@tonic-gate 97677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 97687c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Reset in progress"); 97697c478bd9Sstevel@tonic-gate 97707c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 97717c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESET_TIMEWAIT); 97727c478bd9Sstevel@tonic-gate 97737c478bd9Sstevel@tonic-gate /* Reset HCCA HcFrameNumber */ 97747c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaFrameNo, 0x00000000); 97757c478bd9Sstevel@tonic-gate 97767c478bd9Sstevel@tonic-gate /* 97777c478bd9Sstevel@tonic-gate * Restore previous saved HC register value 97787c478bd9Sstevel@tonic-gate * into the current HC registers. 97797c478bd9Sstevel@tonic-gate */ 97807c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_strt, (uint32_t) 97817c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_periodic_strt); 97827c478bd9Sstevel@tonic-gate 97837c478bd9Sstevel@tonic-gate Set_OpReg(hcr_frame_interval, (uint32_t) 97847c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_frame_interval); 97857c478bd9Sstevel@tonic-gate 97867c478bd9Sstevel@tonic-gate Set_OpReg(hcr_done_head, 0x0); 97877c478bd9Sstevel@tonic-gate 97887c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, 0x0); 97897c478bd9Sstevel@tonic-gate 97907c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, (uint32_t) 97917c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_bulk_head); 97927c478bd9Sstevel@tonic-gate 97937c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, 0x0); 97947c478bd9Sstevel@tonic-gate 97957c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, (uint32_t) 97967c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_ctrl_head); 97977c478bd9Sstevel@tonic-gate 97987c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_curr, 0x0); 97997c478bd9Sstevel@tonic-gate 98007c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, (uint32_t) 98017c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_HCCA); 98027c478bd9Sstevel@tonic-gate 98037c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_status, 0x0); 98047c478bd9Sstevel@tonic-gate 98057c478bd9Sstevel@tonic-gate /* 98067c478bd9Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except 98077c478bd9Sstevel@tonic-gate * Root Hub Status change interrupt. 98087c478bd9Sstevel@tonic-gate */ 98097c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, 98107c478bd9Sstevel@tonic-gate HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE | 98117c478bd9Sstevel@tonic-gate HCR_INTR_FNO | HCR_INTR_SOF | HCR_INTR_MIE); 98127c478bd9Sstevel@tonic-gate 98137c478bd9Sstevel@tonic-gate /* Start Control and Bulk list processing */ 98147c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, (HCR_STATUS_CLF | HCR_STATUS_BLF)); 98157c478bd9Sstevel@tonic-gate 98167c478bd9Sstevel@tonic-gate /* 98177c478bd9Sstevel@tonic-gate * Start up Control, Bulk, Periodic and Isochronous lists 98187c478bd9Sstevel@tonic-gate * processing. 98197c478bd9Sstevel@tonic-gate */ 98207c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (uint32_t) 98217c478bd9Sstevel@tonic-gate (ohci_save_regs->hcr_control & (~HCR_CONTROL_HCFS))); 98227c478bd9Sstevel@tonic-gate 98237c478bd9Sstevel@tonic-gate /* 98247c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 98257c478bd9Sstevel@tonic-gate * HC registers. 98267c478bd9Sstevel@tonic-gate */ 98277c478bd9Sstevel@tonic-gate kmem_free((void *) ohci_save_regs, sizeof (ohci_regs_t)); 98287c478bd9Sstevel@tonic-gate 98297c478bd9Sstevel@tonic-gate /* Resume the host controller */ 98307c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) & 98317c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESUME)); 98327c478bd9Sstevel@tonic-gate 98337c478bd9Sstevel@tonic-gate /* Wait for resume to complete */ 98347c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESUME_TIMEWAIT); 98357c478bd9Sstevel@tonic-gate 98367c478bd9Sstevel@tonic-gate /* Set the Host Controller Functional State to Operational */ 98377c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) & 98387c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_OPERAT)); 98397c478bd9Sstevel@tonic-gate 98407c478bd9Sstevel@tonic-gate /* Wait 10ms for HC to start sending SOF */ 98417c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 98427c478bd9Sstevel@tonic-gate 98437c478bd9Sstevel@tonic-gate /* 98447c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few 98457c478bd9Sstevel@tonic-gate * milliseconds. 98467c478bd9Sstevel@tonic-gate */ 98477c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip); 98487c478bd9Sstevel@tonic-gate 98497c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 98507c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT); 98517c478bd9Sstevel@tonic-gate 98527c478bd9Sstevel@tonic-gate /* 98537c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for few 98547c478bd9Sstevel@tonic-gate * milliseconds. 98557c478bd9Sstevel@tonic-gate */ 98567c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip); 98577c478bd9Sstevel@tonic-gate 98587c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 98597c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Before Frm No 0x%llx After Frm No 0x%llx", 98607c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 98617c478bd9Sstevel@tonic-gate 98627c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 98637c478bd9Sstevel@tonic-gate 98647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl, 98657c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Soft reset failed"); 98667c478bd9Sstevel@tonic-gate 98677c478bd9Sstevel@tonic-gate return (USB_FAILURE); 98687c478bd9Sstevel@tonic-gate } 98697c478bd9Sstevel@tonic-gate 98707c478bd9Sstevel@tonic-gate /* Start the timer for the root hub interrupt pipe polling */ 98717c478bd9Sstevel@tonic-gate if (rh_timer_id) { 98727c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 98737c478bd9Sstevel@tonic-gate timeout(ohci_handle_root_hub_status_change, 98747c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME)); 98757c478bd9Sstevel@tonic-gate 98767c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub. 98777c478bd9Sstevel@tonic-gate rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE; 98787c478bd9Sstevel@tonic-gate } 98797c478bd9Sstevel@tonic-gate 98807c478bd9Sstevel@tonic-gate /* Start the global timer */ 98817c478bd9Sstevel@tonic-gate if (xfer_timer_id) { 98827c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = timeout(ohci_xfer_timeout_handler, 98837c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(1000000)); 98847c478bd9Sstevel@tonic-gate } 98857c478bd9Sstevel@tonic-gate 98867c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 98877c478bd9Sstevel@tonic-gate } 98887c478bd9Sstevel@tonic-gate 98897c478bd9Sstevel@tonic-gate 98907c478bd9Sstevel@tonic-gate /* 98917c478bd9Sstevel@tonic-gate * ohci_get_current_frame_number: 98927c478bd9Sstevel@tonic-gate * 98937c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 98947c478bd9Sstevel@tonic-gate */ 98957c478bd9Sstevel@tonic-gate usb_frame_number_t 98967c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohci_state_t *ohcip) 98977c478bd9Sstevel@tonic-gate { 98987c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 98997c478bd9Sstevel@tonic-gate usb_frame_number_t ohci_fno, frame_number; 99007c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = 9901*29aca3ebSlc &ohcip->ohci_save_intr_sts; 99027c478bd9Sstevel@tonic-gate 99037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 99047c478bd9Sstevel@tonic-gate 99057c478bd9Sstevel@tonic-gate /* 99067c478bd9Sstevel@tonic-gate * Sync HCCA area only if this function 99077c478bd9Sstevel@tonic-gate * is invoked in non interrupt context. 99087c478bd9Sstevel@tonic-gate */ 99097c478bd9Sstevel@tonic-gate if (!(ohci_intr_sts->ohci_intr_flag & 99107c478bd9Sstevel@tonic-gate OHCI_INTR_HANDLING)) { 99117c478bd9Sstevel@tonic-gate 99127c478bd9Sstevel@tonic-gate /* Sync HCCA area */ 99137c478bd9Sstevel@tonic-gate Sync_HCCA(ohcip); 99147c478bd9Sstevel@tonic-gate } 99157c478bd9Sstevel@tonic-gate 99167c478bd9Sstevel@tonic-gate ohci_fno = ohcip->ohci_fno; 99177c478bd9Sstevel@tonic-gate frame_number = Get_HCCA(ohcip->ohci_hccap->HccaFrameNo); 99187c478bd9Sstevel@tonic-gate 99197c478bd9Sstevel@tonic-gate /* 99207c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 99217c478bd9Sstevel@tonic-gate * 99227c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 99237c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ohci driver 99247c478bd9Sstevel@tonic-gate * gets an FrameNumberOverflow (FNO) interrupt that will 99257c478bd9Sstevel@tonic-gate * adjust Frame higher part. 99267c478bd9Sstevel@tonic-gate * 99277c478bd9Sstevel@tonic-gate * Refer ohci specification 1.0a, section 5.4, page 86. 99287c478bd9Sstevel@tonic-gate */ 99297c478bd9Sstevel@tonic-gate usb_frame_number = ((frame_number & 0x7FFF) | ohci_fno) + 99307c478bd9Sstevel@tonic-gate (((frame_number & 0xFFFF) ^ ohci_fno) & 0x8000); 99317c478bd9Sstevel@tonic-gate 99327c478bd9Sstevel@tonic-gate return (usb_frame_number); 99337c478bd9Sstevel@tonic-gate } 99347c478bd9Sstevel@tonic-gate 99357c478bd9Sstevel@tonic-gate 99367c478bd9Sstevel@tonic-gate /* 99377c478bd9Sstevel@tonic-gate * ohci_cpr_cleanup: 99387c478bd9Sstevel@tonic-gate * 99397c478bd9Sstevel@tonic-gate * Cleanup ohci state and other ohci specific informations across 99407c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 99417c478bd9Sstevel@tonic-gate */ 99427c478bd9Sstevel@tonic-gate static void 99437c478bd9Sstevel@tonic-gate ohci_cpr_cleanup(ohci_state_t *ohcip) 99447c478bd9Sstevel@tonic-gate { 99457c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 99467c478bd9Sstevel@tonic-gate 99477c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 99487c478bd9Sstevel@tonic-gate ohcip->ohci_fno = 0; 99497c478bd9Sstevel@tonic-gate 99507c478bd9Sstevel@tonic-gate /* Reset Schedule Overrrun Error Counter */ 99517c478bd9Sstevel@tonic-gate ohcip->ohci_so_error = 0; 99527c478bd9Sstevel@tonic-gate 99537c478bd9Sstevel@tonic-gate /* Reset HCCA HcFrameNumber */ 99547c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaFrameNo, 0x00000000); 99557c478bd9Sstevel@tonic-gate } 99567c478bd9Sstevel@tonic-gate 99577c478bd9Sstevel@tonic-gate 99587c478bd9Sstevel@tonic-gate /* 99597c478bd9Sstevel@tonic-gate * ohci_get_xfer_attrs: 99607c478bd9Sstevel@tonic-gate * 99617c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 99627c478bd9Sstevel@tonic-gate */ 99637c478bd9Sstevel@tonic-gate static usb_req_attrs_t 99647c478bd9Sstevel@tonic-gate ohci_get_xfer_attrs( 99657c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 99667c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 99677c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 99687c478bd9Sstevel@tonic-gate { 99697c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 99707c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = 0; 99717c478bd9Sstevel@tonic-gate 99727c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 99737c478bd9Sstevel@tonic-gate "ohci_get_xfer_attrs:"); 99747c478bd9Sstevel@tonic-gate 99757c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 99767c478bd9Sstevel@tonic-gate 99777c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 99787c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 99797c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 99807c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 99817c478bd9Sstevel@tonic-gate break; 99827c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 99837c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 99847c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 99857c478bd9Sstevel@tonic-gate break; 99867c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 99877c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 99887c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 99897c478bd9Sstevel@tonic-gate break; 99907c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 99917c478bd9Sstevel@tonic-gate attrs = ((usb_isoc_req_t *) 99927c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->isoc_attributes; 99937c478bd9Sstevel@tonic-gate break; 99947c478bd9Sstevel@tonic-gate } 99957c478bd9Sstevel@tonic-gate 99967c478bd9Sstevel@tonic-gate return (attrs); 99977c478bd9Sstevel@tonic-gate } 99987c478bd9Sstevel@tonic-gate 99997c478bd9Sstevel@tonic-gate 100007c478bd9Sstevel@tonic-gate /* 100017c478bd9Sstevel@tonic-gate * ohci_allocate_periodic_in_resource 100027c478bd9Sstevel@tonic-gate * 100037c478bd9Sstevel@tonic-gate * Allocate interrupt/isochronous request structure for the 100047c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. 100057c478bd9Sstevel@tonic-gate */ 100067c478bd9Sstevel@tonic-gate static int 100077c478bd9Sstevel@tonic-gate ohci_allocate_periodic_in_resource( 100087c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 100097c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 100107c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 100117c478bd9Sstevel@tonic-gate usb_flags_t flags) 100127c478bd9Sstevel@tonic-gate { 100137c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 100147c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes; 100157c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 100167c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp; 100177c478bd9Sstevel@tonic-gate usb_opaque_t client_periodic_in_reqp; 100187c478bd9Sstevel@tonic-gate size_t length = 0; 100197c478bd9Sstevel@tonic-gate 100207c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 100217c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource:" 100227c478bd9Sstevel@tonic-gate "pp = 0x%p tw = 0x%p flags = 0x%x", pp, tw, flags); 100237c478bd9Sstevel@tonic-gate 100247c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 100257c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp == NULL); 100267c478bd9Sstevel@tonic-gate 100277c478bd9Sstevel@tonic-gate /* Get the client periodic in request pointer */ 100287c478bd9Sstevel@tonic-gate client_periodic_in_reqp = pp->pp_client_periodic_in_reqp; 100297c478bd9Sstevel@tonic-gate 100307c478bd9Sstevel@tonic-gate /* 100317c478bd9Sstevel@tonic-gate * If it a periodic IN request and periodic request is NULL, 100327c478bd9Sstevel@tonic-gate * allocate corresponding usb periodic IN request for the 100337c478bd9Sstevel@tonic-gate * current periodic polling request and copy the information 100347c478bd9Sstevel@tonic-gate * from the saved periodic request structure. 100357c478bd9Sstevel@tonic-gate */ 100367c478bd9Sstevel@tonic-gate if ((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 100377c478bd9Sstevel@tonic-gate 100387c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp) { 100397c478bd9Sstevel@tonic-gate 100407c478bd9Sstevel@tonic-gate /* Get the interrupt transfer length */ 100417c478bd9Sstevel@tonic-gate length = ((usb_intr_req_t *) 10042*29aca3ebSlc client_periodic_in_reqp)->intr_len; 100437c478bd9Sstevel@tonic-gate 100447c478bd9Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req( 100457c478bd9Sstevel@tonic-gate ph->p_dip, (usb_intr_req_t *) 100467c478bd9Sstevel@tonic-gate client_periodic_in_reqp, length, flags); 100477c478bd9Sstevel@tonic-gate } else { 100487c478bd9Sstevel@tonic-gate curr_intr_reqp = usb_alloc_intr_req( 100497c478bd9Sstevel@tonic-gate ph->p_dip, length, flags); 100507c478bd9Sstevel@tonic-gate } 100517c478bd9Sstevel@tonic-gate 100527c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) { 100537c478bd9Sstevel@tonic-gate 100547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 100557c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource: Interrupt " 100567c478bd9Sstevel@tonic-gate "request structure allocation failed"); 100577c478bd9Sstevel@tonic-gate 100587c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 100597c478bd9Sstevel@tonic-gate } 100607c478bd9Sstevel@tonic-gate 100617c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp == NULL) { 100627c478bd9Sstevel@tonic-gate /* For polled mode */ 100637c478bd9Sstevel@tonic-gate curr_intr_reqp-> 100647c478bd9Sstevel@tonic-gate intr_attributes = USB_ATTRS_SHORT_XFER_OK; 100657c478bd9Sstevel@tonic-gate curr_intr_reqp-> 100667c478bd9Sstevel@tonic-gate intr_len = ph->p_ep.wMaxPacketSize; 100677c478bd9Sstevel@tonic-gate } else { 100687c478bd9Sstevel@tonic-gate /* Check and save the timeout value */ 100697c478bd9Sstevel@tonic-gate tw->tw_timeout = (curr_intr_reqp->intr_attributes & 100707c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) ? 100717c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_timeout: 0; 100727c478bd9Sstevel@tonic-gate } 100737c478bd9Sstevel@tonic-gate 100747c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)curr_intr_reqp; 100757c478bd9Sstevel@tonic-gate tw->tw_length = curr_intr_reqp->intr_len; 100767c478bd9Sstevel@tonic-gate } else { 100777c478bd9Sstevel@tonic-gate ASSERT(client_periodic_in_reqp != NULL); 100787c478bd9Sstevel@tonic-gate 100797c478bd9Sstevel@tonic-gate curr_isoc_reqp = usba_hcdi_dup_isoc_req(ph->p_dip, 100807c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)client_periodic_in_reqp, flags); 100817c478bd9Sstevel@tonic-gate 100827c478bd9Sstevel@tonic-gate if (curr_isoc_reqp == NULL) { 100837c478bd9Sstevel@tonic-gate 100847c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 100857c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource: Isochronous" 100867c478bd9Sstevel@tonic-gate "request structure allocation failed"); 100877c478bd9Sstevel@tonic-gate 100887c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 100897c478bd9Sstevel@tonic-gate } 100907c478bd9Sstevel@tonic-gate 100917c478bd9Sstevel@tonic-gate /* 100927c478bd9Sstevel@tonic-gate * Save the client's isochronous request pointer and 100937c478bd9Sstevel@tonic-gate * length of isochronous transfer in transfer wrapper. 100947c478bd9Sstevel@tonic-gate * The dup'ed request is saved in pp_client_periodic_in_reqp 100957c478bd9Sstevel@tonic-gate */ 100967c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = 100977c478bd9Sstevel@tonic-gate (usb_opaque_t)pp->pp_client_periodic_in_reqp; 100987c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = (usb_opaque_t)curr_isoc_reqp; 100997c478bd9Sstevel@tonic-gate } 101007c478bd9Sstevel@tonic-gate 101017c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 101027c478bd9Sstevel@tonic-gate ph->p_req_count++; 101037c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 101047c478bd9Sstevel@tonic-gate 101057c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_ACTIVE; 101067c478bd9Sstevel@tonic-gate 101077c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 101087c478bd9Sstevel@tonic-gate } 101097c478bd9Sstevel@tonic-gate 101107c478bd9Sstevel@tonic-gate 101117c478bd9Sstevel@tonic-gate /* 101127c478bd9Sstevel@tonic-gate * ohci_wait_for_sof: 101137c478bd9Sstevel@tonic-gate * 101147c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 101157c478bd9Sstevel@tonic-gate */ 101167c478bd9Sstevel@tonic-gate static int 101177c478bd9Sstevel@tonic-gate ohci_wait_for_sof(ohci_state_t *ohcip) 101187c478bd9Sstevel@tonic-gate { 101197c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 101207c478bd9Sstevel@tonic-gate clock_t sof_time_wait; 101217c478bd9Sstevel@tonic-gate int rval, sof_wait_count; 101227c478bd9Sstevel@tonic-gate 101237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 101247c478bd9Sstevel@tonic-gate "ohci_wait_for_sof"); 101257c478bd9Sstevel@tonic-gate 101267c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 101277c478bd9Sstevel@tonic-gate 101287c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 101297c478bd9Sstevel@tonic-gate 101307c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 101317c478bd9Sstevel@tonic-gate 101327c478bd9Sstevel@tonic-gate return (rval); 101337c478bd9Sstevel@tonic-gate } 101347c478bd9Sstevel@tonic-gate 101357c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 101367c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz(OHCI_MAX_SOF_TIMEWAIT * 1000000); 101377c478bd9Sstevel@tonic-gate 101387c478bd9Sstevel@tonic-gate sof_wait_count = 0; 101397c478bd9Sstevel@tonic-gate 101407c478bd9Sstevel@tonic-gate /* 101417c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for the 101427c478bd9Sstevel@tonic-gate * SOF interrupt event. 101437c478bd9Sstevel@tonic-gate */ 101447c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip); 101457c478bd9Sstevel@tonic-gate 101467c478bd9Sstevel@tonic-gate while (sof_wait_count < MAX_SOF_WAIT_COUNT) { 101477c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */ 101487c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF); 101497c478bd9Sstevel@tonic-gate 101507c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_intr_enable) & HCR_INTR_SOF); 101517c478bd9Sstevel@tonic-gate 101527c478bd9Sstevel@tonic-gate /* Wait for the SOF or timeout event */ 101537c478bd9Sstevel@tonic-gate rval = cv_timedwait(&ohcip->ohci_SOF_cv, 101547c478bd9Sstevel@tonic-gate &ohcip->ohci_int_mutex, ddi_get_lbolt() + sof_time_wait); 101557c478bd9Sstevel@tonic-gate 101567c478bd9Sstevel@tonic-gate /* 101577c478bd9Sstevel@tonic-gate * Get the current usb frame number after woken up either 101587c478bd9Sstevel@tonic-gate * from SOF interrupt or timer expired event. 101597c478bd9Sstevel@tonic-gate */ 101607c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip); 101617c478bd9Sstevel@tonic-gate 101627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 101637c478bd9Sstevel@tonic-gate "ohci_wait_for_sof: before 0x%llx, after 0x%llx", 101647c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 101657c478bd9Sstevel@tonic-gate 101667c478bd9Sstevel@tonic-gate /* 101677c478bd9Sstevel@tonic-gate * Return failure, if we are woken up becuase of timer expired 101687c478bd9Sstevel@tonic-gate * event and if usb frame number has not been changed. 101697c478bd9Sstevel@tonic-gate */ 101707c478bd9Sstevel@tonic-gate if ((rval == -1) && 101717c478bd9Sstevel@tonic-gate (after_frame_number <= before_frame_number)) { 101727c478bd9Sstevel@tonic-gate 101737c478bd9Sstevel@tonic-gate if ((ohci_do_soft_reset(ohcip)) != USB_SUCCESS) { 101747c478bd9Sstevel@tonic-gate 101757c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 101767c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, "No SOF interrupts"); 101777c478bd9Sstevel@tonic-gate 101787c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 101797c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = 101807c478bd9Sstevel@tonic-gate OHCI_CTLR_ERROR_STATE; 101817c478bd9Sstevel@tonic-gate 101827c478bd9Sstevel@tonic-gate return (USB_FAILURE); 101837c478bd9Sstevel@tonic-gate } 101847c478bd9Sstevel@tonic-gate 101857c478bd9Sstevel@tonic-gate /* Get new usb frame number */ 101867c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number = 101877c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohcip); 101887c478bd9Sstevel@tonic-gate } 101897c478bd9Sstevel@tonic-gate 101907c478bd9Sstevel@tonic-gate ASSERT(after_frame_number >= before_frame_number); 101917c478bd9Sstevel@tonic-gate 101927c478bd9Sstevel@tonic-gate before_frame_number = after_frame_number; 101937c478bd9Sstevel@tonic-gate sof_wait_count++; 101947c478bd9Sstevel@tonic-gate } 101957c478bd9Sstevel@tonic-gate 101967c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 101977c478bd9Sstevel@tonic-gate } 101987c478bd9Sstevel@tonic-gate 101997c478bd9Sstevel@tonic-gate 102007c478bd9Sstevel@tonic-gate /* 102017c478bd9Sstevel@tonic-gate * ohci_pipe_cleanup 102027c478bd9Sstevel@tonic-gate * 102037c478bd9Sstevel@tonic-gate * Cleanup ohci pipe. 102047c478bd9Sstevel@tonic-gate */ 102057c478bd9Sstevel@tonic-gate static void 102067c478bd9Sstevel@tonic-gate ohci_pipe_cleanup( 102077c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 102087c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 102097c478bd9Sstevel@tonic-gate { 102107c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 102117c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 102127c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 102137c478bd9Sstevel@tonic-gate uint_t pipe_state = pp->pp_state; 102147c478bd9Sstevel@tonic-gate uint_t bit = 0; 102157c478bd9Sstevel@tonic-gate 102167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 102177c478bd9Sstevel@tonic-gate "ohci_pipe_cleanup: ph = 0x%p", ph); 102187c478bd9Sstevel@tonic-gate 102197c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 102207c478bd9Sstevel@tonic-gate 102217c478bd9Sstevel@tonic-gate switch (pipe_state) { 102227c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_CLOSE: 102237c478bd9Sstevel@tonic-gate if (OHCI_NON_PERIODIC_ENDPOINT(eptd)) { 102247c478bd9Sstevel@tonic-gate 102257c478bd9Sstevel@tonic-gate bit = ((eptd->bmAttributes & 102267c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) ? 102277c478bd9Sstevel@tonic-gate HCR_CONTROL_CLE: HCR_CONTROL_BLE; 102287c478bd9Sstevel@tonic-gate 102297c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, 102307c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(bit))); 102317c478bd9Sstevel@tonic-gate 102327c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 102337c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip); 102347c478bd9Sstevel@tonic-gate 102357c478bd9Sstevel@tonic-gate break; 102367c478bd9Sstevel@tonic-gate } 102377c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 102387c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_RESET: 102397c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_STOP_POLLING: 102407c478bd9Sstevel@tonic-gate /* 102417c478bd9Sstevel@tonic-gate * Set the sKip bit to stop all transactions on 102427c478bd9Sstevel@tonic-gate * this pipe 102437c478bd9Sstevel@tonic-gate */ 102447c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, pp, SET_sKip, 102457c478bd9Sstevel@tonic-gate OHCI_FLAGS_SLEEP | OHCI_FLAGS_DMA_SYNC); 102467c478bd9Sstevel@tonic-gate 102477c478bd9Sstevel@tonic-gate break; 102487c478bd9Sstevel@tonic-gate default: 102497c478bd9Sstevel@tonic-gate return; 102507c478bd9Sstevel@tonic-gate } 102517c478bd9Sstevel@tonic-gate 102527c478bd9Sstevel@tonic-gate /* 102537c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and 102547c478bd9Sstevel@tonic-gate * to send results to upstream. 102557c478bd9Sstevel@tonic-gate */ 102567c478bd9Sstevel@tonic-gate ohci_wait_for_transfers_completion(ohcip, pp); 102577c478bd9Sstevel@tonic-gate 102587c478bd9Sstevel@tonic-gate /* Save the data toggle information */ 102597c478bd9Sstevel@tonic-gate ohci_save_data_toggle(ohcip, ph); 102607c478bd9Sstevel@tonic-gate 102617c478bd9Sstevel@tonic-gate /* 102627c478bd9Sstevel@tonic-gate * Traverse the list of TD's on this endpoint and 102637c478bd9Sstevel@tonic-gate * these TD's have outstanding transfer requests. 102647c478bd9Sstevel@tonic-gate * Since the list processing is stopped, these tds 102657c478bd9Sstevel@tonic-gate * can be deallocated. 102667c478bd9Sstevel@tonic-gate */ 102677c478bd9Sstevel@tonic-gate ohci_traverse_tds(ohcip, ph); 102687c478bd9Sstevel@tonic-gate 102697c478bd9Sstevel@tonic-gate /* 102707c478bd9Sstevel@tonic-gate * If all of the endpoint's TD's have been deallocated, 102717c478bd9Sstevel@tonic-gate * then the DMA mappings can be torn down. If not there 102727c478bd9Sstevel@tonic-gate * are some TD's on the done list that have not been 102737c478bd9Sstevel@tonic-gate * processed. Tag these TD's so that they are thrown 102747c478bd9Sstevel@tonic-gate * away when the done list is processed. 102757c478bd9Sstevel@tonic-gate */ 102767c478bd9Sstevel@tonic-gate ohci_done_list_tds(ohcip, ph); 102777c478bd9Sstevel@tonic-gate 102787c478bd9Sstevel@tonic-gate /* Do callbacks for all unfinished requests */ 102797c478bd9Sstevel@tonic-gate ohci_handle_outstanding_requests(ohcip, pp); 102807c478bd9Sstevel@tonic-gate 102817c478bd9Sstevel@tonic-gate /* Free DMA resources */ 102827c478bd9Sstevel@tonic-gate ohci_free_dma_resources(ohcip, ph); 102837c478bd9Sstevel@tonic-gate 102847c478bd9Sstevel@tonic-gate switch (pipe_state) { 102857c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_CLOSE: 102867c478bd9Sstevel@tonic-gate completion_reason = USB_CR_PIPE_CLOSING; 102877c478bd9Sstevel@tonic-gate break; 102887c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_RESET: 102897c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_STOP_POLLING: 102907c478bd9Sstevel@tonic-gate /* Set completion reason */ 102917c478bd9Sstevel@tonic-gate completion_reason = (pipe_state == 102927c478bd9Sstevel@tonic-gate OHCI_PIPE_STATE_RESET) ? 102937c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING; 102947c478bd9Sstevel@tonic-gate 102957c478bd9Sstevel@tonic-gate /* Restore the data toggle information */ 102967c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(ohcip, ph); 102977c478bd9Sstevel@tonic-gate 102987c478bd9Sstevel@tonic-gate /* 102997c478bd9Sstevel@tonic-gate * Clear the sKip bit to restart all the 103007c478bd9Sstevel@tonic-gate * transactions on this pipe. 103017c478bd9Sstevel@tonic-gate */ 103027c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, pp, 103037c478bd9Sstevel@tonic-gate CLEAR_sKip, OHCI_FLAGS_NOSLEEP); 103047c478bd9Sstevel@tonic-gate 103057c478bd9Sstevel@tonic-gate /* Set pipe state to idle */ 103067c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE; 103077c478bd9Sstevel@tonic-gate 103087c478bd9Sstevel@tonic-gate break; 103097c478bd9Sstevel@tonic-gate } 103107c478bd9Sstevel@tonic-gate 103117c478bd9Sstevel@tonic-gate ASSERT((Get_ED(pp->pp_ept->hced_tailp) & HC_EPT_TD_TAIL) == 103127c478bd9Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) & HC_EPT_TD_HEAD)); 103137c478bd9Sstevel@tonic-gate 103147c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head == NULL) && (pp->pp_tw_tail == NULL)); 103157c478bd9Sstevel@tonic-gate 103167c478bd9Sstevel@tonic-gate /* 103177c478bd9Sstevel@tonic-gate * Do the callback for the original client 103187c478bd9Sstevel@tonic-gate * periodic IN request. 103197c478bd9Sstevel@tonic-gate */ 103207c478bd9Sstevel@tonic-gate if ((OHCI_PERIODIC_ENDPOINT(eptd)) && 103217c478bd9Sstevel@tonic-gate ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == 103227c478bd9Sstevel@tonic-gate USB_EP_DIR_IN)) { 103237c478bd9Sstevel@tonic-gate 103247c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback( 103257c478bd9Sstevel@tonic-gate ohcip, pp, completion_reason); 103267c478bd9Sstevel@tonic-gate } 103277c478bd9Sstevel@tonic-gate } 103287c478bd9Sstevel@tonic-gate 103297c478bd9Sstevel@tonic-gate 103307c478bd9Sstevel@tonic-gate /* 103317c478bd9Sstevel@tonic-gate * ohci_wait_for_transfers_completion: 103327c478bd9Sstevel@tonic-gate * 103337c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and to send results 103347c478bd9Sstevel@tonic-gate * to upstream. 103357c478bd9Sstevel@tonic-gate */ 103367c478bd9Sstevel@tonic-gate static void 103377c478bd9Sstevel@tonic-gate ohci_wait_for_transfers_completion( 103387c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 103397c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 103407c478bd9Sstevel@tonic-gate { 103417c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head; 103427c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw; 103437c478bd9Sstevel@tonic-gate clock_t xfer_cmpl_time_wait; 103447c478bd9Sstevel@tonic-gate ohci_td_t *tailp, *headp, *nextp; 103457c478bd9Sstevel@tonic-gate ohci_td_t *head_td, *next_td; 103467c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; 103477c478bd9Sstevel@tonic-gate int rval; 103487c478bd9Sstevel@tonic-gate 103497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 103507c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: pp = 0x%p", pp); 103517c478bd9Sstevel@tonic-gate 103527c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 103537c478bd9Sstevel@tonic-gate 103547c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 103557c478bd9Sstevel@tonic-gate Get_ED(ept->hced_headp) & (uint32_t)HC_EPT_TD_HEAD)); 103567c478bd9Sstevel@tonic-gate 103577c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 103587c478bd9Sstevel@tonic-gate Get_ED(ept->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL)); 103597c478bd9Sstevel@tonic-gate 103607c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip); 103617c478bd9Sstevel@tonic-gate 103627c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) { 103637c478bd9Sstevel@tonic-gate 103647c478bd9Sstevel@tonic-gate return; 103657c478bd9Sstevel@tonic-gate } 103667c478bd9Sstevel@tonic-gate 103677c478bd9Sstevel@tonic-gate pp->pp_count_done_tds = 0; 103687c478bd9Sstevel@tonic-gate 103697c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */ 103707c478bd9Sstevel@tonic-gate next_tw = head_tw; 103717c478bd9Sstevel@tonic-gate while (next_tw) { 103727c478bd9Sstevel@tonic-gate head_td = (ohci_td_t *)next_tw->tw_hctd_head; 103737c478bd9Sstevel@tonic-gate next_td = head_td; 103747c478bd9Sstevel@tonic-gate 103757c478bd9Sstevel@tonic-gate if (head_td) { 103767c478bd9Sstevel@tonic-gate /* 103777c478bd9Sstevel@tonic-gate * Walk through each TD for this transfer 103787c478bd9Sstevel@tonic-gate * wrapper. If a TD still exists, then it 103797c478bd9Sstevel@tonic-gate * is currently on the done list. 103807c478bd9Sstevel@tonic-gate */ 103817c478bd9Sstevel@tonic-gate while (next_td) { 103827c478bd9Sstevel@tonic-gate 103837c478bd9Sstevel@tonic-gate nextp = headp; 103847c478bd9Sstevel@tonic-gate 103857c478bd9Sstevel@tonic-gate while (nextp != tailp) { 103867c478bd9Sstevel@tonic-gate 103877c478bd9Sstevel@tonic-gate /* TD is on the ED */ 103887c478bd9Sstevel@tonic-gate if (nextp == next_td) { 103897c478bd9Sstevel@tonic-gate break; 103907c478bd9Sstevel@tonic-gate } 103917c478bd9Sstevel@tonic-gate 103927c478bd9Sstevel@tonic-gate nextp = (ohci_td_t *) 103937c478bd9Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip, 103947c478bd9Sstevel@tonic-gate (Get_TD(nextp->hctd_next_td) & 103957c478bd9Sstevel@tonic-gate HC_EPT_TD_TAIL))); 103967c478bd9Sstevel@tonic-gate } 103977c478bd9Sstevel@tonic-gate 103987c478bd9Sstevel@tonic-gate if (nextp == tailp) { 103997c478bd9Sstevel@tonic-gate pp->pp_count_done_tds++; 104007c478bd9Sstevel@tonic-gate } 104017c478bd9Sstevel@tonic-gate 104027c478bd9Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip, 104037c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td)); 104047c478bd9Sstevel@tonic-gate } 104057c478bd9Sstevel@tonic-gate } 104067c478bd9Sstevel@tonic-gate 104077c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next; 104087c478bd9Sstevel@tonic-gate } 104097c478bd9Sstevel@tonic-gate 104107c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104117c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: count_done_tds = 0x%x", 104127c478bd9Sstevel@tonic-gate pp->pp_count_done_tds); 104137c478bd9Sstevel@tonic-gate 104147c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_tds) { 104157c478bd9Sstevel@tonic-gate 104167c478bd9Sstevel@tonic-gate return; 104177c478bd9Sstevel@tonic-gate } 104187c478bd9Sstevel@tonic-gate 104197c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 104207c478bd9Sstevel@tonic-gate xfer_cmpl_time_wait = drv_usectohz(OHCI_XFER_CMPL_TIMEWAIT * 1000000); 104217c478bd9Sstevel@tonic-gate 104227c478bd9Sstevel@tonic-gate (void) cv_timedwait(&pp->pp_xfer_cmpl_cv, 104237c478bd9Sstevel@tonic-gate &ohcip->ohci_int_mutex, 104247c478bd9Sstevel@tonic-gate ddi_get_lbolt() + xfer_cmpl_time_wait); 104257c478bd9Sstevel@tonic-gate 104267c478bd9Sstevel@tonic-gate if (pp->pp_count_done_tds) { 104277c478bd9Sstevel@tonic-gate 104287c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104297c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: No transfers " 104307c478bd9Sstevel@tonic-gate "completion confirmation received for 0x%x requests", 104317c478bd9Sstevel@tonic-gate pp->pp_count_done_tds); 104327c478bd9Sstevel@tonic-gate } 104337c478bd9Sstevel@tonic-gate } 104347c478bd9Sstevel@tonic-gate 104357c478bd9Sstevel@tonic-gate 104367c478bd9Sstevel@tonic-gate /* 104377c478bd9Sstevel@tonic-gate * ohci_check_for_transfers_completion: 104387c478bd9Sstevel@tonic-gate * 104397c478bd9Sstevel@tonic-gate * Check whether anybody is waiting for transfers completion event. If so, send 104407c478bd9Sstevel@tonic-gate * this event and also stop initiating any new transfers on this pipe. 104417c478bd9Sstevel@tonic-gate */ 104427c478bd9Sstevel@tonic-gate static void 104437c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion( 104447c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 104457c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 104467c478bd9Sstevel@tonic-gate { 104477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104487c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion: pp = 0x%p", pp); 104497c478bd9Sstevel@tonic-gate 104507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 104517c478bd9Sstevel@tonic-gate 104527c478bd9Sstevel@tonic-gate if ((pp->pp_state == OHCI_PIPE_STATE_STOP_POLLING) && 104537c478bd9Sstevel@tonic-gate (pp->pp_error == USB_CR_NO_RESOURCES) && 104547c478bd9Sstevel@tonic-gate (pp->pp_cur_periodic_req_cnt == 0)) { 104557c478bd9Sstevel@tonic-gate 104567c478bd9Sstevel@tonic-gate /* Reset pipe error to zero */ 104577c478bd9Sstevel@tonic-gate pp->pp_error = 0; 104587c478bd9Sstevel@tonic-gate 104597c478bd9Sstevel@tonic-gate /* Do callback for original request */ 104607c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback( 104617c478bd9Sstevel@tonic-gate ohcip, pp, USB_CR_NO_RESOURCES); 104627c478bd9Sstevel@tonic-gate } 104637c478bd9Sstevel@tonic-gate 104647c478bd9Sstevel@tonic-gate if (pp->pp_count_done_tds) { 104657c478bd9Sstevel@tonic-gate 104667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104677c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion:" 104687c478bd9Sstevel@tonic-gate "count_done_tds = 0x%x", pp->pp_count_done_tds); 104697c478bd9Sstevel@tonic-gate 104707c478bd9Sstevel@tonic-gate /* Decrement the done td count */ 104717c478bd9Sstevel@tonic-gate pp->pp_count_done_tds--; 104727c478bd9Sstevel@tonic-gate 104737c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_tds) { 104747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 104757c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion:" 104767c478bd9Sstevel@tonic-gate "Sent transfers completion event pp = 0x%p", pp); 104777c478bd9Sstevel@tonic-gate 104787c478bd9Sstevel@tonic-gate /* Send the transfer completion signal */ 104797c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_xfer_cmpl_cv); 104807c478bd9Sstevel@tonic-gate } 104817c478bd9Sstevel@tonic-gate } 104827c478bd9Sstevel@tonic-gate } 104837c478bd9Sstevel@tonic-gate 104847c478bd9Sstevel@tonic-gate 104857c478bd9Sstevel@tonic-gate /* 104867c478bd9Sstevel@tonic-gate * ohci_save_data_toggle: 104877c478bd9Sstevel@tonic-gate * 104887c478bd9Sstevel@tonic-gate * Save the data toggle information. 104897c478bd9Sstevel@tonic-gate */ 104907c478bd9Sstevel@tonic-gate static void 104917c478bd9Sstevel@tonic-gate ohci_save_data_toggle( 104927c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 104937c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 104947c478bd9Sstevel@tonic-gate { 104957c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 104967c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 104977c478bd9Sstevel@tonic-gate uint_t data_toggle; 104987c478bd9Sstevel@tonic-gate usb_cr_t error = pp->pp_error; 104997c478bd9Sstevel@tonic-gate ohci_ed_t *ed = pp->pp_ept; 105007c478bd9Sstevel@tonic-gate ohci_td_t *headp, *tailp; 105017c478bd9Sstevel@tonic-gate 105027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 105037c478bd9Sstevel@tonic-gate "ohci_save_data_toggle: ph = 0x%p", ph); 105047c478bd9Sstevel@tonic-gate 105057c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 105067c478bd9Sstevel@tonic-gate 105077c478bd9Sstevel@tonic-gate /* Reset the pipe error value */ 105087c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_OK; 105097c478bd9Sstevel@tonic-gate 105107c478bd9Sstevel@tonic-gate /* Return immediately if it is a control or isoc pipe */ 105117c478bd9Sstevel@tonic-gate if (((eptd->bmAttributes & USB_EP_ATTR_MASK) == 105127c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || ((eptd->bmAttributes & 105137c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH)) { 105147c478bd9Sstevel@tonic-gate 105157c478bd9Sstevel@tonic-gate return; 105167c478bd9Sstevel@tonic-gate } 105177c478bd9Sstevel@tonic-gate 105187c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 105197c478bd9Sstevel@tonic-gate Get_ED(ed->hced_headp) & (uint32_t)HC_EPT_TD_HEAD)); 105207c478bd9Sstevel@tonic-gate 105217c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, 105227c478bd9Sstevel@tonic-gate Get_ED(ed->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL)); 105237c478bd9Sstevel@tonic-gate 105247c478bd9Sstevel@tonic-gate /* 105257c478bd9Sstevel@tonic-gate * Retrieve the data toggle information either from the endpoint 105267c478bd9Sstevel@tonic-gate * (ED) or from the transfer descriptor (TD) depending on the 105277c478bd9Sstevel@tonic-gate * situation. 105287c478bd9Sstevel@tonic-gate */ 105297c478bd9Sstevel@tonic-gate if ((Get_ED(ed->hced_headp) & HC_EPT_Halt) || (headp == tailp)) { 105307c478bd9Sstevel@tonic-gate 105317c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint */ 105327c478bd9Sstevel@tonic-gate data_toggle = (Get_ED(ed->hced_headp) & 105337c478bd9Sstevel@tonic-gate HC_EPT_Carry)? DATA1:DATA0; 105347c478bd9Sstevel@tonic-gate } else { 105357c478bd9Sstevel@tonic-gate /* 105367c478bd9Sstevel@tonic-gate * Retrieve the data toggle information depending on the 105377c478bd9Sstevel@tonic-gate * master data toggle information saved in the transfer 105387c478bd9Sstevel@tonic-gate * descriptor (TD) at the head of the endpoint (ED). 105397c478bd9Sstevel@tonic-gate * 105407c478bd9Sstevel@tonic-gate * Check for master data toggle information . 105417c478bd9Sstevel@tonic-gate */ 105427c478bd9Sstevel@tonic-gate if (Get_TD(headp->hctd_ctrl) & HC_TD_MS_DT) { 105437c478bd9Sstevel@tonic-gate /* Get the data toggle information from td */ 105447c478bd9Sstevel@tonic-gate data_toggle = (Get_TD(headp->hctd_ctrl) & 105457c478bd9Sstevel@tonic-gate HC_TD_DT_1) ? DATA1:DATA0; 105467c478bd9Sstevel@tonic-gate } else { 105477c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint */ 105487c478bd9Sstevel@tonic-gate data_toggle = (Get_ED(ed->hced_headp) & 105497c478bd9Sstevel@tonic-gate HC_EPT_Carry)? DATA1:DATA0; 105507c478bd9Sstevel@tonic-gate } 105517c478bd9Sstevel@tonic-gate } 105527c478bd9Sstevel@tonic-gate 105537c478bd9Sstevel@tonic-gate /* 105547c478bd9Sstevel@tonic-gate * If error is STALL, then, set 105557c478bd9Sstevel@tonic-gate * data toggle to zero. 105567c478bd9Sstevel@tonic-gate */ 105577c478bd9Sstevel@tonic-gate if (error == USB_CR_STALL) { 105587c478bd9Sstevel@tonic-gate data_toggle = DATA0; 105597c478bd9Sstevel@tonic-gate } 105607c478bd9Sstevel@tonic-gate 105617c478bd9Sstevel@tonic-gate /* 105627c478bd9Sstevel@tonic-gate * Save the data toggle information 105637c478bd9Sstevel@tonic-gate * in the usb device structure. 105647c478bd9Sstevel@tonic-gate */ 105657c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 105667c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress, 105677c478bd9Sstevel@tonic-gate data_toggle); 105687c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 105697c478bd9Sstevel@tonic-gate } 105707c478bd9Sstevel@tonic-gate 105717c478bd9Sstevel@tonic-gate 105727c478bd9Sstevel@tonic-gate /* 105737c478bd9Sstevel@tonic-gate * ohci_restore_data_toggle: 105747c478bd9Sstevel@tonic-gate * 105757c478bd9Sstevel@tonic-gate * Restore the data toggle information. 105767c478bd9Sstevel@tonic-gate */ 105777c478bd9Sstevel@tonic-gate static void 105787c478bd9Sstevel@tonic-gate ohci_restore_data_toggle( 105797c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 105807c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 105817c478bd9Sstevel@tonic-gate { 105827c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 105837c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 105847c478bd9Sstevel@tonic-gate uint_t data_toggle = 0; 105857c478bd9Sstevel@tonic-gate 105867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 105877c478bd9Sstevel@tonic-gate "ohci_restore_data_toggle: ph = 0x%p", ph); 105887c478bd9Sstevel@tonic-gate 105897c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 105907c478bd9Sstevel@tonic-gate 105917c478bd9Sstevel@tonic-gate /* 105927c478bd9Sstevel@tonic-gate * Return immediately if it is a control or isoc pipe. 105937c478bd9Sstevel@tonic-gate */ 105947c478bd9Sstevel@tonic-gate if (((eptd->bmAttributes & USB_EP_ATTR_MASK) == 105957c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || ((eptd->bmAttributes & 105967c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH)) { 105977c478bd9Sstevel@tonic-gate 105987c478bd9Sstevel@tonic-gate return; 105997c478bd9Sstevel@tonic-gate } 106007c478bd9Sstevel@tonic-gate 106017c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 106027c478bd9Sstevel@tonic-gate 106037c478bd9Sstevel@tonic-gate data_toggle = usba_hcdi_get_data_toggle(ph->p_usba_device, 106047c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress); 106057c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress, 106067c478bd9Sstevel@tonic-gate 0); 106077c478bd9Sstevel@tonic-gate 106087c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 106097c478bd9Sstevel@tonic-gate 106107c478bd9Sstevel@tonic-gate /* 106117c478bd9Sstevel@tonic-gate * Restore the data toggle bit depending on the 106127c478bd9Sstevel@tonic-gate * previous data toggle information. 106137c478bd9Sstevel@tonic-gate */ 106147c478bd9Sstevel@tonic-gate if (data_toggle) { 106157c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 106167c478bd9Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) | HC_EPT_Carry); 106177c478bd9Sstevel@tonic-gate } else { 106187c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, 106197c478bd9Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) & (~HC_EPT_Carry)); 106207c478bd9Sstevel@tonic-gate } 106217c478bd9Sstevel@tonic-gate } 106227c478bd9Sstevel@tonic-gate 106237c478bd9Sstevel@tonic-gate 106247c478bd9Sstevel@tonic-gate /* 106257c478bd9Sstevel@tonic-gate * ohci_handle_outstanding_requests 106267c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 106277c478bd9Sstevel@tonic-gate * 106287c478bd9Sstevel@tonic-gate * Deallocate interrupt/isochronous request structure for the 106297c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. Do the callbacks for all 106307c478bd9Sstevel@tonic-gate * unfinished requests. 106317c478bd9Sstevel@tonic-gate */ 106327c478bd9Sstevel@tonic-gate void 106337c478bd9Sstevel@tonic-gate ohci_handle_outstanding_requests( 106347c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 106357c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp) 106367c478bd9Sstevel@tonic-gate { 106377c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 106387c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 106397c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *curr_tw; 106407c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw; 106417c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 106427c478bd9Sstevel@tonic-gate 106437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 106447c478bd9Sstevel@tonic-gate "ohci_handle_outstanding_requests: pp = 0x%p", pp); 106457c478bd9Sstevel@tonic-gate 106467c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 106477c478bd9Sstevel@tonic-gate 106487c478bd9Sstevel@tonic-gate /* 106497c478bd9Sstevel@tonic-gate * Deallocate all the pre-allocated interrupt requests 106507c478bd9Sstevel@tonic-gate */ 106517c478bd9Sstevel@tonic-gate next_tw = pp->pp_tw_head; 106527c478bd9Sstevel@tonic-gate 106537c478bd9Sstevel@tonic-gate while (next_tw) { 106547c478bd9Sstevel@tonic-gate curr_tw = next_tw; 106557c478bd9Sstevel@tonic-gate next_tw = curr_tw->tw_next; 106567c478bd9Sstevel@tonic-gate 106577c478bd9Sstevel@tonic-gate curr_xfer_reqp = curr_tw->tw_curr_xfer_reqp; 106587c478bd9Sstevel@tonic-gate 106597c478bd9Sstevel@tonic-gate /* Deallocate current interrupt request */ 106607c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) { 106617c478bd9Sstevel@tonic-gate 106627c478bd9Sstevel@tonic-gate if ((OHCI_PERIODIC_ENDPOINT(eptd)) && 106637c478bd9Sstevel@tonic-gate (curr_tw->tw_direction == HC_TD_IN)) { 106647c478bd9Sstevel@tonic-gate 106657c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 106667c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 106677c478bd9Sstevel@tonic-gate 106687c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 106697c478bd9Sstevel@tonic-gate ohcip, pp, curr_tw); 106707c478bd9Sstevel@tonic-gate } else { 106717c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, 106727c478bd9Sstevel@tonic-gate curr_tw, USB_CR_FLUSHED); 106737c478bd9Sstevel@tonic-gate } 106747c478bd9Sstevel@tonic-gate } 106757c478bd9Sstevel@tonic-gate } 106767c478bd9Sstevel@tonic-gate } 106777c478bd9Sstevel@tonic-gate 106787c478bd9Sstevel@tonic-gate 106797c478bd9Sstevel@tonic-gate /* 106807c478bd9Sstevel@tonic-gate * ohci_deallocate_periodic_in_resource 106817c478bd9Sstevel@tonic-gate * 106827c478bd9Sstevel@tonic-gate * Deallocate interrupt/isochronous request structure for the 106837c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. 106847c478bd9Sstevel@tonic-gate */ 106857c478bd9Sstevel@tonic-gate static void 106867c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource( 106877c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 106887c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 106897c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw) 106907c478bd9Sstevel@tonic-gate { 106917c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 106927c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes; 106937c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 106947c478bd9Sstevel@tonic-gate 106957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 106967c478bd9Sstevel@tonic-gate "ohci_deallocate_periodic_in_resource: " 106977c478bd9Sstevel@tonic-gate "pp = 0x%p tw = 0x%p", pp, tw); 106987c478bd9Sstevel@tonic-gate 106997c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 107007c478bd9Sstevel@tonic-gate 107017c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp; 107027c478bd9Sstevel@tonic-gate 107037c478bd9Sstevel@tonic-gate /* Check the current periodic in request pointer */ 107047c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) { 107057c478bd9Sstevel@tonic-gate /* 107067c478bd9Sstevel@tonic-gate * Reset periodic in request usb isoch 107077c478bd9Sstevel@tonic-gate * packet request pointers to null. 107087c478bd9Sstevel@tonic-gate */ 107097c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL; 107107c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = NULL; 107117c478bd9Sstevel@tonic-gate 107127c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 107137c478bd9Sstevel@tonic-gate ph->p_req_count--; 107147c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 107157c478bd9Sstevel@tonic-gate 107167c478bd9Sstevel@tonic-gate /* 107177c478bd9Sstevel@tonic-gate * Free pre-allocated interrupt 107187c478bd9Sstevel@tonic-gate * or isochronous requests. 107197c478bd9Sstevel@tonic-gate */ 107207c478bd9Sstevel@tonic-gate switch (ep_attr & USB_EP_ATTR_MASK) { 107217c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 107227c478bd9Sstevel@tonic-gate usb_free_intr_req( 107237c478bd9Sstevel@tonic-gate (usb_intr_req_t *)curr_xfer_reqp); 107247c478bd9Sstevel@tonic-gate break; 107257c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 107267c478bd9Sstevel@tonic-gate usb_free_isoc_req( 107277c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)curr_xfer_reqp); 107287c478bd9Sstevel@tonic-gate break; 107297c478bd9Sstevel@tonic-gate } 107307c478bd9Sstevel@tonic-gate } 107317c478bd9Sstevel@tonic-gate } 107327c478bd9Sstevel@tonic-gate 107337c478bd9Sstevel@tonic-gate 107347c478bd9Sstevel@tonic-gate /* 107357c478bd9Sstevel@tonic-gate * ohci_do_client_periodic_in_req_callback 107367c478bd9Sstevel@tonic-gate * 107377c478bd9Sstevel@tonic-gate * Do callback for the original client periodic IN request. 107387c478bd9Sstevel@tonic-gate */ 107397c478bd9Sstevel@tonic-gate static void 107407c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback( 107417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 107427c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp, 107437c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 107447c478bd9Sstevel@tonic-gate { 107457c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 107467c478bd9Sstevel@tonic-gate 107477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 107487c478bd9Sstevel@tonic-gate "ohci_do_client_periodic_in_req_callback: " 107497c478bd9Sstevel@tonic-gate "pp = 0x%p cc = 0x%x", pp, completion_reason); 107507c478bd9Sstevel@tonic-gate 107517c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 107527c478bd9Sstevel@tonic-gate 107537c478bd9Sstevel@tonic-gate /* 107547c478bd9Sstevel@tonic-gate * Check for Interrupt/Isochronous IN, whether we need to do 107557c478bd9Sstevel@tonic-gate * callback for the original client's periodic IN request. 107567c478bd9Sstevel@tonic-gate */ 107577c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) { 107587c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 0); 107597c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, NULL, completion_reason); 107607c478bd9Sstevel@tonic-gate } 107617c478bd9Sstevel@tonic-gate } 107627c478bd9Sstevel@tonic-gate 107637c478bd9Sstevel@tonic-gate 107647c478bd9Sstevel@tonic-gate /* 107657c478bd9Sstevel@tonic-gate * ohci_hcdi_callback() 107667c478bd9Sstevel@tonic-gate * 107677c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() other than root hub. 107687c478bd9Sstevel@tonic-gate */ 107697c478bd9Sstevel@tonic-gate static void 107707c478bd9Sstevel@tonic-gate ohci_hcdi_callback( 107717c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 107727c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, 107737c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 107747c478bd9Sstevel@tonic-gate { 107757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state( 10776*29aca3ebSlc ph->p_usba_device->usb_root_hub_dip); 107777c478bd9Sstevel@tonic-gate uchar_t attributes = ph->p_ep.bmAttributes & 10778*29aca3ebSlc USB_EP_ATTR_MASK; 107797c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private; 107807c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 107817c478bd9Sstevel@tonic-gate uint_t pipe_state = 0; 107827c478bd9Sstevel@tonic-gate 107837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 107847c478bd9Sstevel@tonic-gate "ohci_hcdi_callback: ph = 0x%p, tw = 0x%p, cr = 0x%x", 107857c478bd9Sstevel@tonic-gate ph, tw, completion_reason); 107867c478bd9Sstevel@tonic-gate 107877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 107887c478bd9Sstevel@tonic-gate 107897c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */ 107907c478bd9Sstevel@tonic-gate switch (completion_reason) { 107917c478bd9Sstevel@tonic-gate case USB_CR_OK: 107927c478bd9Sstevel@tonic-gate pipe_state = pp->pp_state; 107937c478bd9Sstevel@tonic-gate break; 107947c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES: 107957c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED: 107967c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 107977c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 107987c478bd9Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_IDLE; 107997c478bd9Sstevel@tonic-gate break; 108007c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING: 108017c478bd9Sstevel@tonic-gate break; 108027c478bd9Sstevel@tonic-gate default: 108037c478bd9Sstevel@tonic-gate /* 108047c478bd9Sstevel@tonic-gate * Set the pipe state to error 108057c478bd9Sstevel@tonic-gate * except for the isoc pipe. 108067c478bd9Sstevel@tonic-gate */ 108077c478bd9Sstevel@tonic-gate if (attributes != USB_EP_ATTR_ISOCH) { 108087c478bd9Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_ERROR; 108097c478bd9Sstevel@tonic-gate pp->pp_error = completion_reason; 108107c478bd9Sstevel@tonic-gate } 108117c478bd9Sstevel@tonic-gate break; 108127c478bd9Sstevel@tonic-gate 108137c478bd9Sstevel@tonic-gate } 108147c478bd9Sstevel@tonic-gate 108157c478bd9Sstevel@tonic-gate pp->pp_state = pipe_state; 108167c478bd9Sstevel@tonic-gate 108177c478bd9Sstevel@tonic-gate if (tw && tw->tw_curr_xfer_reqp) { 108187c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp; 108197c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL; 108207c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = NULL; 108217c478bd9Sstevel@tonic-gate } else { 108227c478bd9Sstevel@tonic-gate ASSERT(pp->pp_client_periodic_in_reqp != NULL); 108237c478bd9Sstevel@tonic-gate 108247c478bd9Sstevel@tonic-gate curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 108257c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 108267c478bd9Sstevel@tonic-gate } 108277c478bd9Sstevel@tonic-gate 108287c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL); 108297c478bd9Sstevel@tonic-gate 108307c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex); 108317c478bd9Sstevel@tonic-gate 108327c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 108337c478bd9Sstevel@tonic-gate 108347c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex); 108357c478bd9Sstevel@tonic-gate } 108367c478bd9Sstevel@tonic-gate 108377c478bd9Sstevel@tonic-gate 108387c478bd9Sstevel@tonic-gate /* 108397c478bd9Sstevel@tonic-gate * ohci kstat functions 108407c478bd9Sstevel@tonic-gate */ 108417c478bd9Sstevel@tonic-gate 108427c478bd9Sstevel@tonic-gate /* 108437c478bd9Sstevel@tonic-gate * ohci_create_stats: 108447c478bd9Sstevel@tonic-gate * 108457c478bd9Sstevel@tonic-gate * Allocate and initialize the ohci kstat structures 108467c478bd9Sstevel@tonic-gate */ 108477c478bd9Sstevel@tonic-gate static void 108487c478bd9Sstevel@tonic-gate ohci_create_stats(ohci_state_t *ohcip) 108497c478bd9Sstevel@tonic-gate { 108507c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 108517c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ohcip->ohci_dip); 108527c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 10853*29aca3ebSlc {"ctrl", "isoch", "bulk", "intr"}; 108547c478bd9Sstevel@tonic-gate uint_t instance = ohcip->ohci_instance; 108557c478bd9Sstevel@tonic-gate ohci_intrs_stats_t *isp; 108567c478bd9Sstevel@tonic-gate int i; 108577c478bd9Sstevel@tonic-gate 108587c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip) == NULL) { 108597c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 108607c478bd9Sstevel@tonic-gate dname, instance); 108617c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip) = kstat_create("usba", instance, 108627c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 108637c478bd9Sstevel@tonic-gate sizeof (ohci_intrs_stats_t) / sizeof (kstat_named_t), 108647c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 108657c478bd9Sstevel@tonic-gate 108667c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) { 108677c478bd9Sstevel@tonic-gate isp = OHCI_INTRS_STATS_DATA(ohcip); 108687c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_total, 10869*29aca3ebSlc "Interrupts Total", KSTAT_DATA_UINT64); 108707c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_not_claimed, 10871*29aca3ebSlc "Not Claimed", KSTAT_DATA_UINT64); 108727c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_so, 10873*29aca3ebSlc "Schedule Overruns", KSTAT_DATA_UINT64); 108747c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_wdh, 10875*29aca3ebSlc "Writeback Done Head", KSTAT_DATA_UINT64); 108767c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_sof, 10877*29aca3ebSlc "Start Of Frame", KSTAT_DATA_UINT64); 108787c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_rd, 10879*29aca3ebSlc "Resume Detected", KSTAT_DATA_UINT64); 108807c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_ue, 10881*29aca3ebSlc "Unrecoverable Error", KSTAT_DATA_UINT64); 108827c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_fno, 10883*29aca3ebSlc "Frame No. Overflow", KSTAT_DATA_UINT64); 108847c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_rhsc, 10885*29aca3ebSlc "Root Hub Status Change", KSTAT_DATA_UINT64); 108867c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_oc, 10887*29aca3ebSlc "Change In Ownership", KSTAT_DATA_UINT64); 108887c478bd9Sstevel@tonic-gate 108897c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip)->ks_private = ohcip; 108907c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip)->ks_update = nulldev; 108917c478bd9Sstevel@tonic-gate kstat_install(OHCI_INTRS_STATS(ohcip)); 108927c478bd9Sstevel@tonic-gate } 108937c478bd9Sstevel@tonic-gate } 108947c478bd9Sstevel@tonic-gate 108957c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip) == NULL) { 108967c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 108977c478bd9Sstevel@tonic-gate dname, instance); 108987c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS(ohcip) = kstat_create("usba", instance, 108997c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 109007c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 109017c478bd9Sstevel@tonic-gate 109027c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip)) { 109037c478bd9Sstevel@tonic-gate kstat_install(OHCI_TOTAL_STATS(ohcip)); 109047c478bd9Sstevel@tonic-gate } 109057c478bd9Sstevel@tonic-gate } 109067c478bd9Sstevel@tonic-gate 109077c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 109087c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i] == NULL) { 109097c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 109107c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 109117c478bd9Sstevel@tonic-gate ohcip->ohci_count_stats[i] = kstat_create("usba", 109127c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 109137c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 109147c478bd9Sstevel@tonic-gate 109157c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i]) { 109167c478bd9Sstevel@tonic-gate kstat_install(ohcip->ohci_count_stats[i]); 109177c478bd9Sstevel@tonic-gate } 109187c478bd9Sstevel@tonic-gate } 109197c478bd9Sstevel@tonic-gate } 109207c478bd9Sstevel@tonic-gate } 109217c478bd9Sstevel@tonic-gate 109227c478bd9Sstevel@tonic-gate 109237c478bd9Sstevel@tonic-gate /* 109247c478bd9Sstevel@tonic-gate * ohci_destroy_stats: 109257c478bd9Sstevel@tonic-gate * 109267c478bd9Sstevel@tonic-gate * Clean up ohci kstat structures 109277c478bd9Sstevel@tonic-gate */ 109287c478bd9Sstevel@tonic-gate static void 109297c478bd9Sstevel@tonic-gate ohci_destroy_stats(ohci_state_t *ohcip) 109307c478bd9Sstevel@tonic-gate { 109317c478bd9Sstevel@tonic-gate int i; 109327c478bd9Sstevel@tonic-gate 109337c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) { 109347c478bd9Sstevel@tonic-gate kstat_delete(OHCI_INTRS_STATS(ohcip)); 109357c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip) = NULL; 109367c478bd9Sstevel@tonic-gate } 109377c478bd9Sstevel@tonic-gate 109387c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip)) { 109397c478bd9Sstevel@tonic-gate kstat_delete(OHCI_TOTAL_STATS(ohcip)); 109407c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS(ohcip) = NULL; 109417c478bd9Sstevel@tonic-gate } 109427c478bd9Sstevel@tonic-gate 109437c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 109447c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i]) { 109457c478bd9Sstevel@tonic-gate kstat_delete(ohcip->ohci_count_stats[i]); 109467c478bd9Sstevel@tonic-gate ohcip->ohci_count_stats[i] = NULL; 109477c478bd9Sstevel@tonic-gate } 109487c478bd9Sstevel@tonic-gate } 109497c478bd9Sstevel@tonic-gate } 109507c478bd9Sstevel@tonic-gate 109517c478bd9Sstevel@tonic-gate 109527c478bd9Sstevel@tonic-gate /* 109537c478bd9Sstevel@tonic-gate * ohci_do_intrs_stats: 109547c478bd9Sstevel@tonic-gate * 109557c478bd9Sstevel@tonic-gate * ohci status information 109567c478bd9Sstevel@tonic-gate */ 109577c478bd9Sstevel@tonic-gate static void 109587c478bd9Sstevel@tonic-gate ohci_do_intrs_stats( 109597c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 109607c478bd9Sstevel@tonic-gate int val) 109617c478bd9Sstevel@tonic-gate { 109627c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) { 109637c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->ohci_hcr_intr_total.value.ui64++; 109647c478bd9Sstevel@tonic-gate switch (val) { 109657c478bd9Sstevel@tonic-gate case HCR_INTR_SO: 109667c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109677c478bd9Sstevel@tonic-gate ohci_hcr_intr_so.value.ui64++; 109687c478bd9Sstevel@tonic-gate break; 109697c478bd9Sstevel@tonic-gate case HCR_INTR_WDH: 109707c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109717c478bd9Sstevel@tonic-gate ohci_hcr_intr_wdh.value.ui64++; 109727c478bd9Sstevel@tonic-gate break; 109737c478bd9Sstevel@tonic-gate case HCR_INTR_SOF: 109747c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109757c478bd9Sstevel@tonic-gate ohci_hcr_intr_sof.value.ui64++; 109767c478bd9Sstevel@tonic-gate break; 109777c478bd9Sstevel@tonic-gate case HCR_INTR_RD: 109787c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109797c478bd9Sstevel@tonic-gate ohci_hcr_intr_rd.value.ui64++; 109807c478bd9Sstevel@tonic-gate break; 109817c478bd9Sstevel@tonic-gate case HCR_INTR_UE: 109827c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109837c478bd9Sstevel@tonic-gate ohci_hcr_intr_ue.value.ui64++; 109847c478bd9Sstevel@tonic-gate break; 109857c478bd9Sstevel@tonic-gate case HCR_INTR_FNO: 109867c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109877c478bd9Sstevel@tonic-gate ohci_hcr_intr_fno.value.ui64++; 109887c478bd9Sstevel@tonic-gate break; 109897c478bd9Sstevel@tonic-gate case HCR_INTR_RHSC: 109907c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109917c478bd9Sstevel@tonic-gate ohci_hcr_intr_rhsc.value.ui64++; 109927c478bd9Sstevel@tonic-gate break; 109937c478bd9Sstevel@tonic-gate case HCR_INTR_OC: 109947c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109957c478bd9Sstevel@tonic-gate ohci_hcr_intr_oc.value.ui64++; 109967c478bd9Sstevel@tonic-gate break; 109977c478bd9Sstevel@tonic-gate default: 109987c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)-> 109997c478bd9Sstevel@tonic-gate ohci_hcr_intr_not_claimed.value.ui64++; 11000*29aca3ebSlc break; 110017c478bd9Sstevel@tonic-gate } 110027c478bd9Sstevel@tonic-gate } 110037c478bd9Sstevel@tonic-gate } 110047c478bd9Sstevel@tonic-gate 110057c478bd9Sstevel@tonic-gate 110067c478bd9Sstevel@tonic-gate /* 110077c478bd9Sstevel@tonic-gate * ohci_do_byte_stats: 110087c478bd9Sstevel@tonic-gate * 110097c478bd9Sstevel@tonic-gate * ohci data xfer information 110107c478bd9Sstevel@tonic-gate */ 110117c478bd9Sstevel@tonic-gate static void 110127c478bd9Sstevel@tonic-gate ohci_do_byte_stats( 110137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 110147c478bd9Sstevel@tonic-gate size_t len, 110157c478bd9Sstevel@tonic-gate uint8_t attr, 110167c478bd9Sstevel@tonic-gate uint8_t addr) 110177c478bd9Sstevel@tonic-gate { 110187c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 110197c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 110207c478bd9Sstevel@tonic-gate 110217c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 110227c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->reads++; 110237c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->nread += len; 110247c478bd9Sstevel@tonic-gate switch (type) { 110257c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 110267c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->reads++; 110277c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->nread += len; 110287c478bd9Sstevel@tonic-gate break; 110297c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 110307c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->reads++; 110317c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->nread += len; 110327c478bd9Sstevel@tonic-gate break; 110337c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 110347c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->reads++; 110357c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->nread += len; 110367c478bd9Sstevel@tonic-gate break; 110377c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 110387c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->reads++; 110397c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->nread += len; 110407c478bd9Sstevel@tonic-gate break; 110417c478bd9Sstevel@tonic-gate } 110427c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 110437c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->writes++; 110447c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->nwritten += len; 110457c478bd9Sstevel@tonic-gate switch (type) { 110467c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 110477c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->writes++; 110487c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->nwritten += len; 110497c478bd9Sstevel@tonic-gate break; 110507c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 110517c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->writes++; 110527c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->nwritten += len; 110537c478bd9Sstevel@tonic-gate break; 110547c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 110557c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->writes++; 110567c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->nwritten += len; 110577c478bd9Sstevel@tonic-gate break; 110587c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 110597c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->writes++; 110607c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->nwritten += len; 110617c478bd9Sstevel@tonic-gate break; 110627c478bd9Sstevel@tonic-gate } 110637c478bd9Sstevel@tonic-gate } 110647c478bd9Sstevel@tonic-gate } 110657c478bd9Sstevel@tonic-gate 110667c478bd9Sstevel@tonic-gate 110677c478bd9Sstevel@tonic-gate /* 110687c478bd9Sstevel@tonic-gate * ohci_print_op_regs: 110697c478bd9Sstevel@tonic-gate * 110707c478bd9Sstevel@tonic-gate * Print Host Controller's (HC) Operational registers. 110717c478bd9Sstevel@tonic-gate */ 110727c478bd9Sstevel@tonic-gate static void 110737c478bd9Sstevel@tonic-gate ohci_print_op_regs(ohci_state_t *ohcip) 110747c478bd9Sstevel@tonic-gate { 110757c478bd9Sstevel@tonic-gate uint_t i; 110767c478bd9Sstevel@tonic-gate 110777c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110787c478bd9Sstevel@tonic-gate "\n\tOHCI%d Operational Registers\n", 110797c478bd9Sstevel@tonic-gate ddi_get_instance(ohcip->ohci_dip)); 110807c478bd9Sstevel@tonic-gate 110817c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110827c478bd9Sstevel@tonic-gate "\thcr_revision: 0x%x \t\thcr_control: 0x%x", 110837c478bd9Sstevel@tonic-gate Get_OpReg(hcr_revision), Get_OpReg(hcr_control)); 110847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110857c478bd9Sstevel@tonic-gate "\thcr_cmd_status: 0x%x \t\thcr_intr_enable: 0x%x", 110867c478bd9Sstevel@tonic-gate Get_OpReg(hcr_cmd_status), Get_OpReg(hcr_intr_enable)); 110877c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110887c478bd9Sstevel@tonic-gate "\thcr_intr_disable: 0x%x \thcr_HCCA: 0x%x", 110897c478bd9Sstevel@tonic-gate Get_OpReg(hcr_intr_disable), Get_OpReg(hcr_HCCA)); 110907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110917c478bd9Sstevel@tonic-gate "\thcr_periodic_curr: 0x%x \t\thcr_ctrl_head: 0x%x", 110927c478bd9Sstevel@tonic-gate Get_OpReg(hcr_periodic_curr), Get_OpReg(hcr_ctrl_head)); 110937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110947c478bd9Sstevel@tonic-gate "\thcr_ctrl_curr: 0x%x \t\thcr_bulk_head: 0x%x", 110957c478bd9Sstevel@tonic-gate Get_OpReg(hcr_ctrl_curr), Get_OpReg(hcr_bulk_head)); 110967c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 110977c478bd9Sstevel@tonic-gate "\thcr_bulk_curr: 0x%x \t\thcr_done_head: 0x%x", 110987c478bd9Sstevel@tonic-gate Get_OpReg(hcr_bulk_curr), Get_OpReg(hcr_done_head)); 110997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 111007c478bd9Sstevel@tonic-gate "\thcr_frame_interval: 0x%x " 111017c478bd9Sstevel@tonic-gate "\thcr_frame_remaining: 0x%x", Get_OpReg(hcr_frame_interval), 111027c478bd9Sstevel@tonic-gate Get_OpReg(hcr_frame_remaining)); 111037c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 111047c478bd9Sstevel@tonic-gate "\thcr_frame_number: 0x%x \thcr_periodic_strt: 0x%x", 111057c478bd9Sstevel@tonic-gate Get_OpReg(hcr_frame_number), Get_OpReg(hcr_periodic_strt)); 111067c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 111077c478bd9Sstevel@tonic-gate "\thcr_transfer_ls: 0x%x \t\thcr_rh_descriptorA: 0x%x", 111087c478bd9Sstevel@tonic-gate Get_OpReg(hcr_transfer_ls), Get_OpReg(hcr_rh_descriptorA)); 111097c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 111107c478bd9Sstevel@tonic-gate "\thcr_rh_descriptorB: 0x%x \thcr_rh_status: 0x%x", 111117c478bd9Sstevel@tonic-gate Get_OpReg(hcr_rh_descriptorB), Get_OpReg(hcr_rh_status)); 111127c478bd9Sstevel@tonic-gate 111137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 111147c478bd9Sstevel@tonic-gate "\tRoot hub port status"); 111157c478bd9Sstevel@tonic-gate 111167c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_OpReg(hcr_rh_descriptorA) & HCR_RHA_NDP); i++) { 111177c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, 111187c478bd9Sstevel@tonic-gate "\thcr_rh_portstatus 0x%x: 0x%x ", i, 111197c478bd9Sstevel@tonic-gate Get_OpReg(hcr_rh_portstatus[i])); 111207c478bd9Sstevel@tonic-gate } 111217c478bd9Sstevel@tonic-gate } 111227c478bd9Sstevel@tonic-gate 111237c478bd9Sstevel@tonic-gate 111247c478bd9Sstevel@tonic-gate /* 111257c478bd9Sstevel@tonic-gate * ohci_print_ed: 111267c478bd9Sstevel@tonic-gate */ 111277c478bd9Sstevel@tonic-gate static void 111287c478bd9Sstevel@tonic-gate ohci_print_ed( 111297c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 111307c478bd9Sstevel@tonic-gate ohci_ed_t *ed) 111317c478bd9Sstevel@tonic-gate { 11132*29aca3ebSlc uint_t ctrl = Get_ED(ed->hced_ctrl); 111337c478bd9Sstevel@tonic-gate 111347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111357c478bd9Sstevel@tonic-gate "ohci_print_ed: ed = 0x%p", (void *)ed); 111367c478bd9Sstevel@tonic-gate 111377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111387c478bd9Sstevel@tonic-gate "\thced_ctrl: 0x%x %s", ctrl, 111397c478bd9Sstevel@tonic-gate ((Get_ED(ed->hced_headp) & HC_EPT_Halt) ? "halted": "")); 111407c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111417c478bd9Sstevel@tonic-gate "\ttoggle carry: 0x%x", Get_ED(ed->hced_headp) & HC_EPT_Carry); 111427c478bd9Sstevel@tonic-gate 111437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111447c478bd9Sstevel@tonic-gate "\tctrl: 0x%x", Get_ED(ed->hced_ctrl)); 111457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111467c478bd9Sstevel@tonic-gate "\ttailp: 0x%x", Get_ED(ed->hced_tailp)); 111477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111487c478bd9Sstevel@tonic-gate "\theadp: 0x%x", Get_ED(ed->hced_headp)); 111497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111507c478bd9Sstevel@tonic-gate "\tnext: 0x%x", Get_ED(ed->hced_next)); 111517c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111527c478bd9Sstevel@tonic-gate "\tprev: 0x%x", Get_ED(ed->hced_prev)); 111537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111547c478bd9Sstevel@tonic-gate "\tnode: 0x%x", Get_ED(ed->hced_node)); 111557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111567c478bd9Sstevel@tonic-gate "\treclaim_next: 0x%x", Get_ED(ed->hced_reclaim_next)); 111577c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111587c478bd9Sstevel@tonic-gate "\treclaim_frame: 0x%x", Get_ED(ed->hced_reclaim_frame)); 111597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111607c478bd9Sstevel@tonic-gate "\tstate: 0x%x", Get_ED(ed->hced_state)); 111617c478bd9Sstevel@tonic-gate } 111627c478bd9Sstevel@tonic-gate 111637c478bd9Sstevel@tonic-gate 111647c478bd9Sstevel@tonic-gate /* 111657c478bd9Sstevel@tonic-gate * ohci_print_td: 111667c478bd9Sstevel@tonic-gate */ 111677c478bd9Sstevel@tonic-gate static void 111687c478bd9Sstevel@tonic-gate ohci_print_td( 111697c478bd9Sstevel@tonic-gate ohci_state_t *ohcip, 111707c478bd9Sstevel@tonic-gate ohci_td_t *td) 111717c478bd9Sstevel@tonic-gate { 111727c478bd9Sstevel@tonic-gate uint_t i; 111737c478bd9Sstevel@tonic-gate uint_t ctrl = Get_TD(td->hctd_ctrl); 111747c478bd9Sstevel@tonic-gate 111757c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111767c478bd9Sstevel@tonic-gate "ohci_print_td: td = 0x%p", (void *)td); 111777c478bd9Sstevel@tonic-gate 111787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111797c478bd9Sstevel@tonic-gate "\tPID: 0x%x ", ctrl & HC_TD_PID); 111807c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111817c478bd9Sstevel@tonic-gate "\tDelay Intr: 0x%x ", ctrl & HC_TD_DI); 111827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111837c478bd9Sstevel@tonic-gate "\tData Toggle: 0x%x ", ctrl & HC_TD_DT); 111847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111857c478bd9Sstevel@tonic-gate "\tError Count: 0x%x ", ctrl & HC_TD_EC); 111867c478bd9Sstevel@tonic-gate 111877c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111887c478bd9Sstevel@tonic-gate "\tctrl: 0x%x ", Get_TD(td->hctd_ctrl)); 111897c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111907c478bd9Sstevel@tonic-gate "\tcbp: 0x%x ", Get_TD(td->hctd_cbp)); 111917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111927c478bd9Sstevel@tonic-gate "\tnext_td: 0x%x ", Get_TD(td->hctd_next_td)); 111937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111947c478bd9Sstevel@tonic-gate "\tbuf_end: 0x%x ", Get_TD(td->hctd_buf_end)); 111957c478bd9Sstevel@tonic-gate 111967c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 111977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 111987c478bd9Sstevel@tonic-gate "\toffset[%d]: 0x%x ", i, Get_TD(td->hctd_offsets[i])); 111997c478bd9Sstevel@tonic-gate } 112007c478bd9Sstevel@tonic-gate 112017c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 112027c478bd9Sstevel@tonic-gate "\ttrans_wrapper: 0x%x ", Get_TD(td->hctd_trans_wrapper)); 112037c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 112047c478bd9Sstevel@tonic-gate "\tstate: 0x%x ", Get_TD(td->hctd_state)); 112057c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 112067c478bd9Sstevel@tonic-gate "\ttw_next_td: 0x%x ", Get_TD(td->hctd_tw_next_td)); 112077c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl, 112087c478bd9Sstevel@tonic-gate "\tctrl_phase: 0x%x ", Get_TD(td->hctd_ctrl_phase)); 112097c478bd9Sstevel@tonic-gate } 11210