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
502acac7eSsl147100 * Common Development and Distribution License (the "License").
602acac7eSsl147100 * 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 /*
22269552cdSguoqing zhu - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * Open Host Controller Driver (OHCI)
297c478bd9Sstevel@tonic-gate *
307c478bd9Sstevel@tonic-gate * The USB Open Host Controller driver is a software driver which interfaces
317c478bd9Sstevel@tonic-gate * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
327c478bd9Sstevel@tonic-gate * The interface to USB Open Host Controller is defined by the OpenHCI Host
337c478bd9Sstevel@tonic-gate * Controller Interface.
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate * NOTE:
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * Currently OHCI driver does not support the following features
387c478bd9Sstevel@tonic-gate *
397c478bd9Sstevel@tonic-gate * - Handle request with multiple TDs under short xfer conditions except for
407c478bd9Sstevel@tonic-gate * bulk transfers.
417c478bd9Sstevel@tonic-gate */
427c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohcid.h>
437c478bd9Sstevel@tonic-gate
4402acac7eSsl147100 #include <sys/disp.h>
45d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
4602acac7eSsl147100
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
727c478bd9Sstevel@tonic-gate /*
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
799c75c6bfSgovinda /*
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);
95269552cdSguoqing zhu - Sun Microsystems - Beijing China static void ohci_hcdi_pipe_reset_data_toggle(
96269552cdSguoqing zhu - Sun Microsystems - Beijing China usba_pipe_handle_data_t *ph);
977c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_ctrl_xfer(
987c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
997c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp,
1007c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
1017c478bd9Sstevel@tonic-gate static int ohci_hcdi_bulk_transfer_size(
1027c478bd9Sstevel@tonic-gate usba_device_t *usba_device,
1037c478bd9Sstevel@tonic-gate size_t *size);
1047c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_bulk_xfer(
1057c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1067c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp,
1077c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
1087c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_intr_xfer(
1097c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1107c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_req,
1117c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
1127c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_stop_intr_polling(
1137c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1147c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
115fffe0b30Sqz150045 static int ohci_hcdi_get_current_frame_number(
116fffe0b30Sqz150045 usba_device_t *usba_device,
117fffe0b30Sqz150045 usb_frame_number_t *frame_number);
118fffe0b30Sqz150045 static int ohci_hcdi_get_max_isoc_pkts(
119fffe0b30Sqz150045 usba_device_t *usba_device,
120fffe0b30Sqz150045 uint_t *max_isoc_pkts_per_request);
1217c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_isoc_xfer(
1227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1237c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp,
1247c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
1257c478bd9Sstevel@tonic-gate static int ohci_hcdi_pipe_stop_isoc_polling(
1267c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1277c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate * Internal Function Prototypes
1317c478bd9Sstevel@tonic-gate */
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */
1347c478bd9Sstevel@tonic-gate static void ohci_set_dma_attributes(ohci_state_t *ohcip);
1357c478bd9Sstevel@tonic-gate static int ohci_allocate_pools(ohci_state_t *ohcip);
1367c478bd9Sstevel@tonic-gate static void ohci_decode_ddi_dma_addr_bind_handle_result(
1377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
1387c478bd9Sstevel@tonic-gate int result);
1397c478bd9Sstevel@tonic-gate static int ohci_map_regs(ohci_state_t *ohcip);
1407c478bd9Sstevel@tonic-gate static int ohci_register_intrs_and_init_mutex(
1417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
1429c75c6bfSgovinda static int ohci_add_intrs(ohci_state_t *ohcip,
1439c75c6bfSgovinda int intr_type);
1447c478bd9Sstevel@tonic-gate static int ohci_init_ctlr(ohci_state_t *ohcip);
1457c478bd9Sstevel@tonic-gate static int ohci_init_hcca(ohci_state_t *ohcip);
1467c478bd9Sstevel@tonic-gate static void ohci_build_interrupt_lattice(
1477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
1487c478bd9Sstevel@tonic-gate static int ohci_take_control(ohci_state_t *ohcip);
1497c478bd9Sstevel@tonic-gate static usba_hcdi_ops_t *ohci_alloc_hcdi_ops(
1507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */
1537c478bd9Sstevel@tonic-gate static int ohci_cleanup(ohci_state_t *ohcip);
1549c75c6bfSgovinda static void ohci_rem_intrs(ohci_state_t *ohcip);
1557c478bd9Sstevel@tonic-gate static int ohci_cpr_suspend(ohci_state_t *ohcip);
1567c478bd9Sstevel@tonic-gate static int ohci_cpr_resume(ohci_state_t *ohcip);
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */
1597c478bd9Sstevel@tonic-gate static int ohci_allocate_bandwidth(ohci_state_t *ohcip,
1607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1617c478bd9Sstevel@tonic-gate uint_t *node);
1627c478bd9Sstevel@tonic-gate static void ohci_deallocate_bandwidth(ohci_state_t *ohcip,
1637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
1647c478bd9Sstevel@tonic-gate static int ohci_compute_total_bandwidth(
1657c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint,
1667c478bd9Sstevel@tonic-gate usb_port_status_t port_status,
1677c478bd9Sstevel@tonic-gate uint_t *bandwidth);
1687c478bd9Sstevel@tonic-gate static int ohci_adjust_polling_interval(
1697c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
1707c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint,
1717c478bd9Sstevel@tonic-gate usb_port_status_t port_status);
1727c478bd9Sstevel@tonic-gate static uint_t ohci_lattice_height(uint_t interval);
1737c478bd9Sstevel@tonic-gate static uint_t ohci_lattice_parent(uint_t node);
1747c478bd9Sstevel@tonic-gate static uint_t ohci_leftmost_leaf(uint_t node,
1757c478bd9Sstevel@tonic-gate uint_t height);
1767c478bd9Sstevel@tonic-gate static uint_t ohci_hcca_intr_index(
1777c478bd9Sstevel@tonic-gate uint_t node);
1787c478bd9Sstevel@tonic-gate static uint_t ohci_hcca_leaf_index(
1797c478bd9Sstevel@tonic-gate uint_t leaf);
1807c478bd9Sstevel@tonic-gate static uint_t ohci_pow_2(uint_t x);
1817c478bd9Sstevel@tonic-gate static uint_t ohci_log_2(uint_t x);
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /* Endpoint Descriptor (ED) related functions */
1847c478bd9Sstevel@tonic-gate static uint_t ohci_unpack_endpoint(ohci_state_t *ohcip,
1857c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
1867c478bd9Sstevel@tonic-gate static void ohci_insert_ed(ohci_state_t *ohcip,
1877c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
1887c478bd9Sstevel@tonic-gate static void ohci_insert_ctrl_ed(
1897c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
1907c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
1917c478bd9Sstevel@tonic-gate static void ohci_insert_bulk_ed(
1927c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
1937c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
1947c478bd9Sstevel@tonic-gate static void ohci_insert_intr_ed(
1957c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
1967c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
1977c478bd9Sstevel@tonic-gate static void ohci_insert_isoc_ed(
1987c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
1997c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
2007c478bd9Sstevel@tonic-gate static void ohci_modify_sKip_bit(ohci_state_t *ohcip,
2017c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2027c478bd9Sstevel@tonic-gate skip_bit_t action,
2037c478bd9Sstevel@tonic-gate usb_flags_t flag);
2047c478bd9Sstevel@tonic-gate static void ohci_remove_ed(ohci_state_t *ohcip,
2057c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
2067c478bd9Sstevel@tonic-gate static void ohci_remove_ctrl_ed(
2077c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2087c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
2097c478bd9Sstevel@tonic-gate static void ohci_remove_bulk_ed(
2107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2117c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
2127c478bd9Sstevel@tonic-gate static void ohci_remove_periodic_ed(
2137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2147c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
2157c478bd9Sstevel@tonic-gate static void ohci_insert_ed_on_reclaim_list(
2167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2177c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
2187c478bd9Sstevel@tonic-gate static void ohci_detach_ed_from_list(
2197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2207c478bd9Sstevel@tonic-gate ohci_ed_t *ept,
2217c478bd9Sstevel@tonic-gate uint_t ept_type);
2227c478bd9Sstevel@tonic-gate static ohci_ed_t *ohci_ed_iommu_to_cpu(
2237c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2247c478bd9Sstevel@tonic-gate uintptr_t addr);
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate /* Transfer Descriptor (TD) related functions */
2277c478bd9Sstevel@tonic-gate static int ohci_initialize_dummy(ohci_state_t *ohcip,
2287c478bd9Sstevel@tonic-gate ohci_ed_t *ept);
2297c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_ctrl_resources(
2307c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2317c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2327c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp,
2337c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
2347c478bd9Sstevel@tonic-gate static void ohci_insert_ctrl_req(
2357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2367c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
2377c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp,
2387c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
2397c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
2407c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_bulk_resources(
2417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2427c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2437c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp,
2447c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
2457c478bd9Sstevel@tonic-gate static void ohci_insert_bulk_req(ohci_state_t *ohcip,
2467c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
2477c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp,
2487c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
2497c478bd9Sstevel@tonic-gate usb_flags_t flags);
2507c478bd9Sstevel@tonic-gate static int ohci_start_pipe_polling(ohci_state_t *ohcip,
2517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
2527c478bd9Sstevel@tonic-gate usb_flags_t flags);
2537c478bd9Sstevel@tonic-gate static void ohci_set_periodic_pipe_polling(
2547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
2567c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_intr_resources(
2577c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2587c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
2597c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp,
2607c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
2617c478bd9Sstevel@tonic-gate static void ohci_insert_intr_req(ohci_state_t *ohcip,
2627c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2637c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
2647c478bd9Sstevel@tonic-gate usb_flags_t flags);
2657c478bd9Sstevel@tonic-gate static int ohci_stop_periodic_pipe_polling(
2667c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2677c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
2687c478bd9Sstevel@tonic-gate usb_flags_t flags);
2697c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_isoc_resources(
2707c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2717c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
2727c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp,
2737c478bd9Sstevel@tonic-gate usb_flags_t usb_flags);
2747c478bd9Sstevel@tonic-gate static int ohci_insert_isoc_req(ohci_state_t *ohcip,
2757c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2767c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
2777c478bd9Sstevel@tonic-gate uint_t flags);
2787c478bd9Sstevel@tonic-gate static int ohci_insert_hc_td(ohci_state_t *ohcip,
2797c478bd9Sstevel@tonic-gate uint_t hctd_ctrl,
28002acac7eSsl147100 uint32_t hctd_dma_offs,
2817c478bd9Sstevel@tonic-gate size_t hctd_length,
2827c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase,
2837c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2847c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
2857c478bd9Sstevel@tonic-gate static ohci_td_t *ohci_allocate_td_from_pool(
2867c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
2877c478bd9Sstevel@tonic-gate static void ohci_fill_in_td(ohci_state_t *ohcip,
2887c478bd9Sstevel@tonic-gate ohci_td_t *td,
2897c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy,
2907c478bd9Sstevel@tonic-gate uint_t hctd_ctrl,
29102acac7eSsl147100 uint32_t hctd_dma_offs,
2927c478bd9Sstevel@tonic-gate size_t hctd_length,
2937c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase,
2947c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
2957c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
2967c478bd9Sstevel@tonic-gate static void ohci_init_itd(
2977c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
2987c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
2997c478bd9Sstevel@tonic-gate uint_t hctd_ctrl,
30002acac7eSsl147100 uint32_t index,
3017c478bd9Sstevel@tonic-gate ohci_td_t *td);
3027c478bd9Sstevel@tonic-gate static int ohci_insert_td_with_frame_number(
3037c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3057c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3067c478bd9Sstevel@tonic-gate ohci_td_t *current_td,
3077c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td);
3087c478bd9Sstevel@tonic-gate static void ohci_insert_td_on_tw(ohci_state_t *ohcip,
3097c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3107c478bd9Sstevel@tonic-gate ohci_td_t *td);
3117c478bd9Sstevel@tonic-gate static void ohci_done_list_tds(ohci_state_t *ohcip,
3127c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /* Transfer Wrapper (TW) functions */
3157c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_create_transfer_wrapper(
3167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3177c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3187c478bd9Sstevel@tonic-gate size_t length,
3197c478bd9Sstevel@tonic-gate uint_t usb_flags);
32002acac7eSsl147100 static ohci_trans_wrapper_t *ohci_create_isoc_transfer_wrapper(
32102acac7eSsl147100 ohci_state_t *ohcip,
32202acac7eSsl147100 ohci_pipe_private_t *pp,
32302acac7eSsl147100 size_t length,
32402acac7eSsl147100 usb_isoc_pkt_descr_t *descr,
32502acac7eSsl147100 ushort_t pkt_count,
32602acac7eSsl147100 size_t td_count,
32702acac7eSsl147100 uint_t usb_flags);
3289b58c2adSzhigang lu - Sun Microsystems - Beijing China int ohci_allocate_tds_for_tw(
3297c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3307c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3317c478bd9Sstevel@tonic-gate size_t td_count);
3327c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *ohci_allocate_tw_resources(
3337c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3347c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3357c478bd9Sstevel@tonic-gate size_t length,
3367c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
3377c478bd9Sstevel@tonic-gate size_t td_count);
3387c478bd9Sstevel@tonic-gate static void ohci_free_tw_tds_resources(
3397c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3407c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
3417c478bd9Sstevel@tonic-gate static void ohci_start_xfer_timer(
3427c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3437c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3447c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
3457c478bd9Sstevel@tonic-gate static void ohci_stop_xfer_timer(
3467c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3477c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3487c478bd9Sstevel@tonic-gate uint_t flag);
3497c478bd9Sstevel@tonic-gate static void ohci_xfer_timeout_handler(void *arg);
3507c478bd9Sstevel@tonic-gate static void ohci_remove_tw_from_timeout_list(
3517c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3527c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
3537c478bd9Sstevel@tonic-gate static void ohci_start_timer(ohci_state_t *ohcip);
3547c478bd9Sstevel@tonic-gate static void ohci_free_dma_resources(ohci_state_t *ohcip,
3557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
3567c478bd9Sstevel@tonic-gate static void ohci_free_tw(ohci_state_t *ohcip,
3577c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
35802acac7eSsl147100 static int ohci_tw_rebind_cookie(
35902acac7eSsl147100 ohci_state_t *ohcip,
36002acac7eSsl147100 ohci_pipe_private_t *pp,
36102acac7eSsl147100 ohci_trans_wrapper_t *tw);
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate /* Interrupt Handling functions */
3649c75c6bfSgovinda static uint_t ohci_intr(caddr_t arg1,
3659c75c6bfSgovinda caddr_t arg2);
3667c478bd9Sstevel@tonic-gate static void ohci_handle_missed_intr(
3677c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
3687c478bd9Sstevel@tonic-gate static void ohci_handle_ue(ohci_state_t *ohcip);
3697c478bd9Sstevel@tonic-gate static void ohci_handle_endpoint_reclaimation(
3707c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
3717c478bd9Sstevel@tonic-gate static void ohci_traverse_done_list(
3727c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3737c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list);
3747c478bd9Sstevel@tonic-gate static ohci_td_t *ohci_reverse_done_list(
3757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3767c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list);
3777c478bd9Sstevel@tonic-gate static usb_cr_t ohci_parse_error(ohci_state_t *ohcip,
3787c478bd9Sstevel@tonic-gate ohci_td_t *td);
3797c478bd9Sstevel@tonic-gate static void ohci_parse_isoc_error(
3807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3817c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3827c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3837c478bd9Sstevel@tonic-gate ohci_td_t *td);
3847c478bd9Sstevel@tonic-gate static usb_cr_t ohci_check_for_error(
3857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3867c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3877c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3887c478bd9Sstevel@tonic-gate ohci_td_t *td,
3897c478bd9Sstevel@tonic-gate uint_t ctrl);
3907c478bd9Sstevel@tonic-gate static void ohci_handle_error(
3917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3927c478bd9Sstevel@tonic-gate ohci_td_t *td,
3937c478bd9Sstevel@tonic-gate usb_cr_t error);
3947c478bd9Sstevel@tonic-gate static int ohci_cleanup_data_underrun(
3957c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
3967c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
3977c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
3987c478bd9Sstevel@tonic-gate ohci_td_t *td);
3997c478bd9Sstevel@tonic-gate static void ohci_handle_normal_td(
4007c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4017c478bd9Sstevel@tonic-gate ohci_td_t *td,
4027c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
4037c478bd9Sstevel@tonic-gate static void ohci_handle_ctrl_td(ohci_state_t *ohcip,
4047c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4057c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4067c478bd9Sstevel@tonic-gate ohci_td_t *td,
4077c478bd9Sstevel@tonic-gate void *);
4087c478bd9Sstevel@tonic-gate static void ohci_handle_bulk_td(ohci_state_t *ohcip,
4097c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4107c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4117c478bd9Sstevel@tonic-gate ohci_td_t *td,
4127c478bd9Sstevel@tonic-gate void *);
4137c478bd9Sstevel@tonic-gate static void ohci_handle_intr_td(ohci_state_t *ohcip,
4147c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4157c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4167c478bd9Sstevel@tonic-gate ohci_td_t *td,
4177c478bd9Sstevel@tonic-gate void *);
4187c478bd9Sstevel@tonic-gate static void ohci_handle_one_xfer_completion(
4197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4207c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
4217c478bd9Sstevel@tonic-gate static void ohci_handle_isoc_td(ohci_state_t *ohcip,
4227c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4237c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4247c478bd9Sstevel@tonic-gate ohci_td_t *td,
4257c478bd9Sstevel@tonic-gate void *);
4267c478bd9Sstevel@tonic-gate static void ohci_sendup_td_message(
4277c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4287c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4297c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4307c478bd9Sstevel@tonic-gate ohci_td_t *td,
4317c478bd9Sstevel@tonic-gate usb_cr_t error);
432688b07c5Sgc161489 static int ohci_check_done_head(
433688b07c5Sgc161489 ohci_state_t *ohcip,
434688b07c5Sgc161489 ohci_td_t *done_head);
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate /* Miscillaneous functions */
4377c478bd9Sstevel@tonic-gate static void ohci_cpr_cleanup(
4387c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
4397c478bd9Sstevel@tonic-gate static usb_req_attrs_t ohci_get_xfer_attrs(ohci_state_t *ohcip,
4407c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4417c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
4427c478bd9Sstevel@tonic-gate static int ohci_allocate_periodic_in_resource(
4437c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4447c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4457c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4467c478bd9Sstevel@tonic-gate usb_flags_t flags);
4477c478bd9Sstevel@tonic-gate static int ohci_wait_for_sof(
4487c478bd9Sstevel@tonic-gate ohci_state_t *ohcip);
4497c478bd9Sstevel@tonic-gate static void ohci_pipe_cleanup(
4507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
4527c478bd9Sstevel@tonic-gate static void ohci_wait_for_transfers_completion(
4537c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4547c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
4557c478bd9Sstevel@tonic-gate static void ohci_check_for_transfers_completion(
4567c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4577c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp);
4587c478bd9Sstevel@tonic-gate static void ohci_save_data_toggle(ohci_state_t *ohcip,
4597c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
4607c478bd9Sstevel@tonic-gate static void ohci_restore_data_toggle(ohci_state_t *ohcip,
4617c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph);
4627c478bd9Sstevel@tonic-gate static void ohci_deallocate_periodic_in_resource(
4637c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4647c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4657c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw);
4667c478bd9Sstevel@tonic-gate static void ohci_do_client_periodic_in_req_callback(
4677c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4687c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
4697c478bd9Sstevel@tonic-gate usb_cr_t completion_reason);
4707c478bd9Sstevel@tonic-gate static void ohci_hcdi_callback(
4717c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
4727c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
4737c478bd9Sstevel@tonic-gate usb_cr_t completion_reason);
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate /* Kstat Support */
4767c478bd9Sstevel@tonic-gate static void ohci_create_stats(ohci_state_t *ohcip);
4777c478bd9Sstevel@tonic-gate static void ohci_destroy_stats(ohci_state_t *ohcip);
4787c478bd9Sstevel@tonic-gate static void ohci_do_byte_stats(
4797c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4807c478bd9Sstevel@tonic-gate size_t len,
4817c478bd9Sstevel@tonic-gate uint8_t attr,
4827c478bd9Sstevel@tonic-gate uint8_t addr);
4837c478bd9Sstevel@tonic-gate static void ohci_do_intrs_stats(
4847c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
4857c478bd9Sstevel@tonic-gate int val);
4867c478bd9Sstevel@tonic-gate static void ohci_print_op_regs(ohci_state_t *ohcip);
4877c478bd9Sstevel@tonic-gate static void ohci_print_ed(ohci_state_t *ohcip,
4887c478bd9Sstevel@tonic-gate ohci_ed_t *ed);
4897c478bd9Sstevel@tonic-gate static void ohci_print_td(ohci_state_t *ohcip,
4907c478bd9Sstevel@tonic-gate ohci_td_t *td);
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /* extern */
4937c478bd9Sstevel@tonic-gate int usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level);
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate * Device operations (dev_ops) entries function prototypes.
4977c478bd9Sstevel@tonic-gate *
4987c478bd9Sstevel@tonic-gate * We use the hub cbops since all nexus ioctl operations defined so far will
4997c478bd9Sstevel@tonic-gate * be executed by the root hub. The following are the Host Controller Driver
5007c478bd9Sstevel@tonic-gate * (HCD) entry points.
5017c478bd9Sstevel@tonic-gate *
5027c478bd9Sstevel@tonic-gate * the open/close/ioctl functions call the corresponding usba_hubdi_*
5037c478bd9Sstevel@tonic-gate * calls after looking up the dip thru the dev_t.
5047c478bd9Sstevel@tonic-gate */
5057c478bd9Sstevel@tonic-gate static int ohci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
5067c478bd9Sstevel@tonic-gate static int ohci_close(dev_t dev, int flag, int otyp, cred_t *credp);
5077c478bd9Sstevel@tonic-gate static int ohci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
5087c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp);
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate static int ohci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
5117c478bd9Sstevel@tonic-gate static int ohci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
51219397407SSherry Moore static int ohci_quiesce(dev_info_t *dip);
51319397407SSherry Moore
5147c478bd9Sstevel@tonic-gate static int ohci_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5157c478bd9Sstevel@tonic-gate void *arg, void **result);
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate static struct cb_ops ohci_cb_ops = {
5187c478bd9Sstevel@tonic-gate ohci_open, /* Open */
5197c478bd9Sstevel@tonic-gate ohci_close, /* Close */
5207c478bd9Sstevel@tonic-gate nodev, /* Strategy */
5217c478bd9Sstevel@tonic-gate nodev, /* Print */
5227c478bd9Sstevel@tonic-gate nodev, /* Dump */
5237c478bd9Sstevel@tonic-gate nodev, /* Read */
5247c478bd9Sstevel@tonic-gate nodev, /* Write */
5257c478bd9Sstevel@tonic-gate ohci_ioctl, /* Ioctl */
5267c478bd9Sstevel@tonic-gate nodev, /* Devmap */
5277c478bd9Sstevel@tonic-gate nodev, /* Mmap */
5287c478bd9Sstevel@tonic-gate nodev, /* Segmap */
5297c478bd9Sstevel@tonic-gate nochpoll, /* Poll */
5307c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */
5317c478bd9Sstevel@tonic-gate NULL, /* Streamtab */
5327c478bd9Sstevel@tonic-gate D_MP /* Driver compatibility flag */
5337c478bd9Sstevel@tonic-gate };
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate static struct dev_ops ohci_ops = {
5367c478bd9Sstevel@tonic-gate DEVO_REV, /* Devo_rev */
5377c478bd9Sstevel@tonic-gate 0, /* Refcnt */
5387c478bd9Sstevel@tonic-gate ohci_info, /* Info */
5397c478bd9Sstevel@tonic-gate nulldev, /* Identify */
5407c478bd9Sstevel@tonic-gate nulldev, /* Probe */
5417c478bd9Sstevel@tonic-gate ohci_attach, /* Attach */
5427c478bd9Sstevel@tonic-gate ohci_detach, /* Detach */
5437c478bd9Sstevel@tonic-gate nodev, /* Reset */
5447c478bd9Sstevel@tonic-gate &ohci_cb_ops, /* Driver operations */
5457c478bd9Sstevel@tonic-gate &usba_hubdi_busops, /* Bus operations */
54619397407SSherry Moore usba_hubdi_root_hub_power, /* Power */
54719397407SSherry Moore ohci_quiesce, /* Quiesce */
5487c478bd9Sstevel@tonic-gate };
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate * The USBA library must be loaded for this driver.
5527c478bd9Sstevel@tonic-gate */
5537c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
5547c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
55577e51571Sgongtian zhao - Sun Microsystems - Beijing China "USB OpenHCI Driver", /* Name of the module. */
5567c478bd9Sstevel@tonic-gate &ohci_ops, /* Driver ops */
5577c478bd9Sstevel@tonic-gate };
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
5607c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
5617c478bd9Sstevel@tonic-gate };
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate int
_init(void)5657c478bd9Sstevel@tonic-gate _init(void)
5667c478bd9Sstevel@tonic-gate {
5677c478bd9Sstevel@tonic-gate int error;
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate /* Initialize the soft state structures */
5707c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&ohci_statep, sizeof (ohci_state_t),
5717c478bd9Sstevel@tonic-gate OHCI_INSTS)) != 0) {
5727c478bd9Sstevel@tonic-gate return (error);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate /* Install the loadable module */
5767c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) {
5777c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ohci_statep);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate return (error);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5857c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate int
_fini(void)5927c478bd9Sstevel@tonic-gate _fini(void)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate int error;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) == 0) {
5977c478bd9Sstevel@tonic-gate /* Release per module resources */
5987c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&ohci_statep);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate return (error);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) entry points
6077c478bd9Sstevel@tonic-gate */
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate /*
6107c478bd9Sstevel@tonic-gate * ohci_attach:
6117c478bd9Sstevel@tonic-gate */
6127c478bd9Sstevel@tonic-gate static int
ohci_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6133e1e1e62SToomas Soome ohci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate int instance;
6167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = NULL;
6177c478bd9Sstevel@tonic-gate usba_hcdi_register_args_t hcdi_args;
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate switch (cmd) {
6207c478bd9Sstevel@tonic-gate case DDI_ATTACH:
6217c478bd9Sstevel@tonic-gate break;
6227c478bd9Sstevel@tonic-gate case DDI_RESUME:
6237c478bd9Sstevel@tonic-gate ohcip = ohci_obtain_state(dip);
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate return (ohci_cpr_resume(ohcip));
6267c478bd9Sstevel@tonic-gate default:
6277c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /* Get the instance and create soft state */
6317c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip);
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(ohci_statep, instance) != 0) {
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate ohcip = ddi_get_soft_state(ohci_statep, instance);
6397c478bd9Sstevel@tonic-gate if (ohcip == NULL) {
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate ohcip->ohci_flags = OHCI_ATTACH;
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl = usb_alloc_log_hdl(dip, "ohci", &ohci_errlevel,
6477c478bd9Sstevel@tonic-gate &ohci_errmask, &ohci_instance_debug, 0);
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_ZALLOC;
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /* Set host controller soft state to initilization */
6527c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_INIT_STATE;
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
6557c478bd9Sstevel@tonic-gate "ohcip = 0x%p", (void *)ohcip);
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */
6587c478bd9Sstevel@tonic-gate ohci_set_dma_attributes(ohcip);
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /* Save the dip and instance */
6617c478bd9Sstevel@tonic-gate ohcip->ohci_dip = dip;
6627c478bd9Sstevel@tonic-gate ohcip->ohci_instance = instance;
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /* Initialize the kstat structures */
6657c478bd9Sstevel@tonic-gate ohci_create_stats(ohcip);
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate /* Create the td and ed pools */
6687c478bd9Sstevel@tonic-gate if (ohci_allocate_pools(ohcip) != DDI_SUCCESS) {
6697c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate /* Map the registers */
6757c478bd9Sstevel@tonic-gate if (ohci_map_regs(ohcip) != DDI_SUCCESS) {
6767c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate
681af95cb89Szhigang lu - Sun Microsystems - Beijing China /* Get the ohci chip vendor and device id */
682af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_vendor_id = pci_config_get16(
683af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_config_handle, PCI_CONF_VENID);
684af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_device_id = pci_config_get16(
685af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_config_handle, PCI_CONF_DEVID);
686af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_rev_id = pci_config_get8(
687af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_config_handle, PCI_CONF_REVID);
688af95cb89Szhigang lu - Sun Microsystems - Beijing China
6897c478bd9Sstevel@tonic-gate /* Register interrupts */
6907c478bd9Sstevel@tonic-gate if (ohci_register_intrs_and_init_mutex(ohcip) != DDI_SUCCESS) {
6917c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate /* Initialize the controller */
6997c478bd9Sstevel@tonic-gate if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) {
7007c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
7017c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate /*
7077c478bd9Sstevel@tonic-gate * At this point, the hardware wiil be okay.
7087c478bd9Sstevel@tonic-gate * Initialize the usba_hcdi structure
7097c478bd9Sstevel@tonic-gate */
7107c478bd9Sstevel@tonic-gate ohcip->ohci_hcdi_ops = ohci_alloc_hcdi_ops(ohcip);
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate * Make this HCD instance known to USBA
7167c478bd9Sstevel@tonic-gate * (dma_attr must be passed for USBA busctl's)
7177c478bd9Sstevel@tonic-gate */
7187c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION;
7197c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dip = dip;
7207c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_ops = ohcip->ohci_hcdi_ops;
7217c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_dma_attr = &ohcip->ohci_dma_attr;
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate * Priority and iblock_cookie are one and the same
7257c478bd9Sstevel@tonic-gate * (However, retaining hcdi_soft_iblock_cookie for now
7267c478bd9Sstevel@tonic-gate * assigning it w/ priority. In future all iblock_cookie
7277c478bd9Sstevel@tonic-gate * could just go)
7287c478bd9Sstevel@tonic-gate */
7297c478bd9Sstevel@tonic-gate hcdi_args.usba_hcdi_register_iblock_cookie =
730abdbd06dSagiri (ddi_iblock_cookie_t)(uintptr_t)ohcip->ohci_intr_pri;
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) {
7337c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_USBAREG;
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate if ((ohci_init_root_hub(ohcip)) != USB_SUCCESS) {
7427c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
7437c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate
7487c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate /* Finally load the root hub driver */
7517c478bd9Sstevel@tonic-gate if (ohci_load_root_hub_driver(ohcip) != USB_SUCCESS) {
7527c478bd9Sstevel@tonic-gate (void) ohci_cleanup(ohcip);
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate ohcip->ohci_flags |= OHCI_RHREG;
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate /* Display information in the banner */
7597c478bd9Sstevel@tonic-gate ddi_report_dev(dip);
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate /* Reset the ohci initilization flag */
7647c478bd9Sstevel@tonic-gate ohcip->ohci_flags &= ~OHCI_ATTACH;
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate /* Print the Host Control's Operational registers */
7677c478bd9Sstevel@tonic-gate ohci_print_op_regs(ohcip);
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate /* For RIO we need to call pci_report_pmcap */
7707c478bd9Sstevel@tonic-gate if (OHCI_IS_RIO(ohcip)) {
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
7787c478bd9Sstevel@tonic-gate "ohci_attach: dip = 0x%p done", (void *)dip);
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7817c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate * ohci_detach:
7867c478bd9Sstevel@tonic-gate */
7877c478bd9Sstevel@tonic-gate int
ohci_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)7883e1e1e62SToomas Soome ohci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7897c478bd9Sstevel@tonic-gate {
7907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(dip);
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_detach:");
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate switch (cmd) {
7957c478bd9Sstevel@tonic-gate case DDI_DETACH:
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate return (ohci_cleanup(ohcip));
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate case DDI_SUSPEND:
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate return (ohci_cpr_suspend(ohcip));
8027c478bd9Sstevel@tonic-gate default:
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate * ohci_info:
8117c478bd9Sstevel@tonic-gate */
8127c478bd9Sstevel@tonic-gate /* ARGSUSED */
8137c478bd9Sstevel@tonic-gate static int
ohci_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)8143e1e1e62SToomas Soome ohci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate dev_t dev;
8177c478bd9Sstevel@tonic-gate ohci_state_t *ohcip;
8187c478bd9Sstevel@tonic-gate int instance;
8197c478bd9Sstevel@tonic-gate int error = DDI_FAILURE;
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate switch (infocmd) {
8227c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
8237c478bd9Sstevel@tonic-gate dev = (dev_t)arg;
8247c478bd9Sstevel@tonic-gate instance = OHCI_UNIT(dev);
8257c478bd9Sstevel@tonic-gate ohcip = ddi_get_soft_state(ohci_statep, instance);
8267c478bd9Sstevel@tonic-gate if (ohcip != NULL) {
8277c478bd9Sstevel@tonic-gate *result = (void *)ohcip->ohci_dip;
8287c478bd9Sstevel@tonic-gate if (*result != NULL) {
8297c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate } else {
8327c478bd9Sstevel@tonic-gate *result = NULL;
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate break;
8367c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
8377c478bd9Sstevel@tonic-gate dev = (dev_t)arg;
8387c478bd9Sstevel@tonic-gate instance = OHCI_UNIT(dev);
8397c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
8407c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
8417c478bd9Sstevel@tonic-gate break;
8427c478bd9Sstevel@tonic-gate default:
8437c478bd9Sstevel@tonic-gate break;
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate return (error);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate * cb_ops entry points
8527c478bd9Sstevel@tonic-gate */
8537c478bd9Sstevel@tonic-gate static dev_info_t *
ohci_get_dip(dev_t dev)8547c478bd9Sstevel@tonic-gate ohci_get_dip(dev_t dev)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate int instance = OHCI_UNIT(dev);
8577c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ddi_get_soft_state(ohci_statep, instance);
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate if (ohcip) {
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate return (ohcip->ohci_dip);
8627c478bd9Sstevel@tonic-gate } else {
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate return (NULL);
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate static int
ohci_open(dev_t * devp,int flags,int otyp,cred_t * credp)8703e1e1e62SToomas Soome ohci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
8717c478bd9Sstevel@tonic-gate {
8727c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(*devp);
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate return (usba_hubdi_open(dip, devp, flags, otyp, credp));
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate static int
ohci_close(dev_t dev,int flag,int otyp,cred_t * credp)8793e1e1e62SToomas Soome ohci_close(dev_t dev, int flag, int otyp, cred_t *credp)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate dev_info_t *dip = ohci_get_dip(dev);
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate return (usba_hubdi_close(dip, dev, flag, otyp, credp));
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate static int
ohci_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)8883e1e1e62SToomas Soome ohci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 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
ohci_set_dma_attributes(ohci_state_t * ohcip)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
ohci_allocate_pools(ohci_state_t * ohcip)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,
9707c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0,
9717c478bd9Sstevel@tonic-gate &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,
9787c478bd9Sstevel@tonic-gate ohci_td_pool_size * sizeof (ohci_td_t),
9797c478bd9Sstevel@tonic-gate &dev_attr,
9807c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT,
9817c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
9827c478bd9Sstevel@tonic-gate 0,
9837c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_td_pool_addr,
9847c478bd9Sstevel@tonic-gate &real_length,
9857c478bd9Sstevel@tonic-gate &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(
9927c478bd9Sstevel@tonic-gate ohcip->ohci_td_pool_dma_handle,
9937c478bd9Sstevel@tonic-gate NULL,
9947c478bd9Sstevel@tonic-gate (caddr_t)ohcip->ohci_td_pool_addr,
9957c478bd9Sstevel@tonic-gate real_length,
9967c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
9977c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
9987c478bd9Sstevel@tonic-gate NULL,
9997c478bd9Sstevel@tonic-gate &ohcip->ohci_td_pool_cookie,
10007c478bd9Sstevel@tonic-gate &ccount);
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_td_pool_addr,
10037c478bd9Sstevel@tonic-gate 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,
10387c478bd9Sstevel@tonic-gate &ohcip->ohci_dma_attr,
10397c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
10407c478bd9Sstevel@tonic-gate 0,
10417c478bd9Sstevel@tonic-gate &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,
10487c478bd9Sstevel@tonic-gate ohci_ed_pool_size * sizeof (ohci_ed_t),
10497c478bd9Sstevel@tonic-gate &dev_attr,
10507c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT,
10517c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
10527c478bd9Sstevel@tonic-gate 0,
10537c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_ed_pool_addr,
10547c478bd9Sstevel@tonic-gate &real_length,
10557c478bd9Sstevel@tonic-gate &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,
10617c478bd9Sstevel@tonic-gate NULL,
10627c478bd9Sstevel@tonic-gate (caddr_t)ohcip->ohci_ed_pool_addr,
10637c478bd9Sstevel@tonic-gate real_length,
10647c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
10657c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
10667c478bd9Sstevel@tonic-gate NULL,
10677c478bd9Sstevel@tonic-gate &ohcip->ohci_ed_pool_cookie,
10687c478bd9Sstevel@tonic-gate &ccount);
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_ed_pool_addr,
10717c478bd9Sstevel@tonic-gate 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
ohci_decode_ddi_dma_addr_bind_handle_result(ohci_state_t * ohcip,int result)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
ohci_map_regs(ohci_state_t * ohcip)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
ohci_is_polled(dev_info_t * dip)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
ohci_poll_intr(void * arg)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
ohci_register_intrs_and_init_mutex(ohci_state_t * ohcip)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
1246af95cb89Szhigang lu - Sun Microsystems - Beijing China /*
1247af95cb89Szhigang lu - Sun Microsystems - Beijing China * Sometimes the OHCI controller of ULI1575 southbridge
1248af95cb89Szhigang lu - Sun Microsystems - Beijing China * could not receive SOF intrs when enable MSI. Hence
1249af95cb89Szhigang lu - Sun Microsystems - Beijing China * MSI is disabled for this chip.
1250af95cb89Szhigang lu - Sun Microsystems - Beijing China */
1251af95cb89Szhigang lu - Sun Microsystems - Beijing China if ((ohcip->ohci_vendor_id == PCI_ULI1575_VENID) &&
1252af95cb89Szhigang lu - Sun Microsystems - Beijing China (ohcip->ohci_device_id == PCI_ULI1575_DEVID)) {
1253af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_msi_enabled = B_FALSE;
1254af95cb89Szhigang lu - Sun Microsystems - Beijing China } else {
1255af95cb89Szhigang lu - Sun Microsystems - Beijing China ohcip->ohci_msi_enabled = ohci_enable_msi;
1256af95cb89Szhigang lu - Sun Microsystems - Beijing China }
1257af95cb89Szhigang lu - Sun Microsystems - Beijing China
125828cdc3d7Sszhou if (ohci_is_polled(ohcip->ohci_dip)) {
125928cdc3d7Sszhou extern pri_t maxclsyspri;
126028cdc3d7Sszhou
12618668df41Slg150142 USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
126228cdc3d7Sszhou "ohci_register_intrs_and_init_mutex: "
126328cdc3d7Sszhou "running in simulated polled mode");
126428cdc3d7Sszhou
126528cdc3d7Sszhou (void) thread_create(NULL, 0, ohci_poll_intr, ohcip, 0, &p0,
126628cdc3d7Sszhou TS_RUN, maxclsyspri);
126728cdc3d7Sszhou
126828cdc3d7Sszhou goto skip_intr;
126928cdc3d7Sszhou }
127028cdc3d7Sszhou
12719c75c6bfSgovinda /* Get supported interrupt types */
12729c75c6bfSgovinda if (ddi_intr_get_supported_types(ohcip->ohci_dip,
12739c75c6bfSgovinda &intr_types) != DDI_SUCCESS) {
12747c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12757c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: "
12769c75c6bfSgovinda "ddi_intr_get_supported_types failed");
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate
12819c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12827c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: "
12839c75c6bfSgovinda "supported interrupt types 0x%x", intr_types);
12847c478bd9Sstevel@tonic-gate
1285af95cb89Szhigang lu - Sun Microsystems - Beijing China if ((intr_types & DDI_INTR_TYPE_MSI) && ohcip->ohci_msi_enabled) {
12869c75c6bfSgovinda if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_MSI)
12879c75c6bfSgovinda != DDI_SUCCESS) {
12889c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12899c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: MSI "
12909c75c6bfSgovinda "registration failed, trying FIXED interrupt \n");
12919c75c6bfSgovinda } else {
12929c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12939c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: "
12949c75c6bfSgovinda "Using MSI interrupt type\n");
12959c75c6bfSgovinda
12969c75c6bfSgovinda ohcip->ohci_intr_type = DDI_INTR_TYPE_MSI;
12979c75c6bfSgovinda ohcip->ohci_flags |= OHCI_INTR;
12989c75c6bfSgovinda }
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate
13019c75c6bfSgovinda if ((!(ohcip->ohci_flags & OHCI_INTR)) &&
13029c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) {
13039c75c6bfSgovinda if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_FIXED)
13047c478bd9Sstevel@tonic-gate != DDI_SUCCESS) {
13057c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13067c478bd9Sstevel@tonic-gate "ohci_register_intrs_and_init_mutex: "
13079c75c6bfSgovinda "FIXED interrupt registration failed\n");
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13139c75c6bfSgovinda "ohci_register_intrs_and_init_mutex: "
13149c75c6bfSgovinda "Using FIXED interrupt type\n");
13159c75c6bfSgovinda
13169c75c6bfSgovinda ohcip->ohci_intr_type = DDI_INTR_TYPE_FIXED;
13179c75c6bfSgovinda ohcip->ohci_flags |= OHCI_INTR;
13189c75c6bfSgovinda }
13199c75c6bfSgovinda
132028cdc3d7Sszhou skip_intr:
13219c75c6bfSgovinda /* Create prototype for SOF condition variable */
13229c75c6bfSgovinda cv_init(&ohcip->ohci_SOF_cv, NULL, CV_DRIVER, NULL);
13239c75c6bfSgovinda
13249c75c6bfSgovinda /* Semaphore to serialize opens and closes */
13259c75c6bfSgovinda sema_init(&ohcip->ohci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
13269c75c6bfSgovinda
13279c75c6bfSgovinda return (DDI_SUCCESS);
13289c75c6bfSgovinda }
13299c75c6bfSgovinda
13309c75c6bfSgovinda
13319c75c6bfSgovinda /*
13329c75c6bfSgovinda * ohci_add_intrs:
13339c75c6bfSgovinda *
13349c75c6bfSgovinda * Register FIXED or MSI interrupts.
13359c75c6bfSgovinda */
13369c75c6bfSgovinda static int
ohci_add_intrs(ohci_state_t * ohcip,int intr_type)13373e1e1e62SToomas Soome ohci_add_intrs(ohci_state_t *ohcip, int intr_type)
13389c75c6bfSgovinda {
13399c75c6bfSgovinda int actual, avail, intr_size, count = 0;
13409c75c6bfSgovinda int i, flag, ret;
13419c75c6bfSgovinda
13429c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13439c75c6bfSgovinda "ohci_add_intrs: interrupt type 0x%x", intr_type);
13449c75c6bfSgovinda
13459c75c6bfSgovinda /* Get number of interrupts */
13469c75c6bfSgovinda ret = ddi_intr_get_nintrs(ohcip->ohci_dip, intr_type, &count);
13479c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) {
13489c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13499c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_nintrs() failure, "
13509c75c6bfSgovinda "ret: %d, count: %d", ret, count);
13519c75c6bfSgovinda
13529c75c6bfSgovinda return (DDI_FAILURE);
13539c75c6bfSgovinda }
13549c75c6bfSgovinda
13559c75c6bfSgovinda /* Get number of available interrupts */
13569c75c6bfSgovinda ret = ddi_intr_get_navail(ohcip->ohci_dip, intr_type, &avail);
13579c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) {
13589c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13599c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_navail() failure, "
13609c75c6bfSgovinda "ret: %d, count: %d", ret, count);
13619c75c6bfSgovinda
13629c75c6bfSgovinda return (DDI_FAILURE);
13639c75c6bfSgovinda }
13649c75c6bfSgovinda
13659c75c6bfSgovinda if (avail < count) {
13669c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13679c75c6bfSgovinda "ohci_add_intrs: ohci_add_intrs: nintrs () "
13689c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail);
13699c75c6bfSgovinda }
13709c75c6bfSgovinda
13719c75c6bfSgovinda /* Allocate an array of interrupt handles */
13729c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t);
13739c75c6bfSgovinda ohcip->ohci_htable = kmem_zalloc(intr_size, KM_SLEEP);
13749c75c6bfSgovinda
13759c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ?
13769c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
13779c75c6bfSgovinda
13789c75c6bfSgovinda /* call ddi_intr_alloc() */
13799c75c6bfSgovinda ret = ddi_intr_alloc(ohcip->ohci_dip, ohcip->ohci_htable,
13809c75c6bfSgovinda intr_type, 0, count, &actual, flag);
13819c75c6bfSgovinda
13829c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) {
13839c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13849c75c6bfSgovinda "ohci_add_intrs: ddi_intr_alloc() failed %d", ret);
13859c75c6bfSgovinda
13869c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size);
13879c75c6bfSgovinda
13889c75c6bfSgovinda return (DDI_FAILURE);
13899c75c6bfSgovinda }
13909c75c6bfSgovinda
13919c75c6bfSgovinda if (actual < count) {
13929c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13939c75c6bfSgovinda "ohci_add_intrs: Requested: %d, Received: %d\n",
13949c75c6bfSgovinda count, actual);
13959c75c6bfSgovinda
13969c75c6bfSgovinda for (i = 0; i < actual; i++)
13979c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]);
13989c75c6bfSgovinda
13999c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size);
14009c75c6bfSgovinda
14019c75c6bfSgovinda return (DDI_FAILURE);
14029c75c6bfSgovinda }
14039c75c6bfSgovinda
14049c75c6bfSgovinda ohcip->ohci_intr_cnt = actual;
14059c75c6bfSgovinda
14069c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ohcip->ohci_htable[0],
14079c75c6bfSgovinda &ohcip->ohci_intr_pri)) != DDI_SUCCESS) {
14089c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14099c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_pri() failed %d", ret);
14109c75c6bfSgovinda
14119c75c6bfSgovinda for (i = 0; i < actual; i++)
14129c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]);
14139c75c6bfSgovinda
14149c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size);
14159c75c6bfSgovinda
14169c75c6bfSgovinda return (DDI_FAILURE);
14179c75c6bfSgovinda }
14189c75c6bfSgovinda
14199c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14209c75c6bfSgovinda "ohci_add_intrs: Supported Interrupt priority 0x%x",
14219c75c6bfSgovinda ohcip->ohci_intr_pri);
14227c478bd9Sstevel@tonic-gate
14237c478bd9Sstevel@tonic-gate /* Test for high level mutex */
14247c478bd9Sstevel@tonic-gate if (ohcip->ohci_intr_pri >= ddi_intr_get_hilevel_pri()) {
14257c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14269c75c6bfSgovinda "ohci_add_intrs: Hi level interrupt not supported");
14277c478bd9Sstevel@tonic-gate
14289c75c6bfSgovinda for (i = 0; i < actual; i++)
14299c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]);
14309c75c6bfSgovinda
14319c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size);
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate /* Initialize the mutex */
14377c478bd9Sstevel@tonic-gate mutex_init(&ohcip->ohci_int_mutex, NULL, MUTEX_DRIVER,
1438a195726fSgovinda DDI_INTR_PRI(ohcip->ohci_intr_pri));
14397c478bd9Sstevel@tonic-gate
14409c75c6bfSgovinda /* Call ddi_intr_add_handler() */
14419c75c6bfSgovinda for (i = 0; i < actual; i++) {
14429c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ohcip->ohci_htable[i],
14439c75c6bfSgovinda ohci_intr, (caddr_t)ohcip,
14449c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
14457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14469c75c6bfSgovinda "ohci_add_intrs: ddi_intr_add_handler() "
14479c75c6bfSgovinda "failed %d", ret);
14489c75c6bfSgovinda
14499c75c6bfSgovinda for (i = 0; i < actual; i++)
14509c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]);
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate mutex_destroy(&ohcip->ohci_int_mutex);
14539c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size);
14549c75c6bfSgovinda
14559c75c6bfSgovinda return (DDI_FAILURE);
14569c75c6bfSgovinda }
14579c75c6bfSgovinda }
14589c75c6bfSgovinda
14599c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ohcip->ohci_htable[0],
14609c75c6bfSgovinda &ohcip->ohci_intr_cap)) != DDI_SUCCESS) {
14619c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14629c75c6bfSgovinda "ohci_add_intrs: ddi_intr_get_cap() failed %d", ret);
14639c75c6bfSgovinda
14649c75c6bfSgovinda for (i = 0; i < actual; i++) {
14659c75c6bfSgovinda (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]);
14669c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]);
14679c75c6bfSgovinda }
14689c75c6bfSgovinda
14699c75c6bfSgovinda mutex_destroy(&ohcip->ohci_int_mutex);
14709c75c6bfSgovinda kmem_free(ohcip->ohci_htable, intr_size);
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
14737c478bd9Sstevel@tonic-gate }
14747c478bd9Sstevel@tonic-gate
14759c75c6bfSgovinda /* Enable all interrupts */
14769c75c6bfSgovinda if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) {
14779c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */
14789c75c6bfSgovinda (void) ddi_intr_block_enable(ohcip->ohci_htable,
14799c75c6bfSgovinda ohcip->ohci_intr_cnt);
14809c75c6bfSgovinda } else {
14819c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */
14829c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++)
14839c75c6bfSgovinda (void) ddi_intr_enable(ohcip->ohci_htable[i]);
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate
14867c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate * ohci_init_ctlr:
14927c478bd9Sstevel@tonic-gate *
14937c478bd9Sstevel@tonic-gate * Initialize the Host Controller (HC).
14947c478bd9Sstevel@tonic-gate */
14957c478bd9Sstevel@tonic-gate static int
ohci_init_ctlr(ohci_state_t * ohcip)14967c478bd9Sstevel@tonic-gate ohci_init_ctlr(ohci_state_t *ohcip)
14977c478bd9Sstevel@tonic-gate {
14987c478bd9Sstevel@tonic-gate int revision, curr_control, max_packet = 0;
14997c478bd9Sstevel@tonic-gate clock_t sof_time_wait;
1500cbab2b26Slg150142 int retry = 0;
1501cbab2b26Slg150142 int ohci_frame_interval;
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_ctlr:");
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate if (ohci_take_control(ohcip) != DDI_SUCCESS) {
15067c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
15077c478bd9Sstevel@tonic-gate "ohci_init_ctlr: ohci_take_control failed\n");
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
15107c478bd9Sstevel@tonic-gate }
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate /*
15137c478bd9Sstevel@tonic-gate * Soft reset the host controller.
15147c478bd9Sstevel@tonic-gate *
15157c478bd9Sstevel@tonic-gate * On soft reset, the ohci host controller moves to the
15167c478bd9Sstevel@tonic-gate * USB Suspend state in which most of the ohci operational
15177c478bd9Sstevel@tonic-gate * registers are reset except stated ones. The soft reset
15187c478bd9Sstevel@tonic-gate * doesn't cause a reset to the ohci root hub and even no
15197c478bd9Sstevel@tonic-gate * subsequent reset signaling should be asserterd to its
15207c478bd9Sstevel@tonic-gate * down stream.
15217c478bd9Sstevel@tonic-gate */
15227c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET);
15237c478bd9Sstevel@tonic-gate
152429aca3ebSlc152243 mutex_exit(&ohcip->ohci_int_mutex);
15257c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */
152629aca3ebSlc152243 delay(drv_usectohz(OHCI_RESET_TIMEWAIT));
152729aca3ebSlc152243 mutex_enter(&ohcip->ohci_int_mutex);
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /*
15307c478bd9Sstevel@tonic-gate * Do hard reset the host controller.
15317c478bd9Sstevel@tonic-gate *
15327c478bd9Sstevel@tonic-gate * Now perform USB reset in order to reset the ohci root
15337c478bd9Sstevel@tonic-gate * hub.
15347c478bd9Sstevel@tonic-gate */
15357c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, HCR_CONTROL_RESET);
15367c478bd9Sstevel@tonic-gate
15377c478bd9Sstevel@tonic-gate /*
15387c478bd9Sstevel@tonic-gate * According to Section 5.1.2.3 of the specification, the
15397c478bd9Sstevel@tonic-gate * host controller will go into suspend state immediately
15407c478bd9Sstevel@tonic-gate * after the reset.
15417c478bd9Sstevel@tonic-gate */
15427c478bd9Sstevel@tonic-gate
15437c478bd9Sstevel@tonic-gate /* Verify the version number */
15447c478bd9Sstevel@tonic-gate revision = Get_OpReg(hcr_revision);
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate if ((revision & HCR_REVISION_MASK) != HCR_REVISION_1_0) {
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
15527c478bd9Sstevel@tonic-gate "ohci_init_ctlr: Revision verified");
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate /* hcca area need not be initialized on resume */
15557c478bd9Sstevel@tonic-gate if (ohcip->ohci_hc_soft_state == OHCI_CTLR_INIT_STATE) {
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate /* Initialize the hcca area */
15587c478bd9Sstevel@tonic-gate if (ohci_init_hcca(ohcip) != DDI_SUCCESS) {
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate
1564f806f48bShs155680 /*
1565f806f48bShs155680 * Workaround for ULI1575 chipset. Following OHCI Operational Memory
1566f806f48bShs155680 * Registers are not cleared to their default value on reset.
1567f806f48bShs155680 * Explicitly set the registers to default value.
1568f806f48bShs155680 */
1569f806f48bShs155680 if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID &&
1570f806f48bShs155680 ohcip->ohci_device_id == PCI_ULI1575_DEVID) {
1571f806f48bShs155680 Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT);
1572f806f48bShs155680 Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT);
1573f806f48bShs155680 Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT);
1574f806f48bShs155680 Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT);
1575f806f48bShs155680 Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT);
1576f806f48bShs155680 Set_OpReg(hcr_frame_interval, HCR_FRAME_INTERVAL_DEFAULT);
1577f806f48bShs155680 Set_OpReg(hcr_periodic_strt, HCR_PERIODIC_START_DEFAULT);
1578f806f48bShs155680 }
1579f806f48bShs155680
15807c478bd9Sstevel@tonic-gate /* Set the HcHCCA to the physical address of the HCCA block */
15817c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, (uint_t)ohcip->ohci_hcca_cookie.dmac_address);
15827c478bd9Sstevel@tonic-gate
15837c478bd9Sstevel@tonic-gate /*
15847c478bd9Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except Root
15857c478bd9Sstevel@tonic-gate * Hub Status change and SOF interrupts.
15867c478bd9Sstevel@tonic-gate */
15877c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SO | HCR_INTR_WDH |
15887c478bd9Sstevel@tonic-gate HCR_INTR_RD | HCR_INTR_UE | HCR_INTR_FNO | HCR_INTR_MIE);
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate /*
15917c478bd9Sstevel@tonic-gate * For non-periodic transfers, reserve atleast for one low-speed
15927c478bd9Sstevel@tonic-gate * device transaction. According to USB Bandwidth Analysis white
15937c478bd9Sstevel@tonic-gate * paper and also as per OHCI Specification 1.0a, section 7.3.5,
15947c478bd9Sstevel@tonic-gate * page 123, one low-speed transaction takes 0x628h full speed
15957c478bd9Sstevel@tonic-gate * bits (197 bytes), which comes to around 13% of USB frame time.
15967c478bd9Sstevel@tonic-gate *
15977c478bd9Sstevel@tonic-gate * The periodic transfers will get around 87% of USB frame time.
15987c478bd9Sstevel@tonic-gate */
15997c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_strt,
16007c478bd9Sstevel@tonic-gate ((PERIODIC_XFER_STARTS * BITS_PER_BYTE) - 1));
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate /* Save the contents of the Frame Interval Registers */
16037c478bd9Sstevel@tonic-gate ohcip->ohci_frame_interval = Get_OpReg(hcr_frame_interval);
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate /*
16067c478bd9Sstevel@tonic-gate * Initialize the FSLargestDataPacket value in the frame interval
16077c478bd9Sstevel@tonic-gate * register. The controller compares the value of MaxPacketSize to
16087c478bd9Sstevel@tonic-gate * this value to see if the entire packet may be sent out before
16097c478bd9Sstevel@tonic-gate * the EOF.
16107c478bd9Sstevel@tonic-gate */
16117c478bd9Sstevel@tonic-gate max_packet = ((((ohcip->ohci_frame_interval -
16127c478bd9Sstevel@tonic-gate MAX_OVERHEAD) * 6) / 7) << HCR_FRME_FSMPS_SHFT);
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate Set_OpReg(hcr_frame_interval,
16157c478bd9Sstevel@tonic-gate (max_packet | ohcip->ohci_frame_interval));
16167c478bd9Sstevel@tonic-gate
1617cbab2b26Slg150142 /*
1618cbab2b26Slg150142 * Sometimes the HcFmInterval register in OHCI controller does not
1619cbab2b26Slg150142 * maintain its value after the first write. This problem is found
1620cbab2b26Slg150142 * on ULI M1575 South Bridge. To workaround the hardware problem,
1621cbab2b26Slg150142 * check the value after write and retry if the last write failed.
1622cbab2b26Slg150142 */
1623cbab2b26Slg150142 if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID &&
1624cbab2b26Slg150142 ohcip->ohci_device_id == PCI_ULI1575_DEVID) {
1625cbab2b26Slg150142 ohci_frame_interval = Get_OpReg(hcr_frame_interval);
1626cbab2b26Slg150142 while ((ohci_frame_interval != (max_packet |
1627cbab2b26Slg150142 ohcip->ohci_frame_interval))) {
1628cbab2b26Slg150142 if (retry >= 10) {
1629cbab2b26Slg150142 USB_DPRINTF_L1(PRINT_MASK_ATTA,
16308668df41Slg150142 ohcip->ohci_log_hdl, "Failed to program"
16318668df41Slg150142 " Frame Interval Register.");
1632cbab2b26Slg150142
1633cbab2b26Slg150142 return (DDI_FAILURE);
1634cbab2b26Slg150142 }
1635cbab2b26Slg150142 retry++;
1636cbab2b26Slg150142 USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
1637cbab2b26Slg150142 "ohci_init_ctlr: Failed to program Frame"
1638cbab2b26Slg150142 " Interval Register, retry=%d", retry);
1639cbab2b26Slg150142 Set_OpReg(hcr_frame_interval,
1640cbab2b26Slg150142 (max_packet | ohcip->ohci_frame_interval));
1641cbab2b26Slg150142 ohci_frame_interval = Get_OpReg(hcr_frame_interval);
1642cbab2b26Slg150142 }
1643cbab2b26Slg150142 }
1644cbab2b26Slg150142
16457c478bd9Sstevel@tonic-gate /* Begin sending SOFs */
16467c478bd9Sstevel@tonic-gate curr_control = Get_OpReg(hcr_control);
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
16497c478bd9Sstevel@tonic-gate "ohci_init_ctlr: curr_control=0x%x", curr_control);
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate /* Set the state to operational */
16527c478bd9Sstevel@tonic-gate curr_control = (curr_control &
16537c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_OPERAT;
16547c478bd9Sstevel@tonic-gate
16557c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, curr_control);
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate ASSERT((Get_OpReg(hcr_control) &
16587c478bd9Sstevel@tonic-gate HCR_CONTROL_HCFS) == HCR_CONTROL_OPERAT);
16597c478bd9Sstevel@tonic-gate
16607c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */
16617c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_OPERATIONAL_STATE;
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */
16647c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz(OHCI_MAX_SOF_TIMEWAIT * 1000000);
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate /* Clear ohci_sof_flag indicating waiting for SOF interrupt */
16677c478bd9Sstevel@tonic-gate ohcip->ohci_sof_flag = B_FALSE;
16687c478bd9Sstevel@tonic-gate
16697c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */
16707c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF);
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_intr_enable) & HCR_INTR_SOF);
16737c478bd9Sstevel@tonic-gate
1674d3d50737SRafael Vanoni (void) cv_reltimedwait(&ohcip->ohci_SOF_cv,
1675d3d50737SRafael Vanoni &ohcip->ohci_int_mutex, sof_time_wait, TR_CLOCK_TICK);
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate /* Wait for the SOF or timeout event */
16787c478bd9Sstevel@tonic-gate if (ohcip->ohci_sof_flag == B_FALSE) {
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */
16817c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_ERROR_STATE;
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
16847c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB OHCI host"
16857c478bd9Sstevel@tonic-gate "controller is unusable");
16867c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
16907c478bd9Sstevel@tonic-gate "ohci_init_ctlr: SOF's have started");
16917c478bd9Sstevel@tonic-gate
16927c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
16937c478bd9Sstevel@tonic-gate }
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate * ohci_init_hcca:
16987c478bd9Sstevel@tonic-gate *
16997c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller Communication
17007c478bd9Sstevel@tonic-gate * Area (HCCA). The HCCA structure must be aligned to a 256-byte boundary.
17017c478bd9Sstevel@tonic-gate */
17027c478bd9Sstevel@tonic-gate static int
ohci_init_hcca(ohci_state_t * ohcip)17037c478bd9Sstevel@tonic-gate ohci_init_hcca(ohci_state_t *ohcip)
17047c478bd9Sstevel@tonic-gate {
17057c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr;
17067c478bd9Sstevel@tonic-gate size_t real_length;
17077c478bd9Sstevel@tonic-gate uint_t mask, ccount;
17087c478bd9Sstevel@tonic-gate int result;
17097c478bd9Sstevel@tonic-gate uintptr_t addr;
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
17127c478bd9Sstevel@tonic-gate
17137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_hcca:");
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate /* The host controller will be little endian */
17167c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
17177c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
17187c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
17197c478bd9Sstevel@tonic-gate
17207c478bd9Sstevel@tonic-gate /* Byte alignment to HCCA alignment */
17217c478bd9Sstevel@tonic-gate ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_HCCA_ALIGNMENT;
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate /* Create space for the HCCA block */
17247c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ohcip->ohci_dip, &ohcip->ohci_dma_attr,
17257c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
17267c478bd9Sstevel@tonic-gate 0,
17277c478bd9Sstevel@tonic-gate &ohcip->ohci_hcca_dma_handle)
17287c478bd9Sstevel@tonic-gate != DDI_SUCCESS) {
17297c478bd9Sstevel@tonic-gate
17307c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ohcip->ohci_hcca_dma_handle,
17347c478bd9Sstevel@tonic-gate 2 * sizeof (ohci_hcca_t),
17357c478bd9Sstevel@tonic-gate &dev_attr,
17367c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT,
17377c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP,
17387c478bd9Sstevel@tonic-gate 0,
17397c478bd9Sstevel@tonic-gate (caddr_t *)&ohcip->ohci_hccap,
17407c478bd9Sstevel@tonic-gate &real_length,
17417c478bd9Sstevel@tonic-gate &ohcip->ohci_hcca_mem_handle)) {
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate
17467c478bd9Sstevel@tonic-gate bzero((void *)ohcip->ohci_hccap, real_length);
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate /* Figure out the alignment requirements */
17497c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, 0xFFFFFFFF);
17507c478bd9Sstevel@tonic-gate
17517c478bd9Sstevel@tonic-gate /*
17527c478bd9Sstevel@tonic-gate * Read the hcr_HCCA register until
17537c478bd9Sstevel@tonic-gate * contenets are non-zero.
17547c478bd9Sstevel@tonic-gate */
17557c478bd9Sstevel@tonic-gate mask = Get_OpReg(hcr_HCCA);
17567c478bd9Sstevel@tonic-gate
175729aca3ebSlc152243 mutex_exit(&ohcip->ohci_int_mutex);
17587c478bd9Sstevel@tonic-gate while (mask == 0) {
175929aca3ebSlc152243 delay(drv_usectohz(OHCI_TIMEWAIT));
17607c478bd9Sstevel@tonic-gate mask = Get_OpReg(hcr_HCCA);
17617c478bd9Sstevel@tonic-gate }
176229aca3ebSlc152243 mutex_enter(&ohcip->ohci_int_mutex);
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate ASSERT(mask != 0);
17657c478bd9Sstevel@tonic-gate
17667c478bd9Sstevel@tonic-gate addr = (uintptr_t)ohcip->ohci_hccap;
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
17697c478bd9Sstevel@tonic-gate "ohci_init_hcca: addr=0x%lx, mask=0x%x", addr, mask);
17707c478bd9Sstevel@tonic-gate
17717c478bd9Sstevel@tonic-gate while (addr & (~mask)) {
17727c478bd9Sstevel@tonic-gate addr++;
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate
17757c478bd9Sstevel@tonic-gate ohcip->ohci_hccap = (ohci_hcca_t *)addr;
17767c478bd9Sstevel@tonic-gate
17777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
17787c478bd9Sstevel@tonic-gate "ohci_init_hcca: Real length %lu", real_length);
17797c478bd9Sstevel@tonic-gate
17807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
17817c478bd9Sstevel@tonic-gate "ohci_init_hcca: virtual hcca 0x%p", (void *)ohcip->ohci_hccap);
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate /* Map the whole HCCA into the I/O address space */
17847c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ohcip->ohci_hcca_dma_handle,
17857c478bd9Sstevel@tonic-gate NULL,
17867c478bd9Sstevel@tonic-gate (caddr_t)ohcip->ohci_hccap,
17877c478bd9Sstevel@tonic-gate real_length,
17887c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
17897c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL,
17907c478bd9Sstevel@tonic-gate &ohcip->ohci_hcca_cookie,
17917c478bd9Sstevel@tonic-gate &ccount);
17927c478bd9Sstevel@tonic-gate
17937c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) {
17947c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */
17957c478bd9Sstevel@tonic-gate if (ccount != 1) {
17967c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
17977c478bd9Sstevel@tonic-gate "ohci_init_hcca: More than 1 cookie");
17987c478bd9Sstevel@tonic-gate
17997c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate } else {
18027c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result);
18037c478bd9Sstevel@tonic-gate
18047c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate
18076d9a41ffSqz150045 /*
18086d9a41ffSqz150045 * DMA addresses for HCCA are bound
18096d9a41ffSqz150045 */
18106d9a41ffSqz150045 ohcip->ohci_dma_addr_bind_flag |= OHCI_HCCA_DMA_BOUND;
18116d9a41ffSqz150045
18127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
18137c478bd9Sstevel@tonic-gate "ohci_init_hcca: physical 0x%p",
18147c478bd9Sstevel@tonic-gate (void *)(uintptr_t)ohcip->ohci_hcca_cookie.dmac_address);
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
18177c478bd9Sstevel@tonic-gate "ohci_init_hcca: size %lu", ohcip->ohci_hcca_cookie.dmac_size);
18187c478bd9Sstevel@tonic-gate
18197c478bd9Sstevel@tonic-gate /* Initialize the interrupt lists */
18207c478bd9Sstevel@tonic-gate ohci_build_interrupt_lattice(ohcip);
18217c478bd9Sstevel@tonic-gate
18227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
18237c478bd9Sstevel@tonic-gate "ohci_init_hcca: End");
18247c478bd9Sstevel@tonic-gate
18257c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate /*
18307c478bd9Sstevel@tonic-gate * ohci_build_interrupt_lattice:
18317c478bd9Sstevel@tonic-gate *
18327c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors
18337c478bd9Sstevel@tonic-gate * (ED). This interrupt lattice tree will have total of 32 interrupt ED
18347c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt ED list in
18357c478bd9Sstevel@tonic-gate * every frame. The lower five bits of the current frame number indexes
18367c478bd9Sstevel@tonic-gate * into an array of 32 interrupt Endpoint Descriptor lists found in the
18377c478bd9Sstevel@tonic-gate * HCCA.
18387c478bd9Sstevel@tonic-gate */
18397c478bd9Sstevel@tonic-gate static void
ohci_build_interrupt_lattice(ohci_state_t * ohcip)18407c478bd9Sstevel@tonic-gate ohci_build_interrupt_lattice(ohci_state_t *ohcip)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate ohci_ed_t *list_array = ohcip->ohci_ed_pool_addr;
18437c478bd9Sstevel@tonic-gate int half_list = NUM_INTR_ED_LISTS / 2;
18447c478bd9Sstevel@tonic-gate ohci_hcca_t *hccap = ohcip->ohci_hccap;
18457c478bd9Sstevel@tonic-gate uintptr_t addr;
18467c478bd9Sstevel@tonic-gate int i;
18477c478bd9Sstevel@tonic-gate
18487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
18497c478bd9Sstevel@tonic-gate "ohci_build_interrupt_lattice:");
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate /*
18527c478bd9Sstevel@tonic-gate * Reserve the first 31 Endpoint Descriptor (ED) structures
18537c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for
18547c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree.
18557c478bd9Sstevel@tonic-gate */
18567c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_STATIC_NODES; i++) {
18577c478bd9Sstevel@tonic-gate Set_ED(list_array[i].hced_ctrl, HC_EPT_sKip);
18587c478bd9Sstevel@tonic-gate
18597c478bd9Sstevel@tonic-gate Set_ED(list_array[i].hced_state, HC_EPT_STATIC);
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */
18637c478bd9Sstevel@tonic-gate for (i = 0; i < half_list - 1; i++) {
18647c478bd9Sstevel@tonic-gate
18657c478bd9Sstevel@tonic-gate /*
18667c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint
18677c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate
18687c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the
18697c478bd9Sstevel@tonic-gate * starting iommu address.
18707c478bd9Sstevel@tonic-gate */
18717c478bd9Sstevel@tonic-gate addr = ohci_ed_cpu_to_iommu(ohcip, (ohci_ed_t *)&list_array[i]);
18727c478bd9Sstevel@tonic-gate
18737c478bd9Sstevel@tonic-gate Set_ED(list_array[2*i + 1].hced_next, addr);
18747c478bd9Sstevel@tonic-gate Set_ED(list_array[2*i + 2].hced_next, addr);
18757c478bd9Sstevel@tonic-gate }
18767c478bd9Sstevel@tonic-gate
18777c478bd9Sstevel@tonic-gate /*
18787c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the HCCA so that it points
18797c478bd9Sstevel@tonic-gate * to the bottom of the tree.
18807c478bd9Sstevel@tonic-gate */
18817c478bd9Sstevel@tonic-gate for (i = 0; i < half_list; i++) {
18827c478bd9Sstevel@tonic-gate addr = ohci_ed_cpu_to_iommu(ohcip,
18837c478bd9Sstevel@tonic-gate (ohci_ed_t *)&list_array[half_list - 1 + ohci_index[i]]);
18847c478bd9Sstevel@tonic-gate
18857c478bd9Sstevel@tonic-gate ASSERT(Get_ED(list_array[half_list - 1 +
18867c478bd9Sstevel@tonic-gate ohci_index[i]].hced_ctrl));
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate ASSERT(addr != 0);
18897c478bd9Sstevel@tonic-gate
18907c478bd9Sstevel@tonic-gate Set_HCCA(hccap->HccaIntTble[i], addr);
18917c478bd9Sstevel@tonic-gate Set_HCCA(hccap->HccaIntTble[i + half_list], addr);
18927c478bd9Sstevel@tonic-gate }
18937c478bd9Sstevel@tonic-gate }
18947c478bd9Sstevel@tonic-gate
18957c478bd9Sstevel@tonic-gate
18967c478bd9Sstevel@tonic-gate /*
18977c478bd9Sstevel@tonic-gate * ohci_take_control:
18987c478bd9Sstevel@tonic-gate *
18997c478bd9Sstevel@tonic-gate * Take control of the host controller. OpenHCI allows for optional support
19007c478bd9Sstevel@tonic-gate * of legacy devices through the use of System Management Mode software and
19017c478bd9Sstevel@tonic-gate * system Management interrupt hardware. See section 5.1.1.3 of the OpenHCI
19027c478bd9Sstevel@tonic-gate * spec for more details.
19037c478bd9Sstevel@tonic-gate */
19047c478bd9Sstevel@tonic-gate static int
ohci_take_control(ohci_state_t * ohcip)19057c478bd9Sstevel@tonic-gate ohci_take_control(ohci_state_t *ohcip)
19067c478bd9Sstevel@tonic-gate {
19077c478bd9Sstevel@tonic-gate #if defined(__x86)
19087c478bd9Sstevel@tonic-gate uint32_t hcr_control_val;
19097c478bd9Sstevel@tonic-gate uint32_t hcr_cmd_status_val;
19107c478bd9Sstevel@tonic-gate int wait;
19117c478bd9Sstevel@tonic-gate #endif /* __x86 */
19127c478bd9Sstevel@tonic-gate
19137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
19147c478bd9Sstevel@tonic-gate "ohci_take_control:");
19157c478bd9Sstevel@tonic-gate
19167c478bd9Sstevel@tonic-gate #if defined(__x86)
19177c478bd9Sstevel@tonic-gate /*
19187c478bd9Sstevel@tonic-gate * On x86, we must tell the BIOS we want the controller,
19197c478bd9Sstevel@tonic-gate * and wait for it to respond that we can have it.
19207c478bd9Sstevel@tonic-gate */
19217c478bd9Sstevel@tonic-gate hcr_control_val = Get_OpReg(hcr_control);
19227c478bd9Sstevel@tonic-gate if ((hcr_control_val & HCR_CONTROL_IR) == 0) {
19237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
19247c478bd9Sstevel@tonic-gate "ohci_take_control: InterruptRouting off\n");
19257c478bd9Sstevel@tonic-gate
19267c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
19277c478bd9Sstevel@tonic-gate }
19287c478bd9Sstevel@tonic-gate
19297c478bd9Sstevel@tonic-gate /* attempt the OwnershipChange request */
19307c478bd9Sstevel@tonic-gate hcr_cmd_status_val = Get_OpReg(hcr_cmd_status);
19317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
19327c478bd9Sstevel@tonic-gate "ohci_take_control: hcr_cmd_status: 0x%x\n",
19337c478bd9Sstevel@tonic-gate hcr_cmd_status_val);
19347c478bd9Sstevel@tonic-gate hcr_cmd_status_val |= HCR_STATUS_OCR;
19357c478bd9Sstevel@tonic-gate
19367c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, hcr_cmd_status_val);
19377c478bd9Sstevel@tonic-gate
193829aca3ebSlc152243
193929aca3ebSlc152243 mutex_exit(&ohcip->ohci_int_mutex);
19407c478bd9Sstevel@tonic-gate /* now wait for 5 seconds for InterruptRouting to go away */
19417c478bd9Sstevel@tonic-gate for (wait = 0; wait < 5000; wait++) {
19427c478bd9Sstevel@tonic-gate if ((Get_OpReg(hcr_control) & HCR_CONTROL_IR) == 0)
19437c478bd9Sstevel@tonic-gate break;
194429aca3ebSlc152243 delay(drv_usectohz(1000));
19457c478bd9Sstevel@tonic-gate }
194629aca3ebSlc152243 mutex_enter(&ohcip->ohci_int_mutex);
194729aca3ebSlc152243
19487c478bd9Sstevel@tonic-gate if (wait >= 5000) {
19497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
19507c478bd9Sstevel@tonic-gate "ohci_take_control: couldn't take control from BIOS\n");
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
19537c478bd9Sstevel@tonic-gate }
19547c478bd9Sstevel@tonic-gate #else /* __x86 */
19557c478bd9Sstevel@tonic-gate /*
19567c478bd9Sstevel@tonic-gate * On Sparc, there won't be special System Management Mode
19577c478bd9Sstevel@tonic-gate * hardware for legacy devices, while the x86 platforms may
19587c478bd9Sstevel@tonic-gate * have to deal with this. This function may be platform
19597c478bd9Sstevel@tonic-gate * specific.
19607c478bd9Sstevel@tonic-gate *
19617c478bd9Sstevel@tonic-gate * The interrupt routing bit should not be set.
19627c478bd9Sstevel@tonic-gate */
19637c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_control) & HCR_CONTROL_IR) {
19647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
19657c478bd9Sstevel@tonic-gate "ohci_take_control: Routing bit set");
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
19687c478bd9Sstevel@tonic-gate }
19697c478bd9Sstevel@tonic-gate #endif /* __x86 */
19707c478bd9Sstevel@tonic-gate
19717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
19727c478bd9Sstevel@tonic-gate "ohci_take_control: End");
19737c478bd9Sstevel@tonic-gate
19747c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
19757c478bd9Sstevel@tonic-gate }
19767c478bd9Sstevel@tonic-gate
19774610e4a0Sfrits /*
19784610e4a0Sfrits * ohci_pm_support:
19794610e4a0Sfrits * always return success since PM has been quite reliable on ohci
19804610e4a0Sfrits */
19814610e4a0Sfrits /*ARGSUSED*/
19824610e4a0Sfrits int
ohci_hcdi_pm_support(dev_info_t * dip)19834610e4a0Sfrits ohci_hcdi_pm_support(dev_info_t *dip)
19844610e4a0Sfrits {
19854610e4a0Sfrits return (USB_SUCCESS);
19864610e4a0Sfrits }
19877c478bd9Sstevel@tonic-gate
19887c478bd9Sstevel@tonic-gate /*
19897c478bd9Sstevel@tonic-gate * ohci_alloc_hcdi_ops:
19907c478bd9Sstevel@tonic-gate *
19917c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by
19927c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the
19937c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA
19947c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points.
19957c478bd9Sstevel@tonic-gate */
19967c478bd9Sstevel@tonic-gate static usba_hcdi_ops_t *
ohci_alloc_hcdi_ops(ohci_state_t * ohcip)19977c478bd9Sstevel@tonic-gate ohci_alloc_hcdi_ops(ohci_state_t *ohcip)
19987c478bd9Sstevel@tonic-gate {
19997c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops;
20007c478bd9Sstevel@tonic-gate
20017c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
20027c478bd9Sstevel@tonic-gate "ohci_alloc_hcdi_ops:");
20037c478bd9Sstevel@tonic-gate
20047c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops();
20057c478bd9Sstevel@tonic-gate
20067c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
20077c478bd9Sstevel@tonic-gate
20084610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ohci_hcdi_pm_support;
20097c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ohci_hcdi_pipe_open;
20107c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ohci_hcdi_pipe_close;
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ohci_hcdi_pipe_reset;
2013269552cdSguoqing zhu - Sun Microsystems - Beijing China usba_hcdi_ops->usba_hcdi_pipe_reset_data_toggle =
2014269552cdSguoqing zhu - Sun Microsystems - Beijing China ohci_hcdi_pipe_reset_data_toggle;
20157c478bd9Sstevel@tonic-gate
20167c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ohci_hcdi_pipe_ctrl_xfer;
20177c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ohci_hcdi_pipe_bulk_xfer;
20187c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ohci_hcdi_pipe_intr_xfer;
20197c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ohci_hcdi_pipe_isoc_xfer;
20207c478bd9Sstevel@tonic-gate
20217c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
20227c478bd9Sstevel@tonic-gate ohci_hcdi_bulk_transfer_size;
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
20257c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_intr_polling;
20267c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
20277c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_isoc_polling;
20287c478bd9Sstevel@tonic-gate
20297c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number =
20307c478bd9Sstevel@tonic-gate ohci_hcdi_get_current_frame_number;
20317c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
20327c478bd9Sstevel@tonic-gate ohci_hcdi_get_max_isoc_pkts;
20337c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init =
20347c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_init;
20357c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter =
20367c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_enter;
20377c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = ohci_hcdi_polled_read;
20387c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit =
20397c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_exit;
20407c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini =
20417c478bd9Sstevel@tonic-gate ohci_hcdi_polled_input_fini;
20427c478bd9Sstevel@tonic-gate
20439b58c2adSzhigang lu - Sun Microsystems - Beijing China usba_hcdi_ops->usba_hcdi_console_output_init =
20449b58c2adSzhigang lu - Sun Microsystems - Beijing China ohci_hcdi_polled_output_init;
20459b58c2adSzhigang lu - Sun Microsystems - Beijing China usba_hcdi_ops->usba_hcdi_console_output_enter =
20469b58c2adSzhigang lu - Sun Microsystems - Beijing China ohci_hcdi_polled_output_enter;
20479b58c2adSzhigang lu - Sun Microsystems - Beijing China usba_hcdi_ops->usba_hcdi_console_write = ohci_hcdi_polled_write;
20489b58c2adSzhigang lu - Sun Microsystems - Beijing China usba_hcdi_ops->usba_hcdi_console_output_exit =
20499b58c2adSzhigang lu - Sun Microsystems - Beijing China ohci_hcdi_polled_output_exit;
20509b58c2adSzhigang lu - Sun Microsystems - Beijing China usba_hcdi_ops->usba_hcdi_console_output_fini =
20519b58c2adSzhigang lu - Sun Microsystems - Beijing China ohci_hcdi_polled_output_fini;
20529b58c2adSzhigang lu - Sun Microsystems - Beijing China
20537c478bd9Sstevel@tonic-gate return (usba_hcdi_ops);
20547c478bd9Sstevel@tonic-gate }
20557c478bd9Sstevel@tonic-gate
20567c478bd9Sstevel@tonic-gate
20577c478bd9Sstevel@tonic-gate /*
20587c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions
20597c478bd9Sstevel@tonic-gate */
20607c478bd9Sstevel@tonic-gate
20617c478bd9Sstevel@tonic-gate /*
20627c478bd9Sstevel@tonic-gate * ohci_cleanup:
20637c478bd9Sstevel@tonic-gate *
20647c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach
20657c478bd9Sstevel@tonic-gate */
20667c478bd9Sstevel@tonic-gate static int
ohci_cleanup(ohci_state_t * ohcip)20677c478bd9Sstevel@tonic-gate ohci_cleanup(ohci_state_t *ohcip)
20687c478bd9Sstevel@tonic-gate {
20697c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
20707c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp;
20717c478bd9Sstevel@tonic-gate ohci_td_t *td;
20727c478bd9Sstevel@tonic-gate int i, state, rval;
20737c478bd9Sstevel@tonic-gate int flags = ohcip->ohci_flags;
20747c478bd9Sstevel@tonic-gate
20757c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_cleanup:");
20767c478bd9Sstevel@tonic-gate
20777c478bd9Sstevel@tonic-gate if (flags & OHCI_RHREG) {
20787c478bd9Sstevel@tonic-gate /* Unload the root hub driver */
20797c478bd9Sstevel@tonic-gate if (ohci_unload_root_hub_driver(ohcip) != USB_SUCCESS) {
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
20827c478bd9Sstevel@tonic-gate }
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate
20857c478bd9Sstevel@tonic-gate if (flags & OHCI_USBAREG) {
20867c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */
20877c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ohcip->ohci_dip);
20887c478bd9Sstevel@tonic-gate }
20897c478bd9Sstevel@tonic-gate
20907c478bd9Sstevel@tonic-gate if (flags & OHCI_INTR) {
20917c478bd9Sstevel@tonic-gate
20927c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate /* Disable all HC ED list processing */
20957c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
20967c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE |
20977c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE)));
20987c478bd9Sstevel@tonic-gate
20997c478bd9Sstevel@tonic-gate /* Disable all HC interrupts */
21007c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable,
21017c478bd9Sstevel@tonic-gate (HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE));
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate /* Wait for the next SOF */
21047c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip);
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate /* Disable Master and SOF interrupts */
21077c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, (HCR_INTR_MIE | HCR_INTR_SOF));
21087c478bd9Sstevel@tonic-gate
21097c478bd9Sstevel@tonic-gate /* Set the Host Controller Functional State to Reset */
21107c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) &
21117c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESET));
21127c478bd9Sstevel@tonic-gate
211329aca3ebSlc152243 mutex_exit(&ohcip->ohci_int_mutex);
21147c478bd9Sstevel@tonic-gate /* Wait for sometime */
211529aca3ebSlc152243 delay(drv_usectohz(OHCI_TIMEWAIT));
211629aca3ebSlc152243 mutex_enter(&ohcip->ohci_int_mutex);
21177c478bd9Sstevel@tonic-gate
2118f806f48bShs155680 /*
2119f806f48bShs155680 * Workaround for ULI1575 chipset. Following OHCI Operational
2120f806f48bShs155680 * Memory Registers are not cleared to their default value
2121f806f48bShs155680 * on reset. Explicitly set the registers to default value.
2122f806f48bShs155680 */
2123f806f48bShs155680 if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID &&
2124f806f48bShs155680 ohcip->ohci_device_id == PCI_ULI1575_DEVID) {
2125f806f48bShs155680 Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT);
2126f806f48bShs155680 Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT);
2127f806f48bShs155680 Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT);
2128f806f48bShs155680 Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT);
2129f806f48bShs155680 Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT);
2130f806f48bShs155680 Set_OpReg(hcr_frame_interval,
2131f806f48bShs155680 HCR_FRAME_INTERVAL_DEFAULT);
2132f806f48bShs155680 Set_OpReg(hcr_periodic_strt,
2133f806f48bShs155680 HCR_PERIODIC_START_DEFAULT);
2134f806f48bShs155680 }
2135f806f48bShs155680
21367c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
21377c478bd9Sstevel@tonic-gate
21389c75c6bfSgovinda ohci_rem_intrs(ohcip);
21397c478bd9Sstevel@tonic-gate }
21407c478bd9Sstevel@tonic-gate
21417c478bd9Sstevel@tonic-gate /* Unmap the OHCI registers */
21427c478bd9Sstevel@tonic-gate if (ohcip->ohci_regs_handle) {
21437c478bd9Sstevel@tonic-gate /* Reset the host controller */
21447c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET);
21457c478bd9Sstevel@tonic-gate
21467c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ohcip->ohci_regs_handle);
21477c478bd9Sstevel@tonic-gate }
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate if (ohcip->ohci_config_handle) {
21507c478bd9Sstevel@tonic-gate pci_config_teardown(&ohcip->ohci_config_handle);
21517c478bd9Sstevel@tonic-gate }
21527c478bd9Sstevel@tonic-gate
21537c478bd9Sstevel@tonic-gate /* Free all the buffers */
21547c478bd9Sstevel@tonic-gate if (ohcip->ohci_td_pool_addr && ohcip->ohci_td_pool_mem_handle) {
21557c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) {
21567c478bd9Sstevel@tonic-gate td = &ohcip->ohci_td_pool_addr[i];
21577c478bd9Sstevel@tonic-gate state = Get_TD(ohcip->ohci_td_pool_addr[i].hctd_state);
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate if ((state != HC_TD_FREE) && (state != HC_TD_DUMMY) &&
21607c478bd9Sstevel@tonic-gate (td->hctd_trans_wrapper)) {
21617c478bd9Sstevel@tonic-gate
21627c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
21637c478bd9Sstevel@tonic-gate
21647c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)
21657c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)
21667c478bd9Sstevel@tonic-gate Get_TD(td->hctd_trans_wrapper));
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */
21697c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private;
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */
21727c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw,
21737c478bd9Sstevel@tonic-gate OHCI_REMOVE_XFER_ALWAYS);
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
21767c478bd9Sstevel@tonic-gate
21777c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
21787c478bd9Sstevel@tonic-gate }
21797c478bd9Sstevel@tonic-gate }
21807c478bd9Sstevel@tonic-gate
21817c478bd9Sstevel@tonic-gate /*
21827c478bd9Sstevel@tonic-gate * If OHCI_TD_POOL_BOUND flag is set, then unbind
21837c478bd9Sstevel@tonic-gate * the handle for TD pools.
21847c478bd9Sstevel@tonic-gate */
21857c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag &
21867c478bd9Sstevel@tonic-gate OHCI_TD_POOL_BOUND) == OHCI_TD_POOL_BOUND) {
21877c478bd9Sstevel@tonic-gate
21887c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle(
21897c478bd9Sstevel@tonic-gate ohcip->ohci_td_pool_dma_handle);
21907c478bd9Sstevel@tonic-gate
21917c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
21927c478bd9Sstevel@tonic-gate }
21937c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_td_pool_mem_handle);
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate
21967c478bd9Sstevel@tonic-gate /* Free the TD pool */
21977c478bd9Sstevel@tonic-gate if (ohcip->ohci_td_pool_dma_handle) {
21987c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_td_pool_dma_handle);
21997c478bd9Sstevel@tonic-gate }
22007c478bd9Sstevel@tonic-gate
22017c478bd9Sstevel@tonic-gate if (ohcip->ohci_ed_pool_addr && ohcip->ohci_ed_pool_mem_handle) {
22027c478bd9Sstevel@tonic-gate /*
22037c478bd9Sstevel@tonic-gate * If OHCI_ED_POOL_BOUND flag is set, then unbind
22047c478bd9Sstevel@tonic-gate * the handle for ED pools.
22057c478bd9Sstevel@tonic-gate */
22067c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag &
22077c478bd9Sstevel@tonic-gate OHCI_ED_POOL_BOUND) == OHCI_ED_POOL_BOUND) {
22087c478bd9Sstevel@tonic-gate
22097c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle(
22107c478bd9Sstevel@tonic-gate ohcip->ohci_ed_pool_dma_handle);
22117c478bd9Sstevel@tonic-gate
22127c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
22137c478bd9Sstevel@tonic-gate }
22147c478bd9Sstevel@tonic-gate
22157c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_ed_pool_mem_handle);
22167c478bd9Sstevel@tonic-gate }
22177c478bd9Sstevel@tonic-gate
22187c478bd9Sstevel@tonic-gate /* Free the ED pool */
22197c478bd9Sstevel@tonic-gate if (ohcip->ohci_ed_pool_dma_handle) {
22207c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_ed_pool_dma_handle);
22217c478bd9Sstevel@tonic-gate }
22227c478bd9Sstevel@tonic-gate
22237c478bd9Sstevel@tonic-gate /* Free the HCCA area */
22247c478bd9Sstevel@tonic-gate if (ohcip->ohci_hccap && ohcip->ohci_hcca_mem_handle) {
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate * If OHCI_HCCA_DMA_BOUND flag is set, then unbind
22277c478bd9Sstevel@tonic-gate * the handle for HCCA.
22287c478bd9Sstevel@tonic-gate */
22297c478bd9Sstevel@tonic-gate if ((ohcip->ohci_dma_addr_bind_flag &
22307c478bd9Sstevel@tonic-gate OHCI_HCCA_DMA_BOUND) == OHCI_HCCA_DMA_BOUND) {
22317c478bd9Sstevel@tonic-gate
22327c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle(
22337c478bd9Sstevel@tonic-gate ohcip->ohci_hcca_dma_handle);
22347c478bd9Sstevel@tonic-gate
22357c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate
22387c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ohcip->ohci_hcca_mem_handle);
22397c478bd9Sstevel@tonic-gate }
22407c478bd9Sstevel@tonic-gate
22417c478bd9Sstevel@tonic-gate if (ohcip->ohci_hcca_dma_handle) {
22427c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ohcip->ohci_hcca_dma_handle);
22437c478bd9Sstevel@tonic-gate }
22447c478bd9Sstevel@tonic-gate
22457c478bd9Sstevel@tonic-gate if (flags & OHCI_INTR) {
22467c478bd9Sstevel@tonic-gate
22477c478bd9Sstevel@tonic-gate /* Destroy the mutex */
22487c478bd9Sstevel@tonic-gate mutex_destroy(&ohcip->ohci_int_mutex);
22497c478bd9Sstevel@tonic-gate
22507c478bd9Sstevel@tonic-gate /* Destroy the SOF condition varibale */
22517c478bd9Sstevel@tonic-gate cv_destroy(&ohcip->ohci_SOF_cv);
22527c478bd9Sstevel@tonic-gate
22537c478bd9Sstevel@tonic-gate /* Destroy the serialize opens and closes semaphore */
22547c478bd9Sstevel@tonic-gate sema_destroy(&ohcip->ohci_ocsem);
22557c478bd9Sstevel@tonic-gate }
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate /* clean up kstat structs */
22587c478bd9Sstevel@tonic-gate ohci_destroy_stats(ohcip);
22597c478bd9Sstevel@tonic-gate
22607c478bd9Sstevel@tonic-gate /* Free ohci hcdi ops */
22617c478bd9Sstevel@tonic-gate if (ohcip->ohci_hcdi_ops) {
22627c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ohcip->ohci_hcdi_ops);
22637c478bd9Sstevel@tonic-gate }
22647c478bd9Sstevel@tonic-gate
22657c478bd9Sstevel@tonic-gate if (flags & OHCI_ZALLOC) {
22667c478bd9Sstevel@tonic-gate
22677c478bd9Sstevel@tonic-gate usb_free_log_hdl(ohcip->ohci_log_hdl);
22687c478bd9Sstevel@tonic-gate
22697c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */
22707c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ohcip->ohci_dip);
22717c478bd9Sstevel@tonic-gate
22727c478bd9Sstevel@tonic-gate /* Free the soft state */
22737c478bd9Sstevel@tonic-gate ddi_soft_state_free(ohci_statep,
22747c478bd9Sstevel@tonic-gate ddi_get_instance(ohcip->ohci_dip));
22757c478bd9Sstevel@tonic-gate }
22767c478bd9Sstevel@tonic-gate
22777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate
22807c478bd9Sstevel@tonic-gate
22817c478bd9Sstevel@tonic-gate /*
22829c75c6bfSgovinda * ohci_rem_intrs:
22839c75c6bfSgovinda *
22849c75c6bfSgovinda * Unregister FIXED or MSI interrupts
22859c75c6bfSgovinda */
22869c75c6bfSgovinda static void
ohci_rem_intrs(ohci_state_t * ohcip)22879c75c6bfSgovinda ohci_rem_intrs(ohci_state_t *ohcip)
22889c75c6bfSgovinda {
22899c75c6bfSgovinda int i;
22909c75c6bfSgovinda
22919c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
22929c75c6bfSgovinda "ohci_rem_intrs: interrupt type 0x%x", ohcip->ohci_intr_type);
22939c75c6bfSgovinda
22949c75c6bfSgovinda /* Disable all interrupts */
22959c75c6bfSgovinda if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) {
22969c75c6bfSgovinda (void) ddi_intr_block_disable(ohcip->ohci_htable,
22979c75c6bfSgovinda ohcip->ohci_intr_cnt);
22989c75c6bfSgovinda } else {
22999c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) {
23009c75c6bfSgovinda (void) ddi_intr_disable(ohcip->ohci_htable[i]);
23019c75c6bfSgovinda }
23029c75c6bfSgovinda }
23039c75c6bfSgovinda
23049c75c6bfSgovinda /* Call ddi_intr_remove_handler() */
23059c75c6bfSgovinda for (i = 0; i < ohcip->ohci_intr_cnt; i++) {
23069c75c6bfSgovinda (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]);
23079c75c6bfSgovinda (void) ddi_intr_free(ohcip->ohci_htable[i]);
23089c75c6bfSgovinda }
23099c75c6bfSgovinda
23109c75c6bfSgovinda kmem_free(ohcip->ohci_htable,
23119c75c6bfSgovinda ohcip->ohci_intr_cnt * sizeof (ddi_intr_handle_t));
23129c75c6bfSgovinda }
23139c75c6bfSgovinda
23149c75c6bfSgovinda
23159c75c6bfSgovinda /*
23167c478bd9Sstevel@tonic-gate * ohci_cpr_suspend
23177c478bd9Sstevel@tonic-gate */
23187c478bd9Sstevel@tonic-gate static int
ohci_cpr_suspend(ohci_state_t * ohcip)23197c478bd9Sstevel@tonic-gate ohci_cpr_suspend(ohci_state_t *ohcip)
23207c478bd9Sstevel@tonic-gate {
23217c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23227c478bd9Sstevel@tonic-gate "ohci_cpr_suspend:");
23237c478bd9Sstevel@tonic-gate
23247c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */
23257c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ohcip->ohci_dip, DDI_SUSPEND) != DDI_SUCCESS) {
23267c478bd9Sstevel@tonic-gate
23277c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
23287c478bd9Sstevel@tonic-gate }
23297c478bd9Sstevel@tonic-gate
23307c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */
23317c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
23327c478bd9Sstevel@tonic-gate
23337c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_pipe_count > 1) {
23347c478bd9Sstevel@tonic-gate
23357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23367c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: fails as open pipe count = %d",
23377c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count);
23387c478bd9Sstevel@tonic-gate
23397c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
23427c478bd9Sstevel@tonic-gate }
23437c478bd9Sstevel@tonic-gate
23447c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23457c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable HC ED list processing");
23467c478bd9Sstevel@tonic-gate
23477c478bd9Sstevel@tonic-gate /* Disable all HC ED list processing */
23487c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE |
23497c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE)));
23507c478bd9Sstevel@tonic-gate
23517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23527c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable HC interrupts");
23537c478bd9Sstevel@tonic-gate
23547c478bd9Sstevel@tonic-gate /* Disable all HC interrupts */
23557c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, ~(HCR_INTR_MIE|HCR_INTR_SOF));
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23587c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Wait for the next SOF");
23597c478bd9Sstevel@tonic-gate
23607c478bd9Sstevel@tonic-gate /* Wait for the next SOF */
23617c478bd9Sstevel@tonic-gate if (ohci_wait_for_sof(ohcip) != USB_SUCCESS) {
23627c478bd9Sstevel@tonic-gate
23637c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23647c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: ohci host controller suspend failed");
23657c478bd9Sstevel@tonic-gate
23667c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
23677c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
23687c478bd9Sstevel@tonic-gate }
23697c478bd9Sstevel@tonic-gate
23707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
23717c478bd9Sstevel@tonic-gate "ohci_cpr_suspend: Disable Master interrupt");
23727c478bd9Sstevel@tonic-gate
23737c478bd9Sstevel@tonic-gate /*
23747c478bd9Sstevel@tonic-gate * Disable Master interrupt so that ohci driver don't
23757c478bd9Sstevel@tonic-gate * get any ohci interrupts.
23767c478bd9Sstevel@tonic-gate */
23777c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE);
23787c478bd9Sstevel@tonic-gate
23797c478bd9Sstevel@tonic-gate /*
23807c478bd9Sstevel@tonic-gate * Suspend the ohci host controller
23817c478bd9Sstevel@tonic-gate * if usb keyboard is not connected.
23827c478bd9Sstevel@tonic-gate */
23832df1fe9cSrandyf if (ohcip->ohci_polled_kbd_count == 0 || force_ohci_off != 0) {
23847c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, HCR_CONTROL_SUSPD);
23857c478bd9Sstevel@tonic-gate }
23867c478bd9Sstevel@tonic-gate
23877c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */
23887c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_SUSPEND_STATE;
23897c478bd9Sstevel@tonic-gate
23907c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
23917c478bd9Sstevel@tonic-gate
23927c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
23937c478bd9Sstevel@tonic-gate }
23947c478bd9Sstevel@tonic-gate
23957c478bd9Sstevel@tonic-gate
23967c478bd9Sstevel@tonic-gate /*
23977c478bd9Sstevel@tonic-gate * ohci_cpr_resume
23987c478bd9Sstevel@tonic-gate */
23997c478bd9Sstevel@tonic-gate static int
ohci_cpr_resume(ohci_state_t * ohcip)24007c478bd9Sstevel@tonic-gate ohci_cpr_resume(ohci_state_t *ohcip)
24017c478bd9Sstevel@tonic-gate {
24027c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
24037c478bd9Sstevel@tonic-gate
24047c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
24057c478bd9Sstevel@tonic-gate "ohci_cpr_resume: Restart the controller");
24067c478bd9Sstevel@tonic-gate
24077c478bd9Sstevel@tonic-gate /* Cleanup ohci specific information across cpr */
24087c478bd9Sstevel@tonic-gate ohci_cpr_cleanup(ohcip);
24097c478bd9Sstevel@tonic-gate
24107c478bd9Sstevel@tonic-gate /* Restart the controller */
24117c478bd9Sstevel@tonic-gate if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) {
24127c478bd9Sstevel@tonic-gate
2413d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
24147c478bd9Sstevel@tonic-gate "ohci_cpr_resume: ohci host controller resume failed ");
24157c478bd9Sstevel@tonic-gate
24167c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
24177c478bd9Sstevel@tonic-gate
24187c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
24197c478bd9Sstevel@tonic-gate }
24207c478bd9Sstevel@tonic-gate
24217c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate /* Now resume the root hub */
24247c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ohcip->ohci_dip, DDI_RESUME) != DDI_SUCCESS) {
24257c478bd9Sstevel@tonic-gate
24267c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
24277c478bd9Sstevel@tonic-gate }
24287c478bd9Sstevel@tonic-gate
24297c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
24307c478bd9Sstevel@tonic-gate }
24317c478bd9Sstevel@tonic-gate
24327c478bd9Sstevel@tonic-gate
24337c478bd9Sstevel@tonic-gate /*
24347c478bd9Sstevel@tonic-gate * HCDI entry points
24357c478bd9Sstevel@tonic-gate *
24367c478bd9Sstevel@tonic-gate * The Host Controller Driver Interfaces (HCDI) are the software interfaces
24377c478bd9Sstevel@tonic-gate * between the Universal Serial Bus Layer (USBA) and the Host Controller
24387c478bd9Sstevel@tonic-gate * Driver (HCD). The HCDI interfaces or entry points are subject to change.
24397c478bd9Sstevel@tonic-gate */
24407c478bd9Sstevel@tonic-gate
24417c478bd9Sstevel@tonic-gate /*
24427c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_open:
24437c478bd9Sstevel@tonic-gate *
24447c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during client specific pipe open
24457c478bd9Sstevel@tonic-gate * Add the pipe to the data structure representing the device and allocate
24467c478bd9Sstevel@tonic-gate * bandwidth for the pipe if it is a interrupt or isochronous endpoint.
24477c478bd9Sstevel@tonic-gate */
24487c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t flags)24497c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_open(
24507c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
24517c478bd9Sstevel@tonic-gate usb_flags_t flags)
24527c478bd9Sstevel@tonic-gate {
24537c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
24547c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
24557c478bd9Sstevel@tonic-gate usb_ep_descr_t *epdt = &ph->p_ep;
24567c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS;
24577c478bd9Sstevel@tonic-gate int kmflag = (flags & USB_FLAGS_SLEEP) ?
24587c478bd9Sstevel@tonic-gate KM_SLEEP : KM_NOSLEEP;
24597c478bd9Sstevel@tonic-gate uint_t node = 0;
24607c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp;
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
24637c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: addr = 0x%x, ep%d",
24647c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_addr,
24657c478bd9Sstevel@tonic-gate epdt->bEndpointAddress & USB_EP_NUM_MASK);
24667c478bd9Sstevel@tonic-gate
24677c478bd9Sstevel@tonic-gate sema_p(&ohcip->ohci_ocsem);
24687c478bd9Sstevel@tonic-gate
24697c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
24707c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
24717c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
24727c478bd9Sstevel@tonic-gate
24737c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
24747c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
24757c478bd9Sstevel@tonic-gate
24767c478bd9Sstevel@tonic-gate return (rval);
24777c478bd9Sstevel@tonic-gate }
24787c478bd9Sstevel@tonic-gate
24797c478bd9Sstevel@tonic-gate /*
24807c478bd9Sstevel@tonic-gate * Check and handle root hub pipe open.
24817c478bd9Sstevel@tonic-gate */
24827c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
24837c478bd9Sstevel@tonic-gate
24847c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
24857c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_open(ph, flags);
24867c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
24877c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
24887c478bd9Sstevel@tonic-gate
24897c478bd9Sstevel@tonic-gate return (error);
24907c478bd9Sstevel@tonic-gate }
24917c478bd9Sstevel@tonic-gate
24927c478bd9Sstevel@tonic-gate /*
24937c478bd9Sstevel@tonic-gate * Opening of other pipes excluding root hub pipe are
24947c478bd9Sstevel@tonic-gate * handled below. Check whether pipe is already opened.
24957c478bd9Sstevel@tonic-gate */
24967c478bd9Sstevel@tonic-gate if (ph->p_hcd_private) {
24977c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
24987c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: Pipe is already opened");
24997c478bd9Sstevel@tonic-gate
25007c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
25017c478bd9Sstevel@tonic-gate
25027c478bd9Sstevel@tonic-gate return (USB_FAILURE);
25037c478bd9Sstevel@tonic-gate }
25047c478bd9Sstevel@tonic-gate
25057c478bd9Sstevel@tonic-gate /*
25067c478bd9Sstevel@tonic-gate * A portion of the bandwidth is reserved for the non-periodic
25077c478bd9Sstevel@tonic-gate * transfers, i.e control and bulk transfers in each of one
25087c478bd9Sstevel@tonic-gate * millisecond frame period & usually it will be 10% of frame
25097c478bd9Sstevel@tonic-gate * period. Hence there is no need to check for the available
25107c478bd9Sstevel@tonic-gate * bandwidth before adding the control or bulk endpoints.
25117c478bd9Sstevel@tonic-gate *
25127c478bd9Sstevel@tonic-gate * There is a need to check for the available bandwidth before
25137c478bd9Sstevel@tonic-gate * adding the periodic transfers, i.e interrupt & isochronous,
25147c478bd9Sstevel@tonic-gate * since all these periodic transfers are guaranteed transfers.
25157c478bd9Sstevel@tonic-gate * Usually 90% of the total frame time is reserved for periodic
25167c478bd9Sstevel@tonic-gate * transfers.
25177c478bd9Sstevel@tonic-gate */
25187c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) {
25197c478bd9Sstevel@tonic-gate
25207c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
25217c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
25227c478bd9Sstevel@tonic-gate
25237c478bd9Sstevel@tonic-gate error = ohci_allocate_bandwidth(ohcip, ph, &node);
25247c478bd9Sstevel@tonic-gate
25257c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
25267c478bd9Sstevel@tonic-gate
25277c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
25287c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: Bandwidth allocation failed");
25297c478bd9Sstevel@tonic-gate
25307c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
25317c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
25327c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
25337c478bd9Sstevel@tonic-gate
25347c478bd9Sstevel@tonic-gate return (error);
25357c478bd9Sstevel@tonic-gate }
25367c478bd9Sstevel@tonic-gate
25377c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
25387c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
25397c478bd9Sstevel@tonic-gate }
25407c478bd9Sstevel@tonic-gate
25417c478bd9Sstevel@tonic-gate /* Create the HCD pipe private structure */
25427c478bd9Sstevel@tonic-gate pp = kmem_zalloc(sizeof (ohci_pipe_private_t), kmflag);
25437c478bd9Sstevel@tonic-gate
25447c478bd9Sstevel@tonic-gate /*
25457c478bd9Sstevel@tonic-gate * Return failure if ohci pipe private
25467c478bd9Sstevel@tonic-gate * structure allocation fails.
25477c478bd9Sstevel@tonic-gate */
25487c478bd9Sstevel@tonic-gate if (pp == NULL) {
25497c478bd9Sstevel@tonic-gate
25507c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
25517c478bd9Sstevel@tonic-gate
25527c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */
25537c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) {
25547c478bd9Sstevel@tonic-gate
25557c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
25567c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph);
25577c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
25587c478bd9Sstevel@tonic-gate }
25597c478bd9Sstevel@tonic-gate
25607c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
25617c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
25627c478bd9Sstevel@tonic-gate
25637c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
25647c478bd9Sstevel@tonic-gate }
25657c478bd9Sstevel@tonic-gate
25667c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
25677c478bd9Sstevel@tonic-gate
25687c478bd9Sstevel@tonic-gate /* Store the node in the interrupt lattice */
25697c478bd9Sstevel@tonic-gate pp->pp_node = node;
25707c478bd9Sstevel@tonic-gate
25717c478bd9Sstevel@tonic-gate /* Create prototype for xfer completion condition variable */
25727c478bd9Sstevel@tonic-gate cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL);
25737c478bd9Sstevel@tonic-gate
25747c478bd9Sstevel@tonic-gate /* Set the state of pipe as idle */
25757c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE;
25767c478bd9Sstevel@tonic-gate
25777c478bd9Sstevel@tonic-gate /* Store a pointer to the pipe handle */
25787c478bd9Sstevel@tonic-gate pp->pp_pipe_handle = ph;
25797c478bd9Sstevel@tonic-gate
25807c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
25817c478bd9Sstevel@tonic-gate
25827c478bd9Sstevel@tonic-gate /* Store the pointer in the pipe handle */
25837c478bd9Sstevel@tonic-gate ph->p_hcd_private = (usb_opaque_t)pp;
25847c478bd9Sstevel@tonic-gate
25857c478bd9Sstevel@tonic-gate /* Store a copy of the pipe policy */
25867c478bd9Sstevel@tonic-gate bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
25877c478bd9Sstevel@tonic-gate
25887c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
25897c478bd9Sstevel@tonic-gate
25907c478bd9Sstevel@tonic-gate /* Allocate the host controller endpoint descriptor */
25917c478bd9Sstevel@tonic-gate pp->pp_ept = ohci_alloc_hc_ed(ohcip, ph);
25927c478bd9Sstevel@tonic-gate
25937c478bd9Sstevel@tonic-gate if (pp->pp_ept == NULL) {
25947c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
25957c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: ED allocation failed");
25967c478bd9Sstevel@tonic-gate
25977c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
25987c478bd9Sstevel@tonic-gate
25997c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */
26007c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(epdt)) {
26017c478bd9Sstevel@tonic-gate
26027c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph);
26037c478bd9Sstevel@tonic-gate }
26047c478bd9Sstevel@tonic-gate
26057c478bd9Sstevel@tonic-gate /* Destroy the xfer completion condition varibale */
26067c478bd9Sstevel@tonic-gate cv_destroy(&pp->pp_xfer_cmpl_cv);
26077c478bd9Sstevel@tonic-gate
26087c478bd9Sstevel@tonic-gate /*
26097c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion
26107c478bd9Sstevel@tonic-gate * of the pipe handle.
26117c478bd9Sstevel@tonic-gate */
26127c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (ohci_pipe_private_t));
26137c478bd9Sstevel@tonic-gate
26147c478bd9Sstevel@tonic-gate /*
26157c478bd9Sstevel@tonic-gate * Set the private structure in the
26167c478bd9Sstevel@tonic-gate * pipe handle equal to NULL.
26177c478bd9Sstevel@tonic-gate */
26187c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL;
26197c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
26207c478bd9Sstevel@tonic-gate
26217c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
26227c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
26237c478bd9Sstevel@tonic-gate
26247c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
26257c478bd9Sstevel@tonic-gate }
26267c478bd9Sstevel@tonic-gate
26277c478bd9Sstevel@tonic-gate /* Restore the data toggle information */
26287c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(ohcip, ph);
26297c478bd9Sstevel@tonic-gate
26307c478bd9Sstevel@tonic-gate /*
26317c478bd9Sstevel@tonic-gate * Insert the endpoint onto the host controller's
26327c478bd9Sstevel@tonic-gate * appropriate endpoint list. The host controller
26337c478bd9Sstevel@tonic-gate * will not schedule this endpoint and will not have
26347c478bd9Sstevel@tonic-gate * any TD's to process.
26357c478bd9Sstevel@tonic-gate */
26367c478bd9Sstevel@tonic-gate ohci_insert_ed(ohcip, ph);
26377c478bd9Sstevel@tonic-gate
26387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
26397c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_open: ph = 0x%p", (void *)ph);
26407c478bd9Sstevel@tonic-gate
26417c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count++;
26427c478bd9Sstevel@tonic-gate
26437c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
26447c478bd9Sstevel@tonic-gate
26457c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
26467c478bd9Sstevel@tonic-gate
26477c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
26487c478bd9Sstevel@tonic-gate }
26497c478bd9Sstevel@tonic-gate
26507c478bd9Sstevel@tonic-gate
26517c478bd9Sstevel@tonic-gate /*
26527c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_close:
26537c478bd9Sstevel@tonic-gate *
26547c478bd9Sstevel@tonic-gate * Member of HCD Ops structure and called during the client specific pipe
26557c478bd9Sstevel@tonic-gate * close. Remove the pipe and the data structure representing the device.
26567c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the pipe if it is a interrupt or isochronous
26577c478bd9Sstevel@tonic-gate * endpoint.
26587c478bd9Sstevel@tonic-gate */
26597c478bd9Sstevel@tonic-gate /* ARGSUSED */
26607c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_close(usba_pipe_handle_data_t * ph,usb_flags_t flags)26617c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_close(
26627c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
26637c478bd9Sstevel@tonic-gate usb_flags_t flags)
26647c478bd9Sstevel@tonic-gate {
26657c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
26667c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
26677c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
26687c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
26697c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
26707c478bd9Sstevel@tonic-gate
26717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
26727c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_close: addr = 0x%x, ep%d",
26737c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_addr,
26747c478bd9Sstevel@tonic-gate eptd->bEndpointAddress & USB_EP_NUM_MASK);
26757c478bd9Sstevel@tonic-gate
26767c478bd9Sstevel@tonic-gate sema_p(&ohcip->ohci_ocsem);
26777c478bd9Sstevel@tonic-gate
26787c478bd9Sstevel@tonic-gate /* Check and handle root hub pipe close */
26797c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
26807c478bd9Sstevel@tonic-gate
26817c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
26827c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_close(ph);
26837c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
26847c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
26857c478bd9Sstevel@tonic-gate
26867c478bd9Sstevel@tonic-gate return (error);
26877c478bd9Sstevel@tonic-gate }
26887c478bd9Sstevel@tonic-gate
26897c478bd9Sstevel@tonic-gate ASSERT(ph->p_hcd_private != NULL);
26907c478bd9Sstevel@tonic-gate
26917c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
26927c478bd9Sstevel@tonic-gate
26937c478bd9Sstevel@tonic-gate /* Set pipe state to pipe close */
26947c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_CLOSE;
26957c478bd9Sstevel@tonic-gate
26967c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph);
26977c478bd9Sstevel@tonic-gate
26987c478bd9Sstevel@tonic-gate /*
26997c478bd9Sstevel@tonic-gate * Remove the endoint descriptor from Host
27007c478bd9Sstevel@tonic-gate * Controller's appropriate endpoint list.
27017c478bd9Sstevel@tonic-gate */
27027c478bd9Sstevel@tonic-gate ohci_remove_ed(ohcip, pp);
27037c478bd9Sstevel@tonic-gate
27047c478bd9Sstevel@tonic-gate /* Deallocate bandwidth */
27057c478bd9Sstevel@tonic-gate if (OHCI_PERIODIC_ENDPOINT(eptd)) {
27067c478bd9Sstevel@tonic-gate
27077c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
27087c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(ohcip, ph);
27097c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate
27127c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
27137c478bd9Sstevel@tonic-gate
27147c478bd9Sstevel@tonic-gate /* Destroy the xfer completion condition varibale */
27157c478bd9Sstevel@tonic-gate cv_destroy(&pp->pp_xfer_cmpl_cv);
27167c478bd9Sstevel@tonic-gate
27177c478bd9Sstevel@tonic-gate /*
27187c478bd9Sstevel@tonic-gate * Deallocate the hcd private portion
27197c478bd9Sstevel@tonic-gate * of the pipe handle.
27207c478bd9Sstevel@tonic-gate */
27217c478bd9Sstevel@tonic-gate kmem_free(ph->p_hcd_private, sizeof (ohci_pipe_private_t));
27227c478bd9Sstevel@tonic-gate ph->p_hcd_private = NULL;
27237c478bd9Sstevel@tonic-gate
27247c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
27257c478bd9Sstevel@tonic-gate
27267c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
27277c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_close: ph = 0x%p", (void *)ph);
27287c478bd9Sstevel@tonic-gate
27297c478bd9Sstevel@tonic-gate ohcip->ohci_open_pipe_count--;
27307c478bd9Sstevel@tonic-gate
27317c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
27327c478bd9Sstevel@tonic-gate sema_v(&ohcip->ohci_ocsem);
27337c478bd9Sstevel@tonic-gate
27347c478bd9Sstevel@tonic-gate return (error);
27357c478bd9Sstevel@tonic-gate }
27367c478bd9Sstevel@tonic-gate
27377c478bd9Sstevel@tonic-gate
27387c478bd9Sstevel@tonic-gate /*
27397c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_reset:
27407c478bd9Sstevel@tonic-gate */
27417c478bd9Sstevel@tonic-gate /* ARGSUSED */
27427c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)27437c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_reset(
27447c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
27457c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
27467c478bd9Sstevel@tonic-gate {
27477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
27487c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
27497c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
27507c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
27517c478bd9Sstevel@tonic-gate
27527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
27537c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_reset: ph = 0x%p ", (void *)ph);
27547c478bd9Sstevel@tonic-gate
27557c478bd9Sstevel@tonic-gate /*
27567c478bd9Sstevel@tonic-gate * Check and handle root hub pipe reset.
27577c478bd9Sstevel@tonic-gate */
27587c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
27597c478bd9Sstevel@tonic-gate
27607c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_reset(ph, usb_flags);
27617c478bd9Sstevel@tonic-gate return (error);
27627c478bd9Sstevel@tonic-gate }
27637c478bd9Sstevel@tonic-gate
27647c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
27657c478bd9Sstevel@tonic-gate
27667c478bd9Sstevel@tonic-gate /* Set pipe state to pipe reset */
27677c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_RESET;
27687c478bd9Sstevel@tonic-gate
27697c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph);
27707c478bd9Sstevel@tonic-gate
27717c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
27727c478bd9Sstevel@tonic-gate
27737c478bd9Sstevel@tonic-gate return (error);
27747c478bd9Sstevel@tonic-gate }
27757c478bd9Sstevel@tonic-gate
2776269552cdSguoqing zhu - Sun Microsystems - Beijing China /*
2777269552cdSguoqing zhu - Sun Microsystems - Beijing China * ohci_hcdi_pipe_reset_data_toggle:
2778269552cdSguoqing zhu - Sun Microsystems - Beijing China */
2779269552cdSguoqing zhu - Sun Microsystems - Beijing China void
ohci_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t * ph)2780269552cdSguoqing zhu - Sun Microsystems - Beijing China ohci_hcdi_pipe_reset_data_toggle(
2781269552cdSguoqing zhu - Sun Microsystems - Beijing China usba_pipe_handle_data_t *ph)
2782269552cdSguoqing zhu - Sun Microsystems - Beijing China {
2783269552cdSguoqing zhu - Sun Microsystems - Beijing China ohci_state_t *ohcip = ohci_obtain_state(
2784269552cdSguoqing zhu - Sun Microsystems - Beijing China ph->p_usba_device->usb_root_hub_dip);
2785269552cdSguoqing zhu - Sun Microsystems - Beijing China ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
2786269552cdSguoqing zhu - Sun Microsystems - Beijing China
2787269552cdSguoqing zhu - Sun Microsystems - Beijing China USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
2788269552cdSguoqing zhu - Sun Microsystems - Beijing China "ohci_hcdi_pipe_reset_data_toggle:");
2789269552cdSguoqing zhu - Sun Microsystems - Beijing China
2790269552cdSguoqing zhu - Sun Microsystems - Beijing China mutex_enter(&ohcip->ohci_int_mutex);
2791269552cdSguoqing zhu - Sun Microsystems - Beijing China
2792269552cdSguoqing zhu - Sun Microsystems - Beijing China mutex_enter(&ph->p_mutex);
2793269552cdSguoqing zhu - Sun Microsystems - Beijing China usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
2794269552cdSguoqing zhu - Sun Microsystems - Beijing China DATA0);
2795269552cdSguoqing zhu - Sun Microsystems - Beijing China mutex_exit(&ph->p_mutex);
2796269552cdSguoqing zhu - Sun Microsystems - Beijing China
2797269552cdSguoqing zhu - Sun Microsystems - Beijing China Set_ED(pp->pp_ept->hced_headp,
2798269552cdSguoqing zhu - Sun Microsystems - Beijing China Get_ED(pp->pp_ept->hced_headp) & (~HC_EPT_Carry));
2799269552cdSguoqing zhu - Sun Microsystems - Beijing China mutex_exit(&ohcip->ohci_int_mutex);
2800269552cdSguoqing zhu - Sun Microsystems - Beijing China
2801269552cdSguoqing zhu - Sun Microsystems - Beijing China }
28027c478bd9Sstevel@tonic-gate
28037c478bd9Sstevel@tonic-gate /*
28047c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_ctrl_xfer:
28057c478bd9Sstevel@tonic-gate */
28067c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)28077c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_ctrl_xfer(
28087c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
28097c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp,
28107c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
28117c478bd9Sstevel@tonic-gate {
28127c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
28137c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
28147c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
28157c478bd9Sstevel@tonic-gate int rval;
28167c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
28177c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
28187c478bd9Sstevel@tonic-gate
28197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
28207c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_ctrl_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x",
2821112116d8Sfb209375 (void *)ph, (void *)ctrl_reqp, usb_flags);
28227c478bd9Sstevel@tonic-gate
28237c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
28247c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
28257c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
28267c478bd9Sstevel@tonic-gate
28277c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
28287c478bd9Sstevel@tonic-gate
28297c478bd9Sstevel@tonic-gate return (rval);
28307c478bd9Sstevel@tonic-gate }
28317c478bd9Sstevel@tonic-gate
28327c478bd9Sstevel@tonic-gate /*
28337c478bd9Sstevel@tonic-gate * Check and handle root hub control request.
28347c478bd9Sstevel@tonic-gate */
28357c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) {
28367c478bd9Sstevel@tonic-gate
28377c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_request(ohcip, ph, ctrl_reqp);
28387c478bd9Sstevel@tonic-gate
28397c478bd9Sstevel@tonic-gate return (error);
28407c478bd9Sstevel@tonic-gate }
28417c478bd9Sstevel@tonic-gate
28427c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
28437c478bd9Sstevel@tonic-gate
28447c478bd9Sstevel@tonic-gate /*
28457c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state.
28467c478bd9Sstevel@tonic-gate */
28477c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) {
28487c478bd9Sstevel@tonic-gate
28497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
28507c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_ctrl_xfer:"
28517c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue");
28527c478bd9Sstevel@tonic-gate
28537c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
28547c478bd9Sstevel@tonic-gate
28557c478bd9Sstevel@tonic-gate return (USB_FAILURE);
28567c478bd9Sstevel@tonic-gate }
28577c478bd9Sstevel@tonic-gate
28587c478bd9Sstevel@tonic-gate /* Allocate a transfer wrapper */
28597c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_ctrl_resources(ohcip, pp, ctrl_reqp,
28607c478bd9Sstevel@tonic-gate usb_flags)) == NULL) {
28617c478bd9Sstevel@tonic-gate
28627c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
28637c478bd9Sstevel@tonic-gate } else {
28647c478bd9Sstevel@tonic-gate /* Insert the td's on the endpoint */
28657c478bd9Sstevel@tonic-gate ohci_insert_ctrl_req(ohcip, ph, ctrl_reqp, tw, usb_flags);
28667c478bd9Sstevel@tonic-gate }
28677c478bd9Sstevel@tonic-gate
28687c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
28697c478bd9Sstevel@tonic-gate
28707c478bd9Sstevel@tonic-gate return (error);
28717c478bd9Sstevel@tonic-gate }
28727c478bd9Sstevel@tonic-gate
28737c478bd9Sstevel@tonic-gate
28747c478bd9Sstevel@tonic-gate /*
28757c478bd9Sstevel@tonic-gate * ohci_hcdi_bulk_transfer_size:
28767c478bd9Sstevel@tonic-gate *
28777c478bd9Sstevel@tonic-gate * Return maximum bulk transfer size
28787c478bd9Sstevel@tonic-gate */
28797c478bd9Sstevel@tonic-gate
28807c478bd9Sstevel@tonic-gate /* ARGSUSED */
28817c478bd9Sstevel@tonic-gate static int
ohci_hcdi_bulk_transfer_size(usba_device_t * usba_device,size_t * size)28827c478bd9Sstevel@tonic-gate ohci_hcdi_bulk_transfer_size(
28837c478bd9Sstevel@tonic-gate usba_device_t *usba_device,
28847c478bd9Sstevel@tonic-gate size_t *size)
28857c478bd9Sstevel@tonic-gate {
28867c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
28877c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip);
28887c478bd9Sstevel@tonic-gate int rval;
28897c478bd9Sstevel@tonic-gate
28907c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
28917c478bd9Sstevel@tonic-gate "ohci_hcdi_bulk_transfer_size:");
28927c478bd9Sstevel@tonic-gate
28937c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
28947c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
28957c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
28967c478bd9Sstevel@tonic-gate
28977c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
28987c478bd9Sstevel@tonic-gate
28997c478bd9Sstevel@tonic-gate return (rval);
29007c478bd9Sstevel@tonic-gate }
29017c478bd9Sstevel@tonic-gate
29027c478bd9Sstevel@tonic-gate *size = OHCI_MAX_BULK_XFER_SIZE;
29037c478bd9Sstevel@tonic-gate
29047c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
29057c478bd9Sstevel@tonic-gate }
29067c478bd9Sstevel@tonic-gate
29077c478bd9Sstevel@tonic-gate
29087c478bd9Sstevel@tonic-gate /*
29097c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_bulk_xfer:
29107c478bd9Sstevel@tonic-gate */
29117c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)29127c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_bulk_xfer(
29137c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
29147c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp,
29157c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
29167c478bd9Sstevel@tonic-gate {
29177c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
29187c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
29197c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
29207c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS;
29217c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
29227c478bd9Sstevel@tonic-gate
29237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
29247c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x",
2925112116d8Sfb209375 (void *)ph, (void *)bulk_reqp, usb_flags);
29267c478bd9Sstevel@tonic-gate
29277c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
29287c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
29297c478bd9Sstevel@tonic-gate
29307c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
29317c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
29327c478bd9Sstevel@tonic-gate
29337c478bd9Sstevel@tonic-gate return (rval);
29347c478bd9Sstevel@tonic-gate }
29357c478bd9Sstevel@tonic-gate
29367c478bd9Sstevel@tonic-gate /*
29377c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state.
29387c478bd9Sstevel@tonic-gate */
29397c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) {
29407c478bd9Sstevel@tonic-gate
29417c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
29427c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_bulk_xfer:"
29437c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue");
29447c478bd9Sstevel@tonic-gate
29457c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
29467c478bd9Sstevel@tonic-gate
29477c478bd9Sstevel@tonic-gate return (USB_FAILURE);
29487c478bd9Sstevel@tonic-gate }
29497c478bd9Sstevel@tonic-gate
29507c478bd9Sstevel@tonic-gate /* Allocate a transfer wrapper */
29517c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_bulk_resources(ohcip, pp, bulk_reqp,
29527c478bd9Sstevel@tonic-gate usb_flags)) == NULL) {
29537c478bd9Sstevel@tonic-gate
29547c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
29557c478bd9Sstevel@tonic-gate } else {
29567c478bd9Sstevel@tonic-gate /* Add the TD into the Host Controller's bulk list */
29577c478bd9Sstevel@tonic-gate ohci_insert_bulk_req(ohcip, ph, bulk_reqp, tw, usb_flags);
29587c478bd9Sstevel@tonic-gate }
29597c478bd9Sstevel@tonic-gate
29607c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
29617c478bd9Sstevel@tonic-gate
29627c478bd9Sstevel@tonic-gate return (error);
29637c478bd9Sstevel@tonic-gate }
29647c478bd9Sstevel@tonic-gate
29657c478bd9Sstevel@tonic-gate
29667c478bd9Sstevel@tonic-gate /*
29677c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_intr_xfer:
29687c478bd9Sstevel@tonic-gate */
29697c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)29707c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_intr_xfer(
29717c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
29727c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp,
29737c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
29747c478bd9Sstevel@tonic-gate {
29757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
29767c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
29777c478bd9Sstevel@tonic-gate int pipe_dir, rval, error = USB_SUCCESS;
29787c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
29797c478bd9Sstevel@tonic-gate
29807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
29817c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_intr_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x",
2982112116d8Sfb209375 (void *)ph, (void *)intr_reqp, usb_flags);
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
29857c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
29867c478bd9Sstevel@tonic-gate
29877c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
29887c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
29897c478bd9Sstevel@tonic-gate
29907c478bd9Sstevel@tonic-gate return (rval);
29917c478bd9Sstevel@tonic-gate }
29927c478bd9Sstevel@tonic-gate
29937c478bd9Sstevel@tonic-gate /* Get the pipe direction */
29947c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
29957c478bd9Sstevel@tonic-gate
29967c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
29977c478bd9Sstevel@tonic-gate error = ohci_start_periodic_pipe_polling(ohcip, ph,
29987c478bd9Sstevel@tonic-gate (usb_opaque_t)intr_reqp, usb_flags);
29997c478bd9Sstevel@tonic-gate } else {
30007c478bd9Sstevel@tonic-gate /* Allocate transaction resources */
30017c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_intr_resources(ohcip, ph,
30027c478bd9Sstevel@tonic-gate intr_reqp, usb_flags)) == NULL) {
30037c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
30047c478bd9Sstevel@tonic-gate } else {
30057c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip,
30067c478bd9Sstevel@tonic-gate (ohci_pipe_private_t *)ph->p_hcd_private,
30077c478bd9Sstevel@tonic-gate tw, usb_flags);
30087c478bd9Sstevel@tonic-gate }
30097c478bd9Sstevel@tonic-gate }
30107c478bd9Sstevel@tonic-gate
30117c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
30127c478bd9Sstevel@tonic-gate
30137c478bd9Sstevel@tonic-gate return (error);
30147c478bd9Sstevel@tonic-gate }
30157c478bd9Sstevel@tonic-gate
30167c478bd9Sstevel@tonic-gate
30177c478bd9Sstevel@tonic-gate /*
30187c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_stop_intr_polling()
30197c478bd9Sstevel@tonic-gate */
30207c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)30217c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_intr_polling(
30227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
30237c478bd9Sstevel@tonic-gate usb_flags_t flags)
30247c478bd9Sstevel@tonic-gate {
30257c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
30267c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
30277c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
30287c478bd9Sstevel@tonic-gate
30297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
30307c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x",
3031112116d8Sfb209375 (void *)ph, flags);
30327c478bd9Sstevel@tonic-gate
30337c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
30347c478bd9Sstevel@tonic-gate
30357c478bd9Sstevel@tonic-gate error = ohci_stop_periodic_pipe_polling(ohcip, ph, flags);
30367c478bd9Sstevel@tonic-gate
30377c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
30387c478bd9Sstevel@tonic-gate
30397c478bd9Sstevel@tonic-gate return (error);
30407c478bd9Sstevel@tonic-gate }
30417c478bd9Sstevel@tonic-gate
30427c478bd9Sstevel@tonic-gate
30437c478bd9Sstevel@tonic-gate /*
30447c478bd9Sstevel@tonic-gate * ohci_hcdi_get_current_frame_number:
30457c478bd9Sstevel@tonic-gate *
3046fffe0b30Sqz150045 * Get the current usb frame number.
3047fffe0b30Sqz150045 * Return whether the request is handled successfully.
30487c478bd9Sstevel@tonic-gate */
3049fffe0b30Sqz150045 static int
ohci_hcdi_get_current_frame_number(usba_device_t * usba_device,usb_frame_number_t * frame_number)3050fffe0b30Sqz150045 ohci_hcdi_get_current_frame_number(
3051fffe0b30Sqz150045 usba_device_t *usba_device,
3052fffe0b30Sqz150045 usb_frame_number_t *frame_number)
30537c478bd9Sstevel@tonic-gate {
30547c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
30557c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip);
30567c478bd9Sstevel@tonic-gate int rval;
30577c478bd9Sstevel@tonic-gate
30587c478bd9Sstevel@tonic-gate ohcip = ohci_obtain_state(usba_device->usb_root_hub_dip);
30597c478bd9Sstevel@tonic-gate
30607c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
30617c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
30627c478bd9Sstevel@tonic-gate
30637c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
30647c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
30657c478bd9Sstevel@tonic-gate
30667c478bd9Sstevel@tonic-gate return (rval);
30677c478bd9Sstevel@tonic-gate }
30687c478bd9Sstevel@tonic-gate
3069fffe0b30Sqz150045 *frame_number = ohci_get_current_frame_number(ohcip);
30707c478bd9Sstevel@tonic-gate
30717c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
30727c478bd9Sstevel@tonic-gate
30737c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
30747c478bd9Sstevel@tonic-gate "ohci_hcdi_get_current_frame_number:"
3075112116d8Sfb209375 "Current frame number 0x%llx", (unsigned long long)(*frame_number));
30767c478bd9Sstevel@tonic-gate
3077fffe0b30Sqz150045 return (rval);
30787c478bd9Sstevel@tonic-gate }
30797c478bd9Sstevel@tonic-gate
30807c478bd9Sstevel@tonic-gate
30817c478bd9Sstevel@tonic-gate /*
30827c478bd9Sstevel@tonic-gate * ohci_hcdi_get_max_isoc_pkts:
30837c478bd9Sstevel@tonic-gate *
3084fffe0b30Sqz150045 * Get maximum isochronous packets per usb isochronous request.
3085fffe0b30Sqz150045 * Return whether the request is handled successfully.
30867c478bd9Sstevel@tonic-gate */
3087fffe0b30Sqz150045 static int
ohci_hcdi_get_max_isoc_pkts(usba_device_t * usba_device,uint_t * max_isoc_pkts_per_request)3088fffe0b30Sqz150045 ohci_hcdi_get_max_isoc_pkts(
3089fffe0b30Sqz150045 usba_device_t *usba_device,
3090fffe0b30Sqz150045 uint_t *max_isoc_pkts_per_request)
30917c478bd9Sstevel@tonic-gate {
30927c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
30937c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip);
30947c478bd9Sstevel@tonic-gate int rval;
30957c478bd9Sstevel@tonic-gate
30967c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
30977c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
30987c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
30997c478bd9Sstevel@tonic-gate
31007c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
31017c478bd9Sstevel@tonic-gate
31027c478bd9Sstevel@tonic-gate return (rval);
31037c478bd9Sstevel@tonic-gate }
31047c478bd9Sstevel@tonic-gate
3105fffe0b30Sqz150045 *max_isoc_pkts_per_request = OHCI_MAX_ISOC_PKTS_PER_XFER;
31067c478bd9Sstevel@tonic-gate
31077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
31087c478bd9Sstevel@tonic-gate "ohci_hcdi_get_max_isoc_pkts: maximum isochronous"
31097c478bd9Sstevel@tonic-gate "packets per usb isochronous request = 0x%x",
3110112116d8Sfb209375 *max_isoc_pkts_per_request);
31117c478bd9Sstevel@tonic-gate
3112fffe0b30Sqz150045 return (rval);
31137c478bd9Sstevel@tonic-gate }
31147c478bd9Sstevel@tonic-gate
31157c478bd9Sstevel@tonic-gate
31167c478bd9Sstevel@tonic-gate /*
31177c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_isoc_xfer:
31187c478bd9Sstevel@tonic-gate */
31197c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t usb_flags)31207c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_isoc_xfer(
31217c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
31227c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp,
31237c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
31247c478bd9Sstevel@tonic-gate {
31257c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
31267c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
31277c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
31287c478bd9Sstevel@tonic-gate int pipe_dir, rval;
31297c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
31307c478bd9Sstevel@tonic-gate
31317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
31327c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_isoc_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x",
3133112116d8Sfb209375 (void *)ph, (void *)isoc_reqp, usb_flags);
31347c478bd9Sstevel@tonic-gate
31357c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
31367c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
31377c478bd9Sstevel@tonic-gate
31387c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
31397c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
31407c478bd9Sstevel@tonic-gate
31417c478bd9Sstevel@tonic-gate return (rval);
31427c478bd9Sstevel@tonic-gate }
31437c478bd9Sstevel@tonic-gate
31447c478bd9Sstevel@tonic-gate /* Get the isochronous pipe direction */
31457c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
31467c478bd9Sstevel@tonic-gate
31477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
31487c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_isoc_xfer: isoc_reqp = 0x%p, uf = 0x%x",
3149112116d8Sfb209375 (void *)isoc_reqp, usb_flags);
31507c478bd9Sstevel@tonic-gate
31517c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
31527c478bd9Sstevel@tonic-gate error = ohci_start_periodic_pipe_polling(ohcip, ph,
31537c478bd9Sstevel@tonic-gate (usb_opaque_t)isoc_reqp, usb_flags);
31547c478bd9Sstevel@tonic-gate } else {
31557c478bd9Sstevel@tonic-gate /* Allocate transaction resources */
31567c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_isoc_resources(ohcip, ph,
31577c478bd9Sstevel@tonic-gate isoc_reqp, usb_flags)) == NULL) {
31587c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
31597c478bd9Sstevel@tonic-gate } else {
31607c478bd9Sstevel@tonic-gate error = ohci_insert_isoc_req(ohcip,
31617c478bd9Sstevel@tonic-gate (ohci_pipe_private_t *)ph->p_hcd_private,
31627c478bd9Sstevel@tonic-gate tw, usb_flags);
31637c478bd9Sstevel@tonic-gate }
31647c478bd9Sstevel@tonic-gate }
31657c478bd9Sstevel@tonic-gate
31667c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
31677c478bd9Sstevel@tonic-gate
31687c478bd9Sstevel@tonic-gate return (error);
31697c478bd9Sstevel@tonic-gate }
31707c478bd9Sstevel@tonic-gate
31717c478bd9Sstevel@tonic-gate
31727c478bd9Sstevel@tonic-gate /*
31737c478bd9Sstevel@tonic-gate * ohci_hcdi_pipe_stop_isoc_polling()
31747c478bd9Sstevel@tonic-gate */
31757c478bd9Sstevel@tonic-gate static int
ohci_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)31767c478bd9Sstevel@tonic-gate ohci_hcdi_pipe_stop_isoc_polling(
31777c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
31787c478bd9Sstevel@tonic-gate usb_flags_t flags)
31797c478bd9Sstevel@tonic-gate {
31807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
31817c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
31827c478bd9Sstevel@tonic-gate int rval, error = USB_SUCCESS;
31837c478bd9Sstevel@tonic-gate
31847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ohcip->ohci_log_hdl,
31857c478bd9Sstevel@tonic-gate "ohci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x",
31867c478bd9Sstevel@tonic-gate (void *)ph, flags);
31877c478bd9Sstevel@tonic-gate
31887c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
31897c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
31907c478bd9Sstevel@tonic-gate
31917c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
31927c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
31937c478bd9Sstevel@tonic-gate return (rval);
31947c478bd9Sstevel@tonic-gate }
31957c478bd9Sstevel@tonic-gate
31967c478bd9Sstevel@tonic-gate error = ohci_stop_periodic_pipe_polling(ohcip, ph, flags);
31977c478bd9Sstevel@tonic-gate
31987c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
31997c478bd9Sstevel@tonic-gate return (error);
32007c478bd9Sstevel@tonic-gate }
32017c478bd9Sstevel@tonic-gate
32027c478bd9Sstevel@tonic-gate
32037c478bd9Sstevel@tonic-gate /*
32047c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions
32057c478bd9Sstevel@tonic-gate */
32067c478bd9Sstevel@tonic-gate
32077c478bd9Sstevel@tonic-gate /*
32087c478bd9Sstevel@tonic-gate * ohci_allocate_bandwidth:
32097c478bd9Sstevel@tonic-gate *
32107c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index
32117c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it
32127c478bd9Sstevel@tonic-gate * can not be supported.
32137c478bd9Sstevel@tonic-gate *
32147c478bd9Sstevel@tonic-gate * The lattice structure looks like this with the bottom leaf actually
32157c478bd9Sstevel@tonic-gate * being an array. There is a total of 63 nodes in this tree. The lattice tree
32167c478bd9Sstevel@tonic-gate * itself is 0 based, while the bottom leaf array is 0 based. The 0 bucket in
32177c478bd9Sstevel@tonic-gate * the bottom leaf array is used to store the smalled allocated bandwidth of all
32187c478bd9Sstevel@tonic-gate * the leaves.
32197c478bd9Sstevel@tonic-gate *
32207c478bd9Sstevel@tonic-gate * 0
32217c478bd9Sstevel@tonic-gate * 1 2
32227c478bd9Sstevel@tonic-gate * 3 4 5 6
32237c478bd9Sstevel@tonic-gate * ...
32247c478bd9Sstevel@tonic-gate * (32 33 ... 62 63) <-- last row does not exist in lattice, but an array
32257c478bd9Sstevel@tonic-gate * 0 1 2 3 ... 30 31
32267c478bd9Sstevel@tonic-gate *
32277c478bd9Sstevel@tonic-gate * We keep track of the bandwidth that each leaf uses. First we search for the
32287c478bd9Sstevel@tonic-gate * first leaf with the smallest used bandwidth. Based on that leaf we find the
32297c478bd9Sstevel@tonic-gate * parent node of that leaf based on the interval time.
32307c478bd9Sstevel@tonic-gate *
32317c478bd9Sstevel@tonic-gate * From the parent node, we find all the leafs of that subtree and update the
32327c478bd9Sstevel@tonic-gate * additional bandwidth needed. In order to balance the load the leaves are not
32337c478bd9Sstevel@tonic-gate * executed directly from left to right, but scattered. For a better picture
32347c478bd9Sstevel@tonic-gate * refer to Section 3.3.2 in the OpenHCI 1.0 spec, there should be a figure
32357c478bd9Sstevel@tonic-gate * showing the Interrupt ED Structure.
32367c478bd9Sstevel@tonic-gate */
32377c478bd9Sstevel@tonic-gate static int
ohci_allocate_bandwidth(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,uint_t * node)32387c478bd9Sstevel@tonic-gate ohci_allocate_bandwidth(
32397c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
32407c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
32417c478bd9Sstevel@tonic-gate uint_t *node)
32427c478bd9Sstevel@tonic-gate {
32437c478bd9Sstevel@tonic-gate int interval, error, i;
32447c478bd9Sstevel@tonic-gate uint_t min, min_index, height;
32457c478bd9Sstevel@tonic-gate uint_t leftmost, list, bandwidth;
32467c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
32477c478bd9Sstevel@tonic-gate
32487c478bd9Sstevel@tonic-gate /* This routine is protected by the ohci_int_mutex */
32497c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
32507c478bd9Sstevel@tonic-gate
32517c478bd9Sstevel@tonic-gate /*
32527c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this
32537c478bd9Sstevel@tonic-gate * periodic endpoint.
32547c478bd9Sstevel@tonic-gate */
32557c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex);
32567c478bd9Sstevel@tonic-gate error = ohci_compute_total_bandwidth(
32577c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status, &bandwidth);
32587c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex);
32597c478bd9Sstevel@tonic-gate
32607c478bd9Sstevel@tonic-gate /*
32617c478bd9Sstevel@tonic-gate * If length is zero, then, it means endpoint maximum packet
32627c478bd9Sstevel@tonic-gate * supported is zero. In that case, return failure without
32637c478bd9Sstevel@tonic-gate * allocating any bandwidth.
32647c478bd9Sstevel@tonic-gate */
32657c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
32667c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl,
32677c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Periodic endpoint with "
32687c478bd9Sstevel@tonic-gate "zero endpoint maximum packet size is not supported");
32697c478bd9Sstevel@tonic-gate
32707c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED);
32717c478bd9Sstevel@tonic-gate }
32727c478bd9Sstevel@tonic-gate
32737c478bd9Sstevel@tonic-gate /*
32747c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds
32757c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure.
32767c478bd9Sstevel@tonic-gate */
32777c478bd9Sstevel@tonic-gate if ((ohcip->ohci_periodic_minimum_bandwidth + bandwidth) >
32787c478bd9Sstevel@tonic-gate (MAX_PERIODIC_BANDWIDTH)) {
32797c478bd9Sstevel@tonic-gate
32807c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl,
32817c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Reached maximum "
32827c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth "
32837c478bd9Sstevel@tonic-gate "for a given periodic endpoint");
32847c478bd9Sstevel@tonic-gate
32857c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH);
32867c478bd9Sstevel@tonic-gate }
32877c478bd9Sstevel@tonic-gate
32887c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */
32897c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex);
32907c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip,
32917c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status);
32927c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex);
32937c478bd9Sstevel@tonic-gate
32947c478bd9Sstevel@tonic-gate /*
32957c478bd9Sstevel@tonic-gate * If this interval can't be supported,
32967c478bd9Sstevel@tonic-gate * return allocation failure.
32977c478bd9Sstevel@tonic-gate */
32987c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) {
32997c478bd9Sstevel@tonic-gate
33007c478bd9Sstevel@tonic-gate return (USB_FAILURE);
33017c478bd9Sstevel@tonic-gate }
33027c478bd9Sstevel@tonic-gate
33037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl,
33047c478bd9Sstevel@tonic-gate "The new interval is %d", interval);
33057c478bd9Sstevel@tonic-gate
33067c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */
33077c478bd9Sstevel@tonic-gate min_index = 0;
33087c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0];
33097c478bd9Sstevel@tonic-gate
33107c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) {
33117c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) {
33127c478bd9Sstevel@tonic-gate min_index = i;
33137c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i];
33147c478bd9Sstevel@tonic-gate }
33157c478bd9Sstevel@tonic-gate }
33167c478bd9Sstevel@tonic-gate
33177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl,
33187c478bd9Sstevel@tonic-gate "The leaf %d for minimal bandwidth %d", min_index, min);
33197c478bd9Sstevel@tonic-gate
33207c478bd9Sstevel@tonic-gate /* Adjust min for the lattice */
33217c478bd9Sstevel@tonic-gate min_index = min_index + NUM_INTR_ED_LISTS - 1;
33227c478bd9Sstevel@tonic-gate
33237c478bd9Sstevel@tonic-gate /*
33247c478bd9Sstevel@tonic-gate * Find the index into the lattice given the
33257c478bd9Sstevel@tonic-gate * leaf with the smallest allocated bandwidth.
33267c478bd9Sstevel@tonic-gate */
33277c478bd9Sstevel@tonic-gate height = ohci_lattice_height(interval);
33287c478bd9Sstevel@tonic-gate
33297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl,
33307c478bd9Sstevel@tonic-gate "The height is %d", height);
33317c478bd9Sstevel@tonic-gate
33327c478bd9Sstevel@tonic-gate *node = min_index;
33337c478bd9Sstevel@tonic-gate
33347c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) {
33357c478bd9Sstevel@tonic-gate *node = ohci_lattice_parent(*node);
33367c478bd9Sstevel@tonic-gate }
33377c478bd9Sstevel@tonic-gate
33387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl,
33397c478bd9Sstevel@tonic-gate "Real node is %d", *node);
33407c478bd9Sstevel@tonic-gate
33417c478bd9Sstevel@tonic-gate /*
33427c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree
33437c478bd9Sstevel@tonic-gate * specified by the node.
33447c478bd9Sstevel@tonic-gate */
33457c478bd9Sstevel@tonic-gate leftmost = ohci_leftmost_leaf(*node, height);
33467c478bd9Sstevel@tonic-gate
33477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ohcip->ohci_log_hdl,
33487c478bd9Sstevel@tonic-gate "Leftmost %d", leftmost);
33497c478bd9Sstevel@tonic-gate
33507c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) {
33517c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i);
33527c478bd9Sstevel@tonic-gate if ((ohcip->ohci_periodic_bandwidth[list] +
33537c478bd9Sstevel@tonic-gate bandwidth) > MAX_PERIODIC_BANDWIDTH) {
33547c478bd9Sstevel@tonic-gate
33557c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl,
33567c478bd9Sstevel@tonic-gate "ohci_allocate_bandwidth: Reached maximum "
33577c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth "
33587c478bd9Sstevel@tonic-gate "for periodic endpoint");
33597c478bd9Sstevel@tonic-gate
33607c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH);
33617c478bd9Sstevel@tonic-gate }
33627c478bd9Sstevel@tonic-gate }
33637c478bd9Sstevel@tonic-gate
33647c478bd9Sstevel@tonic-gate /*
33657c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth.
33667c478bd9Sstevel@tonic-gate */
33677c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) {
33687c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i);
33697c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_bandwidth[list] += bandwidth;
33707c478bd9Sstevel@tonic-gate }
33717c478bd9Sstevel@tonic-gate
33727c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */
33737c478bd9Sstevel@tonic-gate min_index = 0;
33747c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0];
33757c478bd9Sstevel@tonic-gate
33767c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) {
33777c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) {
33787c478bd9Sstevel@tonic-gate min_index = i;
33797c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i];
33807c478bd9Sstevel@tonic-gate }
33817c478bd9Sstevel@tonic-gate }
33827c478bd9Sstevel@tonic-gate
33837c478bd9Sstevel@tonic-gate /* Save the minimum for later use */
33847c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_minimum_bandwidth = min;
33857c478bd9Sstevel@tonic-gate
33867c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
33877c478bd9Sstevel@tonic-gate }
33887c478bd9Sstevel@tonic-gate
33897c478bd9Sstevel@tonic-gate
33907c478bd9Sstevel@tonic-gate /*
33917c478bd9Sstevel@tonic-gate * ohci_deallocate_bandwidth:
33927c478bd9Sstevel@tonic-gate *
33937c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length
33947c478bd9Sstevel@tonic-gate * of transfer.
33957c478bd9Sstevel@tonic-gate */
33967c478bd9Sstevel@tonic-gate static void
ohci_deallocate_bandwidth(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)33977c478bd9Sstevel@tonic-gate ohci_deallocate_bandwidth(
33987c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
33997c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
34007c478bd9Sstevel@tonic-gate {
34017c478bd9Sstevel@tonic-gate uint_t min, node, bandwidth;
34027c478bd9Sstevel@tonic-gate uint_t height, leftmost, list;
34037c478bd9Sstevel@tonic-gate int i, interval;
34047c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
34057c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
34067c478bd9Sstevel@tonic-gate
34077c478bd9Sstevel@tonic-gate /* This routine is protected by the ohci_int_mutex */
34087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
34097c478bd9Sstevel@tonic-gate
34107c478bd9Sstevel@tonic-gate /* Obtain the length */
34117c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex);
34127c478bd9Sstevel@tonic-gate (void) ohci_compute_total_bandwidth(
34137c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status, &bandwidth);
34147c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex);
34157c478bd9Sstevel@tonic-gate
34167c478bd9Sstevel@tonic-gate /* Obtain the node */
34177c478bd9Sstevel@tonic-gate node = pp->pp_node;
34187c478bd9Sstevel@tonic-gate
34197c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */
34207c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex);
34217c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip,
34227c478bd9Sstevel@tonic-gate endpoint, ph->p_usba_device->usb_port_status);
34237c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex);
34247c478bd9Sstevel@tonic-gate
34257c478bd9Sstevel@tonic-gate /* Find the height in the tree */
34267c478bd9Sstevel@tonic-gate height = ohci_lattice_height(interval);
34277c478bd9Sstevel@tonic-gate
34287c478bd9Sstevel@tonic-gate /*
34297c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node
34307c478bd9Sstevel@tonic-gate */
34317c478bd9Sstevel@tonic-gate leftmost = ohci_leftmost_leaf(node, height);
34327c478bd9Sstevel@tonic-gate
34337c478bd9Sstevel@tonic-gate /* Delete the bandwith from the appropriate lists */
34347c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_INTR_ED_LISTS/interval); i++) {
34357c478bd9Sstevel@tonic-gate list = ohci_hcca_leaf_index(leftmost + i);
34367c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_bandwidth[list] -= bandwidth;
34377c478bd9Sstevel@tonic-gate }
34387c478bd9Sstevel@tonic-gate
34397c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[0];
34407c478bd9Sstevel@tonic-gate
34417c478bd9Sstevel@tonic-gate /* Recompute the minimum */
34427c478bd9Sstevel@tonic-gate for (i = 1; i < NUM_INTR_ED_LISTS; i++) {
34437c478bd9Sstevel@tonic-gate if (ohcip->ohci_periodic_bandwidth[i] < min) {
34447c478bd9Sstevel@tonic-gate min = ohcip->ohci_periodic_bandwidth[i];
34457c478bd9Sstevel@tonic-gate }
34467c478bd9Sstevel@tonic-gate }
34477c478bd9Sstevel@tonic-gate
34487c478bd9Sstevel@tonic-gate /* Save the minimum for later use */
34497c478bd9Sstevel@tonic-gate ohcip->ohci_periodic_minimum_bandwidth = min;
34507c478bd9Sstevel@tonic-gate }
34517c478bd9Sstevel@tonic-gate
34527c478bd9Sstevel@tonic-gate
34537c478bd9Sstevel@tonic-gate /*
34547c478bd9Sstevel@tonic-gate * ohci_compute_total_bandwidth:
34557c478bd9Sstevel@tonic-gate *
34567c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total
34577c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The OpenHCI host controller traverses the
34587c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC
34597c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC
34607c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt
34617c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a
34627c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the
34637c478bd9Sstevel@tonic-gate * number of bytes for one transaction.
34647c478bd9Sstevel@tonic-gate *
34657c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms
34667c478bd9Sstevel@tonic-gate * bytes and it is for the single USB full speed and low speed transaction
34677c478bd9Sstevel@tonic-gate * respectively. The protocol overheads will be different for each of type
34687c478bd9Sstevel@tonic-gate * of USB transfer and all these formulas & protocol overheads are derived
34697c478bd9Sstevel@tonic-gate * from the 5.9.3 section of USB Specification & with the help of Bandwidth
34707c478bd9Sstevel@tonic-gate * Analysis white paper which is posted on the USB developer forum.
34717c478bd9Sstevel@tonic-gate *
34727c478bd9Sstevel@tonic-gate * Full-Speed:
34737c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPacketSize * 7)/6 ) + Host_Delay
34747c478bd9Sstevel@tonic-gate *
34757c478bd9Sstevel@tonic-gate * Low-Speed:
34767c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead +
34777c478bd9Sstevel@tonic-gate * (Low-Speed clock * ((MaxPacketSize * 7)/6 )) + Host_Delay
34787c478bd9Sstevel@tonic-gate */
34797c478bd9Sstevel@tonic-gate static int
ohci_compute_total_bandwidth(usb_ep_descr_t * endpoint,usb_port_status_t port_status,uint_t * bandwidth)34807c478bd9Sstevel@tonic-gate ohci_compute_total_bandwidth(
34817c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint,
34827c478bd9Sstevel@tonic-gate usb_port_status_t port_status,
34837c478bd9Sstevel@tonic-gate uint_t *bandwidth)
34847c478bd9Sstevel@tonic-gate {
34857c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize;
34867c478bd9Sstevel@tonic-gate
34877c478bd9Sstevel@tonic-gate /*
34887c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately.
34897c478bd9Sstevel@tonic-gate */
34907c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) {
34917c478bd9Sstevel@tonic-gate
34927c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED);
34937c478bd9Sstevel@tonic-gate }
34947c478bd9Sstevel@tonic-gate
34957c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */
34967c478bd9Sstevel@tonic-gate *bandwidth = HOST_CONTROLLER_DELAY;
34977c478bd9Sstevel@tonic-gate
34987c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */
34997c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
35007c478bd9Sstevel@tonic-gate
35017c478bd9Sstevel@tonic-gate /* Low Speed interrupt transaction */
35027c478bd9Sstevel@tonic-gate if (port_status == USBA_LOW_SPEED_DEV) {
35037c478bd9Sstevel@tonic-gate /* Low Speed interrupt transaction */
35047c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD +
35057c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD +
35067c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize));
35077c478bd9Sstevel@tonic-gate } else {
35087c478bd9Sstevel@tonic-gate /* Full Speed transaction */
35097c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize;
35107c478bd9Sstevel@tonic-gate
35117c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes &
35127c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
35137c478bd9Sstevel@tonic-gate /* Full Speed interrupt transaction */
35147c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD;
35157c478bd9Sstevel@tonic-gate } else {
35167c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */
35177c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress &
35187c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
35197c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD;
35207c478bd9Sstevel@tonic-gate } else {
35217c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */
35227c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD;
35237c478bd9Sstevel@tonic-gate }
35247c478bd9Sstevel@tonic-gate }
35257c478bd9Sstevel@tonic-gate }
35267c478bd9Sstevel@tonic-gate
35277c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
35287c478bd9Sstevel@tonic-gate }
35297c478bd9Sstevel@tonic-gate
35307c478bd9Sstevel@tonic-gate
35317c478bd9Sstevel@tonic-gate /*
35327c478bd9Sstevel@tonic-gate * ohci_adjust_polling_interval:
35337c478bd9Sstevel@tonic-gate */
35347c478bd9Sstevel@tonic-gate static int
ohci_adjust_polling_interval(ohci_state_t * ohcip,usb_ep_descr_t * endpoint,usb_port_status_t port_status)35357c478bd9Sstevel@tonic-gate ohci_adjust_polling_interval(
35367c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
35377c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint,
35387c478bd9Sstevel@tonic-gate usb_port_status_t port_status)
35397c478bd9Sstevel@tonic-gate {
35407c478bd9Sstevel@tonic-gate uint_t interval;
35417c478bd9Sstevel@tonic-gate int i = 0;
35427c478bd9Sstevel@tonic-gate
35437c478bd9Sstevel@tonic-gate /*
35447c478bd9Sstevel@tonic-gate * Get the polling interval from the endpoint descriptor
35457c478bd9Sstevel@tonic-gate */
35467c478bd9Sstevel@tonic-gate interval = endpoint->bInterval;
35477c478bd9Sstevel@tonic-gate
35487c478bd9Sstevel@tonic-gate /*
35497c478bd9Sstevel@tonic-gate * The bInterval value in the endpoint descriptor can range
35507c478bd9Sstevel@tonic-gate * from 1 to 255ms. The interrupt lattice has 32 leaf nodes,
35517c478bd9Sstevel@tonic-gate * and the host controller cycles through these nodes every
35527c478bd9Sstevel@tonic-gate * 32ms. The longest polling interval that the controller
35537c478bd9Sstevel@tonic-gate * supports is 32ms.
35547c478bd9Sstevel@tonic-gate */
35557c478bd9Sstevel@tonic-gate
35567c478bd9Sstevel@tonic-gate /*
35577c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less than 1ms
35587c478bd9Sstevel@tonic-gate * and greater than 255ms
35597c478bd9Sstevel@tonic-gate */
35607c478bd9Sstevel@tonic-gate if ((interval < MIN_POLL_INTERVAL) ||
35617c478bd9Sstevel@tonic-gate (interval > MAX_POLL_INTERVAL)) {
35627c478bd9Sstevel@tonic-gate
3563d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
35647c478bd9Sstevel@tonic-gate "ohci_adjust_polling_interval: "
35657c478bd9Sstevel@tonic-gate "Endpoint's poll interval must be between %d and %d ms",
35667c478bd9Sstevel@tonic-gate MIN_POLL_INTERVAL, MAX_POLL_INTERVAL);
35677c478bd9Sstevel@tonic-gate
35687c478bd9Sstevel@tonic-gate return (USB_FAILURE);
35697c478bd9Sstevel@tonic-gate }
35707c478bd9Sstevel@tonic-gate
35717c478bd9Sstevel@tonic-gate /*
35727c478bd9Sstevel@tonic-gate * According USB Specifications, a full-speed endpoint can
35737c478bd9Sstevel@tonic-gate * specify a desired polling interval 1ms to 255ms and a low
35747c478bd9Sstevel@tonic-gate * speed endpoints are limited to specifying only 10ms to
35757c478bd9Sstevel@tonic-gate * 255ms. But some old keyboards & mice uses polling interval
35767c478bd9Sstevel@tonic-gate * of 8ms. For compatibility purpose, we are using polling
35777c478bd9Sstevel@tonic-gate * interval between 8ms & 255ms for low speed endpoints. But
35787c478bd9Sstevel@tonic-gate * ohci driver will reject the any low speed endpoints which
35797c478bd9Sstevel@tonic-gate * request polling interval less than 8ms.
35807c478bd9Sstevel@tonic-gate */
35817c478bd9Sstevel@tonic-gate if ((port_status == USBA_LOW_SPEED_DEV) &&
35827c478bd9Sstevel@tonic-gate (interval < MIN_LOW_SPEED_POLL_INTERVAL)) {
35837c478bd9Sstevel@tonic-gate
3584d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_BW, ohcip->ohci_log_hdl,
35857c478bd9Sstevel@tonic-gate "ohci_adjust_polling_interval: "
35867c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms "
35877c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms",
35887c478bd9Sstevel@tonic-gate interval, MIN_LOW_SPEED_POLL_INTERVAL);
35897c478bd9Sstevel@tonic-gate
35907c478bd9Sstevel@tonic-gate interval = MIN_LOW_SPEED_POLL_INTERVAL;
35917c478bd9Sstevel@tonic-gate }
35927c478bd9Sstevel@tonic-gate
35937c478bd9Sstevel@tonic-gate /*
35947c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms,
35957c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms.
35967c478bd9Sstevel@tonic-gate */
35977c478bd9Sstevel@tonic-gate if (interval > NUM_INTR_ED_LISTS) {
35987c478bd9Sstevel@tonic-gate interval = NUM_INTR_ED_LISTS;
35997c478bd9Sstevel@tonic-gate }
36007c478bd9Sstevel@tonic-gate
36017c478bd9Sstevel@tonic-gate /*
36027c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that'sless
36037c478bd9Sstevel@tonic-gate * than interval.
36047c478bd9Sstevel@tonic-gate */
36057c478bd9Sstevel@tonic-gate while ((ohci_pow_2(i)) <= interval) {
36067c478bd9Sstevel@tonic-gate i++;
36077c478bd9Sstevel@tonic-gate }
36087c478bd9Sstevel@tonic-gate
36097c478bd9Sstevel@tonic-gate return (ohci_pow_2((i - 1)));
36107c478bd9Sstevel@tonic-gate }
36117c478bd9Sstevel@tonic-gate
36127c478bd9Sstevel@tonic-gate
36137c478bd9Sstevel@tonic-gate /*
36147c478bd9Sstevel@tonic-gate * ohci_lattice_height:
36157c478bd9Sstevel@tonic-gate *
36167c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the
36177c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of
36187c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the
36197c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT.
36207c478bd9Sstevel@tonic-gate */
36217c478bd9Sstevel@tonic-gate static uint_t
ohci_lattice_height(uint_t interval)36227c478bd9Sstevel@tonic-gate ohci_lattice_height(uint_t interval)
36237c478bd9Sstevel@tonic-gate {
36247c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ohci_log_2(interval)));
36257c478bd9Sstevel@tonic-gate }
36267c478bd9Sstevel@tonic-gate
36277c478bd9Sstevel@tonic-gate
36287c478bd9Sstevel@tonic-gate /*
36297c478bd9Sstevel@tonic-gate * ohci_lattice_parent:
36307c478bd9Sstevel@tonic-gate */
36317c478bd9Sstevel@tonic-gate static uint_t
ohci_lattice_parent(uint_t node)36327c478bd9Sstevel@tonic-gate ohci_lattice_parent(uint_t node)
36337c478bd9Sstevel@tonic-gate {
36347c478bd9Sstevel@tonic-gate if ((node % 2) == 0) {
36357c478bd9Sstevel@tonic-gate return ((node/2) - 1);
36367c478bd9Sstevel@tonic-gate } else {
36377c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1);
36387c478bd9Sstevel@tonic-gate }
36397c478bd9Sstevel@tonic-gate }
36407c478bd9Sstevel@tonic-gate
36417c478bd9Sstevel@tonic-gate
36427c478bd9Sstevel@tonic-gate /*
36437c478bd9Sstevel@tonic-gate * ohci_leftmost_leaf:
36447c478bd9Sstevel@tonic-gate *
36457c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers
36467c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the
36477c478bd9Sstevel@tonic-gate * node.
36487c478bd9Sstevel@tonic-gate *
36497c478bd9Sstevel@tonic-gate * The formula for a zero based tree is:
36507c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1
36517c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array.
36527c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array
36537c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (NUM_INTR_ED_LIST - 1) =
36547c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - NUM_INTR_ED_LIST =
36557c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - NUM_INTR_ED_LIST
36567c478bd9Sstevel@tonic-gate * 0
36577c478bd9Sstevel@tonic-gate * 1 2
36587c478bd9Sstevel@tonic-gate * 0 1 2 3
36597c478bd9Sstevel@tonic-gate */
36607c478bd9Sstevel@tonic-gate static uint_t
ohci_leftmost_leaf(uint_t node,uint_t height)36617c478bd9Sstevel@tonic-gate ohci_leftmost_leaf(
36627c478bd9Sstevel@tonic-gate uint_t node,
36637c478bd9Sstevel@tonic-gate uint_t height)
36647c478bd9Sstevel@tonic-gate {
36657c478bd9Sstevel@tonic-gate return ((ohci_pow_2(height) * (node + 1)) - NUM_INTR_ED_LISTS);
36667c478bd9Sstevel@tonic-gate }
36677c478bd9Sstevel@tonic-gate
36687c478bd9Sstevel@tonic-gate /*
36697c478bd9Sstevel@tonic-gate * ohci_hcca_intr_index:
36707c478bd9Sstevel@tonic-gate *
36717c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index for the hcca interrupt table
36727c478bd9Sstevel@tonic-gate */
36737c478bd9Sstevel@tonic-gate static uint_t
ohci_hcca_intr_index(uint_t node)36747c478bd9Sstevel@tonic-gate ohci_hcca_intr_index(uint_t node)
36757c478bd9Sstevel@tonic-gate {
36767c478bd9Sstevel@tonic-gate /*
36777c478bd9Sstevel@tonic-gate * Adjust the node to the array representing
36787c478bd9Sstevel@tonic-gate * the bottom of the tree.
36797c478bd9Sstevel@tonic-gate */
36807c478bd9Sstevel@tonic-gate node = node - NUM_STATIC_NODES;
36817c478bd9Sstevel@tonic-gate
36827c478bd9Sstevel@tonic-gate if ((node % 2) == 0) {
36837c478bd9Sstevel@tonic-gate return (ohci_index[node / 2]);
36847c478bd9Sstevel@tonic-gate } else {
36857c478bd9Sstevel@tonic-gate return (ohci_index[node / 2] + (NUM_INTR_ED_LISTS / 2));
36867c478bd9Sstevel@tonic-gate }
36877c478bd9Sstevel@tonic-gate }
36887c478bd9Sstevel@tonic-gate
36897c478bd9Sstevel@tonic-gate /*
36907c478bd9Sstevel@tonic-gate * ohci_hcca_leaf_index:
36917c478bd9Sstevel@tonic-gate *
36927c478bd9Sstevel@tonic-gate * Given a node in the bottom leaf array of the lattice, find the index
36937c478bd9Sstevel@tonic-gate * for the hcca interrupt table
36947c478bd9Sstevel@tonic-gate */
36957c478bd9Sstevel@tonic-gate static uint_t
ohci_hcca_leaf_index(uint_t leaf)36967c478bd9Sstevel@tonic-gate ohci_hcca_leaf_index(uint_t leaf)
36977c478bd9Sstevel@tonic-gate {
36987c478bd9Sstevel@tonic-gate if ((leaf % 2) == 0) {
36997c478bd9Sstevel@tonic-gate return (ohci_index[leaf / 2]);
37007c478bd9Sstevel@tonic-gate } else {
37017c478bd9Sstevel@tonic-gate return (ohci_index[leaf / 2] + (NUM_INTR_ED_LISTS / 2));
37027c478bd9Sstevel@tonic-gate }
37037c478bd9Sstevel@tonic-gate }
37047c478bd9Sstevel@tonic-gate
37057c478bd9Sstevel@tonic-gate /*
37067c478bd9Sstevel@tonic-gate * ohci_pow_2:
37077c478bd9Sstevel@tonic-gate *
37087c478bd9Sstevel@tonic-gate * Compute 2 to the power
37097c478bd9Sstevel@tonic-gate */
37107c478bd9Sstevel@tonic-gate static uint_t
ohci_pow_2(uint_t x)37117c478bd9Sstevel@tonic-gate ohci_pow_2(uint_t x)
37127c478bd9Sstevel@tonic-gate {
37137c478bd9Sstevel@tonic-gate if (x == 0) {
37147c478bd9Sstevel@tonic-gate return (1);
37157c478bd9Sstevel@tonic-gate } else {
37167c478bd9Sstevel@tonic-gate return (2 << (x - 1));
37177c478bd9Sstevel@tonic-gate }
37187c478bd9Sstevel@tonic-gate }
37197c478bd9Sstevel@tonic-gate
37207c478bd9Sstevel@tonic-gate
37217c478bd9Sstevel@tonic-gate /*
37227c478bd9Sstevel@tonic-gate * ohci_log_2:
37237c478bd9Sstevel@tonic-gate *
37247c478bd9Sstevel@tonic-gate * Compute log base 2 of x
37257c478bd9Sstevel@tonic-gate */
37267c478bd9Sstevel@tonic-gate static uint_t
ohci_log_2(uint_t x)37277c478bd9Sstevel@tonic-gate ohci_log_2(uint_t x)
37287c478bd9Sstevel@tonic-gate {
37297c478bd9Sstevel@tonic-gate int i = 0;
37307c478bd9Sstevel@tonic-gate
37317c478bd9Sstevel@tonic-gate while (x != 1) {
37327c478bd9Sstevel@tonic-gate x = x >> 1;
37337c478bd9Sstevel@tonic-gate i++;
37347c478bd9Sstevel@tonic-gate }
37357c478bd9Sstevel@tonic-gate
37367c478bd9Sstevel@tonic-gate return (i);
37377c478bd9Sstevel@tonic-gate }
37387c478bd9Sstevel@tonic-gate
37397c478bd9Sstevel@tonic-gate
37407c478bd9Sstevel@tonic-gate /*
37417c478bd9Sstevel@tonic-gate * Endpoint Descriptor (ED) manipulations functions
37427c478bd9Sstevel@tonic-gate */
37437c478bd9Sstevel@tonic-gate
37447c478bd9Sstevel@tonic-gate /*
37457c478bd9Sstevel@tonic-gate * ohci_alloc_hc_ed:
37467c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
37477c478bd9Sstevel@tonic-gate *
37487c478bd9Sstevel@tonic-gate * Allocate an endpoint descriptor (ED)
37497c478bd9Sstevel@tonic-gate */
37507c478bd9Sstevel@tonic-gate ohci_ed_t *
ohci_alloc_hc_ed(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)37517c478bd9Sstevel@tonic-gate ohci_alloc_hc_ed(
37527c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
37537c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
37547c478bd9Sstevel@tonic-gate {
37557c478bd9Sstevel@tonic-gate int i, state;
37567c478bd9Sstevel@tonic-gate ohci_ed_t *hc_ed;
37577c478bd9Sstevel@tonic-gate
37587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
37597c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: ph = 0x%p", (void *)ph);
37607c478bd9Sstevel@tonic-gate
37617c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
37627c478bd9Sstevel@tonic-gate
37637c478bd9Sstevel@tonic-gate /*
37647c478bd9Sstevel@tonic-gate * The first 31 endpoints in the Endpoint Descriptor (ED)
37657c478bd9Sstevel@tonic-gate * buffer pool are reserved for building interrupt lattice
37667c478bd9Sstevel@tonic-gate * tree. Search for a blank endpoint descriptor in the ED
37677c478bd9Sstevel@tonic-gate * buffer pool.
37687c478bd9Sstevel@tonic-gate */
37697c478bd9Sstevel@tonic-gate for (i = NUM_STATIC_NODES; i < ohci_ed_pool_size; i ++) {
37707c478bd9Sstevel@tonic-gate state = Get_ED(ohcip->ohci_ed_pool_addr[i].hced_state);
37717c478bd9Sstevel@tonic-gate
37727c478bd9Sstevel@tonic-gate if (state == HC_EPT_FREE) {
37737c478bd9Sstevel@tonic-gate break;
37747c478bd9Sstevel@tonic-gate }
37757c478bd9Sstevel@tonic-gate }
37767c478bd9Sstevel@tonic-gate
37777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
37787c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: Allocated %d", i);
37797c478bd9Sstevel@tonic-gate
37807c478bd9Sstevel@tonic-gate if (i == ohci_ed_pool_size) {
37817c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
37827c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: ED exhausted");
37837c478bd9Sstevel@tonic-gate
37847c478bd9Sstevel@tonic-gate return (NULL);
37857c478bd9Sstevel@tonic-gate } else {
37867c478bd9Sstevel@tonic-gate
37877c478bd9Sstevel@tonic-gate hc_ed = &ohcip->ohci_ed_pool_addr[i];
37887c478bd9Sstevel@tonic-gate
37897c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
37907c478bd9Sstevel@tonic-gate "ohci_alloc_hc_ed: Allocated address 0x%p", (void *)hc_ed);
37917c478bd9Sstevel@tonic-gate
37927c478bd9Sstevel@tonic-gate ohci_print_ed(ohcip, hc_ed);
37937c478bd9Sstevel@tonic-gate
37947c478bd9Sstevel@tonic-gate /* Unpack the endpoint descriptor into a control field */
37957c478bd9Sstevel@tonic-gate if (ph) {
37967c478bd9Sstevel@tonic-gate if ((ohci_initialize_dummy(ohcip,
37977c478bd9Sstevel@tonic-gate hc_ed)) == USB_NO_RESOURCES) {
37987c478bd9Sstevel@tonic-gate bzero((void *)hc_ed, sizeof (ohci_ed_t));
37997c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_FREE);
38007c478bd9Sstevel@tonic-gate return (NULL);
38017c478bd9Sstevel@tonic-gate }
38027c478bd9Sstevel@tonic-gate
38033e1e1e62SToomas Soome Set_ED(hc_ed->hced_prev, 0);
38043e1e1e62SToomas Soome Set_ED(hc_ed->hced_next, 0);
38057c478bd9Sstevel@tonic-gate
38067c478bd9Sstevel@tonic-gate /* Change ED's state Active */
38077c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_ACTIVE);
38087c478bd9Sstevel@tonic-gate
38097c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_ctrl,
38107c478bd9Sstevel@tonic-gate ohci_unpack_endpoint(ohcip, ph));
38117c478bd9Sstevel@tonic-gate } else {
38127c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_ctrl, HC_EPT_sKip);
38137c478bd9Sstevel@tonic-gate
38147c478bd9Sstevel@tonic-gate /* Change ED's state Static */
38157c478bd9Sstevel@tonic-gate Set_ED(hc_ed->hced_state, HC_EPT_STATIC);
38167c478bd9Sstevel@tonic-gate }
38177c478bd9Sstevel@tonic-gate
38187c478bd9Sstevel@tonic-gate return (hc_ed);
38197c478bd9Sstevel@tonic-gate }
38207c478bd9Sstevel@tonic-gate }
38217c478bd9Sstevel@tonic-gate
38227c478bd9Sstevel@tonic-gate
38237c478bd9Sstevel@tonic-gate /*
38247c478bd9Sstevel@tonic-gate * ohci_unpack_endpoint:
38257c478bd9Sstevel@tonic-gate *
38267c478bd9Sstevel@tonic-gate * Unpack the information in the pipe handle and create the first byte
38277c478bd9Sstevel@tonic-gate * of the Host Controller's (HC) Endpoint Descriptor (ED).
38287c478bd9Sstevel@tonic-gate */
38297c478bd9Sstevel@tonic-gate static uint_t
ohci_unpack_endpoint(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)38307c478bd9Sstevel@tonic-gate ohci_unpack_endpoint(
38317c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
38327c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
38337c478bd9Sstevel@tonic-gate {
38347c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
38357c478bd9Sstevel@tonic-gate uint_t maxpacketsize, addr, ctrl = 0;
38367c478bd9Sstevel@tonic-gate
38377c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
38387c478bd9Sstevel@tonic-gate "ohci_unpack_endpoint:");
38397c478bd9Sstevel@tonic-gate
38407c478bd9Sstevel@tonic-gate ctrl = ph->p_usba_device->usb_addr;
38417c478bd9Sstevel@tonic-gate
38427c478bd9Sstevel@tonic-gate addr = endpoint->bEndpointAddress;
38437c478bd9Sstevel@tonic-gate
38447c478bd9Sstevel@tonic-gate /* Assign the endpoint's address */
38457c478bd9Sstevel@tonic-gate ctrl = ctrl | ((addr & USB_EP_NUM_MASK) << HC_EPT_EP_SHFT);
38467c478bd9Sstevel@tonic-gate
38477c478bd9Sstevel@tonic-gate /*
38487c478bd9Sstevel@tonic-gate * Assign the direction. If the endpoint is a control endpoint,
38497c478bd9Sstevel@tonic-gate * the direction is assigned by the Transfer Descriptor (TD).
38507c478bd9Sstevel@tonic-gate */
38517c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes &
38527c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) != USB_EP_ATTR_CONTROL) {
38537c478bd9Sstevel@tonic-gate if (addr & USB_EP_DIR_MASK) {
38547c478bd9Sstevel@tonic-gate /* The direction is IN */
38557c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_DF_IN;
38567c478bd9Sstevel@tonic-gate } else {
38577c478bd9Sstevel@tonic-gate /* The direction is OUT */
38587c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_DF_OUT;
38597c478bd9Sstevel@tonic-gate }
38607c478bd9Sstevel@tonic-gate }
38617c478bd9Sstevel@tonic-gate
38627c478bd9Sstevel@tonic-gate /* Assign the speed */
38637c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex);
38647c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
38657c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_Speed;
38667c478bd9Sstevel@tonic-gate }
38677c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex);
38687c478bd9Sstevel@tonic-gate
38697c478bd9Sstevel@tonic-gate /* Assign the format */
38707c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes &
38717c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
38727c478bd9Sstevel@tonic-gate ctrl = ctrl | HC_EPT_Format;
38737c478bd9Sstevel@tonic-gate }
38747c478bd9Sstevel@tonic-gate
38757c478bd9Sstevel@tonic-gate maxpacketsize = endpoint->wMaxPacketSize;
38767c478bd9Sstevel@tonic-gate maxpacketsize = maxpacketsize << HC_EPT_MAXPKTSZ;
38777c478bd9Sstevel@tonic-gate ctrl = ctrl | (maxpacketsize & HC_EPT_MPS);
38787c478bd9Sstevel@tonic-gate
38797c478bd9Sstevel@tonic-gate return (ctrl);
38807c478bd9Sstevel@tonic-gate }
38817c478bd9Sstevel@tonic-gate
38827c478bd9Sstevel@tonic-gate
38837c478bd9Sstevel@tonic-gate /*
38847c478bd9Sstevel@tonic-gate * ohci_insert_ed:
38857c478bd9Sstevel@tonic-gate *
38867c478bd9Sstevel@tonic-gate * Add the Endpoint Descriptor (ED) into the Host Controller's
38877c478bd9Sstevel@tonic-gate * (HC) appropriate endpoint list.
38887c478bd9Sstevel@tonic-gate */
38897c478bd9Sstevel@tonic-gate static void
ohci_insert_ed(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)38907c478bd9Sstevel@tonic-gate ohci_insert_ed(
38917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
38927c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
38937c478bd9Sstevel@tonic-gate {
38947c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
38957c478bd9Sstevel@tonic-gate
38967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
38977c478bd9Sstevel@tonic-gate "ohci_insert_ed:");
38987c478bd9Sstevel@tonic-gate
38997c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
39007c478bd9Sstevel@tonic-gate
39017c478bd9Sstevel@tonic-gate switch (ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) {
39027c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
39037c478bd9Sstevel@tonic-gate ohci_insert_ctrl_ed(ohcip, pp);
39047c478bd9Sstevel@tonic-gate break;
39057c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
39067c478bd9Sstevel@tonic-gate ohci_insert_bulk_ed(ohcip, pp);
39077c478bd9Sstevel@tonic-gate break;
39087c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
39097c478bd9Sstevel@tonic-gate ohci_insert_intr_ed(ohcip, pp);
39107c478bd9Sstevel@tonic-gate break;
39117c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
39127c478bd9Sstevel@tonic-gate ohci_insert_isoc_ed(ohcip, pp);
39137c478bd9Sstevel@tonic-gate break;
39147c478bd9Sstevel@tonic-gate }
39157c478bd9Sstevel@tonic-gate }
39167c478bd9Sstevel@tonic-gate
39177c478bd9Sstevel@tonic-gate
39187c478bd9Sstevel@tonic-gate /*
39197c478bd9Sstevel@tonic-gate * ohci_insert_ctrl_ed:
39207c478bd9Sstevel@tonic-gate *
39217c478bd9Sstevel@tonic-gate * Insert a control endpoint into the Host Controller's (HC)
39227c478bd9Sstevel@tonic-gate * control endpoint list.
39237c478bd9Sstevel@tonic-gate */
39247c478bd9Sstevel@tonic-gate static void
ohci_insert_ctrl_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)39257c478bd9Sstevel@tonic-gate ohci_insert_ctrl_ed(
39267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
39277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
39287c478bd9Sstevel@tonic-gate {
39297c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
39307c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept;
39317c478bd9Sstevel@tonic-gate
39327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
39337c478bd9Sstevel@tonic-gate "ohci_insert_ctrl_ed:");
39347c478bd9Sstevel@tonic-gate
39357c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
39367c478bd9Sstevel@tonic-gate
39377c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the list */
39387c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_ctrl_head)) {
39397c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip,
39407c478bd9Sstevel@tonic-gate Get_OpReg(hcr_ctrl_head));
39417c478bd9Sstevel@tonic-gate
39427c478bd9Sstevel@tonic-gate /* Set up the backwards pointer */
39437c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, ept));
39447c478bd9Sstevel@tonic-gate }
39457c478bd9Sstevel@tonic-gate
39467c478bd9Sstevel@tonic-gate /* The new endpoint points to the head of the list */
39477c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_OpReg(hcr_ctrl_head));
39487c478bd9Sstevel@tonic-gate
39497c478bd9Sstevel@tonic-gate /* Set the head ptr to the new endpoint */
39507c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, ohci_ed_cpu_to_iommu(ohcip, ept));
39517c478bd9Sstevel@tonic-gate
39527c478bd9Sstevel@tonic-gate /*
39537c478bd9Sstevel@tonic-gate * Enable Control list processing if control open
39547c478bd9Sstevel@tonic-gate * pipe count is zero.
39557c478bd9Sstevel@tonic-gate */
39567c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_ctrl_pipe_count) {
39577c478bd9Sstevel@tonic-gate /* Start Control list processing */
39587c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
39597c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_CLE));
39607c478bd9Sstevel@tonic-gate }
39617c478bd9Sstevel@tonic-gate
39627c478bd9Sstevel@tonic-gate ohcip->ohci_open_ctrl_pipe_count++;
39637c478bd9Sstevel@tonic-gate }
39647c478bd9Sstevel@tonic-gate
39657c478bd9Sstevel@tonic-gate
39667c478bd9Sstevel@tonic-gate /*
39677c478bd9Sstevel@tonic-gate * ohci_insert_bulk_ed:
39687c478bd9Sstevel@tonic-gate *
39697c478bd9Sstevel@tonic-gate * Insert a bulk endpoint into the Host Controller's (HC) bulk endpoint list.
39707c478bd9Sstevel@tonic-gate */
39717c478bd9Sstevel@tonic-gate static void
ohci_insert_bulk_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)39727c478bd9Sstevel@tonic-gate ohci_insert_bulk_ed(
39737c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
39747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
39757c478bd9Sstevel@tonic-gate {
39767c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
39777c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept;
39787c478bd9Sstevel@tonic-gate
39797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
39807c478bd9Sstevel@tonic-gate "ohci_insert_bulk_ed:");
39817c478bd9Sstevel@tonic-gate
39827c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
39837c478bd9Sstevel@tonic-gate
39847c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the Bulk list */
39857c478bd9Sstevel@tonic-gate if (Get_OpReg(hcr_bulk_head)) {
39867c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip,
39877c478bd9Sstevel@tonic-gate Get_OpReg(hcr_bulk_head));
39887c478bd9Sstevel@tonic-gate
39897c478bd9Sstevel@tonic-gate /* Set up the backwards pointer */
39907c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, ept));
39917c478bd9Sstevel@tonic-gate }
39927c478bd9Sstevel@tonic-gate
39937c478bd9Sstevel@tonic-gate /* The new endpoint points to the head of the Bulk list */
39947c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_OpReg(hcr_bulk_head));
39957c478bd9Sstevel@tonic-gate
39967c478bd9Sstevel@tonic-gate /* Set the Bulk head ptr to the new endpoint */
39977c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, ohci_ed_cpu_to_iommu(ohcip, ept));
39987c478bd9Sstevel@tonic-gate
39997c478bd9Sstevel@tonic-gate /*
40007c478bd9Sstevel@tonic-gate * Enable Bulk list processing if bulk open pipe
40017c478bd9Sstevel@tonic-gate * count is zero.
40027c478bd9Sstevel@tonic-gate */
40037c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_bulk_pipe_count) {
40047c478bd9Sstevel@tonic-gate /* Start Bulk list processing */
40057c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
40067c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_BLE));
40077c478bd9Sstevel@tonic-gate }
40087c478bd9Sstevel@tonic-gate
40097c478bd9Sstevel@tonic-gate ohcip->ohci_open_bulk_pipe_count++;
40107c478bd9Sstevel@tonic-gate }
40117c478bd9Sstevel@tonic-gate
40127c478bd9Sstevel@tonic-gate
40137c478bd9Sstevel@tonic-gate /*
40147c478bd9Sstevel@tonic-gate * ohci_insert_intr_ed:
40157c478bd9Sstevel@tonic-gate *
40167c478bd9Sstevel@tonic-gate * Insert a interrupt endpoint into the Host Controller's (HC) interrupt
40177c478bd9Sstevel@tonic-gate * lattice tree.
40187c478bd9Sstevel@tonic-gate */
40197c478bd9Sstevel@tonic-gate static void
ohci_insert_intr_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)40207c478bd9Sstevel@tonic-gate ohci_insert_intr_ed(
40217c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
40227c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
40237c478bd9Sstevel@tonic-gate {
40247c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
40257c478bd9Sstevel@tonic-gate ohci_ed_t *next_lattice_ept, *lattice_ept;
40267c478bd9Sstevel@tonic-gate uint_t node;
40277c478bd9Sstevel@tonic-gate
40287c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
40297c478bd9Sstevel@tonic-gate
40307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
40317c478bd9Sstevel@tonic-gate "ohci_insert_intr_ed:");
40327c478bd9Sstevel@tonic-gate
40337c478bd9Sstevel@tonic-gate /*
40347c478bd9Sstevel@tonic-gate * The appropriate node was found
40357c478bd9Sstevel@tonic-gate * during the opening of the pipe.
40367c478bd9Sstevel@tonic-gate */
40377c478bd9Sstevel@tonic-gate node = pp->pp_node;
40387c478bd9Sstevel@tonic-gate
40397c478bd9Sstevel@tonic-gate if (node >= NUM_STATIC_NODES) {
40407c478bd9Sstevel@tonic-gate /* Get the hcca interrupt table index */
40417c478bd9Sstevel@tonic-gate node = ohci_hcca_intr_index(node);
40427c478bd9Sstevel@tonic-gate
40437c478bd9Sstevel@tonic-gate /* Get the first endpoint on the list */
40447c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu(ohcip,
40457c478bd9Sstevel@tonic-gate Get_HCCA(ohcip->ohci_hccap->HccaIntTble[node]));
40467c478bd9Sstevel@tonic-gate
40477c478bd9Sstevel@tonic-gate /* Update this endpoint to point to it */
40487c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next,
40497c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, next_lattice_ept));
40507c478bd9Sstevel@tonic-gate
40517c478bd9Sstevel@tonic-gate /* Put this endpoint at the head of the list */
40527c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaIntTble[node],
40537c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept));
40547c478bd9Sstevel@tonic-gate
40557c478bd9Sstevel@tonic-gate /* The previous pointer is NULL */
40563e1e1e62SToomas Soome Set_ED(ept->hced_prev, 0);
40577c478bd9Sstevel@tonic-gate
40587c478bd9Sstevel@tonic-gate /* Update the previous pointer of ept->hced_next */
40597c478bd9Sstevel@tonic-gate if (Get_ED(next_lattice_ept->hced_state) != HC_EPT_STATIC) {
40607c478bd9Sstevel@tonic-gate Set_ED(next_lattice_ept->hced_prev,
40617c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept));
40627c478bd9Sstevel@tonic-gate }
40637c478bd9Sstevel@tonic-gate } else {
40647c478bd9Sstevel@tonic-gate /* Find the lattice endpoint */
40657c478bd9Sstevel@tonic-gate lattice_ept = &ohcip->ohci_ed_pool_addr[node];
40667c478bd9Sstevel@tonic-gate
40677c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */
40687c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu(
40697c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next));
40707c478bd9Sstevel@tonic-gate
40717c478bd9Sstevel@tonic-gate /*
40727c478bd9Sstevel@tonic-gate * Update this endpoint to point to the next one in the
40737c478bd9Sstevel@tonic-gate * lattice.
40747c478bd9Sstevel@tonic-gate */
40757c478bd9Sstevel@tonic-gate Set_ED(ept->hced_next, Get_ED(lattice_ept->hced_next));
40767c478bd9Sstevel@tonic-gate
40777c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */
40787c478bd9Sstevel@tonic-gate Set_ED(lattice_ept->hced_next,
40797c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept));
40807c478bd9Sstevel@tonic-gate
40817c478bd9Sstevel@tonic-gate /* Update the previous pointer */
40827c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev,
40837c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, lattice_ept));
40847c478bd9Sstevel@tonic-gate
40857c478bd9Sstevel@tonic-gate /* Update the previous pointer of ept->hced_next */
40867c478bd9Sstevel@tonic-gate if ((next_lattice_ept) &&
40877c478bd9Sstevel@tonic-gate (Get_ED(next_lattice_ept->hced_state) != HC_EPT_STATIC)) {
40887c478bd9Sstevel@tonic-gate
40897c478bd9Sstevel@tonic-gate Set_ED(next_lattice_ept->hced_prev,
40907c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept));
40917c478bd9Sstevel@tonic-gate }
40927c478bd9Sstevel@tonic-gate }
40937c478bd9Sstevel@tonic-gate
40947c478bd9Sstevel@tonic-gate /*
40957c478bd9Sstevel@tonic-gate * Enable periodic list processing if periodic (interrupt
40967c478bd9Sstevel@tonic-gate * and isochronous) open pipe count is zero.
40977c478bd9Sstevel@tonic-gate */
40987c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_periodic_pipe_count) {
40997c478bd9Sstevel@tonic-gate ASSERT(!ohcip->ohci_open_isoch_pipe_count);
41007c478bd9Sstevel@tonic-gate
41017c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
41027c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_PLE));
41037c478bd9Sstevel@tonic-gate }
41047c478bd9Sstevel@tonic-gate
41057c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count++;
41067c478bd9Sstevel@tonic-gate }
41077c478bd9Sstevel@tonic-gate
41087c478bd9Sstevel@tonic-gate
41097c478bd9Sstevel@tonic-gate /*
41107c478bd9Sstevel@tonic-gate * ohci_insert_isoc_ed:
41117c478bd9Sstevel@tonic-gate *
41127c478bd9Sstevel@tonic-gate * Insert a isochronous endpoint into the Host Controller's (HC) interrupt
41137c478bd9Sstevel@tonic-gate * lattice tree. A isochronous endpoint will be inserted at the end of the
41147c478bd9Sstevel@tonic-gate * 1ms interrupt endpoint list.
41157c478bd9Sstevel@tonic-gate */
41167c478bd9Sstevel@tonic-gate static void
ohci_insert_isoc_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)41177c478bd9Sstevel@tonic-gate ohci_insert_isoc_ed(
41187c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
41197c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
41207c478bd9Sstevel@tonic-gate {
41217c478bd9Sstevel@tonic-gate ohci_ed_t *next_lattice_ept, *lattice_ept;
41227c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
41237c478bd9Sstevel@tonic-gate uint_t node;
41247c478bd9Sstevel@tonic-gate
41257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
41267c478bd9Sstevel@tonic-gate
41277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
41287c478bd9Sstevel@tonic-gate "ohci_insert_isoc_ed:");
41297c478bd9Sstevel@tonic-gate
41307c478bd9Sstevel@tonic-gate /*
41317c478bd9Sstevel@tonic-gate * The appropriate node was found during the opening of the pipe.
41327c478bd9Sstevel@tonic-gate * This node must be root of the interrupt lattice tree.
41337c478bd9Sstevel@tonic-gate */
41347c478bd9Sstevel@tonic-gate node = pp->pp_node;
41357c478bd9Sstevel@tonic-gate
41367c478bd9Sstevel@tonic-gate ASSERT(node == 0);
41377c478bd9Sstevel@tonic-gate
41387c478bd9Sstevel@tonic-gate /* Find the 1ms interrupt lattice endpoint */
41397c478bd9Sstevel@tonic-gate lattice_ept = &ohcip->ohci_ed_pool_addr[node];
41407c478bd9Sstevel@tonic-gate
41417c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */
41427c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu(
41437c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next));
41447c478bd9Sstevel@tonic-gate
41457c478bd9Sstevel@tonic-gate while (next_lattice_ept) {
41467c478bd9Sstevel@tonic-gate lattice_ept = next_lattice_ept;
41477c478bd9Sstevel@tonic-gate
41487c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */
41497c478bd9Sstevel@tonic-gate next_lattice_ept = ohci_ed_iommu_to_cpu(
41507c478bd9Sstevel@tonic-gate ohcip, Get_ED(lattice_ept->hced_next));
41517c478bd9Sstevel@tonic-gate }
41527c478bd9Sstevel@tonic-gate
41537c478bd9Sstevel@tonic-gate /* The next pointer is NULL */
41543e1e1e62SToomas Soome Set_ED(ept->hced_next, 0);
41557c478bd9Sstevel@tonic-gate
41567c478bd9Sstevel@tonic-gate /* Update the previous pointer */
41577c478bd9Sstevel@tonic-gate Set_ED(ept->hced_prev, ohci_ed_cpu_to_iommu(ohcip, lattice_ept));
41587c478bd9Sstevel@tonic-gate
41597c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */
41607c478bd9Sstevel@tonic-gate Set_ED(lattice_ept->hced_next, ohci_ed_cpu_to_iommu(ohcip, ept));
41617c478bd9Sstevel@tonic-gate
41627c478bd9Sstevel@tonic-gate /*
41637c478bd9Sstevel@tonic-gate * Enable periodic and isoch lists processing if isoch
41647c478bd9Sstevel@tonic-gate * open pipe count is zero.
41657c478bd9Sstevel@tonic-gate */
41667c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_isoch_pipe_count) {
41677c478bd9Sstevel@tonic-gate
41687c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) |
41697c478bd9Sstevel@tonic-gate HCR_CONTROL_PLE | HCR_CONTROL_IE));
41707c478bd9Sstevel@tonic-gate }
41717c478bd9Sstevel@tonic-gate
41727c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count++;
41737c478bd9Sstevel@tonic-gate ohcip->ohci_open_isoch_pipe_count++;
41747c478bd9Sstevel@tonic-gate }
41757c478bd9Sstevel@tonic-gate
41767c478bd9Sstevel@tonic-gate
41777c478bd9Sstevel@tonic-gate /*
41787c478bd9Sstevel@tonic-gate * ohci_modify_sKip_bit:
41797c478bd9Sstevel@tonic-gate *
41807c478bd9Sstevel@tonic-gate * Modify the sKip bit on the Host Controller (HC) Endpoint Descriptor (ED).
41817c478bd9Sstevel@tonic-gate */
41827c478bd9Sstevel@tonic-gate static void
ohci_modify_sKip_bit(ohci_state_t * ohcip,ohci_pipe_private_t * pp,skip_bit_t action,usb_flags_t flag)41837c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(
41847c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
41857c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
41867c478bd9Sstevel@tonic-gate skip_bit_t action,
41877c478bd9Sstevel@tonic-gate usb_flags_t flag)
41887c478bd9Sstevel@tonic-gate {
41897c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
41907c478bd9Sstevel@tonic-gate
41917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
41927c478bd9Sstevel@tonic-gate "ohci_modify_sKip_bit: action = 0x%x flag = 0x%x",
41937c478bd9Sstevel@tonic-gate action, flag);
41947c478bd9Sstevel@tonic-gate
41957c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
41967c478bd9Sstevel@tonic-gate
41977c478bd9Sstevel@tonic-gate if (action == CLEAR_sKip) {
41987c478bd9Sstevel@tonic-gate /*
41997c478bd9Sstevel@tonic-gate * If the skip bit is to be cleared, just clear it.
42007c478bd9Sstevel@tonic-gate * there shouldn't be any race condition problems.
42017c478bd9Sstevel@tonic-gate * If the host controller reads the bit before the
42027c478bd9Sstevel@tonic-gate * driver has a chance to set the bit, the bit will
42037c478bd9Sstevel@tonic-gate * be reread on the next frame.
42047c478bd9Sstevel@tonic-gate */
42057c478bd9Sstevel@tonic-gate Set_ED(ept->hced_ctrl, (Get_ED(ept->hced_ctrl) & ~HC_EPT_sKip));
42067c478bd9Sstevel@tonic-gate } else {
42077c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */
42087c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_DMA_SYNC) {
42097c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip);
42107c478bd9Sstevel@tonic-gate }
42117c478bd9Sstevel@tonic-gate
42127c478bd9Sstevel@tonic-gate /* Check Halt or Skip bit is already set */
42137c478bd9Sstevel@tonic-gate if ((Get_ED(ept->hced_headp) & HC_EPT_Halt) ||
42147c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_ctrl) & HC_EPT_sKip)) {
42157c478bd9Sstevel@tonic-gate
42167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
42177c478bd9Sstevel@tonic-gate "ohci_modify_sKip_bit: "
42187c478bd9Sstevel@tonic-gate "Halt or Skip bit is already set");
42197c478bd9Sstevel@tonic-gate } else {
42207c478bd9Sstevel@tonic-gate /*
42217c478bd9Sstevel@tonic-gate * The action is to set the skip bit. In order to
42227c478bd9Sstevel@tonic-gate * be sure that the HCD has seen the sKip bit, wait
42237c478bd9Sstevel@tonic-gate * for the next start of frame.
42247c478bd9Sstevel@tonic-gate */
42257c478bd9Sstevel@tonic-gate Set_ED(ept->hced_ctrl,
42267c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_ctrl) | HC_EPT_sKip));
42277c478bd9Sstevel@tonic-gate
42287c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_SLEEP) {
42297c478bd9Sstevel@tonic-gate /* Wait for the next SOF */
42307c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip);
42317c478bd9Sstevel@tonic-gate
42327c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */
42337c478bd9Sstevel@tonic-gate if (flag & OHCI_FLAGS_DMA_SYNC) {
42347c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip);
42357c478bd9Sstevel@tonic-gate }
42367c478bd9Sstevel@tonic-gate }
42377c478bd9Sstevel@tonic-gate }
42387c478bd9Sstevel@tonic-gate }
42397c478bd9Sstevel@tonic-gate }
42407c478bd9Sstevel@tonic-gate
42417c478bd9Sstevel@tonic-gate
42427c478bd9Sstevel@tonic-gate /*
42437c478bd9Sstevel@tonic-gate * ohci_remove_ed:
42447c478bd9Sstevel@tonic-gate *
42457c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (ED) from the Host Controller's appropriate
42467c478bd9Sstevel@tonic-gate * endpoint list.
42477c478bd9Sstevel@tonic-gate */
42487c478bd9Sstevel@tonic-gate static void
ohci_remove_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)42497c478bd9Sstevel@tonic-gate ohci_remove_ed(
42507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
42517c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
42527c478bd9Sstevel@tonic-gate {
42537c478bd9Sstevel@tonic-gate uchar_t attributes;
42547c478bd9Sstevel@tonic-gate
42557c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
42567c478bd9Sstevel@tonic-gate
42577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
42587c478bd9Sstevel@tonic-gate "ohci_remove_ed:");
42597c478bd9Sstevel@tonic-gate
42607c478bd9Sstevel@tonic-gate attributes = pp->pp_pipe_handle->p_ep.bmAttributes & USB_EP_ATTR_MASK;
42617c478bd9Sstevel@tonic-gate
42627c478bd9Sstevel@tonic-gate switch (attributes) {
42637c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
42647c478bd9Sstevel@tonic-gate ohci_remove_ctrl_ed(ohcip, pp);
42657c478bd9Sstevel@tonic-gate break;
42667c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
42677c478bd9Sstevel@tonic-gate ohci_remove_bulk_ed(ohcip, pp);
42687c478bd9Sstevel@tonic-gate break;
42697c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
42707c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
42717c478bd9Sstevel@tonic-gate ohci_remove_periodic_ed(ohcip, pp);
42727c478bd9Sstevel@tonic-gate break;
42737c478bd9Sstevel@tonic-gate }
42747c478bd9Sstevel@tonic-gate }
42757c478bd9Sstevel@tonic-gate
42767c478bd9Sstevel@tonic-gate
42777c478bd9Sstevel@tonic-gate /*
42787c478bd9Sstevel@tonic-gate * ohci_remove_ctrl_ed:
42797c478bd9Sstevel@tonic-gate *
42807c478bd9Sstevel@tonic-gate * Remove a control Endpoint Descriptor (ED) from the Host Controller's (HC)
42817c478bd9Sstevel@tonic-gate * control endpoint list.
42827c478bd9Sstevel@tonic-gate */
42837c478bd9Sstevel@tonic-gate static void
ohci_remove_ctrl_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)42847c478bd9Sstevel@tonic-gate ohci_remove_ctrl_ed(
42857c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
42867c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
42877c478bd9Sstevel@tonic-gate {
42887c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */
42897c478bd9Sstevel@tonic-gate
42907c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
42917c478bd9Sstevel@tonic-gate "ohci_remove_ctrl_ed:");
42927c478bd9Sstevel@tonic-gate
42937c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
42947c478bd9Sstevel@tonic-gate
42957c478bd9Sstevel@tonic-gate /* The control list should already be stopped */
42967c478bd9Sstevel@tonic-gate ASSERT(!(Get_OpReg(hcr_control) & HCR_CONTROL_CLE));
42977c478bd9Sstevel@tonic-gate
42987c478bd9Sstevel@tonic-gate ohcip->ohci_open_ctrl_pipe_count--;
42997c478bd9Sstevel@tonic-gate
43007c478bd9Sstevel@tonic-gate /* Detach the endpoint from the list that it's on */
43017c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, USB_EP_ATTR_CONTROL);
43027c478bd9Sstevel@tonic-gate
43037c478bd9Sstevel@tonic-gate /*
43047c478bd9Sstevel@tonic-gate * If next endpoint pointed by endpoint to be removed is not NULL
43057c478bd9Sstevel@tonic-gate * then set current control pointer to the next endpoint pointed by
43067c478bd9Sstevel@tonic-gate * endpoint to be removed. Otherwise set current control pointer to
43077c478bd9Sstevel@tonic-gate * the beginning of the control list.
43087c478bd9Sstevel@tonic-gate */
43097c478bd9Sstevel@tonic-gate if (Get_ED(ept->hced_next)) {
43107c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, Get_ED(ept->hced_next));
43117c478bd9Sstevel@tonic-gate } else {
43127c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, Get_OpReg(hcr_ctrl_head));
43137c478bd9Sstevel@tonic-gate }
43147c478bd9Sstevel@tonic-gate
43157c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_ctrl_pipe_count) {
43167c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_ctrl_head));
43177c478bd9Sstevel@tonic-gate
43187c478bd9Sstevel@tonic-gate /* Reenable the control list */
43197c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
43207c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_CLE));
43217c478bd9Sstevel@tonic-gate }
43227c478bd9Sstevel@tonic-gate
43237c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp);
43247c478bd9Sstevel@tonic-gate }
43257c478bd9Sstevel@tonic-gate
43267c478bd9Sstevel@tonic-gate
43277c478bd9Sstevel@tonic-gate /*
43287c478bd9Sstevel@tonic-gate * ohci_remove_bulk_ed:
43297c478bd9Sstevel@tonic-gate *
43307c478bd9Sstevel@tonic-gate * Remove free the bulk Endpoint Descriptor (ED) from the Host Controller's
43317c478bd9Sstevel@tonic-gate * (HC) bulk endpoint list.
43327c478bd9Sstevel@tonic-gate */
43337c478bd9Sstevel@tonic-gate static void
ohci_remove_bulk_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)43347c478bd9Sstevel@tonic-gate ohci_remove_bulk_ed(
43357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
43367c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
43377c478bd9Sstevel@tonic-gate {
43387c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */
43397c478bd9Sstevel@tonic-gate
43407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
43417c478bd9Sstevel@tonic-gate "ohci_remove_bulk_ed:");
43427c478bd9Sstevel@tonic-gate
43437c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
43447c478bd9Sstevel@tonic-gate
43457c478bd9Sstevel@tonic-gate /* The bulk list should already be stopped */
43467c478bd9Sstevel@tonic-gate ASSERT(!(Get_OpReg(hcr_control) & HCR_CONTROL_BLE));
43477c478bd9Sstevel@tonic-gate
43487c478bd9Sstevel@tonic-gate ohcip->ohci_open_bulk_pipe_count--;
43497c478bd9Sstevel@tonic-gate
43507c478bd9Sstevel@tonic-gate /* Detach the endpoint from the bulk list */
43517c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, USB_EP_ATTR_BULK);
43527c478bd9Sstevel@tonic-gate
43537c478bd9Sstevel@tonic-gate /*
43547c478bd9Sstevel@tonic-gate * If next endpoint pointed by endpoint to be removed is not NULL
43557c478bd9Sstevel@tonic-gate * then set current bulk pointer to the next endpoint pointed by
43567c478bd9Sstevel@tonic-gate * endpoint to be removed. Otherwise set current bulk pointer to
43577c478bd9Sstevel@tonic-gate * the beginning of the bulk list.
43587c478bd9Sstevel@tonic-gate */
43597c478bd9Sstevel@tonic-gate if (Get_ED(ept->hced_next)) {
43607c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, Get_ED(ept->hced_next));
43617c478bd9Sstevel@tonic-gate } else {
43627c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, Get_OpReg(hcr_bulk_head));
43637c478bd9Sstevel@tonic-gate }
43647c478bd9Sstevel@tonic-gate
43657c478bd9Sstevel@tonic-gate if (ohcip->ohci_open_bulk_pipe_count) {
43667c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_bulk_head));
43677c478bd9Sstevel@tonic-gate
43687c478bd9Sstevel@tonic-gate /* Re-enable the bulk list */
43697c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
43707c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) | HCR_CONTROL_BLE));
43717c478bd9Sstevel@tonic-gate }
43727c478bd9Sstevel@tonic-gate
43737c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp);
43747c478bd9Sstevel@tonic-gate }
43757c478bd9Sstevel@tonic-gate
43767c478bd9Sstevel@tonic-gate
43777c478bd9Sstevel@tonic-gate /*
43787c478bd9Sstevel@tonic-gate * ohci_remove_periodic_ed:
43797c478bd9Sstevel@tonic-gate *
43807c478bd9Sstevel@tonic-gate * Set up an periodic endpoint to be removed from the Host Controller's (HC)
43817c478bd9Sstevel@tonic-gate * interrupt lattice tree. The Endpoint Descriptor (ED) will be freed in the
43827c478bd9Sstevel@tonic-gate * interrupt handler.
43837c478bd9Sstevel@tonic-gate */
43847c478bd9Sstevel@tonic-gate static void
ohci_remove_periodic_ed(ohci_state_t * ohcip,ohci_pipe_private_t * pp)43857c478bd9Sstevel@tonic-gate ohci_remove_periodic_ed(
43867c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
43877c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
43887c478bd9Sstevel@tonic-gate {
43897c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */
43907c478bd9Sstevel@tonic-gate uint_t ept_type;
43917c478bd9Sstevel@tonic-gate
43927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
43937c478bd9Sstevel@tonic-gate "ohci_remove_periodic_ed:");
43947c478bd9Sstevel@tonic-gate
43957c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
43967c478bd9Sstevel@tonic-gate
43977c478bd9Sstevel@tonic-gate ASSERT((Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL) ==
43987c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD));
43997c478bd9Sstevel@tonic-gate
44007c478bd9Sstevel@tonic-gate ohcip->ohci_open_periodic_pipe_count--;
44017c478bd9Sstevel@tonic-gate
44027c478bd9Sstevel@tonic-gate ept_type = pp->pp_pipe_handle->
44037c478bd9Sstevel@tonic-gate p_ep.bmAttributes & USB_EP_ATTR_MASK;
44047c478bd9Sstevel@tonic-gate
44057c478bd9Sstevel@tonic-gate if (ept_type == USB_EP_ATTR_ISOCH) {
44067c478bd9Sstevel@tonic-gate ohcip->ohci_open_isoch_pipe_count--;
44077c478bd9Sstevel@tonic-gate }
44087c478bd9Sstevel@tonic-gate
44097c478bd9Sstevel@tonic-gate /* Store the node number */
44107c478bd9Sstevel@tonic-gate Set_ED(ept->hced_node, pp->pp_node);
44117c478bd9Sstevel@tonic-gate
44127c478bd9Sstevel@tonic-gate /* Remove the endpoint from interrupt lattice tree */
44137c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(ohcip, ept, ept_type);
44147c478bd9Sstevel@tonic-gate
44157c478bd9Sstevel@tonic-gate /*
44167c478bd9Sstevel@tonic-gate * Disable isoch list processing if isoch open pipe count
44177c478bd9Sstevel@tonic-gate * is zero.
44187c478bd9Sstevel@tonic-gate */
44197c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_isoch_pipe_count) {
44207c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
44217c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_IE)));
44227c478bd9Sstevel@tonic-gate }
44237c478bd9Sstevel@tonic-gate
44247c478bd9Sstevel@tonic-gate /*
44257c478bd9Sstevel@tonic-gate * Disable periodic list processing if periodic (interrupt
44267c478bd9Sstevel@tonic-gate * and isochrous) open pipe count is zero.
44277c478bd9Sstevel@tonic-gate */
44287c478bd9Sstevel@tonic-gate if (!ohcip->ohci_open_periodic_pipe_count) {
44297c478bd9Sstevel@tonic-gate ASSERT(!ohcip->ohci_open_isoch_pipe_count);
44307c478bd9Sstevel@tonic-gate
44317c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
44327c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(HCR_CONTROL_PLE)));
44337c478bd9Sstevel@tonic-gate }
44347c478bd9Sstevel@tonic-gate
44357c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(ohcip, pp);
44367c478bd9Sstevel@tonic-gate }
44377c478bd9Sstevel@tonic-gate
44387c478bd9Sstevel@tonic-gate
44397c478bd9Sstevel@tonic-gate /*
44407c478bd9Sstevel@tonic-gate * ohci_detach_ed_from_list:
44417c478bd9Sstevel@tonic-gate *
44427c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (ED) from the appropriate Host Controller's
44437c478bd9Sstevel@tonic-gate * (HC) endpoint list.
44447c478bd9Sstevel@tonic-gate */
44457c478bd9Sstevel@tonic-gate static void
ohci_detach_ed_from_list(ohci_state_t * ohcip,ohci_ed_t * ept,uint_t ept_type)44467c478bd9Sstevel@tonic-gate ohci_detach_ed_from_list(
44477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
44487c478bd9Sstevel@tonic-gate ohci_ed_t *ept,
44497c478bd9Sstevel@tonic-gate uint_t ept_type)
44507c478bd9Sstevel@tonic-gate {
44517c478bd9Sstevel@tonic-gate ohci_ed_t *prev_ept; /* Previous endpoint */
44527c478bd9Sstevel@tonic-gate ohci_ed_t *next_ept; /* Endpoint after one to be removed */
44537c478bd9Sstevel@tonic-gate uint_t node;
44547c478bd9Sstevel@tonic-gate
44557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
44567c478bd9Sstevel@tonic-gate "ohci_detach_ed_from_list:");
44577c478bd9Sstevel@tonic-gate
44587c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
44597c478bd9Sstevel@tonic-gate
44607c478bd9Sstevel@tonic-gate prev_ept = ohci_ed_iommu_to_cpu(ohcip, Get_ED(ept->hced_prev));
44617c478bd9Sstevel@tonic-gate next_ept = ohci_ed_iommu_to_cpu(ohcip, Get_ED(ept->hced_next));
44627c478bd9Sstevel@tonic-gate
44637c478bd9Sstevel@tonic-gate /*
44647c478bd9Sstevel@tonic-gate * If there is no previous endpoint, then this
44657c478bd9Sstevel@tonic-gate * endpoint is at the head of the endpoint list.
44667c478bd9Sstevel@tonic-gate */
44677c478bd9Sstevel@tonic-gate if (prev_ept == NULL) {
44687c478bd9Sstevel@tonic-gate if (next_ept) {
44697c478bd9Sstevel@tonic-gate /*
44707c478bd9Sstevel@tonic-gate * If this endpoint is the first element of the
44717c478bd9Sstevel@tonic-gate * list and there is more than one endpoint on
44727c478bd9Sstevel@tonic-gate * the list then perform specific actions based
44737c478bd9Sstevel@tonic-gate * on the type of endpoint list.
44747c478bd9Sstevel@tonic-gate */
44757c478bd9Sstevel@tonic-gate switch (ept_type) {
44767c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
44777c478bd9Sstevel@tonic-gate /* Set the head of list to next ept */
44787c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head,
44797c478bd9Sstevel@tonic-gate Get_ED(ept->hced_next));
44807c478bd9Sstevel@tonic-gate
44817c478bd9Sstevel@tonic-gate /* Clear prev ptr of next endpoint */
44823e1e1e62SToomas Soome Set_ED(next_ept->hced_prev, 0);
44837c478bd9Sstevel@tonic-gate break;
44847c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
44857c478bd9Sstevel@tonic-gate /* Set the head of list to next ept */
44867c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head,
44877c478bd9Sstevel@tonic-gate Get_ED(ept->hced_next));
44887c478bd9Sstevel@tonic-gate
44897c478bd9Sstevel@tonic-gate /* Clear prev ptr of next endpoint */
44903e1e1e62SToomas Soome Set_ED(next_ept->hced_prev, 0);
44917c478bd9Sstevel@tonic-gate break;
44927c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
44937c478bd9Sstevel@tonic-gate /*
44947c478bd9Sstevel@tonic-gate * HCCA area should point
44957c478bd9Sstevel@tonic-gate * directly to this ept.
44967c478bd9Sstevel@tonic-gate */
44977c478bd9Sstevel@tonic-gate ASSERT(Get_ED(ept->hced_node) >=
44987c478bd9Sstevel@tonic-gate NUM_STATIC_NODES);
44997c478bd9Sstevel@tonic-gate
45007c478bd9Sstevel@tonic-gate /* Get the hcca interrupt table index */
45017c478bd9Sstevel@tonic-gate node = ohci_hcca_intr_index(
45027c478bd9Sstevel@tonic-gate Get_ED(ept->hced_node));
45037c478bd9Sstevel@tonic-gate
45047c478bd9Sstevel@tonic-gate /*
45057c478bd9Sstevel@tonic-gate * Delete the ept from the
45067c478bd9Sstevel@tonic-gate * bottom of the tree.
45077c478bd9Sstevel@tonic-gate */
45087c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->
45097c478bd9Sstevel@tonic-gate HccaIntTble[node], Get_ED(ept->hced_next));
45107c478bd9Sstevel@tonic-gate
45117c478bd9Sstevel@tonic-gate /*
45127c478bd9Sstevel@tonic-gate * Update the previous pointer
45137c478bd9Sstevel@tonic-gate * of ept->hced_next
45147c478bd9Sstevel@tonic-gate */
45157c478bd9Sstevel@tonic-gate if (Get_ED(next_ept->hced_state) !=
45167c478bd9Sstevel@tonic-gate HC_EPT_STATIC) {
45177c478bd9Sstevel@tonic-gate
45183e1e1e62SToomas Soome Set_ED(next_ept->hced_prev, 0);
45197c478bd9Sstevel@tonic-gate }
45207c478bd9Sstevel@tonic-gate
45217c478bd9Sstevel@tonic-gate break;
45227c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
45237c478bd9Sstevel@tonic-gate default:
45247c478bd9Sstevel@tonic-gate break;
45257c478bd9Sstevel@tonic-gate }
45267c478bd9Sstevel@tonic-gate } else {
45277c478bd9Sstevel@tonic-gate /*
45287c478bd9Sstevel@tonic-gate * If there was only one element on the list
45297c478bd9Sstevel@tonic-gate * perform specific actions based on the type
45307c478bd9Sstevel@tonic-gate * of the list.
45317c478bd9Sstevel@tonic-gate */
45327c478bd9Sstevel@tonic-gate switch (ept_type) {
45337c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
45347c478bd9Sstevel@tonic-gate /* Set the head to NULL */
45353e1e1e62SToomas Soome Set_OpReg(hcr_ctrl_head, 0);
45367c478bd9Sstevel@tonic-gate break;
45377c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
45387c478bd9Sstevel@tonic-gate /* Set the head to NULL */
45393e1e1e62SToomas Soome Set_OpReg(hcr_bulk_head, 0);
45407c478bd9Sstevel@tonic-gate break;
45417c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
45427c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
45437c478bd9Sstevel@tonic-gate default:
45447c478bd9Sstevel@tonic-gate break;
45457c478bd9Sstevel@tonic-gate }
45467c478bd9Sstevel@tonic-gate }
45477c478bd9Sstevel@tonic-gate } else {
45487c478bd9Sstevel@tonic-gate /* The previous ept points to the next one */
45497c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_next, Get_ED(ept->hced_next));
45507c478bd9Sstevel@tonic-gate
45517c478bd9Sstevel@tonic-gate /*
45527c478bd9Sstevel@tonic-gate * Set the previous ptr of the next_ept to prev_ept
45537c478bd9Sstevel@tonic-gate * if this isn't the last endpoint on the list
45547c478bd9Sstevel@tonic-gate */
45557c478bd9Sstevel@tonic-gate if ((next_ept) &&
45567c478bd9Sstevel@tonic-gate (Get_ED(next_ept->hced_state) != HC_EPT_STATIC)) {
45577c478bd9Sstevel@tonic-gate
45587c478bd9Sstevel@tonic-gate /* Set the previous ptr of the next one */
45597c478bd9Sstevel@tonic-gate Set_ED(next_ept->hced_prev, Get_ED(ept->hced_prev));
45607c478bd9Sstevel@tonic-gate }
45617c478bd9Sstevel@tonic-gate }
45627c478bd9Sstevel@tonic-gate }
45637c478bd9Sstevel@tonic-gate
45647c478bd9Sstevel@tonic-gate
45657c478bd9Sstevel@tonic-gate /*
45667c478bd9Sstevel@tonic-gate * ohci_insert_ed_on_reclaim_list:
45677c478bd9Sstevel@tonic-gate *
45687c478bd9Sstevel@tonic-gate * Insert Endpoint onto the reclaim list
45697c478bd9Sstevel@tonic-gate */
45707c478bd9Sstevel@tonic-gate static void
ohci_insert_ed_on_reclaim_list(ohci_state_t * ohcip,ohci_pipe_private_t * pp)45717c478bd9Sstevel@tonic-gate ohci_insert_ed_on_reclaim_list(
45727c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
45737c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
45747c478bd9Sstevel@tonic-gate {
45757c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept; /* ept to be removed */
45767c478bd9Sstevel@tonic-gate ohci_ed_t *next_ept, *prev_ept;
45777c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number;
45787c478bd9Sstevel@tonic-gate
45797c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
45807c478bd9Sstevel@tonic-gate
45817c478bd9Sstevel@tonic-gate /*
45827c478bd9Sstevel@tonic-gate * Read current usb frame number and add appropriate number of
45837c478bd9Sstevel@tonic-gate * usb frames needs to wait before reclaiming current endpoint.
45847c478bd9Sstevel@tonic-gate */
45857c478bd9Sstevel@tonic-gate frame_number =
45867c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohcip) + MAX_SOF_WAIT_COUNT;
45877c478bd9Sstevel@tonic-gate
45887c478bd9Sstevel@tonic-gate /* Store 32bit ID */
45897c478bd9Sstevel@tonic-gate Set_ED(ept->hced_reclaim_frame,
45907c478bd9Sstevel@tonic-gate ((uint32_t)(OHCI_GET_ID((void *)(uintptr_t)frame_number))));
45917c478bd9Sstevel@tonic-gate
45927c478bd9Sstevel@tonic-gate /* Insert the endpoint onto the reclaimation list */
45937c478bd9Sstevel@tonic-gate if (ohcip->ohci_reclaim_list) {
45947c478bd9Sstevel@tonic-gate next_ept = ohcip->ohci_reclaim_list;
45957c478bd9Sstevel@tonic-gate
45967c478bd9Sstevel@tonic-gate while (next_ept) {
45977c478bd9Sstevel@tonic-gate prev_ept = next_ept;
45987c478bd9Sstevel@tonic-gate next_ept = ohci_ed_iommu_to_cpu(ohcip,
45997c478bd9Sstevel@tonic-gate Get_ED(next_ept->hced_reclaim_next));
46007c478bd9Sstevel@tonic-gate }
46017c478bd9Sstevel@tonic-gate
46027c478bd9Sstevel@tonic-gate Set_ED(prev_ept->hced_reclaim_next,
46037c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(ohcip, ept));
46047c478bd9Sstevel@tonic-gate } else {
46057c478bd9Sstevel@tonic-gate ohcip->ohci_reclaim_list = ept;
46067c478bd9Sstevel@tonic-gate }
46077c478bd9Sstevel@tonic-gate
4608*3eb8c55cSToomas Soome ASSERT(Get_ED(ept->hced_reclaim_next) == 0);
46097c478bd9Sstevel@tonic-gate
46107c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */
46117c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF);
46127c478bd9Sstevel@tonic-gate }
46137c478bd9Sstevel@tonic-gate
46147c478bd9Sstevel@tonic-gate
46157c478bd9Sstevel@tonic-gate /*
46167c478bd9Sstevel@tonic-gate * ohci_deallocate_ed:
46177c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
46187c478bd9Sstevel@tonic-gate *
46197c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Endpoint Descriptor (ED).
46207c478bd9Sstevel@tonic-gate */
46217c478bd9Sstevel@tonic-gate void
ohci_deallocate_ed(ohci_state_t * ohcip,ohci_ed_t * old_ed)46227c478bd9Sstevel@tonic-gate ohci_deallocate_ed(
46237c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
46247c478bd9Sstevel@tonic-gate ohci_ed_t *old_ed)
46257c478bd9Sstevel@tonic-gate {
46267c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td;
46277c478bd9Sstevel@tonic-gate
46287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
46297c478bd9Sstevel@tonic-gate "ohci_deallocate_ed:");
46307c478bd9Sstevel@tonic-gate
46317c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
46327c478bd9Sstevel@tonic-gate
46337c478bd9Sstevel@tonic-gate dummy_td = ohci_td_iommu_to_cpu(ohcip, Get_ED(old_ed->hced_headp));
46347c478bd9Sstevel@tonic-gate
46357c478bd9Sstevel@tonic-gate if (dummy_td) {
46367c478bd9Sstevel@tonic-gate
46377c478bd9Sstevel@tonic-gate ASSERT(Get_TD(dummy_td->hctd_state) == HC_TD_DUMMY);
46387c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, dummy_td);
46397c478bd9Sstevel@tonic-gate }
46407c478bd9Sstevel@tonic-gate
46417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
46427c478bd9Sstevel@tonic-gate "ohci_deallocate_ed: Deallocated 0x%p", (void *)old_ed);
46437c478bd9Sstevel@tonic-gate
46447c478bd9Sstevel@tonic-gate bzero((void *)old_ed, sizeof (ohci_ed_t));
46457c478bd9Sstevel@tonic-gate Set_ED(old_ed->hced_state, HC_EPT_FREE);
46467c478bd9Sstevel@tonic-gate }
46477c478bd9Sstevel@tonic-gate
46487c478bd9Sstevel@tonic-gate
46497c478bd9Sstevel@tonic-gate /*
46507c478bd9Sstevel@tonic-gate * ohci_ed_cpu_to_iommu:
46517c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
46527c478bd9Sstevel@tonic-gate *
46537c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (ED) CPU address
46547c478bd9Sstevel@tonic-gate * to IO address.
46557c478bd9Sstevel@tonic-gate */
46567c478bd9Sstevel@tonic-gate uint32_t
ohci_ed_cpu_to_iommu(ohci_state_t * ohcip,ohci_ed_t * addr)46577c478bd9Sstevel@tonic-gate ohci_ed_cpu_to_iommu(
46587c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
46597c478bd9Sstevel@tonic-gate ohci_ed_t *addr)
46607c478bd9Sstevel@tonic-gate {
46617c478bd9Sstevel@tonic-gate uint32_t ed;
46627c478bd9Sstevel@tonic-gate
46637c478bd9Sstevel@tonic-gate ed = (uint32_t)ohcip->ohci_ed_pool_cookie.dmac_address +
46647c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ohcip->ohci_ed_pool_addr));
46657c478bd9Sstevel@tonic-gate
46667c478bd9Sstevel@tonic-gate ASSERT(ed >= ohcip->ohci_ed_pool_cookie.dmac_address);
46677c478bd9Sstevel@tonic-gate ASSERT(ed <= ohcip->ohci_ed_pool_cookie.dmac_address +
46687c478bd9Sstevel@tonic-gate sizeof (ohci_ed_t) * ohci_ed_pool_size);
46697c478bd9Sstevel@tonic-gate
46707c478bd9Sstevel@tonic-gate return (ed);
46717c478bd9Sstevel@tonic-gate }
46727c478bd9Sstevel@tonic-gate
46737c478bd9Sstevel@tonic-gate
46747c478bd9Sstevel@tonic-gate /*
46757c478bd9Sstevel@tonic-gate * ohci_ed_iommu_to_cpu:
46767c478bd9Sstevel@tonic-gate *
46777c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (ED) IO address
46787c478bd9Sstevel@tonic-gate * to CPU address.
46797c478bd9Sstevel@tonic-gate */
46807c478bd9Sstevel@tonic-gate static ohci_ed_t *
ohci_ed_iommu_to_cpu(ohci_state_t * ohcip,uintptr_t addr)46817c478bd9Sstevel@tonic-gate ohci_ed_iommu_to_cpu(
46827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
46837c478bd9Sstevel@tonic-gate uintptr_t addr)
46847c478bd9Sstevel@tonic-gate {
46857c478bd9Sstevel@tonic-gate ohci_ed_t *ed;
46867c478bd9Sstevel@tonic-gate
46873e1e1e62SToomas Soome if (addr == 0)
46887c478bd9Sstevel@tonic-gate return (NULL);
46897c478bd9Sstevel@tonic-gate
46907c478bd9Sstevel@tonic-gate ed = (ohci_ed_t *)((uintptr_t)
46917c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_ed_pool_cookie.dmac_address) +
46927c478bd9Sstevel@tonic-gate (uintptr_t)ohcip->ohci_ed_pool_addr);
46937c478bd9Sstevel@tonic-gate
46947c478bd9Sstevel@tonic-gate ASSERT(ed >= ohcip->ohci_ed_pool_addr);
46957c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)ed <= (uintptr_t)ohcip->ohci_ed_pool_addr +
46967c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ohci_ed_t) * ohci_ed_pool_size));
46977c478bd9Sstevel@tonic-gate
46987c478bd9Sstevel@tonic-gate return (ed);
46997c478bd9Sstevel@tonic-gate }
47007c478bd9Sstevel@tonic-gate
47017c478bd9Sstevel@tonic-gate
47027c478bd9Sstevel@tonic-gate /*
47037c478bd9Sstevel@tonic-gate * Transfer Descriptor manipulations functions
47047c478bd9Sstevel@tonic-gate */
47057c478bd9Sstevel@tonic-gate
47067c478bd9Sstevel@tonic-gate /*
47077c478bd9Sstevel@tonic-gate * ohci_initialize_dummy:
47087c478bd9Sstevel@tonic-gate *
47097c478bd9Sstevel@tonic-gate * An Endpoint Descriptor (ED) has a dummy Transfer Descriptor (TD) on the
47107c478bd9Sstevel@tonic-gate * end of its TD list. Initially, both the head and tail pointers of the ED
47117c478bd9Sstevel@tonic-gate * point to the dummy TD.
47127c478bd9Sstevel@tonic-gate */
47137c478bd9Sstevel@tonic-gate static int
ohci_initialize_dummy(ohci_state_t * ohcip,ohci_ed_t * ept)47147c478bd9Sstevel@tonic-gate ohci_initialize_dummy(
47157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
47167c478bd9Sstevel@tonic-gate ohci_ed_t *ept)
47177c478bd9Sstevel@tonic-gate {
47187c478bd9Sstevel@tonic-gate ohci_td_t *dummy;
47197c478bd9Sstevel@tonic-gate
47207c478bd9Sstevel@tonic-gate /* Obtain a dummy TD */
47217c478bd9Sstevel@tonic-gate dummy = ohci_allocate_td_from_pool(ohcip);
47227c478bd9Sstevel@tonic-gate
47237c478bd9Sstevel@tonic-gate if (dummy == NULL) {
47247c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
47257c478bd9Sstevel@tonic-gate }
47267c478bd9Sstevel@tonic-gate
47277c478bd9Sstevel@tonic-gate /*
47287c478bd9Sstevel@tonic-gate * Both the head and tail pointers of an ED point
47297c478bd9Sstevel@tonic-gate * to this new dummy TD.
47307c478bd9Sstevel@tonic-gate */
47317c478bd9Sstevel@tonic-gate Set_ED(ept->hced_headp, (ohci_td_cpu_to_iommu(ohcip, dummy)));
47327c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, dummy)));
47337c478bd9Sstevel@tonic-gate
47347c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
47357c478bd9Sstevel@tonic-gate }
47367c478bd9Sstevel@tonic-gate
47377c478bd9Sstevel@tonic-gate /*
47387c478bd9Sstevel@tonic-gate * ohci_allocate_ctrl_resources:
47397c478bd9Sstevel@tonic-gate *
47407c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates
47417c478bd9Sstevel@tonic-gate * all the resources necessary.
47427c478bd9Sstevel@tonic-gate *
47437c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW.
47447c478bd9Sstevel@tonic-gate */
47457c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *
ohci_allocate_ctrl_resources(ohci_state_t * ohcip,ohci_pipe_private_t * pp,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)47467c478bd9Sstevel@tonic-gate ohci_allocate_ctrl_resources(
47477c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
47487c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
47497c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp,
47507c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
47517c478bd9Sstevel@tonic-gate {
47527c478bd9Sstevel@tonic-gate size_t td_count = 2;
475302acac7eSsl147100 size_t ctrl_buf_size;
47547c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
47557c478bd9Sstevel@tonic-gate
47567c478bd9Sstevel@tonic-gate /* Add one more td for data phase */
47577c478bd9Sstevel@tonic-gate if (ctrl_reqp->ctrl_wLength) {
47587c478bd9Sstevel@tonic-gate td_count++;
47597c478bd9Sstevel@tonic-gate }
47607c478bd9Sstevel@tonic-gate
476102acac7eSsl147100 /*
476202acac7eSsl147100 * If we have a control data phase, the data buffer starts
476302acac7eSsl147100 * on the next 4K page boundary. So the TW buffer is allocated
476402acac7eSsl147100 * to be larger than required. The buffer in the range of
476502acac7eSsl147100 * [SETUP_SIZE, OHCI_MAX_TD_BUF_SIZE) is just for padding
476602acac7eSsl147100 * and not to be transferred.
476702acac7eSsl147100 */
476802acac7eSsl147100 if (ctrl_reqp->ctrl_wLength) {
476902acac7eSsl147100 ctrl_buf_size = OHCI_MAX_TD_BUF_SIZE +
477002acac7eSsl147100 ctrl_reqp->ctrl_wLength;
477102acac7eSsl147100 } else {
477202acac7eSsl147100 ctrl_buf_size = SETUP_SIZE;
477302acac7eSsl147100 }
477402acac7eSsl147100
477502acac7eSsl147100 tw = ohci_allocate_tw_resources(ohcip, pp, ctrl_buf_size,
47767c478bd9Sstevel@tonic-gate usb_flags, td_count);
47777c478bd9Sstevel@tonic-gate
47787c478bd9Sstevel@tonic-gate return (tw);
47797c478bd9Sstevel@tonic-gate }
47807c478bd9Sstevel@tonic-gate
47817c478bd9Sstevel@tonic-gate /*
47827c478bd9Sstevel@tonic-gate * ohci_insert_ctrl_req:
47837c478bd9Sstevel@tonic-gate *
47847c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (TD) and a data buffer for a control endpoint.
47857c478bd9Sstevel@tonic-gate */
47867c478bd9Sstevel@tonic-gate /* ARGSUSED */
47877c478bd9Sstevel@tonic-gate static void
ohci_insert_ctrl_req(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,ohci_trans_wrapper_t * tw,usb_flags_t usb_flags)47887c478bd9Sstevel@tonic-gate ohci_insert_ctrl_req(
47897c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
47907c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
47917c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp,
47927c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
47937c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
47947c478bd9Sstevel@tonic-gate {
47957c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
47967c478bd9Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType;
47977c478bd9Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest;
47987c478bd9Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue;
47997c478bd9Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex;
48007c478bd9Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength;
48017c478bd9Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data;
48027c478bd9Sstevel@tonic-gate uint32_t ctrl = 0;
48037c478bd9Sstevel@tonic-gate int sdata;
48047c478bd9Sstevel@tonic-gate
48057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
48067c478bd9Sstevel@tonic-gate "ohci_insert_ctrl_req:");
48077c478bd9Sstevel@tonic-gate
48087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
48097c478bd9Sstevel@tonic-gate
48107c478bd9Sstevel@tonic-gate /*
48117c478bd9Sstevel@tonic-gate * Save current control request pointer and timeout values
48127c478bd9Sstevel@tonic-gate * in transfer wrapper.
48137c478bd9Sstevel@tonic-gate */
48147c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)ctrl_reqp;
48157c478bd9Sstevel@tonic-gate tw->tw_timeout = ctrl_reqp->ctrl_timeout ?
48167c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_timeout : OHCI_DEFAULT_XFER_TIMEOUT;
48177c478bd9Sstevel@tonic-gate
48187c478bd9Sstevel@tonic-gate /*
48197c478bd9Sstevel@tonic-gate * Initialize the callback and any callback data for when
48207c478bd9Sstevel@tonic-gate * the td completes.
48217c478bd9Sstevel@tonic-gate */
48227c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_ctrl_td;
48237c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL;
48247c478bd9Sstevel@tonic-gate
48257c478bd9Sstevel@tonic-gate /* Create the first four bytes of the setup packet */
48267c478bd9Sstevel@tonic-gate sdata = (bmRequestType << 24) | (bRequest << 16) |
48277c478bd9Sstevel@tonic-gate (((wValue >> 8) | (wValue << 8)) & 0x0000FFFF);
48287c478bd9Sstevel@tonic-gate
48297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
48307c478bd9Sstevel@tonic-gate "ohci_create_setup_pkt: sdata = 0x%x", sdata);
48317c478bd9Sstevel@tonic-gate
48327c478bd9Sstevel@tonic-gate ddi_put32(tw->tw_accesshandle, (uint_t *)tw->tw_buf, sdata);
48337c478bd9Sstevel@tonic-gate
48347c478bd9Sstevel@tonic-gate /* Create the second four bytes */
48357c478bd9Sstevel@tonic-gate sdata = (uint32_t)(((((wIndex >> 8) |
48367c478bd9Sstevel@tonic-gate (wIndex << 8)) << 16) & 0xFFFF0000) |
48377c478bd9Sstevel@tonic-gate (((wLength >> 8) | (wLength << 8)) & 0x0000FFFF));
48387c478bd9Sstevel@tonic-gate
48397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
48407c478bd9Sstevel@tonic-gate "ohci_create_setup_pkt: sdata = 0x%x", sdata);
48417c478bd9Sstevel@tonic-gate
48427c478bd9Sstevel@tonic-gate ddi_put32(tw->tw_accesshandle,
4843d29f5a71Szhigang lu - Sun Microsystems - Beijing China (uint_t *)((uintptr_t)tw->tw_buf + sizeof (uint_t)), sdata);
48447c478bd9Sstevel@tonic-gate
48457c478bd9Sstevel@tonic-gate ctrl = HC_TD_SETUP|HC_TD_MS_DT|HC_TD_DT_0|HC_TD_6I;
48467c478bd9Sstevel@tonic-gate
48477c478bd9Sstevel@tonic-gate /*
48487c478bd9Sstevel@tonic-gate * The TD's are placed on the ED one at a time.
48497c478bd9Sstevel@tonic-gate * Once this TD is placed on the done list, the
48507c478bd9Sstevel@tonic-gate * data or status phase TD will be enqueued.
48517c478bd9Sstevel@tonic-gate */
485202acac7eSsl147100 (void) ohci_insert_hc_td(ohcip, ctrl, 0, SETUP_SIZE,
48537c478bd9Sstevel@tonic-gate OHCI_CTRL_SETUP_PHASE, pp, tw);
48547c478bd9Sstevel@tonic-gate
48557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
48567c478bd9Sstevel@tonic-gate "Create_setup: pp 0x%p", (void *)pp);
48577c478bd9Sstevel@tonic-gate
48587c478bd9Sstevel@tonic-gate /*
48597c478bd9Sstevel@tonic-gate * If this control transfer has a data phase, record the
48607c478bd9Sstevel@tonic-gate * direction. If the data phase is an OUT transaction,
48617c478bd9Sstevel@tonic-gate * copy the data into the buffer of the transfer wrapper.
48627c478bd9Sstevel@tonic-gate */
48637c478bd9Sstevel@tonic-gate if (wLength != 0) {
48647c478bd9Sstevel@tonic-gate /* There is a data stage. Find the direction */
48657c478bd9Sstevel@tonic-gate if (bmRequestType & USB_DEV_REQ_DEV_TO_HOST) {
48667c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN;
48677c478bd9Sstevel@tonic-gate } else {
48687c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT;
48697c478bd9Sstevel@tonic-gate
48707c478bd9Sstevel@tonic-gate /* Copy the data into the message */
48717c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle, data->b_rptr,
487202acac7eSsl147100 (uint8_t *)(tw->tw_buf + OHCI_MAX_TD_BUF_SIZE),
48737c478bd9Sstevel@tonic-gate wLength, DDI_DEV_AUTOINCR);
48747c478bd9Sstevel@tonic-gate
48757c478bd9Sstevel@tonic-gate }
48767c478bd9Sstevel@tonic-gate
48777c478bd9Sstevel@tonic-gate ctrl = (ctrl_reqp->ctrl_attributes & USB_ATTRS_SHORT_XFER_OK) ?
48787c478bd9Sstevel@tonic-gate HC_TD_R : 0;
48797c478bd9Sstevel@tonic-gate
48807c478bd9Sstevel@tonic-gate /*
48817c478bd9Sstevel@tonic-gate * There is a data stage.
48827c478bd9Sstevel@tonic-gate * Find the direction.
48837c478bd9Sstevel@tonic-gate */
48847c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) {
48857c478bd9Sstevel@tonic-gate ctrl = ctrl|HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_6I;
48867c478bd9Sstevel@tonic-gate } else {
48877c478bd9Sstevel@tonic-gate ctrl = ctrl|HC_TD_OUT|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_6I;
48887c478bd9Sstevel@tonic-gate }
48897c478bd9Sstevel@tonic-gate
48907c478bd9Sstevel@tonic-gate /*
48917c478bd9Sstevel@tonic-gate * Create the TD. If this is an OUT transaction,
48927c478bd9Sstevel@tonic-gate * the data is already in the buffer of the TW.
48937c478bd9Sstevel@tonic-gate */
489402acac7eSsl147100 (void) ohci_insert_hc_td(ohcip, ctrl, OHCI_MAX_TD_BUF_SIZE,
489502acac7eSsl147100 wLength, OHCI_CTRL_DATA_PHASE, pp, tw);
48967c478bd9Sstevel@tonic-gate
48977c478bd9Sstevel@tonic-gate /*
48987c478bd9Sstevel@tonic-gate * The direction of the STATUS TD depends on
48997c478bd9Sstevel@tonic-gate * the direction of the transfer.
49007c478bd9Sstevel@tonic-gate */
49017c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) {
49027c478bd9Sstevel@tonic-gate ctrl = HC_TD_OUT|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I;
49037c478bd9Sstevel@tonic-gate } else {
49047c478bd9Sstevel@tonic-gate ctrl = HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I;
49057c478bd9Sstevel@tonic-gate }
49067c478bd9Sstevel@tonic-gate } else {
49077c478bd9Sstevel@tonic-gate ctrl = HC_TD_IN|HC_TD_MS_DT|HC_TD_DT_1|HC_TD_1I;
49087c478bd9Sstevel@tonic-gate }
49097c478bd9Sstevel@tonic-gate
49107c478bd9Sstevel@tonic-gate /* Status stage */
491102acac7eSsl147100 (void) ohci_insert_hc_td(ohcip, ctrl, 0,
49127c478bd9Sstevel@tonic-gate 0, OHCI_CTRL_STATUS_PHASE, pp, tw);
49137c478bd9Sstevel@tonic-gate
49147c478bd9Sstevel@tonic-gate /* Indicate that the control list is filled */
49157c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_CLF);
49167c478bd9Sstevel@tonic-gate
49177c478bd9Sstevel@tonic-gate /* Start the timer for this control transfer */
49187c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw);
49197c478bd9Sstevel@tonic-gate }
49207c478bd9Sstevel@tonic-gate
49217c478bd9Sstevel@tonic-gate /*
49227c478bd9Sstevel@tonic-gate * ohci_allocate_bulk_resources:
49237c478bd9Sstevel@tonic-gate *
49247c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates
49257c478bd9Sstevel@tonic-gate * all the resources necessary.
49267c478bd9Sstevel@tonic-gate *
49277c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW.
49287c478bd9Sstevel@tonic-gate */
49297c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *
ohci_allocate_bulk_resources(ohci_state_t * ohcip,ohci_pipe_private_t * pp,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)49307c478bd9Sstevel@tonic-gate ohci_allocate_bulk_resources(
49317c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
49327c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
49337c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp,
49347c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
49357c478bd9Sstevel@tonic-gate {
49367c478bd9Sstevel@tonic-gate size_t td_count = 0;
49377c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
49387c478bd9Sstevel@tonic-gate
49397c478bd9Sstevel@tonic-gate /* Check the size of bulk request */
49407c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_len > OHCI_MAX_BULK_XFER_SIZE) {
49417c478bd9Sstevel@tonic-gate
49427c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
49437c478bd9Sstevel@tonic-gate "ohci_allocate_bulk_resources: Bulk request size 0x%x is "
49447c478bd9Sstevel@tonic-gate "more than 0x%x", bulk_reqp->bulk_len,
49457c478bd9Sstevel@tonic-gate OHCI_MAX_BULK_XFER_SIZE);
49467c478bd9Sstevel@tonic-gate
49477c478bd9Sstevel@tonic-gate return (NULL);
49487c478bd9Sstevel@tonic-gate }
49497c478bd9Sstevel@tonic-gate
49507c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */
49517c478bd9Sstevel@tonic-gate td_count = bulk_reqp->bulk_len / OHCI_MAX_TD_XFER_SIZE;
4952688b07c5Sgc161489 if (bulk_reqp->bulk_len % OHCI_MAX_TD_XFER_SIZE ||
4953688b07c5Sgc161489 bulk_reqp->bulk_len == 0) {
49547c478bd9Sstevel@tonic-gate td_count++;
49557c478bd9Sstevel@tonic-gate }
49567c478bd9Sstevel@tonic-gate
49577c478bd9Sstevel@tonic-gate tw = ohci_allocate_tw_resources(ohcip, pp, bulk_reqp->bulk_len,
49587c478bd9Sstevel@tonic-gate usb_flags, td_count);
49597c478bd9Sstevel@tonic-gate
49607c478bd9Sstevel@tonic-gate return (tw);
49617c478bd9Sstevel@tonic-gate }
49627c478bd9Sstevel@tonic-gate
49637c478bd9Sstevel@tonic-gate /*
49647c478bd9Sstevel@tonic-gate * ohci_insert_bulk_req:
49657c478bd9Sstevel@tonic-gate *
49667c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (TD) and a data buffer for a bulk
49677c478bd9Sstevel@tonic-gate * endpoint.
49687c478bd9Sstevel@tonic-gate */
49697c478bd9Sstevel@tonic-gate /* ARGSUSED */
49707c478bd9Sstevel@tonic-gate static void
ohci_insert_bulk_req(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,ohci_trans_wrapper_t * tw,usb_flags_t flags)49717c478bd9Sstevel@tonic-gate ohci_insert_bulk_req(
49727c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
49737c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
49747c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp,
49757c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
49767c478bd9Sstevel@tonic-gate usb_flags_t flags)
49777c478bd9Sstevel@tonic-gate {
49787c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
49797c478bd9Sstevel@tonic-gate uint_t bulk_pkt_size, count;
49807c478bd9Sstevel@tonic-gate size_t residue = 0, len = 0;
49817c478bd9Sstevel@tonic-gate uint32_t ctrl = 0;
49827c478bd9Sstevel@tonic-gate int pipe_dir;
49837c478bd9Sstevel@tonic-gate
49847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
49857c478bd9Sstevel@tonic-gate "ohci_insert_bulk_req: bulk_reqp = 0x%p flags = 0x%x",
4986112116d8Sfb209375 (void *)bulk_reqp, flags);
49877c478bd9Sstevel@tonic-gate
49887c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
49897c478bd9Sstevel@tonic-gate
49907c478bd9Sstevel@tonic-gate /* Get the bulk pipe direction */
49917c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
49927c478bd9Sstevel@tonic-gate
49937c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */
49947c478bd9Sstevel@tonic-gate bulk_pkt_size = min(bulk_reqp->bulk_len, OHCI_MAX_TD_XFER_SIZE);
49957c478bd9Sstevel@tonic-gate
4996688b07c5Sgc161489 if (bulk_pkt_size)
49977c478bd9Sstevel@tonic-gate residue = tw->tw_length % bulk_pkt_size;
49987c478bd9Sstevel@tonic-gate
49997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
50007c478bd9Sstevel@tonic-gate "ohci_insert_bulk_req: bulk_pkt_size = %d", bulk_pkt_size);
50017c478bd9Sstevel@tonic-gate
50027c478bd9Sstevel@tonic-gate /*
50037c478bd9Sstevel@tonic-gate * Save current bulk request pointer and timeout values
50047c478bd9Sstevel@tonic-gate * in transfer wrapper.
50057c478bd9Sstevel@tonic-gate */
50067c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)bulk_reqp;
50077c478bd9Sstevel@tonic-gate tw->tw_timeout = bulk_reqp->bulk_timeout;
50087c478bd9Sstevel@tonic-gate
50097c478bd9Sstevel@tonic-gate /*
50107c478bd9Sstevel@tonic-gate * Initialize the callback and any callback
50117c478bd9Sstevel@tonic-gate * data required when the td completes.
50127c478bd9Sstevel@tonic-gate */
50137c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_bulk_td;
50147c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL;
50157c478bd9Sstevel@tonic-gate
50167c478bd9Sstevel@tonic-gate tw->tw_direction =
50177c478bd9Sstevel@tonic-gate (pipe_dir == USB_EP_DIR_OUT) ? HC_TD_OUT : HC_TD_IN;
50187c478bd9Sstevel@tonic-gate
5019688b07c5Sgc161489 if (tw->tw_direction == HC_TD_OUT && bulk_reqp->bulk_len) {
50207c478bd9Sstevel@tonic-gate
50217c478bd9Sstevel@tonic-gate ASSERT(bulk_reqp->bulk_data != NULL);
50227c478bd9Sstevel@tonic-gate
50237c478bd9Sstevel@tonic-gate /* Copy the data into the message */
50247c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle,
50257c478bd9Sstevel@tonic-gate bulk_reqp->bulk_data->b_rptr, (uint8_t *)tw->tw_buf,
50267c478bd9Sstevel@tonic-gate bulk_reqp->bulk_len, DDI_DEV_AUTOINCR);
50277c478bd9Sstevel@tonic-gate }
50287c478bd9Sstevel@tonic-gate
50297c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction|HC_TD_DT_0|HC_TD_6I;
50307c478bd9Sstevel@tonic-gate
50317c478bd9Sstevel@tonic-gate /* Insert all the bulk TDs */
50327c478bd9Sstevel@tonic-gate for (count = 0; count < tw->tw_num_tds; count++) {
50337c478bd9Sstevel@tonic-gate
50347c478bd9Sstevel@tonic-gate /* Check for last td */
50357c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_tds - 1)) {
50367c478bd9Sstevel@tonic-gate
50377c478bd9Sstevel@tonic-gate ctrl = ((ctrl & ~HC_TD_DI) | HC_TD_1I);
50387c478bd9Sstevel@tonic-gate
50397c478bd9Sstevel@tonic-gate /* Check for inserting residue data */
50407c478bd9Sstevel@tonic-gate if (residue) {
5041d29f5a71Szhigang lu - Sun Microsystems - Beijing China bulk_pkt_size = (uint_t)residue;
50427c478bd9Sstevel@tonic-gate }
50437c478bd9Sstevel@tonic-gate
50447c478bd9Sstevel@tonic-gate /*
50457c478bd9Sstevel@tonic-gate * Only set the round bit on the last TD, to ensure
50467c478bd9Sstevel@tonic-gate * the controller will always HALT the ED in case of
50477c478bd9Sstevel@tonic-gate * a short transfer.
50487c478bd9Sstevel@tonic-gate */
50497c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_attributes &
50507c478bd9Sstevel@tonic-gate USB_ATTRS_SHORT_XFER_OK) {
50517c478bd9Sstevel@tonic-gate ctrl |= HC_TD_R;
50527c478bd9Sstevel@tonic-gate }
50537c478bd9Sstevel@tonic-gate }
50547c478bd9Sstevel@tonic-gate
50557c478bd9Sstevel@tonic-gate /* Insert the TD onto the endpoint */
505602acac7eSsl147100 (void) ohci_insert_hc_td(ohcip, ctrl, len,
50577c478bd9Sstevel@tonic-gate bulk_pkt_size, 0, pp, tw);
50587c478bd9Sstevel@tonic-gate
50597c478bd9Sstevel@tonic-gate len = len + bulk_pkt_size;
50607c478bd9Sstevel@tonic-gate }
50617c478bd9Sstevel@tonic-gate
50627c478bd9Sstevel@tonic-gate /* Indicate that the bulk list is filled */
50637c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_BLF);
50647c478bd9Sstevel@tonic-gate
50657c478bd9Sstevel@tonic-gate /* Start the timer for this bulk transfer */
50667c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw);
50677c478bd9Sstevel@tonic-gate }
50687c478bd9Sstevel@tonic-gate
50697c478bd9Sstevel@tonic-gate
50707c478bd9Sstevel@tonic-gate /*
50717c478bd9Sstevel@tonic-gate * ohci_start_periodic_pipe_polling:
50727c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
50737c478bd9Sstevel@tonic-gate */
50747c478bd9Sstevel@tonic-gate int
ohci_start_periodic_pipe_polling(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_opaque_t periodic_in_reqp,usb_flags_t flags)50757c478bd9Sstevel@tonic-gate ohci_start_periodic_pipe_polling(
50767c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
50777c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
50787c478bd9Sstevel@tonic-gate usb_opaque_t periodic_in_reqp,
50797c478bd9Sstevel@tonic-gate usb_flags_t flags)
50807c478bd9Sstevel@tonic-gate {
50817c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
50827c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
50837c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
50847c478bd9Sstevel@tonic-gate
50857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
50867c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: ep%d",
50877c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK);
50887c478bd9Sstevel@tonic-gate
50897c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
50907c478bd9Sstevel@tonic-gate
50917c478bd9Sstevel@tonic-gate /*
50927c478bd9Sstevel@tonic-gate * Check and handle start polling on root hub interrupt pipe.
50937c478bd9Sstevel@tonic-gate */
50947c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) &&
50957c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
50967c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) {
50977c478bd9Sstevel@tonic-gate
50987c478bd9Sstevel@tonic-gate error = ohci_handle_root_hub_pipe_start_intr_polling(ph,
50997c478bd9Sstevel@tonic-gate (usb_intr_req_t *)periodic_in_reqp, flags);
51007c478bd9Sstevel@tonic-gate
51017c478bd9Sstevel@tonic-gate return (error);
51027c478bd9Sstevel@tonic-gate }
51037c478bd9Sstevel@tonic-gate
51047c478bd9Sstevel@tonic-gate switch (pp->pp_state) {
51057c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_IDLE:
51067c478bd9Sstevel@tonic-gate /* Save the Original client's Periodic IN request */
51077c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = periodic_in_reqp;
51087c478bd9Sstevel@tonic-gate
51097c478bd9Sstevel@tonic-gate /*
51107c478bd9Sstevel@tonic-gate * This pipe is uninitialized or if a valid TD is
51117c478bd9Sstevel@tonic-gate * not found then insert a TD on the interrupt or
51127c478bd9Sstevel@tonic-gate * isochronous IN endpoint.
51137c478bd9Sstevel@tonic-gate */
51147c478bd9Sstevel@tonic-gate error = ohci_start_pipe_polling(ohcip, ph, flags);
51157c478bd9Sstevel@tonic-gate
51167c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
51177c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
51187c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: "
51197c478bd9Sstevel@tonic-gate "Start polling failed");
51207c478bd9Sstevel@tonic-gate
51217c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL;
51227c478bd9Sstevel@tonic-gate
51237c478bd9Sstevel@tonic-gate return (error);
51247c478bd9Sstevel@tonic-gate }
51257c478bd9Sstevel@tonic-gate
51267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
5127112116d8Sfb209375 "ohci_start_periodic_pipe_polling: PP = 0x%p", (void *)pp);
51287c478bd9Sstevel@tonic-gate
51297c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head != NULL) && (pp->pp_tw_tail != NULL));
51307c478bd9Sstevel@tonic-gate
51317c478bd9Sstevel@tonic-gate break;
51327c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_ACTIVE:
51337c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
51347c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: "
51357c478bd9Sstevel@tonic-gate "Polling is already in progress");
51367c478bd9Sstevel@tonic-gate
51377c478bd9Sstevel@tonic-gate error = USB_FAILURE;
51387c478bd9Sstevel@tonic-gate break;
51397c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_ERROR:
51407c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
51417c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: "
51427c478bd9Sstevel@tonic-gate "Pipe is halted and perform reset before restart polling");
51437c478bd9Sstevel@tonic-gate
51447c478bd9Sstevel@tonic-gate error = USB_FAILURE;
51457c478bd9Sstevel@tonic-gate break;
51467c478bd9Sstevel@tonic-gate default:
51477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
51487c478bd9Sstevel@tonic-gate "ohci_start_periodic_pipe_polling: Undefined state");
51497c478bd9Sstevel@tonic-gate
51507c478bd9Sstevel@tonic-gate error = USB_FAILURE;
51517c478bd9Sstevel@tonic-gate break;
51527c478bd9Sstevel@tonic-gate }
51537c478bd9Sstevel@tonic-gate
51547c478bd9Sstevel@tonic-gate return (error);
51557c478bd9Sstevel@tonic-gate }
51567c478bd9Sstevel@tonic-gate
51577c478bd9Sstevel@tonic-gate
51587c478bd9Sstevel@tonic-gate /*
51597c478bd9Sstevel@tonic-gate * ohci_start_pipe_polling:
51607c478bd9Sstevel@tonic-gate *
51617c478bd9Sstevel@tonic-gate * Insert the number of periodic requests corresponding to polling
51627c478bd9Sstevel@tonic-gate * interval as calculated during pipe open.
51637c478bd9Sstevel@tonic-gate */
51647c478bd9Sstevel@tonic-gate static int
ohci_start_pipe_polling(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_flags_t flags)51657c478bd9Sstevel@tonic-gate ohci_start_pipe_polling(
51667c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
51677c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
51687c478bd9Sstevel@tonic-gate usb_flags_t flags)
51697c478bd9Sstevel@tonic-gate {
51707c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
51717c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
51727c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw_list, *tw;
51737c478bd9Sstevel@tonic-gate int i, total_tws;
51747c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
51757c478bd9Sstevel@tonic-gate
51767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
51777c478bd9Sstevel@tonic-gate "ohci_start_pipe_polling:");
51787c478bd9Sstevel@tonic-gate
51797c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
51807c478bd9Sstevel@tonic-gate
51817c478bd9Sstevel@tonic-gate /*
51827c478bd9Sstevel@tonic-gate * For the start polling, pp_max_periodic_req_cnt will be zero
51837c478bd9Sstevel@tonic-gate * and for the restart polling request, it will be non zero.
51847c478bd9Sstevel@tonic-gate *
51857c478bd9Sstevel@tonic-gate * In case of start polling request, find out number of requests
51867c478bd9Sstevel@tonic-gate * required for the Interrupt IN endpoints corresponding to the
51877c478bd9Sstevel@tonic-gate * endpoint polling interval. For Isochronous IN endpoints, it is
51887c478bd9Sstevel@tonic-gate * always fixed since its polling interval will be one ms.
51897c478bd9Sstevel@tonic-gate */
51907c478bd9Sstevel@tonic-gate if (pp->pp_max_periodic_req_cnt == 0) {
51917c478bd9Sstevel@tonic-gate
51927c478bd9Sstevel@tonic-gate ohci_set_periodic_pipe_polling(ohcip, ph);
51937c478bd9Sstevel@tonic-gate }
51947c478bd9Sstevel@tonic-gate
51957c478bd9Sstevel@tonic-gate ASSERT(pp->pp_max_periodic_req_cnt != 0);
51967c478bd9Sstevel@tonic-gate
51977c478bd9Sstevel@tonic-gate /* Allocate all the necessary resources for the IN transfer */
51987c478bd9Sstevel@tonic-gate tw_list = NULL;
51997c478bd9Sstevel@tonic-gate total_tws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt;
52007c478bd9Sstevel@tonic-gate for (i = 0; i < total_tws; i++) {
52017c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
52027c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
52037c478bd9Sstevel@tonic-gate tw = ohci_allocate_intr_resources(
52047c478bd9Sstevel@tonic-gate ohcip, ph, NULL, flags);
52057c478bd9Sstevel@tonic-gate break;
52067c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
52077c478bd9Sstevel@tonic-gate tw = ohci_allocate_isoc_resources(
52087c478bd9Sstevel@tonic-gate ohcip, ph, NULL, flags);
52097c478bd9Sstevel@tonic-gate break;
52107c478bd9Sstevel@tonic-gate }
52117c478bd9Sstevel@tonic-gate if (tw == NULL) {
52127c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
52137c478bd9Sstevel@tonic-gate /* There are not enough resources, deallocate the TWs */
52147c478bd9Sstevel@tonic-gate tw = tw_list;
52157c478bd9Sstevel@tonic-gate while (tw != NULL) {
52167c478bd9Sstevel@tonic-gate tw_list = tw->tw_next;
52177c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(
52187c478bd9Sstevel@tonic-gate ohcip, pp, tw);
52197c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
52207c478bd9Sstevel@tonic-gate tw = tw_list;
52217c478bd9Sstevel@tonic-gate }
52227c478bd9Sstevel@tonic-gate return (error);
52237c478bd9Sstevel@tonic-gate } else {
52247c478bd9Sstevel@tonic-gate if (tw_list == NULL) {
52257c478bd9Sstevel@tonic-gate tw_list = tw;
52267c478bd9Sstevel@tonic-gate }
52277c478bd9Sstevel@tonic-gate }
52287c478bd9Sstevel@tonic-gate }
52297c478bd9Sstevel@tonic-gate
52307c478bd9Sstevel@tonic-gate i = 0;
52317c478bd9Sstevel@tonic-gate while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) {
52327c478bd9Sstevel@tonic-gate
52337c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
52347c478bd9Sstevel@tonic-gate "ohci_start_pipe_polling: max = %d curr = %d tw = %p:",
52357c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt,
5236112116d8Sfb209375 (void *)tw_list);
52377c478bd9Sstevel@tonic-gate
52387c478bd9Sstevel@tonic-gate tw = tw_list;
52397c478bd9Sstevel@tonic-gate tw_list = tw->tw_next;
52407c478bd9Sstevel@tonic-gate
52417c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
52427c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
52437c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, pp, tw, flags);
52447c478bd9Sstevel@tonic-gate break;
52457c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
52467c478bd9Sstevel@tonic-gate error = ohci_insert_isoc_req(ohcip, pp, tw, flags);
52477c478bd9Sstevel@tonic-gate break;
52487c478bd9Sstevel@tonic-gate }
52497c478bd9Sstevel@tonic-gate if (error == USB_SUCCESS) {
52507c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++;
52517c478bd9Sstevel@tonic-gate } else {
52527c478bd9Sstevel@tonic-gate /*
52537c478bd9Sstevel@tonic-gate * Deallocate the remaining tw
52547c478bd9Sstevel@tonic-gate * The current tw should have already been deallocated
52557c478bd9Sstevel@tonic-gate */
52567c478bd9Sstevel@tonic-gate tw = tw_list;
52577c478bd9Sstevel@tonic-gate while (tw != NULL) {
52587c478bd9Sstevel@tonic-gate tw_list = tw->tw_next;
52597c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(
52607c478bd9Sstevel@tonic-gate ohcip, pp, tw);
52617c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
52627c478bd9Sstevel@tonic-gate tw = tw_list;
52637c478bd9Sstevel@tonic-gate }
52647c478bd9Sstevel@tonic-gate /*
52657c478bd9Sstevel@tonic-gate * If this is the first req return an error.
52667c478bd9Sstevel@tonic-gate * Otherwise return success.
52677c478bd9Sstevel@tonic-gate */
52687c478bd9Sstevel@tonic-gate if (i != 0) {
52697c478bd9Sstevel@tonic-gate error = USB_SUCCESS;
52707c478bd9Sstevel@tonic-gate }
52717c478bd9Sstevel@tonic-gate
52727c478bd9Sstevel@tonic-gate break;
52737c478bd9Sstevel@tonic-gate }
52747c478bd9Sstevel@tonic-gate i++;
52757c478bd9Sstevel@tonic-gate }
52767c478bd9Sstevel@tonic-gate
52777c478bd9Sstevel@tonic-gate return (error);
52787c478bd9Sstevel@tonic-gate }
52797c478bd9Sstevel@tonic-gate
52807c478bd9Sstevel@tonic-gate
52817c478bd9Sstevel@tonic-gate /*
52827c478bd9Sstevel@tonic-gate * ohci_set_periodic_pipe_polling:
52837c478bd9Sstevel@tonic-gate *
52847c478bd9Sstevel@tonic-gate * Calculate the number of periodic requests needed corresponding to the
52857c478bd9Sstevel@tonic-gate * interrupt/isochronous IN endpoints polling interval. Table below gives
52867c478bd9Sstevel@tonic-gate * the number of periodic requests needed for the interrupt/isochronous
52877c478bd9Sstevel@tonic-gate * IN endpoints according to endpoint polling interval.
52887c478bd9Sstevel@tonic-gate *
52897c478bd9Sstevel@tonic-gate * Polling interval Number of periodic requests
52907c478bd9Sstevel@tonic-gate *
52917c478bd9Sstevel@tonic-gate * 1ms 4
52927c478bd9Sstevel@tonic-gate * 2ms 2
52937c478bd9Sstevel@tonic-gate * 4ms to 32ms 1
52947c478bd9Sstevel@tonic-gate */
52957c478bd9Sstevel@tonic-gate static void
ohci_set_periodic_pipe_polling(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)52967c478bd9Sstevel@tonic-gate ohci_set_periodic_pipe_polling(
52977c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
52987c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
52997c478bd9Sstevel@tonic-gate {
53007c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
53017c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
53027c478bd9Sstevel@tonic-gate uchar_t ep_attr = endpoint->bmAttributes;
53037c478bd9Sstevel@tonic-gate uint_t interval;
53047c478bd9Sstevel@tonic-gate
53057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
53067c478bd9Sstevel@tonic-gate "ohci_set_periodic_pipe_polling:");
53077c478bd9Sstevel@tonic-gate
53087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
53097c478bd9Sstevel@tonic-gate
53107c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt = 0;
53117c478bd9Sstevel@tonic-gate
53127c478bd9Sstevel@tonic-gate /*
53137c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_TIME_POLL flag is
53147c478bd9Sstevel@tonic-gate * set and if so, set pp->pp_max_periodic_req_cnt to one.
53157c478bd9Sstevel@tonic-gate */
53167c478bd9Sstevel@tonic-gate if (((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) &&
53177c478bd9Sstevel@tonic-gate (pp->pp_client_periodic_in_reqp)) {
53187c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp =
53197c478bd9Sstevel@tonic-gate (usb_intr_req_t *)pp->pp_client_periodic_in_reqp;
53207c478bd9Sstevel@tonic-gate
53217c478bd9Sstevel@tonic-gate if (intr_reqp->intr_attributes &
53227c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) {
53237c478bd9Sstevel@tonic-gate
53247c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_XMS_REQS;
53257c478bd9Sstevel@tonic-gate
53267c478bd9Sstevel@tonic-gate return;
53277c478bd9Sstevel@tonic-gate }
53287c478bd9Sstevel@tonic-gate }
53297c478bd9Sstevel@tonic-gate
53307c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex);
53317c478bd9Sstevel@tonic-gate
53327c478bd9Sstevel@tonic-gate /*
53337c478bd9Sstevel@tonic-gate * The ohci_adjust_polling_interval function will not fail
53347c478bd9Sstevel@tonic-gate * at this instance since bandwidth allocation is already
53357c478bd9Sstevel@tonic-gate * done. Here we are getting only the periodic interval.
53367c478bd9Sstevel@tonic-gate */
53377c478bd9Sstevel@tonic-gate interval = ohci_adjust_polling_interval(ohcip, endpoint,
53387c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_port_status);
53397c478bd9Sstevel@tonic-gate
53407c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex);
53417c478bd9Sstevel@tonic-gate
53427c478bd9Sstevel@tonic-gate switch (interval) {
53437c478bd9Sstevel@tonic-gate case INTR_1MS_POLL:
53447c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_1MS_REQS;
53457c478bd9Sstevel@tonic-gate break;
53467c478bd9Sstevel@tonic-gate case INTR_2MS_POLL:
53477c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_2MS_REQS;
53487c478bd9Sstevel@tonic-gate break;
53497c478bd9Sstevel@tonic-gate default:
53507c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = INTR_XMS_REQS;
53517c478bd9Sstevel@tonic-gate break;
53527c478bd9Sstevel@tonic-gate }
53537c478bd9Sstevel@tonic-gate
53547c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
53557c478bd9Sstevel@tonic-gate "ohci_set_periodic_pipe_polling: Max periodic requests = %d",
53567c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt);
53577c478bd9Sstevel@tonic-gate }
53587c478bd9Sstevel@tonic-gate
53597c478bd9Sstevel@tonic-gate /*
53607c478bd9Sstevel@tonic-gate * ohci_allocate_intr_resources:
53617c478bd9Sstevel@tonic-gate *
53627c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates
53637c478bd9Sstevel@tonic-gate * all the necessary resources.
53647c478bd9Sstevel@tonic-gate *
53657c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW.
53667c478bd9Sstevel@tonic-gate */
53677c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *
ohci_allocate_intr_resources(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t flags)53687c478bd9Sstevel@tonic-gate ohci_allocate_intr_resources(
53697c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
53707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
53717c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp,
53727c478bd9Sstevel@tonic-gate usb_flags_t flags)
53737c478bd9Sstevel@tonic-gate {
53747c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
53757c478bd9Sstevel@tonic-gate int pipe_dir;
53767c478bd9Sstevel@tonic-gate size_t td_count = 1;
53777c478bd9Sstevel@tonic-gate size_t tw_length;
53787c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
53797c478bd9Sstevel@tonic-gate
53807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
53817c478bd9Sstevel@tonic-gate "ohci_allocate_intr_resources:");
53827c478bd9Sstevel@tonic-gate
53837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
53847c478bd9Sstevel@tonic-gate
53857c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
53867c478bd9Sstevel@tonic-gate
53877c478bd9Sstevel@tonic-gate /* Get the length of interrupt transfer & alloc data */
53887c478bd9Sstevel@tonic-gate if (intr_reqp) {
53897c478bd9Sstevel@tonic-gate tw_length = intr_reqp->intr_len;
53907c478bd9Sstevel@tonic-gate } else {
53917c478bd9Sstevel@tonic-gate ASSERT(pipe_dir == USB_EP_DIR_IN);
53927c478bd9Sstevel@tonic-gate tw_length = (pp->pp_client_periodic_in_reqp) ?
53937c478bd9Sstevel@tonic-gate (((usb_intr_req_t *)pp->
53947c478bd9Sstevel@tonic-gate pp_client_periodic_in_reqp)->intr_len) :
53957c478bd9Sstevel@tonic-gate ph->p_ep.wMaxPacketSize;
53967c478bd9Sstevel@tonic-gate }
53977c478bd9Sstevel@tonic-gate
53987c478bd9Sstevel@tonic-gate /* Check the size of interrupt request */
53997c478bd9Sstevel@tonic-gate if (tw_length > OHCI_MAX_TD_XFER_SIZE) {
54007c478bd9Sstevel@tonic-gate
54017c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
54027c478bd9Sstevel@tonic-gate "ohci_allocate_intr_resources: Intr request size 0x%lx is "
54037c478bd9Sstevel@tonic-gate "more than 0x%x", tw_length, OHCI_MAX_TD_XFER_SIZE);
54047c478bd9Sstevel@tonic-gate
54057c478bd9Sstevel@tonic-gate return (NULL);
54067c478bd9Sstevel@tonic-gate }
54077c478bd9Sstevel@tonic-gate
54087c478bd9Sstevel@tonic-gate if ((tw = ohci_allocate_tw_resources(ohcip, pp, tw_length,
54097c478bd9Sstevel@tonic-gate flags, td_count)) == NULL) {
54107c478bd9Sstevel@tonic-gate
54117c478bd9Sstevel@tonic-gate return (NULL);
54127c478bd9Sstevel@tonic-gate }
54137c478bd9Sstevel@tonic-gate
54147c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
54157c478bd9Sstevel@tonic-gate if (ohci_allocate_periodic_in_resource(ohcip, pp, tw, flags) !=
54167c478bd9Sstevel@tonic-gate USB_SUCCESS) {
54177c478bd9Sstevel@tonic-gate
54187c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
54197c478bd9Sstevel@tonic-gate return (NULL);
54207c478bd9Sstevel@tonic-gate }
54217c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN;
54227c478bd9Sstevel@tonic-gate } else {
5423688b07c5Sgc161489 if (tw_length) {
54247c478bd9Sstevel@tonic-gate ASSERT(intr_reqp->intr_data != NULL);
54257c478bd9Sstevel@tonic-gate
54267c478bd9Sstevel@tonic-gate /* Copy the data into the message */
54277c478bd9Sstevel@tonic-gate ddi_rep_put8(tw->tw_accesshandle,
54287c478bd9Sstevel@tonic-gate intr_reqp->intr_data->b_rptr, (uint8_t *)tw->tw_buf,
54297c478bd9Sstevel@tonic-gate intr_reqp->intr_len, DDI_DEV_AUTOINCR);
5430688b07c5Sgc161489 }
54317c478bd9Sstevel@tonic-gate
54327c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)intr_reqp;
54337c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT;
54347c478bd9Sstevel@tonic-gate }
54357c478bd9Sstevel@tonic-gate
54367c478bd9Sstevel@tonic-gate if (intr_reqp) {
54377c478bd9Sstevel@tonic-gate tw->tw_timeout = intr_reqp->intr_timeout;
54387c478bd9Sstevel@tonic-gate }
54397c478bd9Sstevel@tonic-gate
54407c478bd9Sstevel@tonic-gate /*
54417c478bd9Sstevel@tonic-gate * Initialize the callback and any callback
54427c478bd9Sstevel@tonic-gate * data required when the td completes.
54437c478bd9Sstevel@tonic-gate */
54447c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_intr_td;
54457c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL;
54467c478bd9Sstevel@tonic-gate
54477c478bd9Sstevel@tonic-gate return (tw);
54487c478bd9Sstevel@tonic-gate }
54497c478bd9Sstevel@tonic-gate
54507c478bd9Sstevel@tonic-gate /*
54517c478bd9Sstevel@tonic-gate * ohci_insert_intr_req:
54527c478bd9Sstevel@tonic-gate *
54537c478bd9Sstevel@tonic-gate * Insert an Interrupt request into the Host Controller's periodic list.
54547c478bd9Sstevel@tonic-gate */
54557c478bd9Sstevel@tonic-gate /* ARGSUSED */
54567c478bd9Sstevel@tonic-gate static void
ohci_insert_intr_req(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,usb_flags_t flags)54577c478bd9Sstevel@tonic-gate ohci_insert_intr_req(
54587c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
54597c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
54607c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
54617c478bd9Sstevel@tonic-gate usb_flags_t flags)
54627c478bd9Sstevel@tonic-gate {
54637c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp = NULL;
54647c478bd9Sstevel@tonic-gate uint_t ctrl = 0;
54657c478bd9Sstevel@tonic-gate
54667c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
54677c478bd9Sstevel@tonic-gate
54687c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp != NULL);
54697c478bd9Sstevel@tonic-gate
54707c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */
54717c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
54727c478bd9Sstevel@tonic-gate
54737c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction | HC_TD_DT_0 | HC_TD_1I;
54747c478bd9Sstevel@tonic-gate
54757c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes & USB_ATTRS_SHORT_XFER_OK) {
54767c478bd9Sstevel@tonic-gate ctrl |= HC_TD_R;
54777c478bd9Sstevel@tonic-gate }
54787c478bd9Sstevel@tonic-gate
54797c478bd9Sstevel@tonic-gate /* Insert another interrupt TD */
548002acac7eSsl147100 (void) ohci_insert_hc_td(ohcip, ctrl, 0, tw->tw_length, 0, pp, tw);
54817c478bd9Sstevel@tonic-gate
54827c478bd9Sstevel@tonic-gate /* Start the timer for this Interrupt transfer */
54837c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(ohcip, pp, tw);
54847c478bd9Sstevel@tonic-gate }
54857c478bd9Sstevel@tonic-gate
54867c478bd9Sstevel@tonic-gate
54877c478bd9Sstevel@tonic-gate /*
54887c478bd9Sstevel@tonic-gate * ohci_stop_periodic_pipe_polling:
54897c478bd9Sstevel@tonic-gate */
54907c478bd9Sstevel@tonic-gate /* ARGSUSED */
54917c478bd9Sstevel@tonic-gate static int
ohci_stop_periodic_pipe_polling(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_flags_t flags)54927c478bd9Sstevel@tonic-gate ohci_stop_periodic_pipe_polling(
54937c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
54947c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
54957c478bd9Sstevel@tonic-gate usb_flags_t flags)
54967c478bd9Sstevel@tonic-gate {
54977c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
54987c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
54997c478bd9Sstevel@tonic-gate
55007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
55017c478bd9Sstevel@tonic-gate "ohci_stop_periodic_pipe_polling: Flags = 0x%x", flags);
55027c478bd9Sstevel@tonic-gate
55037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
55047c478bd9Sstevel@tonic-gate
55057c478bd9Sstevel@tonic-gate /*
55067c478bd9Sstevel@tonic-gate * Check and handle stop polling on root hub interrupt pipe.
55077c478bd9Sstevel@tonic-gate */
55087c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) &&
55097c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
55107c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) {
55117c478bd9Sstevel@tonic-gate
55127c478bd9Sstevel@tonic-gate ohci_handle_root_hub_pipe_stop_intr_polling(
55137c478bd9Sstevel@tonic-gate ph, flags);
55147c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
55157c478bd9Sstevel@tonic-gate }
55167c478bd9Sstevel@tonic-gate
55177c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) {
55187c478bd9Sstevel@tonic-gate
55197c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
55207c478bd9Sstevel@tonic-gate "ohci_stop_periodic_pipe_polling: Polling already stopped");
55217c478bd9Sstevel@tonic-gate
55227c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
55237c478bd9Sstevel@tonic-gate }
55247c478bd9Sstevel@tonic-gate
55257c478bd9Sstevel@tonic-gate /* Set pipe state to pipe stop polling */
55267c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING;
55277c478bd9Sstevel@tonic-gate
55287c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(ohcip, ph);
55297c478bd9Sstevel@tonic-gate
55307c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
55317c478bd9Sstevel@tonic-gate }
55327c478bd9Sstevel@tonic-gate
55337c478bd9Sstevel@tonic-gate /*
55347c478bd9Sstevel@tonic-gate * ohci_allocate_isoc_resources:
55357c478bd9Sstevel@tonic-gate *
55367c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates
55377c478bd9Sstevel@tonic-gate * all the necessary resources.
55387c478bd9Sstevel@tonic-gate *
55397c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW.
55407c478bd9Sstevel@tonic-gate */
55417c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *
ohci_allocate_isoc_resources(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t flags)55427c478bd9Sstevel@tonic-gate ohci_allocate_isoc_resources(
55437c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
55447c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
55457c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp,
55467c478bd9Sstevel@tonic-gate usb_flags_t flags)
55477c478bd9Sstevel@tonic-gate {
55487c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
55497c478bd9Sstevel@tonic-gate int pipe_dir;
55507c478bd9Sstevel@tonic-gate uint_t max_pkt_size = ph->p_ep.wMaxPacketSize;
55517c478bd9Sstevel@tonic-gate uint_t max_isoc_xfer_size;
555202acac7eSsl147100 usb_isoc_pkt_descr_t *isoc_pkt_descr, *start_isoc_pkt_descr;
55537c478bd9Sstevel@tonic-gate ushort_t isoc_pkt_count;
55547c478bd9Sstevel@tonic-gate size_t count, td_count;
55557c478bd9Sstevel@tonic-gate size_t tw_length;
5556b3001defSlg150142 size_t isoc_pkts_length;
55577c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
55587c478bd9Sstevel@tonic-gate
55597c478bd9Sstevel@tonic-gate
55607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
55617c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: flags = ox%x", flags);
55627c478bd9Sstevel@tonic-gate
55637c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
55647c478bd9Sstevel@tonic-gate
55657c478bd9Sstevel@tonic-gate /*
55667c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state.
55677c478bd9Sstevel@tonic-gate */
55687c478bd9Sstevel@tonic-gate if (pp->pp_state == OHCI_PIPE_STATE_ERROR) {
55697c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
55707c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources:"
55717c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue");
55727c478bd9Sstevel@tonic-gate
55737c478bd9Sstevel@tonic-gate return (NULL);
55747c478bd9Sstevel@tonic-gate }
55757c478bd9Sstevel@tonic-gate
55767c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
55777c478bd9Sstevel@tonic-gate
55787c478bd9Sstevel@tonic-gate /* Calculate the maximum isochronous transfer size */
55797c478bd9Sstevel@tonic-gate max_isoc_xfer_size = OHCI_MAX_ISOC_PKTS_PER_XFER * max_pkt_size;
55807c478bd9Sstevel@tonic-gate
55817c478bd9Sstevel@tonic-gate if (isoc_reqp) {
55827c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
55837c478bd9Sstevel@tonic-gate isoc_pkt_count = isoc_reqp->isoc_pkts_count;
5584b3001defSlg150142 isoc_pkts_length = isoc_reqp->isoc_pkts_length;
55857c478bd9Sstevel@tonic-gate } else {
55867c478bd9Sstevel@tonic-gate isoc_pkt_descr = ((usb_isoc_req_t *)
55877c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
55887c478bd9Sstevel@tonic-gate
55897c478bd9Sstevel@tonic-gate isoc_pkt_count = ((usb_isoc_req_t *)
55907c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
5591b3001defSlg150142
5592b3001defSlg150142 isoc_pkts_length = ((usb_isoc_req_t *)
5593b3001defSlg150142 pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
55947c478bd9Sstevel@tonic-gate }
55957c478bd9Sstevel@tonic-gate
559602acac7eSsl147100 start_isoc_pkt_descr = isoc_pkt_descr;
559702acac7eSsl147100
55987c478bd9Sstevel@tonic-gate /*
55997c478bd9Sstevel@tonic-gate * For isochronous IN pipe, get value of number of isochronous
56007c478bd9Sstevel@tonic-gate * packets per usb isochronous request
56017c478bd9Sstevel@tonic-gate */
56027c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
56037c478bd9Sstevel@tonic-gate for (count = 0, tw_length = 0;
56047c478bd9Sstevel@tonic-gate count < isoc_pkt_count; count++) {
56057c478bd9Sstevel@tonic-gate tw_length += isoc_pkt_descr->isoc_pkt_length;
56067c478bd9Sstevel@tonic-gate isoc_pkt_descr++;
56077c478bd9Sstevel@tonic-gate }
5608b3001defSlg150142
5609b3001defSlg150142 if ((isoc_pkts_length) && (isoc_pkts_length != tw_length)) {
5610b3001defSlg150142
5611b3001defSlg150142 USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
5612b3001defSlg150142 "ohci_allocate_isoc_resources: "
5613112116d8Sfb209375 "isoc_pkts_length 0x%lx is not equal to the sum of "
5614112116d8Sfb209375 "all pkt lengths 0x%lx in an isoc request",
5615b3001defSlg150142 isoc_pkts_length, tw_length);
5616b3001defSlg150142
5617b3001defSlg150142 return (NULL);
5618b3001defSlg150142 }
5619b3001defSlg150142
56207c478bd9Sstevel@tonic-gate } else {
56217c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp != NULL);
5622d29f5a71Szhigang lu - Sun Microsystems - Beijing China tw_length = MBLKL(isoc_reqp->isoc_data);
56237c478bd9Sstevel@tonic-gate }
56247c478bd9Sstevel@tonic-gate
56257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
56267c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: length = 0x%lx", tw_length);
56277c478bd9Sstevel@tonic-gate
56287c478bd9Sstevel@tonic-gate /* Check the size of isochronous request */
56297c478bd9Sstevel@tonic-gate if (tw_length > max_isoc_xfer_size) {
56307c478bd9Sstevel@tonic-gate
56317c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
56327c478bd9Sstevel@tonic-gate "ohci_allocate_isoc_resources: Maximum isoc request"
56337c478bd9Sstevel@tonic-gate "size 0x%x Given isoc request size 0x%lx",
56347c478bd9Sstevel@tonic-gate max_isoc_xfer_size, tw_length);
56357c478bd9Sstevel@tonic-gate
56367c478bd9Sstevel@tonic-gate return (NULL);
56377c478bd9Sstevel@tonic-gate }
56387c478bd9Sstevel@tonic-gate
56397c478bd9Sstevel@tonic-gate /*
56407c478bd9Sstevel@tonic-gate * Each isochronous TD can hold data upto eight isochronous
56417c478bd9Sstevel@tonic-gate * data packets. Calculate the number of isochronous TDs needs
56427c478bd9Sstevel@tonic-gate * to be insert to complete current isochronous request.
56437c478bd9Sstevel@tonic-gate */
56447c478bd9Sstevel@tonic-gate td_count = isoc_pkt_count / OHCI_ISOC_PKTS_PER_TD;
56457c478bd9Sstevel@tonic-gate
56467c478bd9Sstevel@tonic-gate if (isoc_pkt_count % OHCI_ISOC_PKTS_PER_TD) {
56477c478bd9Sstevel@tonic-gate td_count++;
56487c478bd9Sstevel@tonic-gate }
56497c478bd9Sstevel@tonic-gate
565002acac7eSsl147100 tw = ohci_create_isoc_transfer_wrapper(ohcip, pp, tw_length,
565102acac7eSsl147100 start_isoc_pkt_descr, isoc_pkt_count, td_count, flags);
565202acac7eSsl147100
565302acac7eSsl147100 if (tw == NULL) {
565402acac7eSsl147100 USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
565502acac7eSsl147100 "ohci_create_isoc_transfer_wrapper: "
565602acac7eSsl147100 "Unable to allocate TW");
565702acac7eSsl147100
565802acac7eSsl147100 return (NULL);
565902acac7eSsl147100 }
566002acac7eSsl147100
566102acac7eSsl147100 if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) ==
566202acac7eSsl147100 USB_SUCCESS) {
5663d29f5a71Szhigang lu - Sun Microsystems - Beijing China tw->tw_num_tds = (uint_t)td_count;
566402acac7eSsl147100 } else {
566502acac7eSsl147100 ohci_deallocate_tw_resources(ohcip, pp, tw);
566602acac7eSsl147100
56677c478bd9Sstevel@tonic-gate return (NULL);
56687c478bd9Sstevel@tonic-gate }
56697c478bd9Sstevel@tonic-gate
56707c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
56717c478bd9Sstevel@tonic-gate if (ohci_allocate_periodic_in_resource(ohcip, pp, tw, flags) !=
56727c478bd9Sstevel@tonic-gate USB_SUCCESS) {
56737c478bd9Sstevel@tonic-gate
56747c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
56757c478bd9Sstevel@tonic-gate return (NULL);
56767c478bd9Sstevel@tonic-gate }
56777c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_IN;
56787c478bd9Sstevel@tonic-gate } else {
56797c478bd9Sstevel@tonic-gate if (tw->tw_length) {
568002acac7eSsl147100 uchar_t *p;
568102acac7eSsl147100 int i;
568202acac7eSsl147100
56837c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp->isoc_data != NULL);
568402acac7eSsl147100 p = isoc_reqp->isoc_data->b_rptr;
56857c478bd9Sstevel@tonic-gate
56867c478bd9Sstevel@tonic-gate /* Copy the data into the message */
568702acac7eSsl147100 for (i = 0; i < td_count; i++) {
568802acac7eSsl147100 ddi_rep_put8(
568902acac7eSsl147100 tw->tw_isoc_bufs[i].mem_handle, p,
569002acac7eSsl147100 (uint8_t *)tw->tw_isoc_bufs[i].buf_addr,
569102acac7eSsl147100 tw->tw_isoc_bufs[i].length,
56927c478bd9Sstevel@tonic-gate DDI_DEV_AUTOINCR);
569302acac7eSsl147100 p += tw->tw_isoc_bufs[i].length;
569402acac7eSsl147100 }
56957c478bd9Sstevel@tonic-gate }
56967c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)isoc_reqp;
56977c478bd9Sstevel@tonic-gate tw->tw_direction = HC_TD_OUT;
56987c478bd9Sstevel@tonic-gate }
56997c478bd9Sstevel@tonic-gate
57007c478bd9Sstevel@tonic-gate /*
57017c478bd9Sstevel@tonic-gate * Initialize the callback and any callback
57027c478bd9Sstevel@tonic-gate * data required when the td completes.
57037c478bd9Sstevel@tonic-gate */
57047c478bd9Sstevel@tonic-gate tw->tw_handle_td = ohci_handle_isoc_td;
57057c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL;
57067c478bd9Sstevel@tonic-gate
57077c478bd9Sstevel@tonic-gate return (tw);
57087c478bd9Sstevel@tonic-gate }
57097c478bd9Sstevel@tonic-gate
57107c478bd9Sstevel@tonic-gate /*
57117c478bd9Sstevel@tonic-gate * ohci_insert_isoc_req:
57127c478bd9Sstevel@tonic-gate *
57137c478bd9Sstevel@tonic-gate * Insert an isochronous request into the Host Controller's
57147c478bd9Sstevel@tonic-gate * isochronous list. If there is an error is will appropriately
57157c478bd9Sstevel@tonic-gate * deallocate the unused resources.
57167c478bd9Sstevel@tonic-gate */
57177c478bd9Sstevel@tonic-gate static int
ohci_insert_isoc_req(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,uint_t flags)57187c478bd9Sstevel@tonic-gate ohci_insert_isoc_req(
57197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
57207c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
57217c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
57227c478bd9Sstevel@tonic-gate uint_t flags)
57237c478bd9Sstevel@tonic-gate {
57247c478bd9Sstevel@tonic-gate size_t curr_isoc_xfer_offset, curr_isoc_xfer_len;
57257c478bd9Sstevel@tonic-gate uint_t isoc_pkts, residue, count;
57267c478bd9Sstevel@tonic-gate uint_t i, ctrl, frame_count;
57277c478bd9Sstevel@tonic-gate uint_t error = USB_SUCCESS;
57287c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp;
57297c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *curr_isoc_pkt_descr;
57307c478bd9Sstevel@tonic-gate
57317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
57327c478bd9Sstevel@tonic-gate "ohci_insert_isoc_req: flags = 0x%x", flags);
57337c478bd9Sstevel@tonic-gate
57347c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
57357c478bd9Sstevel@tonic-gate
57367c478bd9Sstevel@tonic-gate /*
57377c478bd9Sstevel@tonic-gate * Get the current isochronous request and packet
57387c478bd9Sstevel@tonic-gate * descriptor pointers.
57397c478bd9Sstevel@tonic-gate */
57407c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
57417c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = curr_isoc_reqp->isoc_pkt_descr;
57427c478bd9Sstevel@tonic-gate
57437c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL);
57447c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp->isoc_pkt_descr != NULL);
57457c478bd9Sstevel@tonic-gate
57467c478bd9Sstevel@tonic-gate /*
57477c478bd9Sstevel@tonic-gate * Save address of first usb isochronous packet descriptor.
57487c478bd9Sstevel@tonic-gate */
57497c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr;
57507c478bd9Sstevel@tonic-gate
57517c478bd9Sstevel@tonic-gate /* Insert all the isochronous TDs */
57527c478bd9Sstevel@tonic-gate for (count = 0, curr_isoc_xfer_offset = 0,
57537c478bd9Sstevel@tonic-gate isoc_pkts = 0; count < tw->tw_num_tds; count++) {
57547c478bd9Sstevel@tonic-gate
57557c478bd9Sstevel@tonic-gate residue = curr_isoc_reqp->isoc_pkts_count - isoc_pkts;
57567c478bd9Sstevel@tonic-gate
57577c478bd9Sstevel@tonic-gate /* Check for inserting residue data */
57587c478bd9Sstevel@tonic-gate if ((count == (tw->tw_num_tds - 1)) &&
57597c478bd9Sstevel@tonic-gate (residue < OHCI_ISOC_PKTS_PER_TD)) {
57607c478bd9Sstevel@tonic-gate frame_count = residue;
57617c478bd9Sstevel@tonic-gate } else {
57627c478bd9Sstevel@tonic-gate frame_count = OHCI_ISOC_PKTS_PER_TD;
57637c478bd9Sstevel@tonic-gate }
57647c478bd9Sstevel@tonic-gate
57657c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = tw->tw_curr_isoc_pktp;
57667c478bd9Sstevel@tonic-gate
57677c478bd9Sstevel@tonic-gate /*
57687c478bd9Sstevel@tonic-gate * Calculate length of isochronous transfer
57697c478bd9Sstevel@tonic-gate * for the current TD.
57707c478bd9Sstevel@tonic-gate */
57717c478bd9Sstevel@tonic-gate for (i = 0, curr_isoc_xfer_len = 0;
57727c478bd9Sstevel@tonic-gate i < frame_count; i++, curr_isoc_pkt_descr++) {
57737c478bd9Sstevel@tonic-gate curr_isoc_xfer_len +=
57747c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr->isoc_pkt_length;
57757c478bd9Sstevel@tonic-gate }
57767c478bd9Sstevel@tonic-gate
57777c478bd9Sstevel@tonic-gate /*
57787c478bd9Sstevel@tonic-gate * Programm td control field by checking whether this
57797c478bd9Sstevel@tonic-gate * is last td.
57807c478bd9Sstevel@tonic-gate */
57817c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_tds - 1)) {
57827c478bd9Sstevel@tonic-gate ctrl = ((((frame_count - 1) << HC_ITD_FC_SHIFT) &
57837c478bd9Sstevel@tonic-gate HC_ITD_FC) | HC_TD_DT_0 | HC_TD_0I);
57847c478bd9Sstevel@tonic-gate } else {
57857c478bd9Sstevel@tonic-gate ctrl = ((((frame_count - 1) << HC_ITD_FC_SHIFT) &
57867c478bd9Sstevel@tonic-gate HC_ITD_FC) | HC_TD_DT_0 | HC_TD_6I);
57877c478bd9Sstevel@tonic-gate }
57887c478bd9Sstevel@tonic-gate
57897c478bd9Sstevel@tonic-gate /* Insert the TD into the endpoint */
579002acac7eSsl147100 if ((error = ohci_insert_hc_td(ohcip, ctrl, count,
57917c478bd9Sstevel@tonic-gate curr_isoc_xfer_len, 0, pp, tw)) !=
57927c478bd9Sstevel@tonic-gate USB_SUCCESS) {
57937c478bd9Sstevel@tonic-gate tw->tw_num_tds = count;
57947c478bd9Sstevel@tonic-gate tw->tw_length = curr_isoc_xfer_offset;
57957c478bd9Sstevel@tonic-gate break;
57967c478bd9Sstevel@tonic-gate }
57977c478bd9Sstevel@tonic-gate
57987c478bd9Sstevel@tonic-gate isoc_pkts += frame_count;
57997c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp += frame_count;
58007c478bd9Sstevel@tonic-gate curr_isoc_xfer_offset += curr_isoc_xfer_len;
58017c478bd9Sstevel@tonic-gate }
58027c478bd9Sstevel@tonic-gate
58037c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
58047c478bd9Sstevel@tonic-gate /* Free periodic in resources */
58057c478bd9Sstevel@tonic-gate if (tw->tw_direction == USB_EP_DIR_IN) {
58067c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw);
58077c478bd9Sstevel@tonic-gate }
58087c478bd9Sstevel@tonic-gate
58097c478bd9Sstevel@tonic-gate /* Free all resources if IN or if count == 0(for both IN/OUT) */
58107c478bd9Sstevel@tonic-gate if (tw->tw_direction == USB_EP_DIR_IN || count == 0) {
58117c478bd9Sstevel@tonic-gate
58127c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
58137c478bd9Sstevel@tonic-gate
58147c478bd9Sstevel@tonic-gate if (pp->pp_cur_periodic_req_cnt) {
58157c478bd9Sstevel@tonic-gate /*
58167c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and
58177c478bd9Sstevel@tonic-gate * error to no resource. Don't insert
58187c478bd9Sstevel@tonic-gate * any more isochronous polling requests.
58197c478bd9Sstevel@tonic-gate */
58207c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING;
58217c478bd9Sstevel@tonic-gate pp->pp_error = error;
58227c478bd9Sstevel@tonic-gate } else {
58237c478bd9Sstevel@tonic-gate /* Set periodic in pipe state to idle */
58247c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE;
58257c478bd9Sstevel@tonic-gate }
58267c478bd9Sstevel@tonic-gate }
58277c478bd9Sstevel@tonic-gate } else {
58287c478bd9Sstevel@tonic-gate
58297c478bd9Sstevel@tonic-gate /*
58307c478bd9Sstevel@tonic-gate * Reset back to the address of first usb isochronous
58317c478bd9Sstevel@tonic-gate * packet descriptor.
58327c478bd9Sstevel@tonic-gate */
58337c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr;
58347c478bd9Sstevel@tonic-gate
58357c478bd9Sstevel@tonic-gate /* Reset the CONTINUE flag */
58367c478bd9Sstevel@tonic-gate pp->pp_flag &= ~OHCI_ISOC_XFER_CONTINUE;
58377c478bd9Sstevel@tonic-gate }
58387c478bd9Sstevel@tonic-gate
58397c478bd9Sstevel@tonic-gate return (error);
58407c478bd9Sstevel@tonic-gate }
58417c478bd9Sstevel@tonic-gate
58427c478bd9Sstevel@tonic-gate
58437c478bd9Sstevel@tonic-gate /*
58447c478bd9Sstevel@tonic-gate * ohci_insert_hc_td:
58457c478bd9Sstevel@tonic-gate *
58467c478bd9Sstevel@tonic-gate * Insert a Transfer Descriptor (TD) on an Endpoint Descriptor (ED).
58477c478bd9Sstevel@tonic-gate * Always returns USB_SUCCESS, except for ISOCH.
58487c478bd9Sstevel@tonic-gate */
58497c478bd9Sstevel@tonic-gate static int
ohci_insert_hc_td(ohci_state_t * ohcip,uint_t hctd_ctrl,uint32_t hctd_dma_offs,size_t hctd_length,uint32_t hctd_ctrl_phase,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)58507c478bd9Sstevel@tonic-gate ohci_insert_hc_td(
58517c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
58527c478bd9Sstevel@tonic-gate uint_t hctd_ctrl,
585302acac7eSsl147100 uint32_t hctd_dma_offs,
58547c478bd9Sstevel@tonic-gate size_t hctd_length,
58557c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase,
58567c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
58577c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
58587c478bd9Sstevel@tonic-gate {
58597c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy;
58607c478bd9Sstevel@tonic-gate ohci_td_t *cpu_current_dummy;
58617c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
58627c478bd9Sstevel@tonic-gate int error;
58637c478bd9Sstevel@tonic-gate
58647c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
58657c478bd9Sstevel@tonic-gate
58667c478bd9Sstevel@tonic-gate /* Retrieve preallocated td from the TW */
58677c478bd9Sstevel@tonic-gate new_dummy = tw->tw_hctd_free_list;
58687c478bd9Sstevel@tonic-gate
58697c478bd9Sstevel@tonic-gate ASSERT(new_dummy != NULL);
58707c478bd9Sstevel@tonic-gate
58717c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = ohci_td_iommu_to_cpu(ohcip,
58727c478bd9Sstevel@tonic-gate Get_TD(new_dummy->hctd_tw_next_td));
58737c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_tw_next_td, NULL);
58747c478bd9Sstevel@tonic-gate
58757c478bd9Sstevel@tonic-gate /* Fill in the current dummy */
58767c478bd9Sstevel@tonic-gate cpu_current_dummy = (ohci_td_t *)
58777c478bd9Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip, Get_ED(ept->hced_tailp)));
58787c478bd9Sstevel@tonic-gate
58797c478bd9Sstevel@tonic-gate /*
58807c478bd9Sstevel@tonic-gate * Fill in the current dummy td and
58817c478bd9Sstevel@tonic-gate * add the new dummy to the end.
58827c478bd9Sstevel@tonic-gate */
58837c478bd9Sstevel@tonic-gate ohci_fill_in_td(ohcip, cpu_current_dummy, new_dummy,
588402acac7eSsl147100 hctd_ctrl, hctd_dma_offs, hctd_length, hctd_ctrl_phase, pp, tw);
58857c478bd9Sstevel@tonic-gate
58867c478bd9Sstevel@tonic-gate /*
58877c478bd9Sstevel@tonic-gate * If this is an isochronous TD, first write proper
58887c478bd9Sstevel@tonic-gate * starting usb frame number in which this TD must
58897c478bd9Sstevel@tonic-gate * can be processed. After writing the frame number
58907c478bd9Sstevel@tonic-gate * insert this TD into the ED's list.
58917c478bd9Sstevel@tonic-gate */
58927c478bd9Sstevel@tonic-gate if ((pp->pp_pipe_handle->p_ep.bmAttributes &
58937c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
58947c478bd9Sstevel@tonic-gate
58957c478bd9Sstevel@tonic-gate error = ohci_insert_td_with_frame_number(
58967c478bd9Sstevel@tonic-gate ohcip, pp, tw, cpu_current_dummy, new_dummy);
58977c478bd9Sstevel@tonic-gate
58987c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
58997c478bd9Sstevel@tonic-gate /* Reset the current dummy back to a dummy */
59007c478bd9Sstevel@tonic-gate bzero((char *)cpu_current_dummy, sizeof (ohci_td_t));
59017c478bd9Sstevel@tonic-gate Set_TD(cpu_current_dummy->hctd_state, HC_TD_DUMMY);
59027c478bd9Sstevel@tonic-gate
59037c478bd9Sstevel@tonic-gate /* return the new dummy back to the free list */
59047c478bd9Sstevel@tonic-gate bzero((char *)new_dummy, sizeof (ohci_td_t));
59057c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_state, HC_TD_DUMMY);
59067c478bd9Sstevel@tonic-gate if (tw->tw_hctd_free_list != NULL) {
59077c478bd9Sstevel@tonic-gate Set_TD(new_dummy->hctd_tw_next_td,
59087c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip,
59097c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list));
59107c478bd9Sstevel@tonic-gate }
59117c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = new_dummy;
59127c478bd9Sstevel@tonic-gate
59137c478bd9Sstevel@tonic-gate return (error);
59147c478bd9Sstevel@tonic-gate }
59157c478bd9Sstevel@tonic-gate } else {
59167c478bd9Sstevel@tonic-gate /*
59177c478bd9Sstevel@tonic-gate * For control, bulk and interrupt TD, just
59187c478bd9Sstevel@tonic-gate * add the new dummy to the ED's list. When
59197c478bd9Sstevel@tonic-gate * this occurs, the Host Controller ill see
59207c478bd9Sstevel@tonic-gate * the newly filled in dummy TD.
59217c478bd9Sstevel@tonic-gate */
59227c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp,
59237c478bd9Sstevel@tonic-gate (ohci_td_cpu_to_iommu(ohcip, new_dummy)));
59247c478bd9Sstevel@tonic-gate }
59257c478bd9Sstevel@tonic-gate
59267c478bd9Sstevel@tonic-gate /* Insert this td onto the tw */
59277c478bd9Sstevel@tonic-gate ohci_insert_td_on_tw(ohcip, tw, cpu_current_dummy);
59287c478bd9Sstevel@tonic-gate
59297c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
59307c478bd9Sstevel@tonic-gate }
59317c478bd9Sstevel@tonic-gate
59327c478bd9Sstevel@tonic-gate
59337c478bd9Sstevel@tonic-gate /*
59347c478bd9Sstevel@tonic-gate * ohci_allocate_td_from_pool:
59357c478bd9Sstevel@tonic-gate *
59367c478bd9Sstevel@tonic-gate * Allocate a Transfer Descriptor (TD) from the TD buffer pool.
59377c478bd9Sstevel@tonic-gate */
59387c478bd9Sstevel@tonic-gate static ohci_td_t *
ohci_allocate_td_from_pool(ohci_state_t * ohcip)59397c478bd9Sstevel@tonic-gate ohci_allocate_td_from_pool(ohci_state_t *ohcip)
59407c478bd9Sstevel@tonic-gate {
59417c478bd9Sstevel@tonic-gate int i, state;
59427c478bd9Sstevel@tonic-gate ohci_td_t *td;
59437c478bd9Sstevel@tonic-gate
59447c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
59457c478bd9Sstevel@tonic-gate
59467c478bd9Sstevel@tonic-gate /*
59477c478bd9Sstevel@tonic-gate * Search for a blank Transfer Descriptor (TD)
59487c478bd9Sstevel@tonic-gate * in the TD buffer pool.
59497c478bd9Sstevel@tonic-gate */
59507c478bd9Sstevel@tonic-gate for (i = 0; i < ohci_td_pool_size; i ++) {
59517c478bd9Sstevel@tonic-gate state = Get_TD(ohcip->ohci_td_pool_addr[i].hctd_state);
59527c478bd9Sstevel@tonic-gate if (state == HC_TD_FREE) {
59537c478bd9Sstevel@tonic-gate break;
59547c478bd9Sstevel@tonic-gate }
59557c478bd9Sstevel@tonic-gate }
59567c478bd9Sstevel@tonic-gate
59577c478bd9Sstevel@tonic-gate if (i >= ohci_td_pool_size) {
59587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
59597c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: TD exhausted");
59607c478bd9Sstevel@tonic-gate
59617c478bd9Sstevel@tonic-gate return (NULL);
59627c478bd9Sstevel@tonic-gate }
59637c478bd9Sstevel@tonic-gate
59647c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
59657c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: Allocated %d", i);
59667c478bd9Sstevel@tonic-gate
59677c478bd9Sstevel@tonic-gate /* Create a new dummy for the end of the TD list */
59687c478bd9Sstevel@tonic-gate td = &ohcip->ohci_td_pool_addr[i];
59697c478bd9Sstevel@tonic-gate
59707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
59717c478bd9Sstevel@tonic-gate "ohci_allocate_td_from_pool: td 0x%p", (void *)td);
59727c478bd9Sstevel@tonic-gate
59737c478bd9Sstevel@tonic-gate /* Mark the newly allocated TD as a dummy */
59747c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_DUMMY);
59757c478bd9Sstevel@tonic-gate
59767c478bd9Sstevel@tonic-gate return (td);
59777c478bd9Sstevel@tonic-gate }
59787c478bd9Sstevel@tonic-gate
59797c478bd9Sstevel@tonic-gate /*
59807c478bd9Sstevel@tonic-gate * ohci_fill_in_td:
59817c478bd9Sstevel@tonic-gate *
59827c478bd9Sstevel@tonic-gate * Fill in the fields of a Transfer Descriptor (TD).
598302acac7eSsl147100 *
598402acac7eSsl147100 * hctd_dma_offs - different meanings for non-isoc and isoc TDs:
598502acac7eSsl147100 * starting offset into the TW buffer for a non-isoc TD
598602acac7eSsl147100 * and the index into the isoc TD list for an isoc TD.
598702acac7eSsl147100 * For non-isoc TDs, the starting offset should be 4k
598802acac7eSsl147100 * aligned and the TDs in one transfer must be filled in
598902acac7eSsl147100 * increasing order.
59907c478bd9Sstevel@tonic-gate */
59917c478bd9Sstevel@tonic-gate static void
ohci_fill_in_td(ohci_state_t * ohcip,ohci_td_t * td,ohci_td_t * new_dummy,uint_t hctd_ctrl,uint32_t hctd_dma_offs,size_t hctd_length,uint32_t hctd_ctrl_phase,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)59927c478bd9Sstevel@tonic-gate ohci_fill_in_td(
59937c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
59947c478bd9Sstevel@tonic-gate ohci_td_t *td,
59957c478bd9Sstevel@tonic-gate ohci_td_t *new_dummy,
59967c478bd9Sstevel@tonic-gate uint_t hctd_ctrl,
599702acac7eSsl147100 uint32_t hctd_dma_offs,
59987c478bd9Sstevel@tonic-gate size_t hctd_length,
59997c478bd9Sstevel@tonic-gate uint32_t hctd_ctrl_phase,
60007c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
60017c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
60027c478bd9Sstevel@tonic-gate {
600302acac7eSsl147100 USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
600402acac7eSsl147100 "ohci_fill_in_td: td 0x%p bufoffs 0x%x len 0x%lx",
6005112116d8Sfb209375 (void *)td, hctd_dma_offs, hctd_length);
600602acac7eSsl147100
60077c478bd9Sstevel@tonic-gate /* Assert that the td to be filled in is a dummy */
60087c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) == HC_TD_DUMMY);
60097c478bd9Sstevel@tonic-gate
60107c478bd9Sstevel@tonic-gate /* Change TD's state Active */
60117c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_ACTIVE);
60127c478bd9Sstevel@tonic-gate
601302acac7eSsl147100 /* Update the TD special fields */
60147c478bd9Sstevel@tonic-gate if ((pp->pp_pipe_handle->p_ep.bmAttributes &
60157c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
601602acac7eSsl147100 ohci_init_itd(ohcip, tw, hctd_ctrl, hctd_dma_offs, td);
60177c478bd9Sstevel@tonic-gate } else {
60187c478bd9Sstevel@tonic-gate /* Update the dummy with control information */
60197c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA));
60207c478bd9Sstevel@tonic-gate
602102acac7eSsl147100 ohci_init_td(ohcip, tw, hctd_dma_offs, hctd_length, td);
60227c478bd9Sstevel@tonic-gate }
60237c478bd9Sstevel@tonic-gate
60247c478bd9Sstevel@tonic-gate /* The current dummy now points to the new dummy */
60257c478bd9Sstevel@tonic-gate Set_TD(td->hctd_next_td, (ohci_td_cpu_to_iommu(ohcip, new_dummy)));
60267c478bd9Sstevel@tonic-gate
60277c478bd9Sstevel@tonic-gate /*
60287c478bd9Sstevel@tonic-gate * For Control transfer, hctd_ctrl_phase is a valid field.
60297c478bd9Sstevel@tonic-gate */
60307c478bd9Sstevel@tonic-gate if (hctd_ctrl_phase) {
60317c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl_phase, hctd_ctrl_phase);
60327c478bd9Sstevel@tonic-gate }
60337c478bd9Sstevel@tonic-gate
60347c478bd9Sstevel@tonic-gate /* Print the td */
60357c478bd9Sstevel@tonic-gate ohci_print_td(ohcip, td);
60367c478bd9Sstevel@tonic-gate
60377c478bd9Sstevel@tonic-gate /* Fill in the wrapper portion of the TD */
60387c478bd9Sstevel@tonic-gate
60397c478bd9Sstevel@tonic-gate /* Set the transfer wrapper */
60407c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
6041*3eb8c55cSToomas Soome ASSERT(tw->tw_id != 0);
60427c478bd9Sstevel@tonic-gate
6043*3eb8c55cSToomas Soome Set_TD(td->hctd_trans_wrapper, tw->tw_id);
60447c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL);
60457c478bd9Sstevel@tonic-gate }
60467c478bd9Sstevel@tonic-gate
60477c478bd9Sstevel@tonic-gate
60487c478bd9Sstevel@tonic-gate /*
604902acac7eSsl147100 * ohci_init_td:
605002acac7eSsl147100 *
605102acac7eSsl147100 * Initialize the buffer address portion of non-isoc Transfer
605202acac7eSsl147100 * Descriptor (TD).
605302acac7eSsl147100 */
605402acac7eSsl147100 void
ohci_init_td(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw,uint32_t hctd_dma_offs,size_t hctd_length,ohci_td_t * td)605502acac7eSsl147100 ohci_init_td(
605602acac7eSsl147100 ohci_state_t *ohcip,
605702acac7eSsl147100 ohci_trans_wrapper_t *tw,
605802acac7eSsl147100 uint32_t hctd_dma_offs,
605902acac7eSsl147100 size_t hctd_length,
606002acac7eSsl147100 ohci_td_t *td)
606102acac7eSsl147100 {
606202acac7eSsl147100 uint32_t page_addr, start_addr = 0, end_addr = 0;
606302acac7eSsl147100 size_t buf_len = hctd_length;
606402acac7eSsl147100 int rem_len, i;
606502acac7eSsl147100
606602acac7eSsl147100 /*
606702acac7eSsl147100 * TDs must be filled in increasing DMA offset order.
606802acac7eSsl147100 * tw_dma_offs is initialized to be 0 at TW creation and
606902acac7eSsl147100 * is only increased in this function.
607002acac7eSsl147100 */
607102acac7eSsl147100 ASSERT(buf_len == 0 || hctd_dma_offs >= tw->tw_dma_offs);
607202acac7eSsl147100
607302acac7eSsl147100 Set_TD(td->hctd_xfer_offs, hctd_dma_offs);
607402acac7eSsl147100 Set_TD(td->hctd_xfer_len, buf_len);
607502acac7eSsl147100
607602acac7eSsl147100 /* Computing the starting buffer address and end buffer address */
607702acac7eSsl147100 for (i = 0; (i < 2) && (buf_len > 0); i++) {
607802acac7eSsl147100 /* Advance to the next DMA cookie if necessary */
607902acac7eSsl147100 if ((tw->tw_dma_offs + tw->tw_cookie.dmac_size) <=
608002acac7eSsl147100 hctd_dma_offs) {
608102acac7eSsl147100 /*
608202acac7eSsl147100 * tw_dma_offs always points to the starting offset
608302acac7eSsl147100 * of a cookie
608402acac7eSsl147100 */
608502acac7eSsl147100 tw->tw_dma_offs += tw->tw_cookie.dmac_size;
608602acac7eSsl147100 ddi_dma_nextcookie(tw->tw_dmahandle, &tw->tw_cookie);
608702acac7eSsl147100 tw->tw_cookie_idx++;
608802acac7eSsl147100 ASSERT(tw->tw_cookie_idx < tw->tw_ncookies);
608902acac7eSsl147100 }
609002acac7eSsl147100
609102acac7eSsl147100 ASSERT((tw->tw_dma_offs + tw->tw_cookie.dmac_size) >
609202acac7eSsl147100 hctd_dma_offs);
609302acac7eSsl147100
609402acac7eSsl147100 /*
609502acac7eSsl147100 * Counting the remained buffer length to be filled in
609602acac7eSsl147100 * the TD for current DMA cookie
609702acac7eSsl147100 */
609802acac7eSsl147100 rem_len = (tw->tw_dma_offs + tw->tw_cookie.dmac_size) -
609902acac7eSsl147100 hctd_dma_offs;
610002acac7eSsl147100
610102acac7eSsl147100 /* Get the beginning address of the buffer */
610202acac7eSsl147100 page_addr = (hctd_dma_offs - tw->tw_dma_offs) +
610302acac7eSsl147100 tw->tw_cookie.dmac_address;
610402acac7eSsl147100 ASSERT((page_addr % OHCI_4K_ALIGN) == 0);
610502acac7eSsl147100
610602acac7eSsl147100 if (i == 0) {
610702acac7eSsl147100 start_addr = page_addr;
610802acac7eSsl147100 }
610902acac7eSsl147100
611002acac7eSsl147100 USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
6111112116d8Sfb209375 "ohci_init_td: page_addr 0x%x dmac_size "
611202acac7eSsl147100 "0x%lx idx %d", page_addr, tw->tw_cookie.dmac_size,
611302acac7eSsl147100 tw->tw_cookie_idx);
611402acac7eSsl147100
611502acac7eSsl147100 if (buf_len <= OHCI_MAX_TD_BUF_SIZE) {
611602acac7eSsl147100 ASSERT(buf_len <= rem_len);
611702acac7eSsl147100 end_addr = page_addr + buf_len - 1;
611802acac7eSsl147100 buf_len = 0;
611902acac7eSsl147100 break;
612002acac7eSsl147100 } else {
612102acac7eSsl147100 ASSERT(rem_len >= OHCI_MAX_TD_BUF_SIZE);
612202acac7eSsl147100 buf_len -= OHCI_MAX_TD_BUF_SIZE;
612302acac7eSsl147100 hctd_dma_offs += OHCI_MAX_TD_BUF_SIZE;
612402acac7eSsl147100 }
612502acac7eSsl147100 }
612602acac7eSsl147100
612702acac7eSsl147100 ASSERT(buf_len == 0);
612802acac7eSsl147100
612902acac7eSsl147100 Set_TD(td->hctd_cbp, start_addr);
613002acac7eSsl147100 Set_TD(td->hctd_buf_end, end_addr);
613102acac7eSsl147100 }
613202acac7eSsl147100
613302acac7eSsl147100
613402acac7eSsl147100 /*
61357c478bd9Sstevel@tonic-gate * ohci_init_itd:
61367c478bd9Sstevel@tonic-gate *
613702acac7eSsl147100 * Initialize the buffer address portion of isoc Transfer Descriptor (TD).
61387c478bd9Sstevel@tonic-gate */
61397c478bd9Sstevel@tonic-gate static void
ohci_init_itd(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw,uint_t hctd_ctrl,uint32_t index,ohci_td_t * td)61407c478bd9Sstevel@tonic-gate ohci_init_itd(
61417c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
61427c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
61437c478bd9Sstevel@tonic-gate uint_t hctd_ctrl,
614402acac7eSsl147100 uint32_t index,
61457c478bd9Sstevel@tonic-gate ohci_td_t *td)
61467c478bd9Sstevel@tonic-gate {
614702acac7eSsl147100 uint32_t start_addr, end_addr, offset, offset_addr;
614802acac7eSsl147100 ohci_isoc_buf_t *bufp;
614902acac7eSsl147100 size_t buf_len;
61507c478bd9Sstevel@tonic-gate uint_t buf, fc, toggle, flag;
61517c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *temp_pkt_descr;
61527c478bd9Sstevel@tonic-gate int i;
61537c478bd9Sstevel@tonic-gate
61547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
61557c478bd9Sstevel@tonic-gate
61567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
61577c478bd9Sstevel@tonic-gate "ohci_init_itd: ctrl = 0x%x", hctd_ctrl);
61587c478bd9Sstevel@tonic-gate
61597c478bd9Sstevel@tonic-gate /*
61607c478bd9Sstevel@tonic-gate * Write control information except starting
61617c478bd9Sstevel@tonic-gate * usb frame number.
61627c478bd9Sstevel@tonic-gate */
61637c478bd9Sstevel@tonic-gate Set_TD(td->hctd_ctrl, (hctd_ctrl | HC_TD_CC_NA));
61647c478bd9Sstevel@tonic-gate
616502acac7eSsl147100 bufp = &tw->tw_isoc_bufs[index];
616602acac7eSsl147100 Set_TD(td->hctd_xfer_offs, index);
616702acac7eSsl147100 Set_TD(td->hctd_xfer_len, bufp->length);
616802acac7eSsl147100
616902acac7eSsl147100 start_addr = bufp->cookie.dmac_address;
617002acac7eSsl147100 ASSERT((start_addr % OHCI_4K_ALIGN) == 0);
617102acac7eSsl147100
617202acac7eSsl147100 buf_len = bufp->length;
617302acac7eSsl147100 if (bufp->ncookies == OHCI_DMA_ATTR_TD_SGLLEN) {
617402acac7eSsl147100 buf_len = bufp->length - bufp->cookie.dmac_size;
617502acac7eSsl147100 ddi_dma_nextcookie(bufp->dma_handle, &bufp->cookie);
617602acac7eSsl147100 }
617702acac7eSsl147100 end_addr = bufp->cookie.dmac_address + buf_len - 1;
617802acac7eSsl147100
61797c478bd9Sstevel@tonic-gate /*
61807c478bd9Sstevel@tonic-gate * For an isochronous transfer, the hctd_cbp contains,
61817c478bd9Sstevel@tonic-gate * the 4k page, and not the actual start of the buffer.
61827c478bd9Sstevel@tonic-gate */
618302acac7eSsl147100 Set_TD(td->hctd_cbp, ((uint32_t)start_addr & HC_ITD_PAGE_MASK));
618402acac7eSsl147100 Set_TD(td->hctd_buf_end, end_addr);
61857c478bd9Sstevel@tonic-gate
61867c478bd9Sstevel@tonic-gate fc = (hctd_ctrl & HC_ITD_FC) >> HC_ITD_FC_SHIFT;
61877c478bd9Sstevel@tonic-gate toggle = 0;
618802acac7eSsl147100 buf = start_addr;
61897c478bd9Sstevel@tonic-gate
61907c478bd9Sstevel@tonic-gate /*
61917c478bd9Sstevel@tonic-gate * Get the address of first isochronous data packet
61927c478bd9Sstevel@tonic-gate * for the current isochronous TD.
61937c478bd9Sstevel@tonic-gate */
61947c478bd9Sstevel@tonic-gate temp_pkt_descr = tw->tw_curr_isoc_pktp;
61957c478bd9Sstevel@tonic-gate
61967c478bd9Sstevel@tonic-gate /* The offsets are actually offsets into the page */
61977c478bd9Sstevel@tonic-gate for (i = 0; i <= fc; i++) {
61987c478bd9Sstevel@tonic-gate offset_addr = (uint32_t)((buf &
6199b3001defSlg150142 HC_ITD_OFFSET_ADDR) | (HC_ITD_OFFSET_CC));
62007c478bd9Sstevel@tonic-gate
620102acac7eSsl147100 flag = ((start_addr &
62027c478bd9Sstevel@tonic-gate HC_ITD_PAGE_MASK) ^ (buf & HC_ITD_PAGE_MASK));
62037c478bd9Sstevel@tonic-gate
62047c478bd9Sstevel@tonic-gate if (flag) {
62057c478bd9Sstevel@tonic-gate offset_addr |= HC_ITD_4KBOUNDARY_CROSS;
62067c478bd9Sstevel@tonic-gate }
62077c478bd9Sstevel@tonic-gate
62087c478bd9Sstevel@tonic-gate if (toggle) {
62097c478bd9Sstevel@tonic-gate offset = (uint32_t)((offset_addr <<
62107c478bd9Sstevel@tonic-gate HC_ITD_OFFSET_SHIFT) & HC_ITD_ODD_OFFSET);
62117c478bd9Sstevel@tonic-gate
62127c478bd9Sstevel@tonic-gate Set_TD(td->hctd_offsets[i / 2],
62137c478bd9Sstevel@tonic-gate Get_TD(td->hctd_offsets[i / 2]) | offset);
62147c478bd9Sstevel@tonic-gate toggle = 0;
62157c478bd9Sstevel@tonic-gate } else {
62167c478bd9Sstevel@tonic-gate offset = (uint32_t)(offset_addr & HC_ITD_EVEN_OFFSET);
62177c478bd9Sstevel@tonic-gate
62187c478bd9Sstevel@tonic-gate Set_TD(td->hctd_offsets[i / 2],
62197c478bd9Sstevel@tonic-gate Get_TD(td->hctd_offsets[i / 2]) | offset);
62207c478bd9Sstevel@tonic-gate toggle = 1;
62217c478bd9Sstevel@tonic-gate }
62227c478bd9Sstevel@tonic-gate
62237c478bd9Sstevel@tonic-gate buf = (uint32_t)(buf + temp_pkt_descr->isoc_pkt_length);
62247c478bd9Sstevel@tonic-gate temp_pkt_descr++;
62257c478bd9Sstevel@tonic-gate }
62267c478bd9Sstevel@tonic-gate }
62277c478bd9Sstevel@tonic-gate
62287c478bd9Sstevel@tonic-gate
62297c478bd9Sstevel@tonic-gate /*
62307c478bd9Sstevel@tonic-gate * ohci_insert_td_with_frame_number:
62317c478bd9Sstevel@tonic-gate *
62327c478bd9Sstevel@tonic-gate * Insert current isochronous TD into the ED's list. with proper
62337c478bd9Sstevel@tonic-gate * usb frame number in which this TD can be processed.
62347c478bd9Sstevel@tonic-gate */
62357c478bd9Sstevel@tonic-gate static int
ohci_insert_td_with_frame_number(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * current_td,ohci_td_t * dummy_td)62367c478bd9Sstevel@tonic-gate ohci_insert_td_with_frame_number(
62377c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
62387c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
62397c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
62407c478bd9Sstevel@tonic-gate ohci_td_t *current_td,
62417c478bd9Sstevel@tonic-gate ohci_td_t *dummy_td)
62427c478bd9Sstevel@tonic-gate {
62437c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp =
62447c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
62457c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number, start_frame_number;
62467c478bd9Sstevel@tonic-gate uint_t ddic, ctrl, isoc_pkts;
62477c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
62487c478bd9Sstevel@tonic-gate
62497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
62507c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:"
62517c478bd9Sstevel@tonic-gate "isoc flags 0x%x", isoc_reqp->isoc_attributes);
62527c478bd9Sstevel@tonic-gate
62537c478bd9Sstevel@tonic-gate /* Get the TD ctrl information */
62547c478bd9Sstevel@tonic-gate isoc_pkts = ((Get_TD(current_td->hctd_ctrl) &
62557c478bd9Sstevel@tonic-gate HC_ITD_FC) >> HC_ITD_FC_SHIFT) + 1;
62567c478bd9Sstevel@tonic-gate
62577c478bd9Sstevel@tonic-gate /*
62587c478bd9Sstevel@tonic-gate * Enter critical, while programming the usb frame number
62597c478bd9Sstevel@tonic-gate * and inserting current isochronous TD into the ED's list.
62607c478bd9Sstevel@tonic-gate */
62617c478bd9Sstevel@tonic-gate ddic = ddi_enter_critical();
62627c478bd9Sstevel@tonic-gate
62637c478bd9Sstevel@tonic-gate /* Get the current frame number */
62647c478bd9Sstevel@tonic-gate current_frame_number = ohci_get_current_frame_number(ohcip);
62657c478bd9Sstevel@tonic-gate
62667c478bd9Sstevel@tonic-gate /* Check the given isochronous flags */
62677c478bd9Sstevel@tonic-gate switch (isoc_reqp->isoc_attributes &
62687c478bd9Sstevel@tonic-gate (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) {
62697c478bd9Sstevel@tonic-gate case USB_ATTRS_ISOC_START_FRAME:
62707c478bd9Sstevel@tonic-gate /* Starting frame number is specified */
62717c478bd9Sstevel@tonic-gate if (pp->pp_flag & OHCI_ISOC_XFER_CONTINUE) {
62727c478bd9Sstevel@tonic-gate /* Get the starting usb frame number */
62737c478bd9Sstevel@tonic-gate start_frame_number = pp->pp_next_frame_number;
62747c478bd9Sstevel@tonic-gate } else {
62757c478bd9Sstevel@tonic-gate /* Check for the Starting usb frame number */
62767c478bd9Sstevel@tonic-gate if ((isoc_reqp->isoc_frame_no == 0) ||
62777c478bd9Sstevel@tonic-gate ((isoc_reqp->isoc_frame_no +
62787c478bd9Sstevel@tonic-gate isoc_reqp->isoc_pkts_count) <
62797c478bd9Sstevel@tonic-gate current_frame_number)) {
62807c478bd9Sstevel@tonic-gate
62817c478bd9Sstevel@tonic-gate /* Exit the critical */
62827c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic);
62837c478bd9Sstevel@tonic-gate
62847c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS,
62857c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl,
62867c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:"
62877c478bd9Sstevel@tonic-gate "Invalid starting frame number");
62887c478bd9Sstevel@tonic-gate
62897c478bd9Sstevel@tonic-gate return (USB_INVALID_START_FRAME);
62907c478bd9Sstevel@tonic-gate }
62917c478bd9Sstevel@tonic-gate
62927c478bd9Sstevel@tonic-gate /* Get the starting usb frame number */
62937c478bd9Sstevel@tonic-gate start_frame_number = isoc_reqp->isoc_frame_no;
62947c478bd9Sstevel@tonic-gate
62957c478bd9Sstevel@tonic-gate pp->pp_next_frame_number = 0;
62967c478bd9Sstevel@tonic-gate }
62977c478bd9Sstevel@tonic-gate break;
62987c478bd9Sstevel@tonic-gate case USB_ATTRS_ISOC_XFER_ASAP:
62997c478bd9Sstevel@tonic-gate /* ohci has to specify starting frame number */
63007c478bd9Sstevel@tonic-gate if ((pp->pp_next_frame_number) &&
63017c478bd9Sstevel@tonic-gate (pp->pp_next_frame_number > current_frame_number)) {
63027c478bd9Sstevel@tonic-gate /*
63037c478bd9Sstevel@tonic-gate * Get the next usb frame number.
63047c478bd9Sstevel@tonic-gate */
63057c478bd9Sstevel@tonic-gate start_frame_number = pp->pp_next_frame_number;
63067c478bd9Sstevel@tonic-gate } else {
63077c478bd9Sstevel@tonic-gate /*
63087c478bd9Sstevel@tonic-gate * Add appropriate offset to the current usb
63097c478bd9Sstevel@tonic-gate * frame number and use it as a starting frame
63107c478bd9Sstevel@tonic-gate * number.
63117c478bd9Sstevel@tonic-gate */
63127c478bd9Sstevel@tonic-gate start_frame_number =
63137c478bd9Sstevel@tonic-gate current_frame_number + OHCI_FRAME_OFFSET;
63147c478bd9Sstevel@tonic-gate }
63157c478bd9Sstevel@tonic-gate
63167c478bd9Sstevel@tonic-gate if (!(pp->pp_flag & OHCI_ISOC_XFER_CONTINUE)) {
63177c478bd9Sstevel@tonic-gate isoc_reqp->isoc_frame_no = start_frame_number;
63187c478bd9Sstevel@tonic-gate }
63197c478bd9Sstevel@tonic-gate break;
63207c478bd9Sstevel@tonic-gate default:
63217c478bd9Sstevel@tonic-gate /* Exit the critical */
63227c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic);
63237c478bd9Sstevel@tonic-gate
63247c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
63257c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number: Either starting "
63267c478bd9Sstevel@tonic-gate "frame number or ASAP flags are not set, attrs = 0x%x",
63277c478bd9Sstevel@tonic-gate isoc_reqp->isoc_attributes);
63287c478bd9Sstevel@tonic-gate
63297c478bd9Sstevel@tonic-gate return (USB_NO_FRAME_NUMBER);
63307c478bd9Sstevel@tonic-gate }
63317c478bd9Sstevel@tonic-gate
63327c478bd9Sstevel@tonic-gate /* Get the TD ctrl information */
63337c478bd9Sstevel@tonic-gate ctrl = Get_TD(current_td->hctd_ctrl) & (~(HC_ITD_SF));
63347c478bd9Sstevel@tonic-gate
63357c478bd9Sstevel@tonic-gate /* Set the frame number field */
63367c478bd9Sstevel@tonic-gate Set_TD(current_td->hctd_ctrl, ctrl | (start_frame_number & HC_ITD_SF));
63377c478bd9Sstevel@tonic-gate
63387c478bd9Sstevel@tonic-gate /*
63397c478bd9Sstevel@tonic-gate * Add the new dummy to the ED's list. When this occurs,
63407c478bd9Sstevel@tonic-gate * the Host Controller will see newly filled in dummy TD.
63417c478bd9Sstevel@tonic-gate */
63427c478bd9Sstevel@tonic-gate Set_ED(ept->hced_tailp, (ohci_td_cpu_to_iommu(ohcip, dummy_td)));
63437c478bd9Sstevel@tonic-gate
63447c478bd9Sstevel@tonic-gate /* Exit the critical */
63457c478bd9Sstevel@tonic-gate ddi_exit_critical(ddic);
63467c478bd9Sstevel@tonic-gate
63477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
63487c478bd9Sstevel@tonic-gate "ohci_insert_td_with_frame_number:"
63497c478bd9Sstevel@tonic-gate "current frame number 0x%llx start frame number 0x%llx",
6350112116d8Sfb209375 (unsigned long long)current_frame_number,
6351112116d8Sfb209375 (unsigned long long)start_frame_number);
63527c478bd9Sstevel@tonic-gate
63537c478bd9Sstevel@tonic-gate /*
63547c478bd9Sstevel@tonic-gate * Increment this saved frame number by current number
63557c478bd9Sstevel@tonic-gate * of data packets needs to be transfer.
63567c478bd9Sstevel@tonic-gate */
63577c478bd9Sstevel@tonic-gate pp->pp_next_frame_number = start_frame_number + isoc_pkts;
63587c478bd9Sstevel@tonic-gate
63597c478bd9Sstevel@tonic-gate /*
63607c478bd9Sstevel@tonic-gate * Set OHCI_ISOC_XFER_CONTINUE flag in order to send other
63617c478bd9Sstevel@tonic-gate * isochronous packets, part of the current isoch request
63627c478bd9Sstevel@tonic-gate * in the subsequent frames.
63637c478bd9Sstevel@tonic-gate */
63647c478bd9Sstevel@tonic-gate pp->pp_flag |= OHCI_ISOC_XFER_CONTINUE;
63657c478bd9Sstevel@tonic-gate
63667c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
63677c478bd9Sstevel@tonic-gate }
63687c478bd9Sstevel@tonic-gate
63697c478bd9Sstevel@tonic-gate
63707c478bd9Sstevel@tonic-gate /*
63717c478bd9Sstevel@tonic-gate * ohci_insert_td_on_tw:
63727c478bd9Sstevel@tonic-gate *
63737c478bd9Sstevel@tonic-gate * The transfer wrapper keeps a list of all Transfer Descriptors (TD) that
63747c478bd9Sstevel@tonic-gate * are allocated for this transfer. Insert a TD onto this list. The list
63757c478bd9Sstevel@tonic-gate * of TD's does not include the dummy TD that is at the end of the list of
63767c478bd9Sstevel@tonic-gate * TD's for the endpoint.
63777c478bd9Sstevel@tonic-gate */
63787c478bd9Sstevel@tonic-gate static void
ohci_insert_td_on_tw(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw,ohci_td_t * td)63797c478bd9Sstevel@tonic-gate ohci_insert_td_on_tw(
63807c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
63817c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
63827c478bd9Sstevel@tonic-gate ohci_td_t *td)
63837c478bd9Sstevel@tonic-gate {
63847c478bd9Sstevel@tonic-gate /*
63857c478bd9Sstevel@tonic-gate * Set the next pointer to NULL because
63867c478bd9Sstevel@tonic-gate * this is the last TD on list.
63877c478bd9Sstevel@tonic-gate */
63887c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL);
63897c478bd9Sstevel@tonic-gate
63907c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head == NULL) {
63917c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL);
63927c478bd9Sstevel@tonic-gate tw->tw_hctd_head = td;
63937c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td;
63947c478bd9Sstevel@tonic-gate } else {
63957c478bd9Sstevel@tonic-gate ohci_td_t *dummy = (ohci_td_t *)tw->tw_hctd_tail;
63967c478bd9Sstevel@tonic-gate
63977c478bd9Sstevel@tonic-gate ASSERT(dummy != NULL);
63987c478bd9Sstevel@tonic-gate ASSERT(dummy != td);
63997c478bd9Sstevel@tonic-gate ASSERT(Get_TD(td->hctd_state) != HC_TD_DUMMY);
64007c478bd9Sstevel@tonic-gate
64017c478bd9Sstevel@tonic-gate /* Add the td to the end of the list */
64027c478bd9Sstevel@tonic-gate Set_TD(dummy->hctd_tw_next_td,
64037c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, td));
64047c478bd9Sstevel@tonic-gate
64057c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td;
64067c478bd9Sstevel@tonic-gate
6407*3eb8c55cSToomas Soome ASSERT(Get_TD(td->hctd_tw_next_td) == 0);
64087c478bd9Sstevel@tonic-gate }
64097c478bd9Sstevel@tonic-gate }
64107c478bd9Sstevel@tonic-gate
64117c478bd9Sstevel@tonic-gate
64127c478bd9Sstevel@tonic-gate /*
64137c478bd9Sstevel@tonic-gate * ohci_traverse_tds:
64147c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
64157c478bd9Sstevel@tonic-gate *
64167c478bd9Sstevel@tonic-gate * Traverse the list of TD's for an endpoint. Since the endpoint is marked
64177c478bd9Sstevel@tonic-gate * as sKipped, the Host Controller (HC) is no longer accessing these TD's.
64187c478bd9Sstevel@tonic-gate * Remove all the TD's that are attached to the endpoint.
64197c478bd9Sstevel@tonic-gate */
64207c478bd9Sstevel@tonic-gate void
ohci_traverse_tds(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)64217c478bd9Sstevel@tonic-gate ohci_traverse_tds(
64227c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
64237c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
64247c478bd9Sstevel@tonic-gate {
64257c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
64267c478bd9Sstevel@tonic-gate ohci_ed_t *ept;
64277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp;
64287c478bd9Sstevel@tonic-gate uint32_t addr;
64297c478bd9Sstevel@tonic-gate ohci_td_t *tailp, *headp, *next;
64307c478bd9Sstevel@tonic-gate
64317c478bd9Sstevel@tonic-gate pp = (ohci_pipe_private_t *)ph->p_hcd_private;
64327c478bd9Sstevel@tonic-gate ept = pp->pp_ept;
64337c478bd9Sstevel@tonic-gate
64347c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64357c478bd9Sstevel@tonic-gate "ohci_traverse_tds: ph = 0x%p ept = 0x%p",
64367c478bd9Sstevel@tonic-gate (void *)ph, (void *)ept);
64377c478bd9Sstevel@tonic-gate
64387c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
64397c478bd9Sstevel@tonic-gate
64407c478bd9Sstevel@tonic-gate addr = Get_ED(ept->hced_headp) & (uint32_t)HC_EPT_TD_HEAD;
64417c478bd9Sstevel@tonic-gate
64427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64437c478bd9Sstevel@tonic-gate "ohci_traverse_tds: addr (head) = 0x%x", addr);
64447c478bd9Sstevel@tonic-gate
64457c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, addr));
64467c478bd9Sstevel@tonic-gate
64477c478bd9Sstevel@tonic-gate addr = Get_ED(ept->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL;
64487c478bd9Sstevel@tonic-gate
64497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64507c478bd9Sstevel@tonic-gate "ohci_traverse_tds: addr (tail) = 0x%x", addr);
64517c478bd9Sstevel@tonic-gate
64527c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip, addr));
64537c478bd9Sstevel@tonic-gate
64547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64557c478bd9Sstevel@tonic-gate "ohci_traverse_tds: cpu head = 0x%p cpu tail = 0x%p",
64567c478bd9Sstevel@tonic-gate (void *)headp, (void *)tailp);
64577c478bd9Sstevel@tonic-gate
64587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64597c478bd9Sstevel@tonic-gate "ohci_traverse_tds: iommu head = 0x%x iommu tail = 0x%x",
64607c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, headp),
64617c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, tailp));
64627c478bd9Sstevel@tonic-gate
64637c478bd9Sstevel@tonic-gate /*
64647c478bd9Sstevel@tonic-gate * Traverse the list of TD's that are currently on the endpoint.
64657c478bd9Sstevel@tonic-gate * These TD's have not been processed and will not be processed
64667c478bd9Sstevel@tonic-gate * because the endpoint processing is stopped.
64677c478bd9Sstevel@tonic-gate */
64687c478bd9Sstevel@tonic-gate while (headp != tailp) {
64697c478bd9Sstevel@tonic-gate next = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip,
64707c478bd9Sstevel@tonic-gate (Get_TD(headp->hctd_next_td) & HC_EPT_TD_TAIL)));
64717c478bd9Sstevel@tonic-gate
64727c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
64737c478bd9Sstevel@tonic-gate (uint32_t)Get_TD(headp->hctd_trans_wrapper));
64747c478bd9Sstevel@tonic-gate
64757c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */
64767c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, OHCI_REMOVE_XFER_ALWAYS);
64777c478bd9Sstevel@tonic-gate
64787c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, headp);
64797c478bd9Sstevel@tonic-gate headp = next;
64807c478bd9Sstevel@tonic-gate }
64817c478bd9Sstevel@tonic-gate
64827c478bd9Sstevel@tonic-gate /* Both head and tail pointers must be same */
64837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64847c478bd9Sstevel@tonic-gate "ohci_traverse_tds: head = 0x%p tail = 0x%p",
64857c478bd9Sstevel@tonic-gate (void *)headp, (void *)tailp);
64867c478bd9Sstevel@tonic-gate
64877c478bd9Sstevel@tonic-gate /* Update the pointer in the endpoint descriptor */
64887c478bd9Sstevel@tonic-gate Set_ED(ept->hced_headp, (ohci_td_cpu_to_iommu(ohcip, headp)));
64897c478bd9Sstevel@tonic-gate
64907c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64917c478bd9Sstevel@tonic-gate "ohci_traverse_tds: new head = 0x%x",
64927c478bd9Sstevel@tonic-gate (ohci_td_cpu_to_iommu(ohcip, headp)));
64937c478bd9Sstevel@tonic-gate
64947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
64957c478bd9Sstevel@tonic-gate "ohci_traverse_tds: tailp = 0x%x headp = 0x%x",
64967c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL),
64977c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD));
64987c478bd9Sstevel@tonic-gate
64997c478bd9Sstevel@tonic-gate ASSERT((Get_ED(ept->hced_tailp) & HC_EPT_TD_TAIL) ==
65007c478bd9Sstevel@tonic-gate (Get_ED(ept->hced_headp) & HC_EPT_TD_HEAD));
65017c478bd9Sstevel@tonic-gate }
65027c478bd9Sstevel@tonic-gate
65037c478bd9Sstevel@tonic-gate
65047c478bd9Sstevel@tonic-gate /*
65057c478bd9Sstevel@tonic-gate * ohci_done_list_tds:
65067c478bd9Sstevel@tonic-gate *
65077c478bd9Sstevel@tonic-gate * There may be TD's on the done list that have not been processed yet. Walk
65087c478bd9Sstevel@tonic-gate * through these TD's and mark them as RECLAIM. All the mappings for the TD
65097c478bd9Sstevel@tonic-gate * will be torn down, so the interrupt handle is alerted of this fact through
65107c478bd9Sstevel@tonic-gate * the RECLAIM flag.
65117c478bd9Sstevel@tonic-gate */
65127c478bd9Sstevel@tonic-gate static void
ohci_done_list_tds(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)65137c478bd9Sstevel@tonic-gate ohci_done_list_tds(
65147c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
65157c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
65167c478bd9Sstevel@tonic-gate {
65177c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
65187c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head;
65197c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw;
65207c478bd9Sstevel@tonic-gate ohci_td_t *head_td, *next_td;
65217c478bd9Sstevel@tonic-gate
65227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
65237c478bd9Sstevel@tonic-gate
65247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
65257c478bd9Sstevel@tonic-gate "ohci_done_list_tds:");
65267c478bd9Sstevel@tonic-gate
65277c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */
65287c478bd9Sstevel@tonic-gate next_tw = head_tw;
65297c478bd9Sstevel@tonic-gate while (next_tw) {
65307c478bd9Sstevel@tonic-gate head_td = (ohci_td_t *)next_tw->tw_hctd_head;
65317c478bd9Sstevel@tonic-gate next_td = head_td;
65327c478bd9Sstevel@tonic-gate
65337c478bd9Sstevel@tonic-gate if (head_td) {
65347c478bd9Sstevel@tonic-gate /*
65357c478bd9Sstevel@tonic-gate * Walk through each TD for this transfer
65367c478bd9Sstevel@tonic-gate * wrapper. If a TD still exists, then it
65377c478bd9Sstevel@tonic-gate * is currently on the done list.
65387c478bd9Sstevel@tonic-gate */
65397c478bd9Sstevel@tonic-gate while (next_td) {
65407c478bd9Sstevel@tonic-gate
65417c478bd9Sstevel@tonic-gate /* To free TD, set TD state to RECLAIM */
65427c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_state, HC_TD_RECLAIM);
65437c478bd9Sstevel@tonic-gate
65447c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_trans_wrapper, NULL);
65457c478bd9Sstevel@tonic-gate
65467c478bd9Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip,
65477c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td));
65487c478bd9Sstevel@tonic-gate }
65497c478bd9Sstevel@tonic-gate }
65507c478bd9Sstevel@tonic-gate
65517c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */
65527c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, next_tw, OHCI_REMOVE_XFER_ALWAYS);
65537c478bd9Sstevel@tonic-gate
65547c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next;
65557c478bd9Sstevel@tonic-gate }
65567c478bd9Sstevel@tonic-gate }
65577c478bd9Sstevel@tonic-gate
65587c478bd9Sstevel@tonic-gate
65597c478bd9Sstevel@tonic-gate /*
6560277d02f6Sgc161489 * Remove old_td from tw and update the links.
6561277d02f6Sgc161489 */
6562277d02f6Sgc161489 void
ohci_unlink_td_from_tw(ohci_state_t * ohcip,ohci_td_t * old_td,ohci_trans_wrapper_t * tw)6563277d02f6Sgc161489 ohci_unlink_td_from_tw(
6564277d02f6Sgc161489 ohci_state_t *ohcip,
6565277d02f6Sgc161489 ohci_td_t *old_td,
6566277d02f6Sgc161489 ohci_trans_wrapper_t *tw)
6567277d02f6Sgc161489 {
6568277d02f6Sgc161489 ohci_td_t *next, *head, *tail;
6569277d02f6Sgc161489
6570277d02f6Sgc161489 USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
6571277d02f6Sgc161489 "ohci_unlink_td_from_tw: ohcip = 0x%p, old_td = 0x%p, tw = 0x%p",
6572277d02f6Sgc161489 (void *)ohcip, (void *)old_td, (void *)tw);
6573277d02f6Sgc161489
6574277d02f6Sgc161489 if (old_td == NULL || tw == NULL) {
6575277d02f6Sgc161489
6576277d02f6Sgc161489 return;
6577277d02f6Sgc161489 }
6578277d02f6Sgc161489
6579277d02f6Sgc161489 head = tw->tw_hctd_head;
6580277d02f6Sgc161489 tail = tw->tw_hctd_tail;
6581277d02f6Sgc161489
6582277d02f6Sgc161489 if (head == NULL) {
6583277d02f6Sgc161489
6584277d02f6Sgc161489 return;
6585277d02f6Sgc161489 }
6586277d02f6Sgc161489
6587277d02f6Sgc161489 /* if this old_td is on head */
6588277d02f6Sgc161489 if (old_td == head) {
6589277d02f6Sgc161489 if (old_td == tail) {
6590277d02f6Sgc161489 tw->tw_hctd_head = NULL;
6591277d02f6Sgc161489 tw->tw_hctd_tail = NULL;
6592277d02f6Sgc161489 } else {
6593277d02f6Sgc161489 tw->tw_hctd_head = ohci_td_iommu_to_cpu(ohcip,
6594277d02f6Sgc161489 Get_TD(head->hctd_tw_next_td));
6595277d02f6Sgc161489 }
6596277d02f6Sgc161489
6597277d02f6Sgc161489 return;
6598277d02f6Sgc161489 }
6599277d02f6Sgc161489
6600277d02f6Sgc161489 /* find this old_td's position in the tw */
6601277d02f6Sgc161489 next = ohci_td_iommu_to_cpu(ohcip, Get_TD(head->hctd_tw_next_td));
6602277d02f6Sgc161489 while (next && (old_td != next)) {
6603277d02f6Sgc161489 head = next;
6604277d02f6Sgc161489 next = ohci_td_iommu_to_cpu(ohcip,
6605277d02f6Sgc161489 Get_TD(next->hctd_tw_next_td));
6606277d02f6Sgc161489 }
6607277d02f6Sgc161489
6608277d02f6Sgc161489 /* unlink the found old_td from the tw */
6609277d02f6Sgc161489 if (old_td == next) {
6610277d02f6Sgc161489 Set_TD(head->hctd_tw_next_td, Get_TD(next->hctd_tw_next_td));
6611277d02f6Sgc161489 if (old_td == tail) {
6612277d02f6Sgc161489 tw->tw_hctd_tail = head;
6613277d02f6Sgc161489 }
6614277d02f6Sgc161489 }
6615277d02f6Sgc161489 }
6616277d02f6Sgc161489
6617277d02f6Sgc161489
6618277d02f6Sgc161489 /*
66197c478bd9Sstevel@tonic-gate * ohci_deallocate_td:
66207c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
66217c478bd9Sstevel@tonic-gate *
66227c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Transfer Descriptor (TD).
66237c478bd9Sstevel@tonic-gate */
66247c478bd9Sstevel@tonic-gate void
ohci_deallocate_td(ohci_state_t * ohcip,ohci_td_t * old_td)66257c478bd9Sstevel@tonic-gate ohci_deallocate_td(
66267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
66277c478bd9Sstevel@tonic-gate ohci_td_t *old_td)
66287c478bd9Sstevel@tonic-gate {
66297c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
66307c478bd9Sstevel@tonic-gate
66317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
66327c478bd9Sstevel@tonic-gate "ohci_deallocate_td: old_td = 0x%p", (void *)old_td);
66337c478bd9Sstevel@tonic-gate
66347c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
66357c478bd9Sstevel@tonic-gate
66367c478bd9Sstevel@tonic-gate /*
66377c478bd9Sstevel@tonic-gate * Obtain the transaction wrapper and tw will be
66387c478bd9Sstevel@tonic-gate * NULL for the dummy and for the reclaim TD's.
66397c478bd9Sstevel@tonic-gate */
66407c478bd9Sstevel@tonic-gate if ((Get_TD(old_td->hctd_state) == HC_TD_DUMMY) ||
66417c478bd9Sstevel@tonic-gate (Get_TD(old_td->hctd_state) == HC_TD_RECLAIM)) {
66427c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)((uintptr_t)
66437c478bd9Sstevel@tonic-gate Get_TD(old_td->hctd_trans_wrapper));
66447c478bd9Sstevel@tonic-gate ASSERT(tw == NULL);
66457c478bd9Sstevel@tonic-gate } else {
66467c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)
66477c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)
66487c478bd9Sstevel@tonic-gate Get_TD(old_td->hctd_trans_wrapper));
66497c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
66507c478bd9Sstevel@tonic-gate }
66517c478bd9Sstevel@tonic-gate
66527c478bd9Sstevel@tonic-gate /*
66537c478bd9Sstevel@tonic-gate * If this TD should be reclaimed, don't try to access its
66547c478bd9Sstevel@tonic-gate * transfer wrapper.
66557c478bd9Sstevel@tonic-gate */
66567c478bd9Sstevel@tonic-gate if ((Get_TD(old_td->hctd_state) != HC_TD_RECLAIM) && tw) {
66577c478bd9Sstevel@tonic-gate
6658277d02f6Sgc161489 ohci_unlink_td_from_tw(ohcip, old_td, tw);
66597c478bd9Sstevel@tonic-gate }
66607c478bd9Sstevel@tonic-gate
66617c478bd9Sstevel@tonic-gate bzero((void *)old_td, sizeof (ohci_td_t));
66627c478bd9Sstevel@tonic-gate Set_TD(old_td->hctd_state, HC_TD_FREE);
66637c478bd9Sstevel@tonic-gate
66647c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
66657c478bd9Sstevel@tonic-gate "ohci_deallocate_td: td 0x%p", (void *)old_td);
66667c478bd9Sstevel@tonic-gate }
66677c478bd9Sstevel@tonic-gate
66687c478bd9Sstevel@tonic-gate
66697c478bd9Sstevel@tonic-gate /*
66707c478bd9Sstevel@tonic-gate * ohci_td_cpu_to_iommu:
66717c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
66727c478bd9Sstevel@tonic-gate *
66737c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (TD) CPU address
66747c478bd9Sstevel@tonic-gate * to IO address.
66757c478bd9Sstevel@tonic-gate */
66767c478bd9Sstevel@tonic-gate uint32_t
ohci_td_cpu_to_iommu(ohci_state_t * ohcip,ohci_td_t * addr)66777c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(
66787c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
66797c478bd9Sstevel@tonic-gate ohci_td_t *addr)
66807c478bd9Sstevel@tonic-gate {
66817c478bd9Sstevel@tonic-gate uint32_t td;
66827c478bd9Sstevel@tonic-gate
66837c478bd9Sstevel@tonic-gate td = (uint32_t)ohcip->ohci_td_pool_cookie.dmac_address +
66847c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ohcip->ohci_td_pool_addr));
66857c478bd9Sstevel@tonic-gate
66867c478bd9Sstevel@tonic-gate ASSERT((ohcip->ohci_td_pool_cookie.dmac_address +
66877c478bd9Sstevel@tonic-gate (uint32_t) (sizeof (ohci_td_t) *
66887c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_td_pool_addr))) ==
66897c478bd9Sstevel@tonic-gate (ohcip->ohci_td_pool_cookie.dmac_address +
66907c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)
66917c478bd9Sstevel@tonic-gate (ohcip->ohci_td_pool_addr))));
66927c478bd9Sstevel@tonic-gate
66937c478bd9Sstevel@tonic-gate ASSERT(td >= ohcip->ohci_td_pool_cookie.dmac_address);
66947c478bd9Sstevel@tonic-gate ASSERT(td <= ohcip->ohci_td_pool_cookie.dmac_address +
66957c478bd9Sstevel@tonic-gate sizeof (ohci_td_t) * ohci_td_pool_size);
66967c478bd9Sstevel@tonic-gate
66977c478bd9Sstevel@tonic-gate return (td);
66987c478bd9Sstevel@tonic-gate }
66997c478bd9Sstevel@tonic-gate
67007c478bd9Sstevel@tonic-gate
67017c478bd9Sstevel@tonic-gate /*
67027c478bd9Sstevel@tonic-gate * ohci_td_iommu_to_cpu:
67037c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
67047c478bd9Sstevel@tonic-gate *
67057c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (TD) IO address
67067c478bd9Sstevel@tonic-gate * to CPU address.
67077c478bd9Sstevel@tonic-gate */
67087c478bd9Sstevel@tonic-gate ohci_td_t *
ohci_td_iommu_to_cpu(ohci_state_t * ohcip,uintptr_t addr)67097c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(
67107c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
67117c478bd9Sstevel@tonic-gate uintptr_t addr)
67127c478bd9Sstevel@tonic-gate {
67137c478bd9Sstevel@tonic-gate ohci_td_t *td;
67147c478bd9Sstevel@tonic-gate
67153e1e1e62SToomas Soome if (addr == 0)
67167c478bd9Sstevel@tonic-gate return (NULL);
67177c478bd9Sstevel@tonic-gate
67187c478bd9Sstevel@tonic-gate td = (ohci_td_t *)((uintptr_t)
67197c478bd9Sstevel@tonic-gate (addr - ohcip->ohci_td_pool_cookie.dmac_address) +
67207c478bd9Sstevel@tonic-gate (uintptr_t)ohcip->ohci_td_pool_addr);
67217c478bd9Sstevel@tonic-gate
67227c478bd9Sstevel@tonic-gate ASSERT(td >= ohcip->ohci_td_pool_addr);
67237c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)td <= (uintptr_t)ohcip->ohci_td_pool_addr +
67247c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ohci_td_t) * ohci_td_pool_size));
67257c478bd9Sstevel@tonic-gate
67267c478bd9Sstevel@tonic-gate return (td);
67277c478bd9Sstevel@tonic-gate }
67287c478bd9Sstevel@tonic-gate
67297c478bd9Sstevel@tonic-gate /*
67307c478bd9Sstevel@tonic-gate * ohci_allocate_tds_for_tw:
67317c478bd9Sstevel@tonic-gate *
67327c478bd9Sstevel@tonic-gate * Allocate n Transfer Descriptors (TD) from the TD buffer pool and places it
67337c478bd9Sstevel@tonic-gate * into the TW.
67347c478bd9Sstevel@tonic-gate *
67357c478bd9Sstevel@tonic-gate * Returns USB_NO_RESOURCES if it was not able to allocate all the requested TD
67367c478bd9Sstevel@tonic-gate * otherwise USB_SUCCESS.
67377c478bd9Sstevel@tonic-gate */
67389b58c2adSzhigang lu - Sun Microsystems - Beijing China int
ohci_allocate_tds_for_tw(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw,size_t td_count)67397c478bd9Sstevel@tonic-gate ohci_allocate_tds_for_tw(
67407c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
67417c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
67427c478bd9Sstevel@tonic-gate size_t td_count)
67437c478bd9Sstevel@tonic-gate {
67447c478bd9Sstevel@tonic-gate ohci_td_t *td;
67457c478bd9Sstevel@tonic-gate uint32_t td_addr;
67467c478bd9Sstevel@tonic-gate int i;
67477c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
67487c478bd9Sstevel@tonic-gate
67497c478bd9Sstevel@tonic-gate for (i = 0; i < td_count; i++) {
67507c478bd9Sstevel@tonic-gate td = ohci_allocate_td_from_pool(ohcip);
67517c478bd9Sstevel@tonic-gate if (td == NULL) {
67527c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
67537c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
67547c478bd9Sstevel@tonic-gate "ohci_allocate_tds_for_tw: "
67557c478bd9Sstevel@tonic-gate "Unable to allocate %lu TDs",
67567c478bd9Sstevel@tonic-gate td_count);
67577c478bd9Sstevel@tonic-gate break;
67587c478bd9Sstevel@tonic-gate }
67597c478bd9Sstevel@tonic-gate if (tw->tw_hctd_free_list != NULL) {
67607c478bd9Sstevel@tonic-gate td_addr = ohci_td_cpu_to_iommu(ohcip,
67617c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list);
67627c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, td_addr);
67637c478bd9Sstevel@tonic-gate }
67647c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = td;
67657c478bd9Sstevel@tonic-gate }
67667c478bd9Sstevel@tonic-gate
67677c478bd9Sstevel@tonic-gate return (error);
67687c478bd9Sstevel@tonic-gate }
67697c478bd9Sstevel@tonic-gate
67707c478bd9Sstevel@tonic-gate /*
67717c478bd9Sstevel@tonic-gate * ohci_allocate_tw_resources:
67727c478bd9Sstevel@tonic-gate *
67737c478bd9Sstevel@tonic-gate * Allocate a Transaction Wrapper (TW) and n Transfer Descriptors (TD)
67747c478bd9Sstevel@tonic-gate * from the TD buffer pool and places it into the TW. It does an all
67757c478bd9Sstevel@tonic-gate * or nothing transaction.
67767c478bd9Sstevel@tonic-gate *
67777c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW.
67787c478bd9Sstevel@tonic-gate */
67797c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *
ohci_allocate_tw_resources(ohci_state_t * ohcip,ohci_pipe_private_t * pp,size_t tw_length,usb_flags_t usb_flags,size_t td_count)67807c478bd9Sstevel@tonic-gate ohci_allocate_tw_resources(
67817c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
67827c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
67837c478bd9Sstevel@tonic-gate size_t tw_length,
67847c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
67857c478bd9Sstevel@tonic-gate size_t td_count)
67867c478bd9Sstevel@tonic-gate {
67877c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
67887c478bd9Sstevel@tonic-gate
67897c478bd9Sstevel@tonic-gate tw = ohci_create_transfer_wrapper(ohcip, pp, tw_length, usb_flags);
67907c478bd9Sstevel@tonic-gate
67917c478bd9Sstevel@tonic-gate if (tw == NULL) {
67927c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
67937c478bd9Sstevel@tonic-gate "ohci_allocate_tw_resources: Unable to allocate TW");
67947c478bd9Sstevel@tonic-gate } else {
67957c478bd9Sstevel@tonic-gate if (ohci_allocate_tds_for_tw(ohcip, tw, td_count) ==
67967c478bd9Sstevel@tonic-gate USB_SUCCESS) {
6797d29f5a71Szhigang lu - Sun Microsystems - Beijing China tw->tw_num_tds = (uint_t)td_count;
67987c478bd9Sstevel@tonic-gate } else {
67997c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
68007c478bd9Sstevel@tonic-gate tw = NULL;
68017c478bd9Sstevel@tonic-gate }
68027c478bd9Sstevel@tonic-gate }
68037c478bd9Sstevel@tonic-gate
68047c478bd9Sstevel@tonic-gate return (tw);
68057c478bd9Sstevel@tonic-gate }
68067c478bd9Sstevel@tonic-gate
68077c478bd9Sstevel@tonic-gate /*
68087c478bd9Sstevel@tonic-gate * ohci_free_tw_tds_resources:
68097c478bd9Sstevel@tonic-gate *
68107c478bd9Sstevel@tonic-gate * Free all allocated resources for Transaction Wrapper (TW).
68117c478bd9Sstevel@tonic-gate * Does not free the TW itself.
68127c478bd9Sstevel@tonic-gate */
68137c478bd9Sstevel@tonic-gate static void
ohci_free_tw_tds_resources(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw)68147c478bd9Sstevel@tonic-gate ohci_free_tw_tds_resources(
68157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
68167c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
68177c478bd9Sstevel@tonic-gate {
68187c478bd9Sstevel@tonic-gate ohci_td_t *td;
68197c478bd9Sstevel@tonic-gate ohci_td_t *temp_td;
68207c478bd9Sstevel@tonic-gate
68217c478bd9Sstevel@tonic-gate td = tw->tw_hctd_free_list;
68227c478bd9Sstevel@tonic-gate while (td != NULL) {
68237c478bd9Sstevel@tonic-gate /* Save the pointer to the next td before destroying it */
68247c478bd9Sstevel@tonic-gate temp_td = ohci_td_iommu_to_cpu(ohcip,
68257c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td));
68267c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, td);
68277c478bd9Sstevel@tonic-gate td = temp_td;
68287c478bd9Sstevel@tonic-gate }
68297c478bd9Sstevel@tonic-gate tw->tw_hctd_free_list = NULL;
68307c478bd9Sstevel@tonic-gate }
68317c478bd9Sstevel@tonic-gate
68327c478bd9Sstevel@tonic-gate
68337c478bd9Sstevel@tonic-gate /*
68347c478bd9Sstevel@tonic-gate * Transfer Wrapper functions
68357c478bd9Sstevel@tonic-gate *
68367c478bd9Sstevel@tonic-gate * ohci_create_transfer_wrapper:
68377c478bd9Sstevel@tonic-gate *
683802acac7eSsl147100 * Create a Transaction Wrapper (TW) for non-isoc transfer types
683902acac7eSsl147100 * and this involves the allocating of DMA resources.
68407c478bd9Sstevel@tonic-gate */
68417c478bd9Sstevel@tonic-gate static ohci_trans_wrapper_t *
ohci_create_transfer_wrapper(ohci_state_t * ohcip,ohci_pipe_private_t * pp,size_t length,uint_t usb_flags)68427c478bd9Sstevel@tonic-gate ohci_create_transfer_wrapper(
68437c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
68447c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
68457c478bd9Sstevel@tonic-gate size_t length,
68467c478bd9Sstevel@tonic-gate uint_t usb_flags)
68477c478bd9Sstevel@tonic-gate {
68487c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr;
68497c478bd9Sstevel@tonic-gate int result;
68507c478bd9Sstevel@tonic-gate size_t real_length;
68517c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
685202acac7eSsl147100 ddi_dma_attr_t dma_attr;
685302acac7eSsl147100 int kmem_flag;
685402acac7eSsl147100 int (*dmamem_wait)(caddr_t);
685502acac7eSsl147100 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
68567c478bd9Sstevel@tonic-gate
68577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
68587c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: length = 0x%lx flags = 0x%x",
68597c478bd9Sstevel@tonic-gate length, usb_flags);
68607c478bd9Sstevel@tonic-gate
68617c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
68627c478bd9Sstevel@tonic-gate
686302acac7eSsl147100 /* isochronous pipe should not call into this function */
686402acac7eSsl147100 if ((ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) ==
686502acac7eSsl147100 USB_EP_ATTR_ISOCH) {
686602acac7eSsl147100
686702acac7eSsl147100 return (NULL);
686802acac7eSsl147100 }
686902acac7eSsl147100
6870f9190914Szhigang lu - Sun Microsystems - Beijing China /* SLEEP flag should not be used while holding mutex */
687102acac7eSsl147100 kmem_flag = KM_NOSLEEP;
687202acac7eSsl147100 dmamem_wait = DDI_DMA_DONTWAIT;
687302acac7eSsl147100
68747c478bd9Sstevel@tonic-gate /* Allocate space for the transfer wrapper */
687502acac7eSsl147100 tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t), kmem_flag);
68767c478bd9Sstevel@tonic-gate
68777c478bd9Sstevel@tonic-gate if (tw == NULL) {
68787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
68797c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: kmem_zalloc failed");
68807c478bd9Sstevel@tonic-gate
68817c478bd9Sstevel@tonic-gate return (NULL);
68827c478bd9Sstevel@tonic-gate }
68837c478bd9Sstevel@tonic-gate
6884688b07c5Sgc161489 /* zero-length packet doesn't need to allocate dma memory */
6885688b07c5Sgc161489 if (length == 0) {
6886688b07c5Sgc161489
6887688b07c5Sgc161489 goto dmadone;
6888688b07c5Sgc161489 }
6889688b07c5Sgc161489
689002acac7eSsl147100 /* allow sg lists for transfer wrapper dma memory */
689102acac7eSsl147100 bcopy(&ohcip->ohci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
689202acac7eSsl147100 dma_attr.dma_attr_sgllen = OHCI_DMA_ATTR_TW_SGLLEN;
689302acac7eSsl147100 dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT;
68947c478bd9Sstevel@tonic-gate
68957c478bd9Sstevel@tonic-gate /* Allocate the DMA handle */
68967c478bd9Sstevel@tonic-gate result = ddi_dma_alloc_handle(ohcip->ohci_dip,
689702acac7eSsl147100 &dma_attr, dmamem_wait, 0, &tw->tw_dmahandle);
68987c478bd9Sstevel@tonic-gate
68997c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) {
69007c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
69017c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: Alloc handle failed");
69027c478bd9Sstevel@tonic-gate
69037c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t));
69047c478bd9Sstevel@tonic-gate
69057c478bd9Sstevel@tonic-gate return (NULL);
69067c478bd9Sstevel@tonic-gate }
69077c478bd9Sstevel@tonic-gate
69087c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
69097c478bd9Sstevel@tonic-gate
69107c478bd9Sstevel@tonic-gate /* The host controller will be little endian */
69117c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
69127c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
69137c478bd9Sstevel@tonic-gate
69147c478bd9Sstevel@tonic-gate /* Allocate the memory */
69157c478bd9Sstevel@tonic-gate result = ddi_dma_mem_alloc(tw->tw_dmahandle, length,
691602acac7eSsl147100 &dev_attr, DDI_DMA_CONSISTENT, dmamem_wait, NULL,
69177c478bd9Sstevel@tonic-gate (caddr_t *)&tw->tw_buf, &real_length, &tw->tw_accesshandle);
69187c478bd9Sstevel@tonic-gate
69197c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) {
69207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
69217c478bd9Sstevel@tonic-gate "ohci_create_transfer_wrapper: dma_mem_alloc fail");
69227c478bd9Sstevel@tonic-gate
69237c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle);
69247c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t));
69257c478bd9Sstevel@tonic-gate
69267c478bd9Sstevel@tonic-gate return (NULL);
69277c478bd9Sstevel@tonic-gate }
69287c478bd9Sstevel@tonic-gate
69297c478bd9Sstevel@tonic-gate ASSERT(real_length >= length);
69307c478bd9Sstevel@tonic-gate
69317c478bd9Sstevel@tonic-gate /* Bind the handle */
69327c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
69337c478bd9Sstevel@tonic-gate (caddr_t)tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
693402acac7eSsl147100 dmamem_wait, NULL, &tw->tw_cookie, &tw->tw_ncookies);
69357c478bd9Sstevel@tonic-gate
693602acac7eSsl147100 if (result != DDI_DMA_MAPPED) {
69377c478bd9Sstevel@tonic-gate ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result);
69387c478bd9Sstevel@tonic-gate
69397c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&tw->tw_accesshandle);
69407c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle);
69417c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t));
69427c478bd9Sstevel@tonic-gate
69437c478bd9Sstevel@tonic-gate return (NULL);
69447c478bd9Sstevel@tonic-gate }
69457c478bd9Sstevel@tonic-gate
694602acac7eSsl147100 tw->tw_cookie_idx = 0;
694702acac7eSsl147100 tw->tw_dma_offs = 0;
694802acac7eSsl147100
6949688b07c5Sgc161489 dmadone:
69507c478bd9Sstevel@tonic-gate /*
69517c478bd9Sstevel@tonic-gate * Only allow one wrapper to be added at a time. Insert the
69527c478bd9Sstevel@tonic-gate * new transaction wrapper into the list for this pipe.
69537c478bd9Sstevel@tonic-gate */
69547c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == NULL) {
69557c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw;
69567c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw;
69577c478bd9Sstevel@tonic-gate } else {
69587c478bd9Sstevel@tonic-gate pp->pp_tw_tail->tw_next = tw;
69597c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw;
69607c478bd9Sstevel@tonic-gate }
69617c478bd9Sstevel@tonic-gate
69627c478bd9Sstevel@tonic-gate /* Store the transfer length */
69637c478bd9Sstevel@tonic-gate tw->tw_length = length;
69647c478bd9Sstevel@tonic-gate
69657c478bd9Sstevel@tonic-gate /* Store a back pointer to the pipe private structure */
69667c478bd9Sstevel@tonic-gate tw->tw_pipe_private = pp;
69677c478bd9Sstevel@tonic-gate
69687c478bd9Sstevel@tonic-gate /* Store the transfer type - synchronous or asynchronous */
69697c478bd9Sstevel@tonic-gate tw->tw_flags = usb_flags;
69707c478bd9Sstevel@tonic-gate
69717c478bd9Sstevel@tonic-gate /* Get and Store 32bit ID */
69727c478bd9Sstevel@tonic-gate tw->tw_id = OHCI_GET_ID((void *)tw);
69737c478bd9Sstevel@tonic-gate
6974*3eb8c55cSToomas Soome ASSERT(tw->tw_id != 0);
69757c478bd9Sstevel@tonic-gate
69767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
697702acac7eSsl147100 "ohci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
6978112116d8Sfb209375 (void *)tw, tw->tw_ncookies);
697902acac7eSsl147100
698002acac7eSsl147100 return (tw);
698102acac7eSsl147100 }
698202acac7eSsl147100
698302acac7eSsl147100
698402acac7eSsl147100 /*
698502acac7eSsl147100 * Transfer Wrapper functions
698602acac7eSsl147100 *
698702acac7eSsl147100 * ohci_create_isoc_transfer_wrapper:
698802acac7eSsl147100 *
698902acac7eSsl147100 * Create a Transaction Wrapper (TW) for isoc transfer
699002acac7eSsl147100 * and this involves the allocating of DMA resources.
699102acac7eSsl147100 */
699202acac7eSsl147100 static ohci_trans_wrapper_t *
ohci_create_isoc_transfer_wrapper(ohci_state_t * ohcip,ohci_pipe_private_t * pp,size_t length,usb_isoc_pkt_descr_t * descr,ushort_t pkt_count,size_t td_count,uint_t usb_flags)699302acac7eSsl147100 ohci_create_isoc_transfer_wrapper(
699402acac7eSsl147100 ohci_state_t *ohcip,
699502acac7eSsl147100 ohci_pipe_private_t *pp,
699602acac7eSsl147100 size_t length,
699702acac7eSsl147100 usb_isoc_pkt_descr_t *descr,
699802acac7eSsl147100 ushort_t pkt_count,
699902acac7eSsl147100 size_t td_count,
700002acac7eSsl147100 uint_t usb_flags)
700102acac7eSsl147100 {
700202acac7eSsl147100 ddi_device_acc_attr_t dev_attr;
700302acac7eSsl147100 int result;
700402acac7eSsl147100 size_t real_length, xfer_size;
700502acac7eSsl147100 uint_t ccount;
700602acac7eSsl147100 ohci_trans_wrapper_t *tw;
700702acac7eSsl147100 ddi_dma_attr_t dma_attr;
700802acac7eSsl147100 int kmem_flag;
700902acac7eSsl147100 uint_t i, j, frame_count, residue;
701002acac7eSsl147100 int (*dmamem_wait)(caddr_t);
701102acac7eSsl147100 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
701202acac7eSsl147100 usb_isoc_pkt_descr_t *isoc_pkt_descr = descr;
701302acac7eSsl147100
701402acac7eSsl147100 USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
701502acac7eSsl147100 "ohci_create_isoc_transfer_wrapper: length = 0x%lx flags = 0x%x",
701602acac7eSsl147100 length, usb_flags);
701702acac7eSsl147100
701802acac7eSsl147100 ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
701902acac7eSsl147100
702002acac7eSsl147100 /* non-isochronous pipe should not call into this function */
702102acac7eSsl147100 if ((ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) !=
702202acac7eSsl147100 USB_EP_ATTR_ISOCH) {
702302acac7eSsl147100
702402acac7eSsl147100 return (NULL);
702502acac7eSsl147100 }
702602acac7eSsl147100
702702acac7eSsl147100 /* SLEEP flag should not be used in interrupt context */
702802acac7eSsl147100 if (servicing_interrupt()) {
702902acac7eSsl147100 kmem_flag = KM_NOSLEEP;
703002acac7eSsl147100 dmamem_wait = DDI_DMA_DONTWAIT;
703102acac7eSsl147100 } else {
703202acac7eSsl147100 kmem_flag = KM_SLEEP;
703302acac7eSsl147100 dmamem_wait = DDI_DMA_SLEEP;
703402acac7eSsl147100 }
703502acac7eSsl147100
703602acac7eSsl147100 /* Allocate space for the transfer wrapper */
703702acac7eSsl147100 tw = kmem_zalloc(sizeof (ohci_trans_wrapper_t), kmem_flag);
703802acac7eSsl147100
703902acac7eSsl147100 if (tw == NULL) {
704002acac7eSsl147100 USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
704102acac7eSsl147100 "ohci_create_transfer_wrapper: kmem_zalloc failed");
704202acac7eSsl147100
704302acac7eSsl147100 return (NULL);
704402acac7eSsl147100 }
704502acac7eSsl147100
704602acac7eSsl147100 /* Allocate space for the isoc buffer handles */
704702acac7eSsl147100 tw->tw_isoc_strtlen = sizeof (ohci_isoc_buf_t) * td_count;
704802acac7eSsl147100 if ((tw->tw_isoc_bufs = kmem_zalloc(tw->tw_isoc_strtlen,
704902acac7eSsl147100 kmem_flag)) == NULL) {
705002acac7eSsl147100 USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
705102acac7eSsl147100 "ohci_create_isoc_transfer_wrapper: kmem_alloc "
705202acac7eSsl147100 "isoc buffer failed");
705302acac7eSsl147100 kmem_free(tw, sizeof (ohci_trans_wrapper_t));
705402acac7eSsl147100
705502acac7eSsl147100 return (NULL);
705602acac7eSsl147100 }
705702acac7eSsl147100
705802acac7eSsl147100 /* allow sg lists for transfer wrapper dma memory */
705902acac7eSsl147100 bcopy(&ohcip->ohci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
706002acac7eSsl147100 dma_attr.dma_attr_sgllen = OHCI_DMA_ATTR_TD_SGLLEN;
706102acac7eSsl147100 dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT;
706202acac7eSsl147100
706302acac7eSsl147100 dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
706402acac7eSsl147100
706502acac7eSsl147100 /* The host controller will be little endian */
706602acac7eSsl147100 dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
706702acac7eSsl147100 dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
706802acac7eSsl147100
706902acac7eSsl147100 residue = pkt_count % OHCI_ISOC_PKTS_PER_TD;
707002acac7eSsl147100
707102acac7eSsl147100 for (i = 0; i < td_count; i++) {
707202acac7eSsl147100 tw->tw_isoc_bufs[i].index = i;
707302acac7eSsl147100
707402acac7eSsl147100 if ((i == (td_count - 1)) && (residue != 0)) {
707502acac7eSsl147100 frame_count = residue;
707602acac7eSsl147100 } else {
707702acac7eSsl147100 frame_count = OHCI_ISOC_PKTS_PER_TD;
707802acac7eSsl147100 }
707902acac7eSsl147100
708002acac7eSsl147100 /* Allocate the DMA handle */
708102acac7eSsl147100 result = ddi_dma_alloc_handle(ohcip->ohci_dip, &dma_attr,
708202acac7eSsl147100 dmamem_wait, 0, &tw->tw_isoc_bufs[i].dma_handle);
708302acac7eSsl147100
708402acac7eSsl147100 if (result != DDI_SUCCESS) {
708502acac7eSsl147100 USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
708602acac7eSsl147100 "ohci_create_isoc_transfer_wrapper: "
708702acac7eSsl147100 "Alloc handle failed");
708802acac7eSsl147100
708902acac7eSsl147100 for (j = 0; j < i; j++) {
709002acac7eSsl147100 result = ddi_dma_unbind_handle(
709102acac7eSsl147100 tw->tw_isoc_bufs[j].dma_handle);
709202acac7eSsl147100 ASSERT(result == USB_SUCCESS);
709302acac7eSsl147100 ddi_dma_mem_free(&tw->tw_isoc_bufs[j].
709402acac7eSsl147100 mem_handle);
709502acac7eSsl147100 ddi_dma_free_handle(&tw->tw_isoc_bufs[j].
709602acac7eSsl147100 dma_handle);
709702acac7eSsl147100 }
709802acac7eSsl147100 kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen);
709902acac7eSsl147100 kmem_free(tw, sizeof (ohci_trans_wrapper_t));
710002acac7eSsl147100
710102acac7eSsl147100 return (NULL);
710202acac7eSsl147100 }
710302acac7eSsl147100
710402acac7eSsl147100 /* Compute the memory length */
710502acac7eSsl147100 for (xfer_size = 0, j = 0; j < frame_count; j++) {
710602acac7eSsl147100 ASSERT(isoc_pkt_descr != NULL);
710702acac7eSsl147100 xfer_size += isoc_pkt_descr->isoc_pkt_length;
710802acac7eSsl147100 isoc_pkt_descr++;
710902acac7eSsl147100 }
711002acac7eSsl147100
711102acac7eSsl147100 /* Allocate the memory */
711202acac7eSsl147100 result = ddi_dma_mem_alloc(tw->tw_isoc_bufs[i].dma_handle,
711302acac7eSsl147100 xfer_size, &dev_attr, DDI_DMA_CONSISTENT, dmamem_wait,
711402acac7eSsl147100 NULL, (caddr_t *)&tw->tw_isoc_bufs[i].buf_addr,
711502acac7eSsl147100 &real_length, &tw->tw_isoc_bufs[i].mem_handle);
711602acac7eSsl147100
711702acac7eSsl147100 if (result != DDI_SUCCESS) {
711802acac7eSsl147100 USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
711902acac7eSsl147100 "ohci_create_isoc_transfer_wrapper: "
712002acac7eSsl147100 "dma_mem_alloc %d fail", i);
712102acac7eSsl147100 ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle);
712202acac7eSsl147100
712302acac7eSsl147100 for (j = 0; j < i; j++) {
712402acac7eSsl147100 result = ddi_dma_unbind_handle(
712502acac7eSsl147100 tw->tw_isoc_bufs[j].dma_handle);
712602acac7eSsl147100 ASSERT(result == USB_SUCCESS);
712702acac7eSsl147100 ddi_dma_mem_free(&tw->tw_isoc_bufs[j].
712802acac7eSsl147100 mem_handle);
712902acac7eSsl147100 ddi_dma_free_handle(&tw->tw_isoc_bufs[j].
713002acac7eSsl147100 dma_handle);
713102acac7eSsl147100 }
713202acac7eSsl147100 kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen);
713302acac7eSsl147100 kmem_free(tw, sizeof (ohci_trans_wrapper_t));
713402acac7eSsl147100
713502acac7eSsl147100 return (NULL);
713602acac7eSsl147100 }
713702acac7eSsl147100
713802acac7eSsl147100 ASSERT(real_length >= xfer_size);
713902acac7eSsl147100
714002acac7eSsl147100 /* Bind the handle */
714102acac7eSsl147100 result = ddi_dma_addr_bind_handle(
714202acac7eSsl147100 tw->tw_isoc_bufs[i].dma_handle, NULL,
714302acac7eSsl147100 (caddr_t)tw->tw_isoc_bufs[i].buf_addr, real_length,
714402acac7eSsl147100 DDI_DMA_RDWR|DDI_DMA_CONSISTENT, dmamem_wait, NULL,
714502acac7eSsl147100 &tw->tw_isoc_bufs[i].cookie, &ccount);
714602acac7eSsl147100
714702acac7eSsl147100 if ((result == DDI_DMA_MAPPED) &&
714802acac7eSsl147100 (ccount <= OHCI_DMA_ATTR_TD_SGLLEN)) {
714902acac7eSsl147100 tw->tw_isoc_bufs[i].length = xfer_size;
715002acac7eSsl147100 tw->tw_isoc_bufs[i].ncookies = ccount;
715102acac7eSsl147100
715202acac7eSsl147100 continue;
715302acac7eSsl147100 } else {
715402acac7eSsl147100 USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
715502acac7eSsl147100 "ohci_create_isoc_transfer_wrapper: "
715602acac7eSsl147100 "Bind handle %d failed", i);
715702acac7eSsl147100 if (result == DDI_DMA_MAPPED) {
715802acac7eSsl147100 result = ddi_dma_unbind_handle(
715902acac7eSsl147100 tw->tw_isoc_bufs[i].dma_handle);
716002acac7eSsl147100 ASSERT(result == USB_SUCCESS);
716102acac7eSsl147100 }
716202acac7eSsl147100 ddi_dma_mem_free(&tw->tw_isoc_bufs[i].mem_handle);
716302acac7eSsl147100 ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle);
716402acac7eSsl147100
716502acac7eSsl147100 for (j = 0; j < i; j++) {
716602acac7eSsl147100 result = ddi_dma_unbind_handle(
716702acac7eSsl147100 tw->tw_isoc_bufs[j].dma_handle);
716802acac7eSsl147100 ASSERT(result == USB_SUCCESS);
716902acac7eSsl147100 ddi_dma_mem_free(&tw->tw_isoc_bufs[j].
717002acac7eSsl147100 mem_handle);
717102acac7eSsl147100 ddi_dma_free_handle(&tw->tw_isoc_bufs[j].
717202acac7eSsl147100 dma_handle);
717302acac7eSsl147100 }
717402acac7eSsl147100 kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen);
717502acac7eSsl147100 kmem_free(tw, sizeof (ohci_trans_wrapper_t));
717602acac7eSsl147100
717702acac7eSsl147100 return (NULL);
717802acac7eSsl147100 }
717902acac7eSsl147100 }
718002acac7eSsl147100
718102acac7eSsl147100 /*
718202acac7eSsl147100 * Only allow one wrapper to be added at a time. Insert the
718302acac7eSsl147100 * new transaction wrapper into the list for this pipe.
718402acac7eSsl147100 */
718502acac7eSsl147100 if (pp->pp_tw_head == NULL) {
718602acac7eSsl147100 pp->pp_tw_head = tw;
718702acac7eSsl147100 pp->pp_tw_tail = tw;
718802acac7eSsl147100 } else {
718902acac7eSsl147100 pp->pp_tw_tail->tw_next = tw;
719002acac7eSsl147100 pp->pp_tw_tail = tw;
719102acac7eSsl147100 }
719202acac7eSsl147100
719302acac7eSsl147100 /* Store the transfer length */
719402acac7eSsl147100 tw->tw_length = length;
719502acac7eSsl147100
719602acac7eSsl147100 /* Store the td numbers */
7197d29f5a71Szhigang lu - Sun Microsystems - Beijing China tw->tw_ncookies = (uint_t)td_count;
719802acac7eSsl147100
719902acac7eSsl147100 /* Store a back pointer to the pipe private structure */
720002acac7eSsl147100 tw->tw_pipe_private = pp;
720102acac7eSsl147100
720202acac7eSsl147100 /* Store the transfer type - synchronous or asynchronous */
720302acac7eSsl147100 tw->tw_flags = usb_flags;
720402acac7eSsl147100
720502acac7eSsl147100 /* Get and Store 32bit ID */
720602acac7eSsl147100 tw->tw_id = OHCI_GET_ID((void *)tw);
720702acac7eSsl147100
7208*3eb8c55cSToomas Soome ASSERT(tw->tw_id != 0);
720902acac7eSsl147100
721002acac7eSsl147100 USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
7211112116d8Sfb209375 "ohci_create_isoc_transfer_wrapper: tw = 0x%p", (void *)tw);
72127c478bd9Sstevel@tonic-gate
72137c478bd9Sstevel@tonic-gate return (tw);
72147c478bd9Sstevel@tonic-gate }
72157c478bd9Sstevel@tonic-gate
72167c478bd9Sstevel@tonic-gate
72177c478bd9Sstevel@tonic-gate /*
72187c478bd9Sstevel@tonic-gate * ohci_start_xfer_timer:
72197c478bd9Sstevel@tonic-gate *
72207c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt
72217c478bd9Sstevel@tonic-gate * transfers.
72227c478bd9Sstevel@tonic-gate */
72237c478bd9Sstevel@tonic-gate /* ARGSUSED */
72247c478bd9Sstevel@tonic-gate static void
ohci_start_xfer_timer(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)72257c478bd9Sstevel@tonic-gate ohci_start_xfer_timer(
72267c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
72277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
72287c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
72297c478bd9Sstevel@tonic-gate {
72307c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
7231112116d8Sfb209375 "ohci_start_xfer_timer: tw = 0x%p", (void *)tw);
72327c478bd9Sstevel@tonic-gate
72337c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
72347c478bd9Sstevel@tonic-gate
72357c478bd9Sstevel@tonic-gate /*
72367c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk and for
72377c478bd9Sstevel@tonic-gate * one time Interrupt transfers.
72387c478bd9Sstevel@tonic-gate *
72397c478bd9Sstevel@tonic-gate * NOTE: If timeout is zero; Assume infinite timeout and don't
72407c478bd9Sstevel@tonic-gate * insert this transfer on the timeout list.
72417c478bd9Sstevel@tonic-gate */
72427c478bd9Sstevel@tonic-gate if (tw->tw_timeout) {
72437c478bd9Sstevel@tonic-gate /*
72447c478bd9Sstevel@tonic-gate * Increase timeout value by one second and this extra one
72457c478bd9Sstevel@tonic-gate * second is used to halt the endpoint if given transfer
72467c478bd9Sstevel@tonic-gate * times out.
72477c478bd9Sstevel@tonic-gate */
72487c478bd9Sstevel@tonic-gate tw->tw_timeout++;
72497c478bd9Sstevel@tonic-gate
72507c478bd9Sstevel@tonic-gate /*
72517c478bd9Sstevel@tonic-gate * Add this transfer wrapper into the transfer timeout list.
72527c478bd9Sstevel@tonic-gate */
72537c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list) {
72547c478bd9Sstevel@tonic-gate tw->tw_timeout_next = ohcip->ohci_timeout_list;
72557c478bd9Sstevel@tonic-gate }
72567c478bd9Sstevel@tonic-gate
72577c478bd9Sstevel@tonic-gate ohcip->ohci_timeout_list = tw;
72587c478bd9Sstevel@tonic-gate ohci_start_timer(ohcip);
72597c478bd9Sstevel@tonic-gate }
72607c478bd9Sstevel@tonic-gate }
72617c478bd9Sstevel@tonic-gate
72627c478bd9Sstevel@tonic-gate
72637c478bd9Sstevel@tonic-gate /*
72647c478bd9Sstevel@tonic-gate * ohci_stop_xfer_timer:
72657c478bd9Sstevel@tonic-gate *
72667c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt
72677c478bd9Sstevel@tonic-gate * transfers.
72687c478bd9Sstevel@tonic-gate */
72697c478bd9Sstevel@tonic-gate void
ohci_stop_xfer_timer(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw,uint_t flag)72707c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(
72717c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
72727c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
72737c478bd9Sstevel@tonic-gate uint_t flag)
72747c478bd9Sstevel@tonic-gate {
72757c478bd9Sstevel@tonic-gate timeout_id_t timer_id;
72767c478bd9Sstevel@tonic-gate
72777c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
7278112116d8Sfb209375 "ohci_stop_xfer_timer: tw = 0x%p", (void *)tw);
72797c478bd9Sstevel@tonic-gate
72807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
72817c478bd9Sstevel@tonic-gate
72827c478bd9Sstevel@tonic-gate /*
72837c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk
72847c478bd9Sstevel@tonic-gate * and for one time Interrupt transfers.
72857c478bd9Sstevel@tonic-gate */
72867c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list == NULL) {
72877c478bd9Sstevel@tonic-gate return;
72887c478bd9Sstevel@tonic-gate }
72897c478bd9Sstevel@tonic-gate
72907c478bd9Sstevel@tonic-gate switch (flag) {
72917c478bd9Sstevel@tonic-gate case OHCI_REMOVE_XFER_IFLAST:
72927c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head != tw->tw_hctd_tail) {
72937c478bd9Sstevel@tonic-gate break;
72947c478bd9Sstevel@tonic-gate }
72957c478bd9Sstevel@tonic-gate /* FALLTHRU */
72967c478bd9Sstevel@tonic-gate case OHCI_REMOVE_XFER_ALWAYS:
72977c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(ohcip, tw);
72987c478bd9Sstevel@tonic-gate
72997c478bd9Sstevel@tonic-gate if ((ohcip->ohci_timeout_list == NULL) &&
73007c478bd9Sstevel@tonic-gate (ohcip->ohci_timer_id)) {
73017c478bd9Sstevel@tonic-gate
73027c478bd9Sstevel@tonic-gate timer_id = ohcip->ohci_timer_id;
73037c478bd9Sstevel@tonic-gate
73047c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */
73057c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0;
73067c478bd9Sstevel@tonic-gate
73077c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
73087c478bd9Sstevel@tonic-gate
73097c478bd9Sstevel@tonic-gate (void) untimeout(timer_id);
73107c478bd9Sstevel@tonic-gate
73117c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
73127c478bd9Sstevel@tonic-gate }
73137c478bd9Sstevel@tonic-gate break;
73147c478bd9Sstevel@tonic-gate default:
73157c478bd9Sstevel@tonic-gate break;
73167c478bd9Sstevel@tonic-gate }
73177c478bd9Sstevel@tonic-gate }
73187c478bd9Sstevel@tonic-gate
73197c478bd9Sstevel@tonic-gate
73207c478bd9Sstevel@tonic-gate /*
73217c478bd9Sstevel@tonic-gate * ohci_xfer_timeout_handler:
73227c478bd9Sstevel@tonic-gate *
73237c478bd9Sstevel@tonic-gate * Control or bulk transfer timeout handler.
73247c478bd9Sstevel@tonic-gate */
73257c478bd9Sstevel@tonic-gate static void
ohci_xfer_timeout_handler(void * arg)73267c478bd9Sstevel@tonic-gate ohci_xfer_timeout_handler(void *arg)
73277c478bd9Sstevel@tonic-gate {
73287c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = (ohci_state_t *)arg;
73297c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *exp_xfer_list_head = NULL;
73307c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *exp_xfer_list_tail = NULL;
73317c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw, *next;
73327c478bd9Sstevel@tonic-gate ohci_td_t *td;
73337c478bd9Sstevel@tonic-gate usb_flags_t flags;
73347c478bd9Sstevel@tonic-gate
73357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
7336112116d8Sfb209375 "ohci_xfer_timeout_handler: ohcip = 0x%p", (void *)ohcip);
73377c478bd9Sstevel@tonic-gate
73387c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
73397c478bd9Sstevel@tonic-gate
73407c478bd9Sstevel@tonic-gate /* Set the required flags */
73417c478bd9Sstevel@tonic-gate flags = OHCI_FLAGS_NOSLEEP | OHCI_FLAGS_DMA_SYNC;
73427c478bd9Sstevel@tonic-gate
73437c478bd9Sstevel@tonic-gate /*
73447c478bd9Sstevel@tonic-gate * Check whether still timeout handler is valid.
73457c478bd9Sstevel@tonic-gate */
73467c478bd9Sstevel@tonic-gate if (ohcip->ohci_timer_id) {
73477c478bd9Sstevel@tonic-gate
73487c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */
73497c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0;
73507c478bd9Sstevel@tonic-gate } else {
73517c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
73527c478bd9Sstevel@tonic-gate
73537c478bd9Sstevel@tonic-gate return;
73547c478bd9Sstevel@tonic-gate }
73557c478bd9Sstevel@tonic-gate
73567c478bd9Sstevel@tonic-gate /* Get the transfer timeout list head */
73577c478bd9Sstevel@tonic-gate tw = ohcip->ohci_timeout_list;
73587c478bd9Sstevel@tonic-gate
73597c478bd9Sstevel@tonic-gate /*
73607c478bd9Sstevel@tonic-gate * Process ohci timeout list and look whether the timer
73617c478bd9Sstevel@tonic-gate * has expired for any transfers. Create a temporary list
73627c478bd9Sstevel@tonic-gate * of expired transfers and process them later.
73637c478bd9Sstevel@tonic-gate */
73647c478bd9Sstevel@tonic-gate while (tw) {
73657c478bd9Sstevel@tonic-gate /* Get the transfer on the timeout list */
73667c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next;
73677c478bd9Sstevel@tonic-gate
73687c478bd9Sstevel@tonic-gate tw->tw_timeout--;
73697c478bd9Sstevel@tonic-gate
73707c478bd9Sstevel@tonic-gate /*
73717c478bd9Sstevel@tonic-gate * Set the sKip bit to stop all transactions on
73727c478bd9Sstevel@tonic-gate * this pipe
73737c478bd9Sstevel@tonic-gate */
73747c478bd9Sstevel@tonic-gate if (tw->tw_timeout == 1) {
73757c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip,
73767c478bd9Sstevel@tonic-gate tw->tw_pipe_private, SET_sKip, flags);
73777c478bd9Sstevel@tonic-gate
73787c478bd9Sstevel@tonic-gate /* Reset dma sync flag */
73797c478bd9Sstevel@tonic-gate flags &= ~OHCI_FLAGS_DMA_SYNC;
73807c478bd9Sstevel@tonic-gate }
73817c478bd9Sstevel@tonic-gate
73827c478bd9Sstevel@tonic-gate /* Remove tw from the timeout list */
7383d29f5a71Szhigang lu - Sun Microsystems - Beijing China if (tw->tw_timeout == 0) {
73847c478bd9Sstevel@tonic-gate
73857c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(ohcip, tw);
73867c478bd9Sstevel@tonic-gate
73877c478bd9Sstevel@tonic-gate /* Add tw to the end of expire list */
73887c478bd9Sstevel@tonic-gate if (exp_xfer_list_head) {
73897c478bd9Sstevel@tonic-gate exp_xfer_list_tail->tw_timeout_next = tw;
73907c478bd9Sstevel@tonic-gate } else {
73917c478bd9Sstevel@tonic-gate exp_xfer_list_head = tw;
73927c478bd9Sstevel@tonic-gate }
73937c478bd9Sstevel@tonic-gate exp_xfer_list_tail = tw;
73947c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL;
73957c478bd9Sstevel@tonic-gate }
73967c478bd9Sstevel@tonic-gate
73977c478bd9Sstevel@tonic-gate tw = next;
73987c478bd9Sstevel@tonic-gate }
73997c478bd9Sstevel@tonic-gate
74007c478bd9Sstevel@tonic-gate /* Get the expired transfer timeout list head */
74017c478bd9Sstevel@tonic-gate tw = exp_xfer_list_head;
74027c478bd9Sstevel@tonic-gate
74037c478bd9Sstevel@tonic-gate if (tw && (flags & OHCI_FLAGS_DMA_SYNC)) {
74047c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */
74057c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip);
74067c478bd9Sstevel@tonic-gate }
74077c478bd9Sstevel@tonic-gate
74087c478bd9Sstevel@tonic-gate /*
74097c478bd9Sstevel@tonic-gate * Process the expired transfers by notifing the corrsponding
74107c478bd9Sstevel@tonic-gate * client driver through the exception callback.
74117c478bd9Sstevel@tonic-gate */
74127c478bd9Sstevel@tonic-gate while (tw) {
74137c478bd9Sstevel@tonic-gate /* Get the transfer on the expired transfer timeout list */
74147c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next;
74157c478bd9Sstevel@tonic-gate
74167c478bd9Sstevel@tonic-gate td = tw->tw_hctd_head;
74177c478bd9Sstevel@tonic-gate
74187c478bd9Sstevel@tonic-gate while (td) {
74197c478bd9Sstevel@tonic-gate /* Set TD state to TIMEOUT */
74207c478bd9Sstevel@tonic-gate Set_TD(td->hctd_state, HC_TD_TIMEOUT);
74217c478bd9Sstevel@tonic-gate
74227c478bd9Sstevel@tonic-gate /* Get the next TD from the wrapper */
74237c478bd9Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip,
74247c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td));
74257c478bd9Sstevel@tonic-gate }
74267c478bd9Sstevel@tonic-gate
74277c478bd9Sstevel@tonic-gate ohci_handle_error(ohcip, tw->tw_hctd_head, USB_CR_TIMEOUT);
74287c478bd9Sstevel@tonic-gate
74297c478bd9Sstevel@tonic-gate tw = next;
74307c478bd9Sstevel@tonic-gate }
74317c478bd9Sstevel@tonic-gate
74327c478bd9Sstevel@tonic-gate ohci_start_timer(ohcip);
74337c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
74347c478bd9Sstevel@tonic-gate }
74357c478bd9Sstevel@tonic-gate
74367c478bd9Sstevel@tonic-gate
74377c478bd9Sstevel@tonic-gate /*
74387c478bd9Sstevel@tonic-gate * ohci_remove_tw_from_timeout_list:
74397c478bd9Sstevel@tonic-gate *
74407c478bd9Sstevel@tonic-gate * Remove Control or bulk transfer from the timeout list.
74417c478bd9Sstevel@tonic-gate */
74427c478bd9Sstevel@tonic-gate static void
ohci_remove_tw_from_timeout_list(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw)74437c478bd9Sstevel@tonic-gate ohci_remove_tw_from_timeout_list(
74447c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
74457c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
74467c478bd9Sstevel@tonic-gate {
74477c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *prev, *next;
74487c478bd9Sstevel@tonic-gate
74497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
7450112116d8Sfb209375 "ohci_remove_tw_from_timeout_list: tw = 0x%p", (void *)tw);
74517c478bd9Sstevel@tonic-gate
74527c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
74537c478bd9Sstevel@tonic-gate
74547c478bd9Sstevel@tonic-gate if (ohcip->ohci_timeout_list == tw) {
74557c478bd9Sstevel@tonic-gate ohcip->ohci_timeout_list = tw->tw_timeout_next;
74567c478bd9Sstevel@tonic-gate } else {
74577c478bd9Sstevel@tonic-gate prev = ohcip->ohci_timeout_list;
74587c478bd9Sstevel@tonic-gate next = prev->tw_timeout_next;
74597c478bd9Sstevel@tonic-gate
74607c478bd9Sstevel@tonic-gate while (next && (next != tw)) {
74617c478bd9Sstevel@tonic-gate prev = next;
74627c478bd9Sstevel@tonic-gate next = next->tw_timeout_next;
74637c478bd9Sstevel@tonic-gate }
74647c478bd9Sstevel@tonic-gate
74657c478bd9Sstevel@tonic-gate if (next == tw) {
74667c478bd9Sstevel@tonic-gate prev->tw_timeout_next = next->tw_timeout_next;
74677c478bd9Sstevel@tonic-gate }
74687c478bd9Sstevel@tonic-gate }
74697c478bd9Sstevel@tonic-gate
74707c478bd9Sstevel@tonic-gate /* Reset the xfer timeout */
74717c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL;
74727c478bd9Sstevel@tonic-gate }
74737c478bd9Sstevel@tonic-gate
74747c478bd9Sstevel@tonic-gate
74757c478bd9Sstevel@tonic-gate /*
74767c478bd9Sstevel@tonic-gate * ohci_start_timer:
74777c478bd9Sstevel@tonic-gate *
74787c478bd9Sstevel@tonic-gate * Start the ohci timer
74797c478bd9Sstevel@tonic-gate */
74807c478bd9Sstevel@tonic-gate static void
ohci_start_timer(ohci_state_t * ohcip)74817c478bd9Sstevel@tonic-gate ohci_start_timer(ohci_state_t *ohcip)
74827c478bd9Sstevel@tonic-gate {
74837c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
7484112116d8Sfb209375 "ohci_start_timer: ohcip = 0x%p", (void *)ohcip);
74857c478bd9Sstevel@tonic-gate
74867c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
74877c478bd9Sstevel@tonic-gate
74887c478bd9Sstevel@tonic-gate /*
74897c478bd9Sstevel@tonic-gate * Start the global timer only if currently timer is not
74907c478bd9Sstevel@tonic-gate * running and if there are any transfers on the timeout
74917c478bd9Sstevel@tonic-gate * list. This timer will be per USB Host Controller.
74927c478bd9Sstevel@tonic-gate */
74937c478bd9Sstevel@tonic-gate if ((!ohcip->ohci_timer_id) && (ohcip->ohci_timeout_list)) {
74947c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = timeout(ohci_xfer_timeout_handler,
74957c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(1000000));
74967c478bd9Sstevel@tonic-gate }
74977c478bd9Sstevel@tonic-gate }
74987c478bd9Sstevel@tonic-gate
74997c478bd9Sstevel@tonic-gate
75007c478bd9Sstevel@tonic-gate /*
75017c478bd9Sstevel@tonic-gate * ohci_deallocate_tw_resources:
75027c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
75037c478bd9Sstevel@tonic-gate *
75047c478bd9Sstevel@tonic-gate * Deallocate of a Transaction Wrapper (TW) and this involves the freeing of
75057c478bd9Sstevel@tonic-gate * of DMA resources.
75067c478bd9Sstevel@tonic-gate */
75077c478bd9Sstevel@tonic-gate void
ohci_deallocate_tw_resources(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)75087c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(
75097c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
75107c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
75117c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
75127c478bd9Sstevel@tonic-gate {
75137c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *prev, *next;
75147c478bd9Sstevel@tonic-gate
75157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
7516112116d8Sfb209375 "ohci_deallocate_tw_resources: tw = 0x%p", (void *)tw);
75177c478bd9Sstevel@tonic-gate
75187c478bd9Sstevel@tonic-gate /*
75197c478bd9Sstevel@tonic-gate * If the transfer wrapper has no Host Controller (HC)
75207c478bd9Sstevel@tonic-gate * Transfer Descriptors (TD) associated with it, then
75217c478bd9Sstevel@tonic-gate * remove the transfer wrapper.
75227c478bd9Sstevel@tonic-gate */
75237c478bd9Sstevel@tonic-gate if (tw->tw_hctd_head) {
75247c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail != NULL);
75257c478bd9Sstevel@tonic-gate
75267c478bd9Sstevel@tonic-gate return;
75277c478bd9Sstevel@tonic-gate }
75287c478bd9Sstevel@tonic-gate
75297c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_tail == NULL);
75307c478bd9Sstevel@tonic-gate
75317c478bd9Sstevel@tonic-gate /* Make sure we return all the unused td's to the pool as well */
75327c478bd9Sstevel@tonic-gate ohci_free_tw_tds_resources(ohcip, tw);
75337c478bd9Sstevel@tonic-gate
75347c478bd9Sstevel@tonic-gate /*
75357c478bd9Sstevel@tonic-gate * If pp->pp_tw_head and pp->pp_tw_tail are pointing to
75367c478bd9Sstevel@tonic-gate * given TW then set the head and tail equal to NULL.
75377c478bd9Sstevel@tonic-gate * Otherwise search for this TW in the linked TW's list
75387c478bd9Sstevel@tonic-gate * and then remove this TW from the list.
75397c478bd9Sstevel@tonic-gate */
75407c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == tw) {
75417c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) {
75427c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL;
75437c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL;
75447c478bd9Sstevel@tonic-gate } else {
75457c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw->tw_next;
75467c478bd9Sstevel@tonic-gate }
75477c478bd9Sstevel@tonic-gate } else {
75487c478bd9Sstevel@tonic-gate prev = pp->pp_tw_head;
75497c478bd9Sstevel@tonic-gate next = prev->tw_next;
75507c478bd9Sstevel@tonic-gate
75517c478bd9Sstevel@tonic-gate while (next && (next != tw)) {
75527c478bd9Sstevel@tonic-gate prev = next;
75537c478bd9Sstevel@tonic-gate next = next->tw_next;
75547c478bd9Sstevel@tonic-gate }
75557c478bd9Sstevel@tonic-gate
75567c478bd9Sstevel@tonic-gate if (next == tw) {
75577c478bd9Sstevel@tonic-gate prev->tw_next = next->tw_next;
75587c478bd9Sstevel@tonic-gate
75597c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) {
75607c478bd9Sstevel@tonic-gate pp->pp_tw_tail = prev;
75617c478bd9Sstevel@tonic-gate }
75627c478bd9Sstevel@tonic-gate }
75637c478bd9Sstevel@tonic-gate }
75647c478bd9Sstevel@tonic-gate
75657c478bd9Sstevel@tonic-gate ohci_free_tw(ohcip, tw);
75667c478bd9Sstevel@tonic-gate }
75677c478bd9Sstevel@tonic-gate
75687c478bd9Sstevel@tonic-gate
75697c478bd9Sstevel@tonic-gate /*
75707c478bd9Sstevel@tonic-gate * ohci_free_dma_resources:
75717c478bd9Sstevel@tonic-gate *
75727c478bd9Sstevel@tonic-gate * Free dma resources of a Transfer Wrapper (TW) and also free the TW.
75737c478bd9Sstevel@tonic-gate */
75747c478bd9Sstevel@tonic-gate static void
ohci_free_dma_resources(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)75757c478bd9Sstevel@tonic-gate ohci_free_dma_resources(
75767c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
75777c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
75787c478bd9Sstevel@tonic-gate {
75797c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
75807c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head;
75817c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw, *tw;
75827c478bd9Sstevel@tonic-gate
75837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
75847c478bd9Sstevel@tonic-gate "ohci_free_dma_resources: ph = 0x%p", (void *)ph);
75857c478bd9Sstevel@tonic-gate
75867c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
75877c478bd9Sstevel@tonic-gate
75887c478bd9Sstevel@tonic-gate /* Process the Transfer Wrappers */
75897c478bd9Sstevel@tonic-gate next_tw = head_tw;
75907c478bd9Sstevel@tonic-gate while (next_tw) {
75917c478bd9Sstevel@tonic-gate tw = next_tw;
75927c478bd9Sstevel@tonic-gate next_tw = tw->tw_next;
75937c478bd9Sstevel@tonic-gate
75947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
75957c478bd9Sstevel@tonic-gate "ohci_free_dma_resources: Free TW = 0x%p", (void *)tw);
75967c478bd9Sstevel@tonic-gate
75977c478bd9Sstevel@tonic-gate ohci_free_tw(ohcip, tw);
75987c478bd9Sstevel@tonic-gate }
75997c478bd9Sstevel@tonic-gate
76007c478bd9Sstevel@tonic-gate /* Adjust the head and tail pointers */
76017c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL;
76027c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL;
76037c478bd9Sstevel@tonic-gate }
76047c478bd9Sstevel@tonic-gate
76057c478bd9Sstevel@tonic-gate
76067c478bd9Sstevel@tonic-gate /*
76077c478bd9Sstevel@tonic-gate * ohci_free_tw:
76087c478bd9Sstevel@tonic-gate *
76097c478bd9Sstevel@tonic-gate * Free the Transfer Wrapper (TW).
76107c478bd9Sstevel@tonic-gate */
76117c478bd9Sstevel@tonic-gate static void
ohci_free_tw(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw)76127c478bd9Sstevel@tonic-gate ohci_free_tw(
76137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
76147c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
76157c478bd9Sstevel@tonic-gate {
761602acac7eSsl147100 int rval, i;
76177c478bd9Sstevel@tonic-gate
76187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
7619112116d8Sfb209375 "ohci_free_tw: tw = 0x%p", (void *)tw);
76207c478bd9Sstevel@tonic-gate
76217c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
7622*3eb8c55cSToomas Soome ASSERT(tw->tw_id != 0);
76237c478bd9Sstevel@tonic-gate
76247c478bd9Sstevel@tonic-gate /* Free 32bit ID */
76257c478bd9Sstevel@tonic-gate OHCI_FREE_ID((uint32_t)tw->tw_id);
76267c478bd9Sstevel@tonic-gate
762702acac7eSsl147100 if (tw->tw_isoc_strtlen > 0) {
762802acac7eSsl147100 ASSERT(tw->tw_isoc_bufs != NULL);
762902acac7eSsl147100 for (i = 0; i < tw->tw_ncookies; i++) {
763002acac7eSsl147100 if (tw->tw_isoc_bufs[i].ncookies > 0) {
763102acac7eSsl147100 rval = ddi_dma_unbind_handle(
763202acac7eSsl147100 tw->tw_isoc_bufs[i].dma_handle);
763302acac7eSsl147100 ASSERT(rval == USB_SUCCESS);
763402acac7eSsl147100 }
763502acac7eSsl147100 ddi_dma_mem_free(&tw->tw_isoc_bufs[i].mem_handle);
763602acac7eSsl147100 ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle);
763702acac7eSsl147100 }
763802acac7eSsl147100 kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen);
763902acac7eSsl147100 } else if (tw->tw_dmahandle != NULL) {
764002acac7eSsl147100 if (tw->tw_ncookies > 0) {
76417c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle(tw->tw_dmahandle);
76427c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
764302acac7eSsl147100 }
76447c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&tw->tw_accesshandle);
76457c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle);
764602acac7eSsl147100 }
76477c478bd9Sstevel@tonic-gate
76487c478bd9Sstevel@tonic-gate /* Free transfer wrapper */
76497c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ohci_trans_wrapper_t));
76507c478bd9Sstevel@tonic-gate }
76517c478bd9Sstevel@tonic-gate
76527c478bd9Sstevel@tonic-gate
76537c478bd9Sstevel@tonic-gate /*
76547c478bd9Sstevel@tonic-gate * Interrupt Handling functions
76557c478bd9Sstevel@tonic-gate */
76567c478bd9Sstevel@tonic-gate
76577c478bd9Sstevel@tonic-gate /*
76587c478bd9Sstevel@tonic-gate * ohci_intr:
76597c478bd9Sstevel@tonic-gate *
76607c478bd9Sstevel@tonic-gate * OpenHCI (OHCI) interrupt handling routine.
76617c478bd9Sstevel@tonic-gate */
76627c478bd9Sstevel@tonic-gate static uint_t
ohci_intr(caddr_t arg1,caddr_t arg2)76639c75c6bfSgovinda ohci_intr(caddr_t arg1, caddr_t arg2)
76647c478bd9Sstevel@tonic-gate {
76659c75c6bfSgovinda ohci_state_t *ohcip = (ohci_state_t *)arg1;
76667c478bd9Sstevel@tonic-gate uint_t intr;
76677c478bd9Sstevel@tonic-gate ohci_td_t *done_head = NULL;
76687c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts = &ohcip->ohci_save_intr_sts;
76697c478bd9Sstevel@tonic-gate
76707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
7671112116d8Sfb209375 "ohci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p",
7672112116d8Sfb209375 (void *)arg1, (void *)arg2);
76737c478bd9Sstevel@tonic-gate
76747c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
76757c478bd9Sstevel@tonic-gate
7676fffe0b30Sqz150045 /* Any interrupt is not handled for the suspended device. */
7677fffe0b30Sqz150045 if (ohcip->ohci_hc_soft_state == OHCI_CTLR_SUSPEND_STATE) {
7678fffe0b30Sqz150045 mutex_exit(&ohcip->ohci_int_mutex);
7679fffe0b30Sqz150045
7680fffe0b30Sqz150045 return (DDI_INTR_UNCLAIMED);
7681fffe0b30Sqz150045 }
7682fffe0b30Sqz150045
76837c478bd9Sstevel@tonic-gate /*
76847c478bd9Sstevel@tonic-gate * Suppose if we switched to the polled mode from the normal
76857c478bd9Sstevel@tonic-gate * mode when interrupt handler is executing then we need to
76867c478bd9Sstevel@tonic-gate * save the interrupt status information in the polled mode
76877c478bd9Sstevel@tonic-gate * to avoid race conditions. The following flag will be set
76887c478bd9Sstevel@tonic-gate * and reset on entering & exiting of ohci interrupt handler
76897c478bd9Sstevel@tonic-gate * respectively. This flag will be used in the polled mode
76907c478bd9Sstevel@tonic-gate * to check whether the interrupt handler was running when we
76917c478bd9Sstevel@tonic-gate * switched to the polled mode from the normal mode.
76927c478bd9Sstevel@tonic-gate */
76937c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag = OHCI_INTR_HANDLING;
76947c478bd9Sstevel@tonic-gate
76957c478bd9Sstevel@tonic-gate /* Temporarily turn off interrupts */
76967c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_MIE);
76977c478bd9Sstevel@tonic-gate
76987c478bd9Sstevel@tonic-gate /*
76997c478bd9Sstevel@tonic-gate * Handle any missed ohci interrupt especially WriteDoneHead
77007c478bd9Sstevel@tonic-gate * and SOF interrupts because of previous polled mode switch.
77017c478bd9Sstevel@tonic-gate */
77027c478bd9Sstevel@tonic-gate ohci_handle_missed_intr(ohcip);
77037c478bd9Sstevel@tonic-gate
77047c478bd9Sstevel@tonic-gate /*
77057c478bd9Sstevel@tonic-gate * Now process the actual ohci interrupt events that caused
77067c478bd9Sstevel@tonic-gate * invocation of this ohci interrupt handler.
77077c478bd9Sstevel@tonic-gate */
77087c478bd9Sstevel@tonic-gate
77097c478bd9Sstevel@tonic-gate /*
77107c478bd9Sstevel@tonic-gate * Updating the WriteDoneHead interrupt:
77117c478bd9Sstevel@tonic-gate *
77127c478bd9Sstevel@tonic-gate * (a) Host Controller
77137c478bd9Sstevel@tonic-gate *
77147c478bd9Sstevel@tonic-gate * - First Host controller (HC) checks whether WDH bit
77157c478bd9Sstevel@tonic-gate * in the interrupt status register is cleared.
77167c478bd9Sstevel@tonic-gate *
77177c478bd9Sstevel@tonic-gate * - If WDH bit is cleared then HC writes new done head
77187c478bd9Sstevel@tonic-gate * list information into the HCCA done head field.
77197c478bd9Sstevel@tonic-gate *
77207c478bd9Sstevel@tonic-gate * - Set WDH bit in the interrupt status register.
77217c478bd9Sstevel@tonic-gate *
77227c478bd9Sstevel@tonic-gate * (b) Host Controller Driver (HCD)
77237c478bd9Sstevel@tonic-gate *
77247c478bd9Sstevel@tonic-gate * - First read the interrupt status register. The HCCA
77257c478bd9Sstevel@tonic-gate * done head and WDH bit may be set or may not be set
77267c478bd9Sstevel@tonic-gate * while reading the interrupt status register.
77277c478bd9Sstevel@tonic-gate *
77287c478bd9Sstevel@tonic-gate * - Read the HCCA done head list. By this time may be
77297c478bd9Sstevel@tonic-gate * HC has updated HCCA done head and WDH bit in ohci
77307c478bd9Sstevel@tonic-gate * interrupt status register.
77317c478bd9Sstevel@tonic-gate *
77327c478bd9Sstevel@tonic-gate * - If done head is non-null and if WDH bit is not set
77337c478bd9Sstevel@tonic-gate * then Host Controller has updated HCCA done head &
77347c478bd9Sstevel@tonic-gate * WDH bit in the interrupt stats register in between
77357c478bd9Sstevel@tonic-gate * reading the interrupt status register & HCCA done
77367c478bd9Sstevel@tonic-gate * head. In that case, definitely WDH bit will be set
77377c478bd9Sstevel@tonic-gate * in the interrupt status register & driver can take
77387c478bd9Sstevel@tonic-gate * it for granted.
77397c478bd9Sstevel@tonic-gate *
77407c478bd9Sstevel@tonic-gate * Now read the Interrupt Status & Interrupt enable register
77417c478bd9Sstevel@tonic-gate * to determine the exact interrupt events.
77427c478bd9Sstevel@tonic-gate */
77437c478bd9Sstevel@tonic-gate intr = ohci_intr_sts->ohci_curr_intr_sts =
77447c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_intr_status) & Get_OpReg(hcr_intr_enable));
77457c478bd9Sstevel@tonic-gate
77467c478bd9Sstevel@tonic-gate if (ohcip->ohci_hccap) {
77477c478bd9Sstevel@tonic-gate /* Sync HCCA area */
77487c478bd9Sstevel@tonic-gate Sync_HCCA(ohcip);
77497c478bd9Sstevel@tonic-gate
77507c478bd9Sstevel@tonic-gate /* Read and Save the HCCA DoneHead value */
77517c478bd9Sstevel@tonic-gate done_head = ohci_intr_sts->ohci_curr_done_lst =
77527c478bd9Sstevel@tonic-gate (ohci_td_t *)(uintptr_t)
7753e026ab87Sgc161489 (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) &
7754e026ab87Sgc161489 HCCA_DONE_HEAD_MASK);
77557c478bd9Sstevel@tonic-gate
77567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
77577c478bd9Sstevel@tonic-gate "ohci_intr: Done head! 0x%p", (void *)done_head);
77587c478bd9Sstevel@tonic-gate }
77597c478bd9Sstevel@tonic-gate
77607c478bd9Sstevel@tonic-gate /* Update kstat values */
77617c478bd9Sstevel@tonic-gate ohci_do_intrs_stats(ohcip, intr);
77627c478bd9Sstevel@tonic-gate
77637c478bd9Sstevel@tonic-gate /*
7764e026ab87Sgc161489 * Look at the HccaDoneHead, if it is a non-zero valid address,
7765e026ab87Sgc161489 * a done list update interrupt is indicated. Otherwise, this
7766e026ab87Sgc161489 * intr bit is cleared.
77677c478bd9Sstevel@tonic-gate */
7768688b07c5Sgc161489 if (ohci_check_done_head(ohcip, done_head) == USB_SUCCESS) {
77697c478bd9Sstevel@tonic-gate
7770688b07c5Sgc161489 /* Set the WriteDoneHead bit in the interrupt events */
7771e026ab87Sgc161489 intr |= HCR_INTR_WDH;
7772688b07c5Sgc161489 } else {
7773688b07c5Sgc161489
7774688b07c5Sgc161489 /* Clear the WriteDoneHead bit */
7775688b07c5Sgc161489 intr &= ~HCR_INTR_WDH;
77767c478bd9Sstevel@tonic-gate }
77777c478bd9Sstevel@tonic-gate
77787c478bd9Sstevel@tonic-gate /*
77797c478bd9Sstevel@tonic-gate * We could have gotten a spurious interrupts. If so, do not
77807c478bd9Sstevel@tonic-gate * claim it. This is quite possible on some architectures
77817c478bd9Sstevel@tonic-gate * where more than one PCI slots share the IRQs. If so, the
77827c478bd9Sstevel@tonic-gate * associated driver's interrupt routine may get called even
77837c478bd9Sstevel@tonic-gate * if the interrupt is not meant for them.
77847c478bd9Sstevel@tonic-gate *
77857c478bd9Sstevel@tonic-gate * By unclaiming the interrupt, the other driver gets chance
77867c478bd9Sstevel@tonic-gate * to service its interrupt.
77877c478bd9Sstevel@tonic-gate */
77887c478bd9Sstevel@tonic-gate if (!intr) {
77897c478bd9Sstevel@tonic-gate
77907c478bd9Sstevel@tonic-gate /* Reset the interrupt handler flag */
77917c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_HANDLING;
77927c478bd9Sstevel@tonic-gate
77937c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_MIE);
77947c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
77957c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED);
77967c478bd9Sstevel@tonic-gate }
77977c478bd9Sstevel@tonic-gate
77987c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
77997c478bd9Sstevel@tonic-gate "Interrupt status 0x%x", intr);
78007c478bd9Sstevel@tonic-gate
78017c478bd9Sstevel@tonic-gate /*
78027c478bd9Sstevel@tonic-gate * Check for Frame Number Overflow.
78037c478bd9Sstevel@tonic-gate */
78047c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_FNO) {
78057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78067c478bd9Sstevel@tonic-gate "ohci_intr: Frame Number Overflow");
78077c478bd9Sstevel@tonic-gate
78087c478bd9Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohcip);
78097c478bd9Sstevel@tonic-gate }
78107c478bd9Sstevel@tonic-gate
78117c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SOF) {
78127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78137c478bd9Sstevel@tonic-gate "ohci_intr: Start of Frame");
78147c478bd9Sstevel@tonic-gate
78157c478bd9Sstevel@tonic-gate /* Set ohci_sof_flag indicating SOF interrupt occurred */
78167c478bd9Sstevel@tonic-gate ohcip->ohci_sof_flag = B_TRUE;
78177c478bd9Sstevel@tonic-gate
78187c478bd9Sstevel@tonic-gate /* Disabel SOF interrupt */
78197c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SOF);
78207c478bd9Sstevel@tonic-gate
78217c478bd9Sstevel@tonic-gate /*
78227c478bd9Sstevel@tonic-gate * Call cv_broadcast on every SOF interrupt to wakeup
78237c478bd9Sstevel@tonic-gate * all the threads that are waiting the SOF. Calling
78247c478bd9Sstevel@tonic-gate * cv_broadcast on every SOF has no effect even if no
78257c478bd9Sstevel@tonic-gate * threads are waiting for the SOF.
78267c478bd9Sstevel@tonic-gate */
78277c478bd9Sstevel@tonic-gate cv_broadcast(&ohcip->ohci_SOF_cv);
78287c478bd9Sstevel@tonic-gate }
78297c478bd9Sstevel@tonic-gate
78307c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SO) {
78317c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78327c478bd9Sstevel@tonic-gate "ohci_intr: Schedule overrun");
78337c478bd9Sstevel@tonic-gate
78347c478bd9Sstevel@tonic-gate ohcip->ohci_so_error++;
78357c478bd9Sstevel@tonic-gate }
78367c478bd9Sstevel@tonic-gate
78377c478bd9Sstevel@tonic-gate if ((intr & HCR_INTR_WDH) && (done_head)) {
78387c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78397c478bd9Sstevel@tonic-gate "ohci_intr: Done Head");
78407c478bd9Sstevel@tonic-gate
78417c478bd9Sstevel@tonic-gate /*
78427c478bd9Sstevel@tonic-gate * Currently if we are processing one WriteDoneHead
78437c478bd9Sstevel@tonic-gate * interrupt and also if we switched to the polled
78447c478bd9Sstevel@tonic-gate * mode at least once during this time, then there
78457c478bd9Sstevel@tonic-gate * may be chance that Host Controller generates one
78467c478bd9Sstevel@tonic-gate * more Write DoneHead or Start of Frame interrupts
78477c478bd9Sstevel@tonic-gate * for the normal since the polled code clears WDH &
78487c478bd9Sstevel@tonic-gate * SOF interrupt bits before returning to the normal
78497c478bd9Sstevel@tonic-gate * mode. Under this condition, we must not clear the
78507c478bd9Sstevel@tonic-gate * HCCA done head field & also we must not clear WDH
78517c478bd9Sstevel@tonic-gate * interrupt bit in the interrupt status register.
78527c478bd9Sstevel@tonic-gate */
78537c478bd9Sstevel@tonic-gate if (done_head == (ohci_td_t *)(uintptr_t)
7854e026ab87Sgc161489 (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) &
7855e026ab87Sgc161489 HCCA_DONE_HEAD_MASK)) {
78567c478bd9Sstevel@tonic-gate
78577c478bd9Sstevel@tonic-gate /* Reset the done head to NULL */
78583e1e1e62SToomas Soome Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, 0);
78597c478bd9Sstevel@tonic-gate } else {
78607c478bd9Sstevel@tonic-gate intr &= ~HCR_INTR_WDH;
78617c478bd9Sstevel@tonic-gate }
78627c478bd9Sstevel@tonic-gate
78637c478bd9Sstevel@tonic-gate /* Clear the current done head field */
78647c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_curr_done_lst = NULL;
78657c478bd9Sstevel@tonic-gate
78667c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head);
78677c478bd9Sstevel@tonic-gate }
78687c478bd9Sstevel@tonic-gate
78697c478bd9Sstevel@tonic-gate /* Process endpoint reclaimation list */
78707c478bd9Sstevel@tonic-gate if (ohcip->ohci_reclaim_list) {
78717c478bd9Sstevel@tonic-gate ohci_handle_endpoint_reclaimation(ohcip);
78727c478bd9Sstevel@tonic-gate }
78737c478bd9Sstevel@tonic-gate
78747c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_RD) {
78757c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78767c478bd9Sstevel@tonic-gate "ohci_intr: Resume Detected");
78777c478bd9Sstevel@tonic-gate }
78787c478bd9Sstevel@tonic-gate
78797c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_RHSC) {
78807c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78817c478bd9Sstevel@tonic-gate "ohci_intr: Root hub status change");
78827c478bd9Sstevel@tonic-gate }
78837c478bd9Sstevel@tonic-gate
78847c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_OC) {
78857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78867c478bd9Sstevel@tonic-gate "ohci_intr: Change ownership");
78877c478bd9Sstevel@tonic-gate
78887c478bd9Sstevel@tonic-gate }
78897c478bd9Sstevel@tonic-gate
78907c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_UE) {
78917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
78927c478bd9Sstevel@tonic-gate "ohci_intr: Unrecoverable error");
78937c478bd9Sstevel@tonic-gate
78947c478bd9Sstevel@tonic-gate ohci_handle_ue(ohcip);
78957c478bd9Sstevel@tonic-gate }
78967c478bd9Sstevel@tonic-gate
78977c478bd9Sstevel@tonic-gate /* Acknowledge the interrupt */
78987c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_status, intr);
78997c478bd9Sstevel@tonic-gate
79007c478bd9Sstevel@tonic-gate /* Clear the current interrupt event field */
79017c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_curr_intr_sts = 0;
79027c478bd9Sstevel@tonic-gate
79037c478bd9Sstevel@tonic-gate /*
79047c478bd9Sstevel@tonic-gate * Reset the following flag indicating exiting the interrupt
79057c478bd9Sstevel@tonic-gate * handler and this flag will be used in the polled mode to
79067c478bd9Sstevel@tonic-gate * do some extra processing.
79077c478bd9Sstevel@tonic-gate */
79087c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_HANDLING;
79097c478bd9Sstevel@tonic-gate
79107c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_MIE);
79117c478bd9Sstevel@tonic-gate
79127c478bd9Sstevel@tonic-gate /*
79137c478bd9Sstevel@tonic-gate * Read interrupt status register to make sure that any PIO
79147c478bd9Sstevel@tonic-gate * store to clear the ISR has made it on the PCI bus before
79157c478bd9Sstevel@tonic-gate * returning from its interrupt handler.
79167c478bd9Sstevel@tonic-gate */
79177c478bd9Sstevel@tonic-gate (void) Get_OpReg(hcr_intr_status);
79187c478bd9Sstevel@tonic-gate
79197c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
79207c478bd9Sstevel@tonic-gate
79217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
79227c478bd9Sstevel@tonic-gate "Interrupt handling completed");
79237c478bd9Sstevel@tonic-gate
79247c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
79257c478bd9Sstevel@tonic-gate }
79267c478bd9Sstevel@tonic-gate
7927688b07c5Sgc161489 /*
7928688b07c5Sgc161489 * Check whether done_head is a valid td point address.
7929e026ab87Sgc161489 * It should be non-zero, 16-byte aligned, and fall in ohci_td_pool.
7930688b07c5Sgc161489 */
7931688b07c5Sgc161489 static int
ohci_check_done_head(ohci_state_t * ohcip,ohci_td_t * done_head)7932688b07c5Sgc161489 ohci_check_done_head(ohci_state_t *ohcip, ohci_td_t *done_head)
7933688b07c5Sgc161489 {
7934688b07c5Sgc161489 uintptr_t lower, upper, headp;
7935688b07c5Sgc161489 lower = ohcip->ohci_td_pool_cookie.dmac_address;
7936688b07c5Sgc161489 upper = lower + ohcip->ohci_td_pool_cookie.dmac_size;
7937688b07c5Sgc161489 headp = (uintptr_t)done_head;
7938688b07c5Sgc161489
7939688b07c5Sgc161489 if (headp && !(headp & ~HCCA_DONE_HEAD_MASK) &&
7940688b07c5Sgc161489 (headp >= lower) && (headp < upper)) {
7941688b07c5Sgc161489
7942688b07c5Sgc161489 return (USB_SUCCESS);
7943688b07c5Sgc161489 } else {
7944688b07c5Sgc161489
7945688b07c5Sgc161489 return (USB_FAILURE);
7946688b07c5Sgc161489 }
7947688b07c5Sgc161489 }
79487c478bd9Sstevel@tonic-gate
79497c478bd9Sstevel@tonic-gate /*
79507c478bd9Sstevel@tonic-gate * ohci_handle_missed_intr:
79517c478bd9Sstevel@tonic-gate *
79527c478bd9Sstevel@tonic-gate * Handle any ohci missed interrupts because of polled mode switch.
79537c478bd9Sstevel@tonic-gate */
79547c478bd9Sstevel@tonic-gate static void
ohci_handle_missed_intr(ohci_state_t * ohcip)79557c478bd9Sstevel@tonic-gate ohci_handle_missed_intr(ohci_state_t *ohcip)
79567c478bd9Sstevel@tonic-gate {
79577c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts =
79587c478bd9Sstevel@tonic-gate &ohcip->ohci_save_intr_sts;
79597c478bd9Sstevel@tonic-gate ohci_td_t *done_head;
79607c478bd9Sstevel@tonic-gate uint_t intr;
79617c478bd9Sstevel@tonic-gate
79627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
79637c478bd9Sstevel@tonic-gate
79647c478bd9Sstevel@tonic-gate /*
79657c478bd9Sstevel@tonic-gate * Check whether we have missed any ohci interrupts because
79667c478bd9Sstevel@tonic-gate * of the polled mode switch during previous ohci interrupt
79677c478bd9Sstevel@tonic-gate * handler execution. Only Write Done Head & SOF interrupts
79687c478bd9Sstevel@tonic-gate * saved in the polled mode. First process these interrupts
79697c478bd9Sstevel@tonic-gate * before processing actual interrupts that caused invocation
79707c478bd9Sstevel@tonic-gate * of ohci interrupt handler.
79717c478bd9Sstevel@tonic-gate */
79727c478bd9Sstevel@tonic-gate if (!ohci_intr_sts->ohci_missed_intr_sts) {
79737c478bd9Sstevel@tonic-gate /* No interrupts are missed, simply return */
79747c478bd9Sstevel@tonic-gate
79757c478bd9Sstevel@tonic-gate return;
79767c478bd9Sstevel@tonic-gate }
79777c478bd9Sstevel@tonic-gate
79787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
79797c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Handle ohci missed interrupts");
79807c478bd9Sstevel@tonic-gate
79817c478bd9Sstevel@tonic-gate /*
79827c478bd9Sstevel@tonic-gate * The functionality and importance of critical code section
79837c478bd9Sstevel@tonic-gate * in the normal mode ohci interrupt handler & its usage in
79847c478bd9Sstevel@tonic-gate * the polled mode is explained below.
79857c478bd9Sstevel@tonic-gate *
79867c478bd9Sstevel@tonic-gate * (a) Normal mode:
79877c478bd9Sstevel@tonic-gate *
79887c478bd9Sstevel@tonic-gate * - Set the flag indicating that processing critical
79897c478bd9Sstevel@tonic-gate * code in ohci interrupt handler.
79907c478bd9Sstevel@tonic-gate *
79917c478bd9Sstevel@tonic-gate * - Process the missed ohci interrupts by copying the
79927c478bd9Sstevel@tonic-gate * miised interrupt events and done head list fields
79937c478bd9Sstevel@tonic-gate * information to the critical interrupt event & done
79947c478bd9Sstevel@tonic-gate * list fields.
79957c478bd9Sstevel@tonic-gate *
79967c478bd9Sstevel@tonic-gate * - Reset the missed ohci interrupt events & done head
79977c478bd9Sstevel@tonic-gate * list fields so that the new missed interrupt event
79987c478bd9Sstevel@tonic-gate * and done head list information can be saved.
79997c478bd9Sstevel@tonic-gate *
80007c478bd9Sstevel@tonic-gate * - All above steps will be executed with in critical
80017c478bd9Sstevel@tonic-gate * section of the interrupt handler.Then ohci missed
80027c478bd9Sstevel@tonic-gate * interrupt handler will be called to service missed
80037c478bd9Sstevel@tonic-gate * ohci interrupts.
80047c478bd9Sstevel@tonic-gate *
80057c478bd9Sstevel@tonic-gate * (b) Polled mode:
80067c478bd9Sstevel@tonic-gate *
80077c478bd9Sstevel@tonic-gate * - On entering the polled code,it checks for critical
80087c478bd9Sstevel@tonic-gate * section code execution within the normal mode ohci
80097c478bd9Sstevel@tonic-gate * interrupt handler.
80107c478bd9Sstevel@tonic-gate *
80117c478bd9Sstevel@tonic-gate * - If the critical section code is executing in normal
80127c478bd9Sstevel@tonic-gate * mode ohci interrupt handler and if copying of ohci
80137c478bd9Sstevel@tonic-gate * missed interrupt events & done head list fields to
80147c478bd9Sstevel@tonic-gate * the critical fields is finished then save the "any
80157c478bd9Sstevel@tonic-gate * missed interrupt events & done head list" because
80167c478bd9Sstevel@tonic-gate * of current polled mode switch into "critical missed
80177c478bd9Sstevel@tonic-gate * interrupt events & done list fields" instead actual
80187c478bd9Sstevel@tonic-gate * missed events and done list fields.
80197c478bd9Sstevel@tonic-gate *
80207c478bd9Sstevel@tonic-gate * - Otherwise save "any missed interrupt events & done
80217c478bd9Sstevel@tonic-gate * list" because of this current polled mode switch
80227c478bd9Sstevel@tonic-gate * in the actual missed interrupt events & done head
80237c478bd9Sstevel@tonic-gate * list fields.
80247c478bd9Sstevel@tonic-gate */
80257c478bd9Sstevel@tonic-gate
80267c478bd9Sstevel@tonic-gate /*
80277c478bd9Sstevel@tonic-gate * Set flag indicating that interrupt handler is processing
80287c478bd9Sstevel@tonic-gate * critical interrupt code, so that polled mode code checks
80297c478bd9Sstevel@tonic-gate * for this condition & will do extra processing as explained
80307c478bd9Sstevel@tonic-gate * above in order to aviod the race conditions.
80317c478bd9Sstevel@tonic-gate */
80327c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag |= OHCI_INTR_CRITICAL;
80337c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts |=
80347c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts;
80357c478bd9Sstevel@tonic-gate
80367c478bd9Sstevel@tonic-gate if (ohci_intr_sts->ohci_missed_done_lst) {
80377c478bd9Sstevel@tonic-gate
80387c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_done_lst =
80397c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_done_lst;
80407c478bd9Sstevel@tonic-gate }
80417c478bd9Sstevel@tonic-gate
80427c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_intr_sts = 0;
80437c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_missed_done_lst = NULL;
80447c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_intr_flag &= ~OHCI_INTR_CRITICAL;
80457c478bd9Sstevel@tonic-gate
80467c478bd9Sstevel@tonic-gate intr = ohci_intr_sts->ohci_critical_intr_sts;
80477c478bd9Sstevel@tonic-gate done_head = ohci_intr_sts->ohci_critical_done_lst;
80487c478bd9Sstevel@tonic-gate
80497c478bd9Sstevel@tonic-gate if (intr & HCR_INTR_SOF) {
80507c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
80517c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Start of Frame");
80527c478bd9Sstevel@tonic-gate
80537c478bd9Sstevel@tonic-gate /*
80547c478bd9Sstevel@tonic-gate * Call cv_broadcast on every SOF interrupt to wakeup
80557c478bd9Sstevel@tonic-gate * all the threads that are waiting the SOF. Calling
80567c478bd9Sstevel@tonic-gate * cv_broadcast on every SOF has no effect even if no
80577c478bd9Sstevel@tonic-gate * threads are waiting for the SOF.
80587c478bd9Sstevel@tonic-gate */
80597c478bd9Sstevel@tonic-gate cv_broadcast(&ohcip->ohci_SOF_cv);
80607c478bd9Sstevel@tonic-gate }
80617c478bd9Sstevel@tonic-gate
80627c478bd9Sstevel@tonic-gate if ((intr & HCR_INTR_WDH) && (done_head)) {
80637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
80647c478bd9Sstevel@tonic-gate "ohci_handle_missed_intr: Done Head");
80657c478bd9Sstevel@tonic-gate
80667c478bd9Sstevel@tonic-gate /* Clear the critical done head field */
80677c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_done_lst = NULL;
80687c478bd9Sstevel@tonic-gate
80697c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head);
80707c478bd9Sstevel@tonic-gate }
80717c478bd9Sstevel@tonic-gate
80727c478bd9Sstevel@tonic-gate /* Clear the critical interrupt event field */
80737c478bd9Sstevel@tonic-gate ohci_intr_sts->ohci_critical_intr_sts = 0;
80747c478bd9Sstevel@tonic-gate }
80757c478bd9Sstevel@tonic-gate
80767c478bd9Sstevel@tonic-gate
80777c478bd9Sstevel@tonic-gate /*
80787c478bd9Sstevel@tonic-gate * ohci_handle_ue:
80797c478bd9Sstevel@tonic-gate *
80807c478bd9Sstevel@tonic-gate * Handling of Unrecoverable Error interrupt (UE).
80817c478bd9Sstevel@tonic-gate */
80827c478bd9Sstevel@tonic-gate static void
ohci_handle_ue(ohci_state_t * ohcip)80837c478bd9Sstevel@tonic-gate ohci_handle_ue(ohci_state_t *ohcip)
80847c478bd9Sstevel@tonic-gate {
80857c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number;
80867c478bd9Sstevel@tonic-gate
80877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
80887c478bd9Sstevel@tonic-gate
80897c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
80907c478bd9Sstevel@tonic-gate "ohci_handle_ue: Handling of UE interrupt");
80917c478bd9Sstevel@tonic-gate
80927c478bd9Sstevel@tonic-gate /*
80937c478bd9Sstevel@tonic-gate * First check whether current UE error occured due to USB or
80947c478bd9Sstevel@tonic-gate * due to some other subsystem. This can be verified by reading
80957c478bd9Sstevel@tonic-gate * usb frame numbers before & after a delay of few milliseconds.
80967c478bd9Sstevel@tonic-gate * If usb frame number read after delay is greater than the one
80977c478bd9Sstevel@tonic-gate * read before delay, then, USB subsystem is fine. In this case,
80987c478bd9Sstevel@tonic-gate * disable UE error interrupt and return without shutdowning the
80997c478bd9Sstevel@tonic-gate * USB subsystem.
81007c478bd9Sstevel@tonic-gate *
81017c478bd9Sstevel@tonic-gate * Otherwise, if usb frame number read after delay is less than
81027c478bd9Sstevel@tonic-gate * or equal to one read before the delay, then, current UE error
81037c478bd9Sstevel@tonic-gate * occured from USB susbsystem. In this case,go ahead with actual
81047c478bd9Sstevel@tonic-gate * UE error recovery procedure.
81057c478bd9Sstevel@tonic-gate *
81067c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few
81077c478bd9Sstevel@tonic-gate * milliseconds.
81087c478bd9Sstevel@tonic-gate */
81097c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip);
81107c478bd9Sstevel@tonic-gate
81117c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */
81127c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT);
81137c478bd9Sstevel@tonic-gate
81147c478bd9Sstevel@tonic-gate /*
81157c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for
81167c478bd9Sstevel@tonic-gate * milliseconds.
81177c478bd9Sstevel@tonic-gate */
81187c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip);
81197c478bd9Sstevel@tonic-gate
81207c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
81217c478bd9Sstevel@tonic-gate "ohci_handle_ue: Before Frm No 0x%llx After Frm No 0x%llx",
8122112116d8Sfb209375 (unsigned long long)before_frame_number,
8123112116d8Sfb209375 (unsigned long long)after_frame_number);
81247c478bd9Sstevel@tonic-gate
81257c478bd9Sstevel@tonic-gate if (after_frame_number > before_frame_number) {
81267c478bd9Sstevel@tonic-gate
81277c478bd9Sstevel@tonic-gate /* Disable UE interrupt */
81287c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_UE);
81297c478bd9Sstevel@tonic-gate
81307c478bd9Sstevel@tonic-gate return;
81317c478bd9Sstevel@tonic-gate }
81327c478bd9Sstevel@tonic-gate
81337c478bd9Sstevel@tonic-gate /*
81347c478bd9Sstevel@tonic-gate * This UE is due to USB hardware error. Reset ohci controller
81357c478bd9Sstevel@tonic-gate * and reprogram to bring it back to functional state.
81367c478bd9Sstevel@tonic-gate */
81377c478bd9Sstevel@tonic-gate if ((ohci_do_soft_reset(ohcip)) != USB_SUCCESS) {
81387c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
81397c478bd9Sstevel@tonic-gate "Unrecoverable USB Hardware Error");
81407c478bd9Sstevel@tonic-gate
81417c478bd9Sstevel@tonic-gate /* Disable UE interrupt */
81427c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_UE);
81437c478bd9Sstevel@tonic-gate
81447c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */
81457c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state = OHCI_CTLR_ERROR_STATE;
81467c478bd9Sstevel@tonic-gate }
81477c478bd9Sstevel@tonic-gate }
81487c478bd9Sstevel@tonic-gate
81497c478bd9Sstevel@tonic-gate
81507c478bd9Sstevel@tonic-gate /*
81517c478bd9Sstevel@tonic-gate * ohci_handle_frame_number_overflow:
81527c478bd9Sstevel@tonic-gate *
81537c478bd9Sstevel@tonic-gate * Update software based usb frame number part on every frame number
81547c478bd9Sstevel@tonic-gate * overflow interrupt.
81557c478bd9Sstevel@tonic-gate *
81567c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
81577c478bd9Sstevel@tonic-gate *
81587c478bd9Sstevel@tonic-gate * Refer ohci spec 1.0a, section 5.3, page 81 for more details.
81597c478bd9Sstevel@tonic-gate */
81607c478bd9Sstevel@tonic-gate void
ohci_handle_frame_number_overflow(ohci_state_t * ohcip)81617c478bd9Sstevel@tonic-gate ohci_handle_frame_number_overflow(ohci_state_t *ohcip)
81627c478bd9Sstevel@tonic-gate {
81637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
81647c478bd9Sstevel@tonic-gate "ohci_handle_frame_number_overflow:");
81657c478bd9Sstevel@tonic-gate
81667c478bd9Sstevel@tonic-gate ohcip->ohci_fno += (0x10000 -
81677c478bd9Sstevel@tonic-gate (((Get_HCCA(ohcip->ohci_hccap->HccaFrameNo) &
81687c478bd9Sstevel@tonic-gate 0xFFFF) ^ ohcip->ohci_fno) & 0x8000));
81697c478bd9Sstevel@tonic-gate
81707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
81717c478bd9Sstevel@tonic-gate "ohci_handle_frame_number_overflow:"
8172112116d8Sfb209375 "Frame Number Higher Part 0x%llx\n",
8173112116d8Sfb209375 (unsigned long long)(ohcip->ohci_fno));
81747c478bd9Sstevel@tonic-gate }
81757c478bd9Sstevel@tonic-gate
81767c478bd9Sstevel@tonic-gate
81777c478bd9Sstevel@tonic-gate /*
81787c478bd9Sstevel@tonic-gate * ohci_handle_endpoint_reclaimation:
81797c478bd9Sstevel@tonic-gate *
81807c478bd9Sstevel@tonic-gate * Reclamation of Host Controller (HC) Endpoint Descriptors (ED).
81817c478bd9Sstevel@tonic-gate */
81827c478bd9Sstevel@tonic-gate static void
ohci_handle_endpoint_reclaimation(ohci_state_t * ohcip)81837c478bd9Sstevel@tonic-gate ohci_handle_endpoint_reclaimation(ohci_state_t *ohcip)
81847c478bd9Sstevel@tonic-gate {
81857c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number;
81867c478bd9Sstevel@tonic-gate usb_frame_number_t endpoint_frame_number;
81877c478bd9Sstevel@tonic-gate ohci_ed_t *reclaim_ed;
81887c478bd9Sstevel@tonic-gate
81897c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
81907c478bd9Sstevel@tonic-gate "ohci_handle_endpoint_reclaimation:");
81917c478bd9Sstevel@tonic-gate
81927c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
81937c478bd9Sstevel@tonic-gate
81947c478bd9Sstevel@tonic-gate current_frame_number = ohci_get_current_frame_number(ohcip);
81957c478bd9Sstevel@tonic-gate
81967c478bd9Sstevel@tonic-gate /*
81977c478bd9Sstevel@tonic-gate * Deallocate all Endpoint Descriptors (ED) which are on the
81987c478bd9Sstevel@tonic-gate * reclaimation list. These ED's are already removed from the
81997c478bd9Sstevel@tonic-gate * interrupt lattice tree.
82007c478bd9Sstevel@tonic-gate */
82017c478bd9Sstevel@tonic-gate while (ohcip->ohci_reclaim_list) {
82027c478bd9Sstevel@tonic-gate reclaim_ed = ohcip->ohci_reclaim_list;
82037c478bd9Sstevel@tonic-gate
82047c478bd9Sstevel@tonic-gate endpoint_frame_number = (usb_frame_number_t)(uintptr_t)
82057c478bd9Sstevel@tonic-gate (OHCI_LOOKUP_ID(Get_ED(reclaim_ed->hced_reclaim_frame)));
82067c478bd9Sstevel@tonic-gate
82077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
82087c478bd9Sstevel@tonic-gate "ohci_handle_endpoint_reclaimation:"
82097c478bd9Sstevel@tonic-gate "current frame number 0x%llx endpoint frame number 0x%llx",
8210112116d8Sfb209375 (unsigned long long)current_frame_number,
8211112116d8Sfb209375 (unsigned long long)endpoint_frame_number);
82127c478bd9Sstevel@tonic-gate
82137c478bd9Sstevel@tonic-gate /*
82147c478bd9Sstevel@tonic-gate * Deallocate current endpoint only if endpoint's usb frame
82157c478bd9Sstevel@tonic-gate * number is less than or equal to current usb frame number.
82167c478bd9Sstevel@tonic-gate *
82177c478bd9Sstevel@tonic-gate * If endpoint's usb frame number is greater than the current
82187c478bd9Sstevel@tonic-gate * usb frame number, ignore rest of the endpoints in the list
82197c478bd9Sstevel@tonic-gate * since rest of the endpoints are inserted into the reclaim
82207c478bd9Sstevel@tonic-gate * list later than the current reclaim endpoint.
82217c478bd9Sstevel@tonic-gate */
82227c478bd9Sstevel@tonic-gate if (endpoint_frame_number > current_frame_number) {
82237c478bd9Sstevel@tonic-gate break;
82247c478bd9Sstevel@tonic-gate }
82257c478bd9Sstevel@tonic-gate
82267c478bd9Sstevel@tonic-gate /* Get the next endpoint from the rec. list */
82277c478bd9Sstevel@tonic-gate ohcip->ohci_reclaim_list = ohci_ed_iommu_to_cpu(ohcip,
82287c478bd9Sstevel@tonic-gate Get_ED(reclaim_ed->hced_reclaim_next));
82297c478bd9Sstevel@tonic-gate
82307c478bd9Sstevel@tonic-gate /* Free 32bit ID */
82317c478bd9Sstevel@tonic-gate OHCI_FREE_ID((uint32_t)Get_ED(reclaim_ed->hced_reclaim_frame));
82327c478bd9Sstevel@tonic-gate
82337c478bd9Sstevel@tonic-gate /* Deallocate the endpoint */
82347c478bd9Sstevel@tonic-gate ohci_deallocate_ed(ohcip, reclaim_ed);
82357c478bd9Sstevel@tonic-gate }
82367c478bd9Sstevel@tonic-gate }
82377c478bd9Sstevel@tonic-gate
82387c478bd9Sstevel@tonic-gate
82397c478bd9Sstevel@tonic-gate /*
82407c478bd9Sstevel@tonic-gate * ohci_traverse_done_list:
82417c478bd9Sstevel@tonic-gate */
82427c478bd9Sstevel@tonic-gate static void
ohci_traverse_done_list(ohci_state_t * ohcip,ohci_td_t * head_done_list)82437c478bd9Sstevel@tonic-gate ohci_traverse_done_list(
82447c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
82457c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list)
82467c478bd9Sstevel@tonic-gate {
82477c478bd9Sstevel@tonic-gate uint_t state; /* TD state */
82487c478bd9Sstevel@tonic-gate ohci_td_t *td, *old_td; /* TD pointers */
82497c478bd9Sstevel@tonic-gate usb_cr_t error; /* Error from TD */
82507c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw = NULL; /* Transfer wrapper */
82517c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = NULL; /* Pipe private field */
82527c478bd9Sstevel@tonic-gate
82537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
82547c478bd9Sstevel@tonic-gate "ohci_traverse_done_list:");
82557c478bd9Sstevel@tonic-gate
82567c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
82577c478bd9Sstevel@tonic-gate
82587c478bd9Sstevel@tonic-gate /* Sync ED and TD pool */
82597c478bd9Sstevel@tonic-gate Sync_ED_TD_Pool(ohcip);
82607c478bd9Sstevel@tonic-gate
82617c478bd9Sstevel@tonic-gate /* Reverse the done list */
82627c478bd9Sstevel@tonic-gate td = ohci_reverse_done_list(ohcip, head_done_list);
82637c478bd9Sstevel@tonic-gate
82647c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */
82657c478bd9Sstevel@tonic-gate while (td) {
82667c478bd9Sstevel@tonic-gate /* Check for TD state */
82677c478bd9Sstevel@tonic-gate state = Get_TD(td->hctd_state);
82687c478bd9Sstevel@tonic-gate
82697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
82707c478bd9Sstevel@tonic-gate "ohci_traverse_done_list:\n\t"
82717c478bd9Sstevel@tonic-gate "td = 0x%p state = 0x%x", (void *)td, state);
82727c478bd9Sstevel@tonic-gate
82737c478bd9Sstevel@tonic-gate /*
82747c478bd9Sstevel@tonic-gate * Obtain the transfer wrapper only if the TD is
82757c478bd9Sstevel@tonic-gate * not marked as RECLAIM.
82767c478bd9Sstevel@tonic-gate *
82777c478bd9Sstevel@tonic-gate * A TD that is marked as RECLAIM has had its DMA
82787c478bd9Sstevel@tonic-gate * mappings, ED, TD and pipe private structure are
82797c478bd9Sstevel@tonic-gate * ripped down. Just deallocate this TD.
82807c478bd9Sstevel@tonic-gate */
82817c478bd9Sstevel@tonic-gate if (state != HC_TD_RECLAIM) {
82827c478bd9Sstevel@tonic-gate
82837c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)OHCI_LOOKUP_ID(
82847c478bd9Sstevel@tonic-gate (uint32_t)Get_TD(td->hctd_trans_wrapper));
82857c478bd9Sstevel@tonic-gate
82867c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
82877c478bd9Sstevel@tonic-gate
82887c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private;
82897c478bd9Sstevel@tonic-gate
82907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
82917c478bd9Sstevel@tonic-gate "ohci_traverse_done_list: PP = 0x%p TW = 0x%p",
8292112116d8Sfb209375 (void *)pp, (void *)tw);
82937c478bd9Sstevel@tonic-gate }
82947c478bd9Sstevel@tonic-gate
82957c478bd9Sstevel@tonic-gate /*
82967c478bd9Sstevel@tonic-gate * Don't process the TD if its state is marked as
82977c478bd9Sstevel@tonic-gate * either RECLAIM or TIMEOUT.
82987c478bd9Sstevel@tonic-gate *
82997c478bd9Sstevel@tonic-gate * A TD that is marked as TIMEOUT has already been
83007c478bd9Sstevel@tonic-gate * processed by TD timeout handler & client driver
83017c478bd9Sstevel@tonic-gate * has been informed through exception callback.
83027c478bd9Sstevel@tonic-gate */
83037c478bd9Sstevel@tonic-gate if ((state != HC_TD_RECLAIM) && (state != HC_TD_TIMEOUT)) {
83047c478bd9Sstevel@tonic-gate
83057c478bd9Sstevel@tonic-gate /* Look at the error status */
83067c478bd9Sstevel@tonic-gate error = ohci_parse_error(ohcip, td);
83077c478bd9Sstevel@tonic-gate
83087c478bd9Sstevel@tonic-gate if (error == USB_CR_OK) {
83097c478bd9Sstevel@tonic-gate ohci_handle_normal_td(ohcip, td, tw);
83107c478bd9Sstevel@tonic-gate } else {
83117c478bd9Sstevel@tonic-gate /* handle the error condition */
83127c478bd9Sstevel@tonic-gate ohci_handle_error(ohcip, td, error);
83137c478bd9Sstevel@tonic-gate }
83147c478bd9Sstevel@tonic-gate } else {
83157c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
83167c478bd9Sstevel@tonic-gate "ohci_traverse_done_list: TD State = %d", state);
83177c478bd9Sstevel@tonic-gate }
83187c478bd9Sstevel@tonic-gate
83197c478bd9Sstevel@tonic-gate /*
83207c478bd9Sstevel@tonic-gate * Save a pointer to the current transfer descriptor
83217c478bd9Sstevel@tonic-gate */
83227c478bd9Sstevel@tonic-gate old_td = td;
83237c478bd9Sstevel@tonic-gate
83247c478bd9Sstevel@tonic-gate td = ohci_td_iommu_to_cpu(ohcip, Get_TD(td->hctd_next_td));
83257c478bd9Sstevel@tonic-gate
83267c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */
83277c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, old_td);
83287c478bd9Sstevel@tonic-gate
83297c478bd9Sstevel@tonic-gate /*
83307c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more
83317c478bd9Sstevel@tonic-gate * TD's for the transfer wrapper. ohci_deallocate_tw_resources()
83327c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic endpoint
83337c478bd9Sstevel@tonic-gate * since it will always have a TD attached to it.
83347c478bd9Sstevel@tonic-gate *
83357c478bd9Sstevel@tonic-gate * Do not deallocate the TW if it is a isoc or intr pipe in.
83367c478bd9Sstevel@tonic-gate * The tw's are reused.
83377c478bd9Sstevel@tonic-gate *
83387c478bd9Sstevel@tonic-gate * An TD that is marked as reclaim doesn't have a pipe
83397c478bd9Sstevel@tonic-gate * or a TW associated with it anymore so don't call this
83407c478bd9Sstevel@tonic-gate * function.
83417c478bd9Sstevel@tonic-gate */
83427c478bd9Sstevel@tonic-gate if (state != HC_TD_RECLAIM) {
83437c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
83447c478bd9Sstevel@tonic-gate ohci_deallocate_tw_resources(ohcip, pp, tw);
83457c478bd9Sstevel@tonic-gate }
83467c478bd9Sstevel@tonic-gate }
83477c478bd9Sstevel@tonic-gate }
83487c478bd9Sstevel@tonic-gate
83497c478bd9Sstevel@tonic-gate
83507c478bd9Sstevel@tonic-gate /*
83517c478bd9Sstevel@tonic-gate * ohci_reverse_done_list:
83527c478bd9Sstevel@tonic-gate *
83537c478bd9Sstevel@tonic-gate * Reverse the order of the Transfer Descriptor (TD) Done List.
83547c478bd9Sstevel@tonic-gate */
83557c478bd9Sstevel@tonic-gate static ohci_td_t *
ohci_reverse_done_list(ohci_state_t * ohcip,ohci_td_t * head_done_list)83567c478bd9Sstevel@tonic-gate ohci_reverse_done_list(
83577c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
83587c478bd9Sstevel@tonic-gate ohci_td_t *head_done_list)
83597c478bd9Sstevel@tonic-gate {
83607c478bd9Sstevel@tonic-gate ohci_td_t *cpu_new_tail, *cpu_new_head, *cpu_save;
83617c478bd9Sstevel@tonic-gate
83627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
83637c478bd9Sstevel@tonic-gate "ohci_reverse_done_list:");
83647c478bd9Sstevel@tonic-gate
83657c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
83667c478bd9Sstevel@tonic-gate ASSERT(head_done_list != NULL);
83677c478bd9Sstevel@tonic-gate
83687c478bd9Sstevel@tonic-gate /* At first, both the tail and head pointers point to the same elem */
83697c478bd9Sstevel@tonic-gate cpu_new_tail = cpu_new_head =
83707c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, (uintptr_t)head_done_list);
83717c478bd9Sstevel@tonic-gate
83727c478bd9Sstevel@tonic-gate /* See if the list has only one element */
83733e1e1e62SToomas Soome if (Get_TD(cpu_new_head->hctd_next_td) == 0) {
83747c478bd9Sstevel@tonic-gate
83757c478bd9Sstevel@tonic-gate return (cpu_new_head);
83767c478bd9Sstevel@tonic-gate }
83777c478bd9Sstevel@tonic-gate
83787c478bd9Sstevel@tonic-gate /* Advance the head pointer */
83797c478bd9Sstevel@tonic-gate cpu_new_head = (ohci_td_t *)
83807c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(cpu_new_head->hctd_next_td));
83817c478bd9Sstevel@tonic-gate
83827c478bd9Sstevel@tonic-gate /* The new tail now points to nothing */
83837c478bd9Sstevel@tonic-gate Set_TD(cpu_new_tail->hctd_next_td, NULL);
83847c478bd9Sstevel@tonic-gate
83857c478bd9Sstevel@tonic-gate cpu_save = (ohci_td_t *)
83867c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip, Get_TD(cpu_new_head->hctd_next_td));
83877c478bd9Sstevel@tonic-gate
83887c478bd9Sstevel@tonic-gate /* Reverse the list and store the pointers as CPU addresses */
83897c478bd9Sstevel@tonic-gate while (cpu_save) {
83907c478bd9Sstevel@tonic-gate Set_TD(cpu_new_head->hctd_next_td,
83917c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, cpu_new_tail));
83927c478bd9Sstevel@tonic-gate
83937c478bd9Sstevel@tonic-gate cpu_new_tail = cpu_new_head;
83947c478bd9Sstevel@tonic-gate cpu_new_head = cpu_save;
83957c478bd9Sstevel@tonic-gate
83967c478bd9Sstevel@tonic-gate cpu_save = (ohci_td_t *)
83977c478bd9Sstevel@tonic-gate ohci_td_iommu_to_cpu(ohcip,
83987c478bd9Sstevel@tonic-gate Get_TD(cpu_new_head->hctd_next_td));
83997c478bd9Sstevel@tonic-gate }
84007c478bd9Sstevel@tonic-gate
84017c478bd9Sstevel@tonic-gate Set_TD(cpu_new_head->hctd_next_td,
84027c478bd9Sstevel@tonic-gate ohci_td_cpu_to_iommu(ohcip, cpu_new_tail));
84037c478bd9Sstevel@tonic-gate
84047c478bd9Sstevel@tonic-gate return (cpu_new_head);
84057c478bd9Sstevel@tonic-gate }
84067c478bd9Sstevel@tonic-gate
84077c478bd9Sstevel@tonic-gate
84087c478bd9Sstevel@tonic-gate /*
84097c478bd9Sstevel@tonic-gate * ohci_parse_error:
84107c478bd9Sstevel@tonic-gate *
84117c478bd9Sstevel@tonic-gate * Parse the result for any errors.
84127c478bd9Sstevel@tonic-gate */
84137c478bd9Sstevel@tonic-gate static usb_cr_t
ohci_parse_error(ohci_state_t * ohcip,ohci_td_t * td)84147c478bd9Sstevel@tonic-gate ohci_parse_error(
84157c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
84167c478bd9Sstevel@tonic-gate ohci_td_t *td)
84177c478bd9Sstevel@tonic-gate {
84187c478bd9Sstevel@tonic-gate uint_t ctrl;
84197c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd;
84207c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
84217c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp;
84227c478bd9Sstevel@tonic-gate uint_t flag;
84237c478bd9Sstevel@tonic-gate usb_cr_t error;
84247c478bd9Sstevel@tonic-gate
84257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
84267c478bd9Sstevel@tonic-gate "ohci_parse_error:");
84277c478bd9Sstevel@tonic-gate
84287c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
84297c478bd9Sstevel@tonic-gate
84307c478bd9Sstevel@tonic-gate ASSERT(td != NULL);
84317c478bd9Sstevel@tonic-gate
84327c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */
84337c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)
84347c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)Get_TD(td->hctd_trans_wrapper));
84357c478bd9Sstevel@tonic-gate
84367c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
84377c478bd9Sstevel@tonic-gate
84387c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */
84397c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private;
84407c478bd9Sstevel@tonic-gate
84417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
8442112116d8Sfb209375 "ohci_parse_error: PP 0x%p TW 0x%p", (void *)pp, (void *)tw);
84437c478bd9Sstevel@tonic-gate
84447c478bd9Sstevel@tonic-gate eptd = &pp->pp_pipe_handle->p_ep;
84457c478bd9Sstevel@tonic-gate
84467c478bd9Sstevel@tonic-gate ctrl = (uint_t)Get_TD(td->hctd_ctrl) & (uint32_t)HC_TD_CC;
84477c478bd9Sstevel@tonic-gate
84487c478bd9Sstevel@tonic-gate /*
84497c478bd9Sstevel@tonic-gate * Check the condition code of completed TD and report errors
84507c478bd9Sstevel@tonic-gate * if any. This checking will be done both for the general and
84517c478bd9Sstevel@tonic-gate * the isochronous TDs.
84527c478bd9Sstevel@tonic-gate */
84537c478bd9Sstevel@tonic-gate if ((error = ohci_check_for_error(ohcip, pp, tw, td, ctrl)) !=
84547c478bd9Sstevel@tonic-gate USB_CR_OK) {
84557c478bd9Sstevel@tonic-gate flag = OHCI_REMOVE_XFER_ALWAYS;
84567c478bd9Sstevel@tonic-gate } else {
84577c478bd9Sstevel@tonic-gate flag = OHCI_REMOVE_XFER_IFLAST;
84587c478bd9Sstevel@tonic-gate }
84597c478bd9Sstevel@tonic-gate
84607c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */
84617c478bd9Sstevel@tonic-gate ohci_stop_xfer_timer(ohcip, tw, flag);
84627c478bd9Sstevel@tonic-gate
84637c478bd9Sstevel@tonic-gate /*
84647c478bd9Sstevel@tonic-gate * The isochronous endpoint needs additional error checking
84657c478bd9Sstevel@tonic-gate * and special processing.
84667c478bd9Sstevel@tonic-gate */
84677c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
84687c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) {
84697c478bd9Sstevel@tonic-gate
84707c478bd9Sstevel@tonic-gate ohci_parse_isoc_error(ohcip, pp, tw, td);
84717c478bd9Sstevel@tonic-gate
84727c478bd9Sstevel@tonic-gate /* always reset error */
84737c478bd9Sstevel@tonic-gate error = USB_CR_OK;
84747c478bd9Sstevel@tonic-gate }
84757c478bd9Sstevel@tonic-gate
84767c478bd9Sstevel@tonic-gate return (error);
84777c478bd9Sstevel@tonic-gate }
84787c478bd9Sstevel@tonic-gate
84797c478bd9Sstevel@tonic-gate
84807c478bd9Sstevel@tonic-gate /*
84817c478bd9Sstevel@tonic-gate * ohci_parse_isoc_error:
84827c478bd9Sstevel@tonic-gate *
84837c478bd9Sstevel@tonic-gate * Check for any errors in the isochronous data packets. Also fillup
84847c478bd9Sstevel@tonic-gate * the status for each of the isochrnous data packets.
84857c478bd9Sstevel@tonic-gate */
84867c478bd9Sstevel@tonic-gate void
ohci_parse_isoc_error(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td)84877c478bd9Sstevel@tonic-gate ohci_parse_isoc_error(
84887c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
84897c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
84907c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
84917c478bd9Sstevel@tonic-gate ohci_td_t *td)
84927c478bd9Sstevel@tonic-gate {
84937c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp;
84947c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *isoc_pkt_descr;
84957c478bd9Sstevel@tonic-gate uint_t toggle = 0, fc, ctrl, psw;
84967c478bd9Sstevel@tonic-gate int i;
84977c478bd9Sstevel@tonic-gate
84987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
8499112116d8Sfb209375 "ohci_parse_isoc_error: td 0x%p", (void *)td);
85007c478bd9Sstevel@tonic-gate
85017c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
85027c478bd9Sstevel@tonic-gate
85037c478bd9Sstevel@tonic-gate fc = ((uint_t)Get_TD(td->hctd_ctrl) &
85047c478bd9Sstevel@tonic-gate HC_ITD_FC) >> HC_ITD_FC_SHIFT;
85057c478bd9Sstevel@tonic-gate
85067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
85077c478bd9Sstevel@tonic-gate "ohci_parse_isoc_error: frame count %d", fc);
85087c478bd9Sstevel@tonic-gate
85097c478bd9Sstevel@tonic-gate /*
85107c478bd9Sstevel@tonic-gate * Get the address of current usb isochronous request
85117c478bd9Sstevel@tonic-gate * and array of packet descriptors.
85127c478bd9Sstevel@tonic-gate */
85137c478bd9Sstevel@tonic-gate isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
85147c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
8515b3001defSlg150142 isoc_pkt_descr += tw->tw_pkt_idx;
85167c478bd9Sstevel@tonic-gate
85177c478bd9Sstevel@tonic-gate for (i = 0; i <= fc; i++) {
85187c478bd9Sstevel@tonic-gate
85197c478bd9Sstevel@tonic-gate psw = Get_TD(td->hctd_offsets[i / 2]);
85207c478bd9Sstevel@tonic-gate
85217c478bd9Sstevel@tonic-gate if (toggle) {
85227c478bd9Sstevel@tonic-gate ctrl = psw & HC_ITD_ODD_OFFSET;
85237c478bd9Sstevel@tonic-gate toggle = 0;
85247c478bd9Sstevel@tonic-gate } else {
85257c478bd9Sstevel@tonic-gate ctrl = (psw & HC_ITD_EVEN_OFFSET) <<
85267c478bd9Sstevel@tonic-gate HC_ITD_OFFSET_SHIFT;
85277c478bd9Sstevel@tonic-gate toggle = 1;
85287c478bd9Sstevel@tonic-gate }
85297c478bd9Sstevel@tonic-gate
85307c478bd9Sstevel@tonic-gate isoc_pkt_descr->isoc_pkt_actual_length =
85317c478bd9Sstevel@tonic-gate (ctrl >> HC_ITD_OFFSET_SHIFT) & HC_ITD_OFFSET_ADDR;
85327c478bd9Sstevel@tonic-gate
85337c478bd9Sstevel@tonic-gate ctrl = (uint_t)(ctrl & (uint32_t)HC_TD_CC);
85347c478bd9Sstevel@tonic-gate
85357c478bd9Sstevel@tonic-gate /* Write the status of isoc data packet */
85367c478bd9Sstevel@tonic-gate isoc_pkt_descr->isoc_pkt_status =
85377c478bd9Sstevel@tonic-gate ohci_check_for_error(ohcip, pp, tw, td, ctrl);
85387c478bd9Sstevel@tonic-gate
85397c478bd9Sstevel@tonic-gate if (isoc_pkt_descr->isoc_pkt_status) {
85407c478bd9Sstevel@tonic-gate /* Increment isoc data packet error count */
85417c478bd9Sstevel@tonic-gate isoc_reqp->isoc_error_count++;
85427c478bd9Sstevel@tonic-gate }
85437c478bd9Sstevel@tonic-gate
85447c478bd9Sstevel@tonic-gate /*
85457c478bd9Sstevel@tonic-gate * Get the address of next isoc data packet descriptor.
85467c478bd9Sstevel@tonic-gate */
85477c478bd9Sstevel@tonic-gate isoc_pkt_descr++;
85487c478bd9Sstevel@tonic-gate }
8549b3001defSlg150142 tw->tw_pkt_idx = tw->tw_pkt_idx + fc + 1;
8550b3001defSlg150142
8551b3001defSlg150142 USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
8552b3001defSlg150142 "ohci_parse_isoc_error: tw_pkt_idx %d", tw->tw_pkt_idx);
8553b3001defSlg150142
85547c478bd9Sstevel@tonic-gate }
85557c478bd9Sstevel@tonic-gate
85567c478bd9Sstevel@tonic-gate
85577c478bd9Sstevel@tonic-gate /*
85587c478bd9Sstevel@tonic-gate * ohci_check_for_error:
85597c478bd9Sstevel@tonic-gate *
85607c478bd9Sstevel@tonic-gate * Check for any errors.
85617c478bd9Sstevel@tonic-gate */
85627c478bd9Sstevel@tonic-gate static usb_cr_t
ohci_check_for_error(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td,uint_t ctrl)85637c478bd9Sstevel@tonic-gate ohci_check_for_error(
85647c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
85657c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
85667c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
85677c478bd9Sstevel@tonic-gate ohci_td_t *td,
85687c478bd9Sstevel@tonic-gate uint_t ctrl)
85697c478bd9Sstevel@tonic-gate {
85707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
85717c478bd9Sstevel@tonic-gate uchar_t ep_attrs = ph->p_ep.bmAttributes;
85727c478bd9Sstevel@tonic-gate usb_cr_t error = USB_CR_OK;
85737c478bd9Sstevel@tonic-gate usb_req_attrs_t xfer_attrs;
85747c478bd9Sstevel@tonic-gate
85757c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
85767c478bd9Sstevel@tonic-gate "ohci_check_for_error: td = 0x%p ctrl = 0x%x",
8577112116d8Sfb209375 (void *)td, ctrl);
85787c478bd9Sstevel@tonic-gate
85797c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
85807c478bd9Sstevel@tonic-gate
85817c478bd9Sstevel@tonic-gate switch (ctrl) {
85827c478bd9Sstevel@tonic-gate case HC_TD_CC_NO_E:
85837c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
85847c478bd9Sstevel@tonic-gate "ohci_check_for_error: No Error");
85857c478bd9Sstevel@tonic-gate error = USB_CR_OK;
85867c478bd9Sstevel@tonic-gate break;
85877c478bd9Sstevel@tonic-gate case HC_TD_CC_CRC:
85887c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
85897c478bd9Sstevel@tonic-gate "ohci_check_for_error: CRC error");
85907c478bd9Sstevel@tonic-gate error = USB_CR_CRC;
85917c478bd9Sstevel@tonic-gate break;
85927c478bd9Sstevel@tonic-gate case HC_TD_CC_BS:
85937c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
85947c478bd9Sstevel@tonic-gate "ohci_check_for_error: Bit stuffing");
85957c478bd9Sstevel@tonic-gate error = USB_CR_BITSTUFFING;
85967c478bd9Sstevel@tonic-gate break;
85977c478bd9Sstevel@tonic-gate case HC_TD_CC_DTM:
85987c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
85997c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data Toggle Mismatch");
86007c478bd9Sstevel@tonic-gate error = USB_CR_DATA_TOGGLE_MM;
86017c478bd9Sstevel@tonic-gate break;
86027c478bd9Sstevel@tonic-gate case HC_TD_CC_STALL:
86037c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86047c478bd9Sstevel@tonic-gate "ohci_check_for_error: Stall");
86057c478bd9Sstevel@tonic-gate error = USB_CR_STALL;
86067c478bd9Sstevel@tonic-gate break;
86077c478bd9Sstevel@tonic-gate case HC_TD_CC_DNR:
86087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86097c478bd9Sstevel@tonic-gate "ohci_check_for_error: Device not responding");
86107c478bd9Sstevel@tonic-gate error = USB_CR_DEV_NOT_RESP;
86117c478bd9Sstevel@tonic-gate break;
86127c478bd9Sstevel@tonic-gate case HC_TD_CC_PCF:
86137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86147c478bd9Sstevel@tonic-gate "ohci_check_for_error: PID check failure");
86157c478bd9Sstevel@tonic-gate error = USB_CR_PID_CHECKFAILURE;
86167c478bd9Sstevel@tonic-gate break;
86177c478bd9Sstevel@tonic-gate case HC_TD_CC_UPID:
86187c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86197c478bd9Sstevel@tonic-gate "ohci_check_for_error: Unexpected PID");
86207c478bd9Sstevel@tonic-gate error = USB_CR_UNEXP_PID;
86217c478bd9Sstevel@tonic-gate break;
86227c478bd9Sstevel@tonic-gate case HC_TD_CC_DO:
86237c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86247c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data overrrun");
86257c478bd9Sstevel@tonic-gate error = USB_CR_DATA_OVERRUN;
86267c478bd9Sstevel@tonic-gate break;
86277c478bd9Sstevel@tonic-gate case HC_TD_CC_DU:
86287c478bd9Sstevel@tonic-gate /*
86297c478bd9Sstevel@tonic-gate * Check whether short packets are acceptable.
86307c478bd9Sstevel@tonic-gate * If so don't report error to client drivers
86317c478bd9Sstevel@tonic-gate * and restart the endpoint. Otherwise report
86327c478bd9Sstevel@tonic-gate * data underrun error to client driver.
86337c478bd9Sstevel@tonic-gate */
86347c478bd9Sstevel@tonic-gate xfer_attrs = ohci_get_xfer_attrs(ohcip, pp, tw);
86357c478bd9Sstevel@tonic-gate
86367c478bd9Sstevel@tonic-gate if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) {
86377c478bd9Sstevel@tonic-gate error = USB_CR_OK;
86387c478bd9Sstevel@tonic-gate if ((ep_attrs & USB_EP_ATTR_MASK) !=
86397c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) {
86407c478bd9Sstevel@tonic-gate /*
86417c478bd9Sstevel@tonic-gate * Cleanup the remaining resources that may have
86427c478bd9Sstevel@tonic-gate * been allocated for this transfer.
86437c478bd9Sstevel@tonic-gate */
86447c478bd9Sstevel@tonic-gate if (ohci_cleanup_data_underrun(ohcip, pp, tw,
86457c478bd9Sstevel@tonic-gate td) == USB_SUCCESS) {
86467c478bd9Sstevel@tonic-gate /* Clear the halt bit */
86477c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
86487c478bd9Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) &
86497c478bd9Sstevel@tonic-gate ~HC_EPT_Halt));
86507c478bd9Sstevel@tonic-gate } else {
86517c478bd9Sstevel@tonic-gate error = USB_CR_UNSPECIFIED_ERR;
86527c478bd9Sstevel@tonic-gate }
86537c478bd9Sstevel@tonic-gate }
86547c478bd9Sstevel@tonic-gate } else {
86557c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86567c478bd9Sstevel@tonic-gate "ohci_check_for_error: Data underrun");
86577c478bd9Sstevel@tonic-gate
86587c478bd9Sstevel@tonic-gate error = USB_CR_DATA_UNDERRUN;
86597c478bd9Sstevel@tonic-gate }
86607c478bd9Sstevel@tonic-gate
86617c478bd9Sstevel@tonic-gate break;
86627c478bd9Sstevel@tonic-gate case HC_TD_CC_BO:
86637c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86647c478bd9Sstevel@tonic-gate "ohci_check_for_error: Buffer overrun");
86657c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_OVERRUN;
86667c478bd9Sstevel@tonic-gate break;
86677c478bd9Sstevel@tonic-gate case HC_TD_CC_BU:
86687c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86697c478bd9Sstevel@tonic-gate "ohci_check_for_error: Buffer underrun");
86707c478bd9Sstevel@tonic-gate error = USB_CR_BUFFER_UNDERRUN;
86717c478bd9Sstevel@tonic-gate break;
86727c478bd9Sstevel@tonic-gate case HC_TD_CC_NA:
86737c478bd9Sstevel@tonic-gate default:
86747c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86757c478bd9Sstevel@tonic-gate "ohci_check_for_error: Not accessed");
86767c478bd9Sstevel@tonic-gate error = USB_CR_NOT_ACCESSED;
86777c478bd9Sstevel@tonic-gate break;
86787c478bd9Sstevel@tonic-gate }
86797c478bd9Sstevel@tonic-gate
86807c478bd9Sstevel@tonic-gate if (error) {
86817c478bd9Sstevel@tonic-gate uint_t hced_ctrl = Get_ED(pp->pp_ept->hced_ctrl);
86827c478bd9Sstevel@tonic-gate
86837c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
86847c478bd9Sstevel@tonic-gate "ohci_check_for_error: Error %d Device address %d "
86857c478bd9Sstevel@tonic-gate "Endpoint number %d", error, (hced_ctrl & HC_EPT_FUNC),
86867c478bd9Sstevel@tonic-gate ((hced_ctrl & HC_EPT_EP) >> HC_EPT_EP_SHFT));
86877c478bd9Sstevel@tonic-gate }
86887c478bd9Sstevel@tonic-gate
86897c478bd9Sstevel@tonic-gate return (error);
86907c478bd9Sstevel@tonic-gate }
86917c478bd9Sstevel@tonic-gate
86927c478bd9Sstevel@tonic-gate
86937c478bd9Sstevel@tonic-gate /*
86947c478bd9Sstevel@tonic-gate * ohci_handle_error:
86957c478bd9Sstevel@tonic-gate *
86967c478bd9Sstevel@tonic-gate * Inform USBA about occured transaction errors by calling the USBA callback
86977c478bd9Sstevel@tonic-gate * routine.
86987c478bd9Sstevel@tonic-gate */
86997c478bd9Sstevel@tonic-gate static void
ohci_handle_error(ohci_state_t * ohcip,ohci_td_t * td,usb_cr_t error)87007c478bd9Sstevel@tonic-gate ohci_handle_error(
87017c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
87027c478bd9Sstevel@tonic-gate ohci_td_t *td,
87037c478bd9Sstevel@tonic-gate usb_cr_t error)
87047c478bd9Sstevel@tonic-gate {
87057c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw;
87067c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
87077c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp;
87087c478bd9Sstevel@tonic-gate mblk_t *mp = NULL;
87097c478bd9Sstevel@tonic-gate size_t length = 0;
87107c478bd9Sstevel@tonic-gate uchar_t attributes;
87117c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
87127c478bd9Sstevel@tonic-gate
87137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
87147c478bd9Sstevel@tonic-gate "ohci_handle_error: error = 0x%x", error);
87157c478bd9Sstevel@tonic-gate
87167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
87177c478bd9Sstevel@tonic-gate
87187c478bd9Sstevel@tonic-gate ASSERT(td != NULL);
87197c478bd9Sstevel@tonic-gate
87207c478bd9Sstevel@tonic-gate /* Print the values in the td */
87217c478bd9Sstevel@tonic-gate ohci_print_td(ohcip, td);
87227c478bd9Sstevel@tonic-gate
87237c478bd9Sstevel@tonic-gate /* Obtain the transfer wrapper from the TD */
87247c478bd9Sstevel@tonic-gate tw = (ohci_trans_wrapper_t *)
87257c478bd9Sstevel@tonic-gate OHCI_LOOKUP_ID((uint32_t)Get_TD(td->hctd_trans_wrapper));
87267c478bd9Sstevel@tonic-gate
87277c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
87287c478bd9Sstevel@tonic-gate
87297c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */
87307c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private;
87317c478bd9Sstevel@tonic-gate
87327c478bd9Sstevel@tonic-gate ph = tw->tw_pipe_private->pp_pipe_handle;
87337c478bd9Sstevel@tonic-gate attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
87347c478bd9Sstevel@tonic-gate
87357c478bd9Sstevel@tonic-gate /*
87367c478bd9Sstevel@tonic-gate * Special error handling
87377c478bd9Sstevel@tonic-gate */
87387c478bd9Sstevel@tonic-gate if (tw->tw_direction == HC_TD_IN) {
87397c478bd9Sstevel@tonic-gate
87407c478bd9Sstevel@tonic-gate switch (attributes) {
87417c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
87427c478bd9Sstevel@tonic-gate if (((ph->p_ep.bmAttributes &
87437c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) ==
87447c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) &&
87457c478bd9Sstevel@tonic-gate (Get_TD(td->hctd_ctrl_phase) ==
87467c478bd9Sstevel@tonic-gate OHCI_CTRL_SETUP_PHASE)) {
87477c478bd9Sstevel@tonic-gate
87487c478bd9Sstevel@tonic-gate break;
87497c478bd9Sstevel@tonic-gate }
87507c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
87517c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
87527c478bd9Sstevel@tonic-gate /*
87537c478bd9Sstevel@tonic-gate * Call ohci_sendup_td_message
87547c478bd9Sstevel@tonic-gate * to send message to upstream.
87557c478bd9Sstevel@tonic-gate */
87567c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, error);
87577c478bd9Sstevel@tonic-gate
87587c478bd9Sstevel@tonic-gate return;
87597c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
87607c478bd9Sstevel@tonic-gate curr_intr_reqp =
87617c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
87627c478bd9Sstevel@tonic-gate
87637c478bd9Sstevel@tonic-gate if (curr_intr_reqp->intr_attributes &
87647c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) {
87657c478bd9Sstevel@tonic-gate
87667c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(ohcip, tw);
87677c478bd9Sstevel@tonic-gate }
87687c478bd9Sstevel@tonic-gate
87697c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */
87707c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--;
87717c478bd9Sstevel@tonic-gate break;
87727c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
87737c478bd9Sstevel@tonic-gate default:
87747c478bd9Sstevel@tonic-gate break;
87757c478bd9Sstevel@tonic-gate }
87767c478bd9Sstevel@tonic-gate } else {
87777c478bd9Sstevel@tonic-gate switch (attributes) {
87787c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
87797c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
87807c478bd9Sstevel@tonic-gate /*
87817c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer
87827c478bd9Sstevel@tonic-gate * Descriptor (TD) is not equal to zero,
87837c478bd9Sstevel@tonic-gate * then we sent less data to the device
87847c478bd9Sstevel@tonic-gate * than requested by client. In that case,
87857c478bd9Sstevel@tonic-gate * return the mblk after updating the
87867c478bd9Sstevel@tonic-gate * data->r_ptr.
87877c478bd9Sstevel@tonic-gate */
87887c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) {
87897c478bd9Sstevel@tonic-gate usb_opaque_t xfer_reqp = tw->tw_curr_xfer_reqp;
879002acac7eSsl147100 size_t residue;
87917c478bd9Sstevel@tonic-gate
879202acac7eSsl147100 residue = ohci_get_td_residue(ohcip, td);
879302acac7eSsl147100 length = Get_TD(td->hctd_xfer_offs) +
879402acac7eSsl147100 Get_TD(td->hctd_xfer_len) - residue;
87957c478bd9Sstevel@tonic-gate
87967c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR,
87977c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl,
87987c478bd9Sstevel@tonic-gate "ohci_handle_error: requested data %lu "
87997c478bd9Sstevel@tonic-gate "sent data %lu", tw->tw_length, length);
88007c478bd9Sstevel@tonic-gate
88017c478bd9Sstevel@tonic-gate if (attributes == USB_EP_ATTR_BULK) {
88027c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_bulk_req_t *)
88037c478bd9Sstevel@tonic-gate (xfer_reqp))->bulk_data;
88047c478bd9Sstevel@tonic-gate } else {
88057c478bd9Sstevel@tonic-gate mp = (mblk_t *)((usb_intr_req_t *)
88067c478bd9Sstevel@tonic-gate (xfer_reqp))->intr_data;
88077c478bd9Sstevel@tonic-gate }
88087c478bd9Sstevel@tonic-gate
88097c478bd9Sstevel@tonic-gate /* Increment the read pointer */
88107c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_rptr + length;
88117c478bd9Sstevel@tonic-gate }
88127c478bd9Sstevel@tonic-gate break;
88137c478bd9Sstevel@tonic-gate default:
88147c478bd9Sstevel@tonic-gate break;
88157c478bd9Sstevel@tonic-gate }
88167c478bd9Sstevel@tonic-gate }
88177c478bd9Sstevel@tonic-gate
88187c478bd9Sstevel@tonic-gate /*
88197c478bd9Sstevel@tonic-gate * Callback the client with the
88207c478bd9Sstevel@tonic-gate * failure reason.
88217c478bd9Sstevel@tonic-gate */
88227c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, error);
88237c478bd9Sstevel@tonic-gate
88247c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */
88257c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(ohcip, pp);
88267c478bd9Sstevel@tonic-gate }
88277c478bd9Sstevel@tonic-gate
88287c478bd9Sstevel@tonic-gate /*
88297c478bd9Sstevel@tonic-gate * ohci_cleanup_data_underrun:
88307c478bd9Sstevel@tonic-gate *
88317c478bd9Sstevel@tonic-gate * Cleans up resources when a short xfer occurs
88327c478bd9Sstevel@tonic-gate */
88337c478bd9Sstevel@tonic-gate static int
ohci_cleanup_data_underrun(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td)88347c478bd9Sstevel@tonic-gate ohci_cleanup_data_underrun(
88357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
88367c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
88377c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
88387c478bd9Sstevel@tonic-gate ohci_td_t *td)
88397c478bd9Sstevel@tonic-gate {
88407c478bd9Sstevel@tonic-gate ohci_td_t *next_td;
88417c478bd9Sstevel@tonic-gate ohci_td_t *last_td;
88427c478bd9Sstevel@tonic-gate ohci_td_t *temp_td;
88437c478bd9Sstevel@tonic-gate uint32_t last_td_addr;
88447c478bd9Sstevel@tonic-gate uint_t hced_head;
88457c478bd9Sstevel@tonic-gate
88467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
8847112116d8Sfb209375 "ohci_cleanup_data_underrun: td 0x%p, tw 0x%p",
8848112116d8Sfb209375 (void *)td, (void *)tw);
88497c478bd9Sstevel@tonic-gate
88507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
88517c478bd9Sstevel@tonic-gate ASSERT(tw->tw_hctd_head == td);
88527c478bd9Sstevel@tonic-gate
88537c478bd9Sstevel@tonic-gate /* Check if this TD is the last td in the tw */
88547c478bd9Sstevel@tonic-gate last_td = tw->tw_hctd_tail;
88557c478bd9Sstevel@tonic-gate if (td == last_td) {
88567c478bd9Sstevel@tonic-gate /* There is no need for cleanup */
88577c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
88587c478bd9Sstevel@tonic-gate }
88597c478bd9Sstevel@tonic-gate
88607c478bd9Sstevel@tonic-gate /*
88617c478bd9Sstevel@tonic-gate * Make sure the ED is halted before we change any td's.
88627c478bd9Sstevel@tonic-gate * If for some reason it is not halted, return error to client
88637c478bd9Sstevel@tonic-gate * driver so they can reset the port.
88647c478bd9Sstevel@tonic-gate */
88657c478bd9Sstevel@tonic-gate hced_head = Get_ED(pp->pp_ept->hced_headp);
88667c478bd9Sstevel@tonic-gate if (!(hced_head & HC_EPT_Halt)) {
88677c478bd9Sstevel@tonic-gate uint_t hced_ctrl = Get_ED(pp->pp_ept->hced_ctrl);
88687c478bd9Sstevel@tonic-gate
8869d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
88707c478bd9Sstevel@tonic-gate "ohci_cleanup_data_underrun: Unable to clean up a short "
88717c478bd9Sstevel@tonic-gate "xfer error. Client might send/receive irrelevant data."
88727c478bd9Sstevel@tonic-gate " Device address %d Endpoint number %d",
88737c478bd9Sstevel@tonic-gate (hced_ctrl & HC_EPT_FUNC),
88747c478bd9Sstevel@tonic-gate ((hced_ctrl & HC_EPT_EP) >> HC_EPT_EP_SHFT));
88757c478bd9Sstevel@tonic-gate
88767c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp, hced_head | HC_EPT_Halt);
88777c478bd9Sstevel@tonic-gate
88787c478bd9Sstevel@tonic-gate return (USB_FAILURE);
88797c478bd9Sstevel@tonic-gate }
88807c478bd9Sstevel@tonic-gate
88817c478bd9Sstevel@tonic-gate /*
88827c478bd9Sstevel@tonic-gate * Get the address of the first td of the next transfer (tw).
88837c478bd9Sstevel@tonic-gate * This td, may currently be a dummy td, but when a new request
88847c478bd9Sstevel@tonic-gate * arrives, it will be transformed into a regular td.
88857c478bd9Sstevel@tonic-gate */
88867c478bd9Sstevel@tonic-gate last_td_addr = Get_TD(last_td->hctd_next_td);
88877c478bd9Sstevel@tonic-gate /* Set ED head to this last td */
88887c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
88897c478bd9Sstevel@tonic-gate (last_td_addr & HC_EPT_TD_HEAD) |
88907c478bd9Sstevel@tonic-gate (hced_head & ~HC_EPT_TD_HEAD));
88917c478bd9Sstevel@tonic-gate
88927c478bd9Sstevel@tonic-gate /*
88937c478bd9Sstevel@tonic-gate * Start removing all the unused TD's from the TW,
88947c478bd9Sstevel@tonic-gate * but keep the first one.
88957c478bd9Sstevel@tonic-gate */
88967c478bd9Sstevel@tonic-gate tw->tw_hctd_tail = td;
88977c478bd9Sstevel@tonic-gate
88987c478bd9Sstevel@tonic-gate /*
88997c478bd9Sstevel@tonic-gate * Get the last_td, the next td in the tw list.
89007c478bd9Sstevel@tonic-gate * Afterwards completely disassociate the current td from other tds
89017c478bd9Sstevel@tonic-gate */
89027c478bd9Sstevel@tonic-gate next_td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip,
89037c478bd9Sstevel@tonic-gate Get_TD(td->hctd_tw_next_td));
89047c478bd9Sstevel@tonic-gate Set_TD(td->hctd_tw_next_td, NULL);
89057c478bd9Sstevel@tonic-gate
89067c478bd9Sstevel@tonic-gate /*
89077c478bd9Sstevel@tonic-gate * Iterate down the tw list and deallocate them
89087c478bd9Sstevel@tonic-gate */
89097c478bd9Sstevel@tonic-gate while (next_td != NULL) {
89107c478bd9Sstevel@tonic-gate tw->tw_num_tds--;
89117c478bd9Sstevel@tonic-gate /* Disassociate this td from it's TW and set to RECLAIM */
89127c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_trans_wrapper, NULL);
89137c478bd9Sstevel@tonic-gate Set_TD(next_td->hctd_state, HC_TD_RECLAIM);
89147c478bd9Sstevel@tonic-gate
89157c478bd9Sstevel@tonic-gate temp_td = next_td;
89167c478bd9Sstevel@tonic-gate
89177c478bd9Sstevel@tonic-gate next_td = (ohci_td_t *)ohci_td_iommu_to_cpu(ohcip,
89187c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td));
89197c478bd9Sstevel@tonic-gate
89207c478bd9Sstevel@tonic-gate ohci_deallocate_td(ohcip, temp_td);
89217c478bd9Sstevel@tonic-gate }
89227c478bd9Sstevel@tonic-gate
89237c478bd9Sstevel@tonic-gate ASSERT(tw->tw_num_tds == 1);
89247c478bd9Sstevel@tonic-gate
89257c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
89267c478bd9Sstevel@tonic-gate }
89277c478bd9Sstevel@tonic-gate
89287c478bd9Sstevel@tonic-gate /*
89297c478bd9Sstevel@tonic-gate * ohci_handle_normal_td:
89307c478bd9Sstevel@tonic-gate */
89317c478bd9Sstevel@tonic-gate static void
ohci_handle_normal_td(ohci_state_t * ohcip,ohci_td_t * td,ohci_trans_wrapper_t * tw)89327c478bd9Sstevel@tonic-gate ohci_handle_normal_td(
89337c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
89347c478bd9Sstevel@tonic-gate ohci_td_t *td,
89357c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
89367c478bd9Sstevel@tonic-gate {
89377c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp; /* Pipe private field */
89387c478bd9Sstevel@tonic-gate
89397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
89407c478bd9Sstevel@tonic-gate "ohci_handle_normal_td:");
89417c478bd9Sstevel@tonic-gate
89427c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
89437c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
89447c478bd9Sstevel@tonic-gate
89457c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */
89467c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private;
89477c478bd9Sstevel@tonic-gate
89487c478bd9Sstevel@tonic-gate (*tw->tw_handle_td)(ohcip, pp, tw,
89497c478bd9Sstevel@tonic-gate td, tw->tw_handle_callback_value);
89507c478bd9Sstevel@tonic-gate
89517c478bd9Sstevel@tonic-gate /* Check anybody is waiting for transfers completion event */
89527c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(ohcip, pp);
89537c478bd9Sstevel@tonic-gate }
89547c478bd9Sstevel@tonic-gate
89557c478bd9Sstevel@tonic-gate
89567c478bd9Sstevel@tonic-gate /*
89577c478bd9Sstevel@tonic-gate * ohci_handle_ctrl_td:
89587c478bd9Sstevel@tonic-gate *
89597c478bd9Sstevel@tonic-gate * Handle a control Transfer Descriptor (TD).
89607c478bd9Sstevel@tonic-gate */
89617c478bd9Sstevel@tonic-gate /* ARGSUSED */
89627c478bd9Sstevel@tonic-gate static void
ohci_handle_ctrl_td(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td,void * tw_handle_callback_value)89637c478bd9Sstevel@tonic-gate ohci_handle_ctrl_td(
89647c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
89657c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
89667c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
89677c478bd9Sstevel@tonic-gate ohci_td_t *td,
89687c478bd9Sstevel@tonic-gate void *tw_handle_callback_value)
89697c478bd9Sstevel@tonic-gate {
89707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
89717c478bd9Sstevel@tonic-gate
89727c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
89737c478bd9Sstevel@tonic-gate "ohci_handle_ctrl_td: pp = 0x%p tw = 0x%p td = 0x%p state = 0x%x",
89747c478bd9Sstevel@tonic-gate (void *)pp, (void *)tw, (void *)td, Get_TD(td->hctd_ctrl_phase));
89757c478bd9Sstevel@tonic-gate
89767c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
89777c478bd9Sstevel@tonic-gate
89787c478bd9Sstevel@tonic-gate /*
89797c478bd9Sstevel@tonic-gate * Check which control transfer phase got completed.
89807c478bd9Sstevel@tonic-gate */
89817c478bd9Sstevel@tonic-gate tw->tw_num_tds--;
89827c478bd9Sstevel@tonic-gate switch (Get_TD(td->hctd_ctrl_phase)) {
89837c478bd9Sstevel@tonic-gate case OHCI_CTRL_SETUP_PHASE:
89847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
89857c478bd9Sstevel@tonic-gate "Setup complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
89867c478bd9Sstevel@tonic-gate
89877c478bd9Sstevel@tonic-gate break;
89887c478bd9Sstevel@tonic-gate case OHCI_CTRL_DATA_PHASE:
89897c478bd9Sstevel@tonic-gate /*
89907c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor (TD)
89917c478bd9Sstevel@tonic-gate * is not equal to zero, then we received less data from
89927c478bd9Sstevel@tonic-gate * the device than requested by us. In that case, get the
89937c478bd9Sstevel@tonic-gate * actual received data size.
89947c478bd9Sstevel@tonic-gate */
89957c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) {
899602acac7eSsl147100 size_t length, residue;
89977c478bd9Sstevel@tonic-gate
899802acac7eSsl147100 residue = ohci_get_td_residue(ohcip, td);
899902acac7eSsl147100 length = Get_TD(td->hctd_xfer_offs) +
900002acac7eSsl147100 Get_TD(td->hctd_xfer_len) - residue;
90017c478bd9Sstevel@tonic-gate
90027c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
90037c478bd9Sstevel@tonic-gate "ohci_handle_ctrl_qtd: requested data %lu "
90047c478bd9Sstevel@tonic-gate "received data %lu", tw->tw_length, length);
90057c478bd9Sstevel@tonic-gate
90067c478bd9Sstevel@tonic-gate /* Save actual received data length */
90077c478bd9Sstevel@tonic-gate tw->tw_length = length;
90087c478bd9Sstevel@tonic-gate }
90097c478bd9Sstevel@tonic-gate
90107c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
90117c478bd9Sstevel@tonic-gate "Data complete: pp 0x%p td 0x%p",
90127c478bd9Sstevel@tonic-gate (void *)pp, (void *)td);
90137c478bd9Sstevel@tonic-gate
90147c478bd9Sstevel@tonic-gate break;
90157c478bd9Sstevel@tonic-gate case OHCI_CTRL_STATUS_PHASE:
90167c478bd9Sstevel@tonic-gate if ((tw->tw_length != 0) &&
90177c478bd9Sstevel@tonic-gate (tw->tw_direction == HC_TD_IN)) {
90187c478bd9Sstevel@tonic-gate
90197c478bd9Sstevel@tonic-gate /*
90207c478bd9Sstevel@tonic-gate * Call ohci_sendup_td_message
90217c478bd9Sstevel@tonic-gate * to send message to upstream.
90227c478bd9Sstevel@tonic-gate */
90237c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip,
90247c478bd9Sstevel@tonic-gate pp, tw, td, USB_CR_OK);
90257c478bd9Sstevel@tonic-gate } else {
90267c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip,
902702acac7eSsl147100 tw->tw_length - OHCI_MAX_TD_BUF_SIZE,
90287c478bd9Sstevel@tonic-gate ph->p_ep.bmAttributes,
90297c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress);
90307c478bd9Sstevel@tonic-gate
90317c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK);
90327c478bd9Sstevel@tonic-gate }
90337c478bd9Sstevel@tonic-gate
90347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
90357c478bd9Sstevel@tonic-gate "Status complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
90367c478bd9Sstevel@tonic-gate
90377c478bd9Sstevel@tonic-gate break;
90387c478bd9Sstevel@tonic-gate }
90397c478bd9Sstevel@tonic-gate }
90407c478bd9Sstevel@tonic-gate
90417c478bd9Sstevel@tonic-gate
90427c478bd9Sstevel@tonic-gate /*
90437c478bd9Sstevel@tonic-gate * ohci_handle_bulk_td:
90447c478bd9Sstevel@tonic-gate *
90457c478bd9Sstevel@tonic-gate * Handle a bulk Transfer Descriptor (TD).
90467c478bd9Sstevel@tonic-gate */
90477c478bd9Sstevel@tonic-gate /* ARGSUSED */
90487c478bd9Sstevel@tonic-gate static void
ohci_handle_bulk_td(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td,void * tw_handle_callback_value)90497c478bd9Sstevel@tonic-gate ohci_handle_bulk_td(
90507c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
90517c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
90527c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
90537c478bd9Sstevel@tonic-gate ohci_td_t *td,
90547c478bd9Sstevel@tonic-gate void *tw_handle_callback_value)
90557c478bd9Sstevel@tonic-gate {
90567c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
90577c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
90587c478bd9Sstevel@tonic-gate
90597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
90607c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td:");
90617c478bd9Sstevel@tonic-gate
90627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
90637c478bd9Sstevel@tonic-gate
90647c478bd9Sstevel@tonic-gate /*
90657c478bd9Sstevel@tonic-gate * Decrement the TDs counter and check whether all the bulk
90667c478bd9Sstevel@tonic-gate * data has been send or received. If TDs counter reaches
90677c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current
90687c478bd9Sstevel@tonic-gate * bulk request. Other wise wait for completion of other bulk
90697c478bd9Sstevel@tonic-gate * TDs or transactions on this pipe.
90707c478bd9Sstevel@tonic-gate */
90717c478bd9Sstevel@tonic-gate if (--tw->tw_num_tds != 0) {
90727c478bd9Sstevel@tonic-gate
90737c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
90747c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td: Number of TDs %d", tw->tw_num_tds);
90757c478bd9Sstevel@tonic-gate
90767c478bd9Sstevel@tonic-gate return;
90777c478bd9Sstevel@tonic-gate }
90787c478bd9Sstevel@tonic-gate
90797c478bd9Sstevel@tonic-gate /*
90807c478bd9Sstevel@tonic-gate * If this is a bulk in pipe, return the data to the client.
90817c478bd9Sstevel@tonic-gate * For a bulk out pipe, there is no need to do anything.
90827c478bd9Sstevel@tonic-gate */
90837c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress &
90847c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
90857c478bd9Sstevel@tonic-gate
90867c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
90877c478bd9Sstevel@tonic-gate "ohci_handle_bulk_td: Bulk out pipe");
90887c478bd9Sstevel@tonic-gate
90897c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length,
90907c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress);
90917c478bd9Sstevel@tonic-gate
90927c478bd9Sstevel@tonic-gate /* Do the callback */
90937c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK);
90947c478bd9Sstevel@tonic-gate
90957c478bd9Sstevel@tonic-gate return;
90967c478bd9Sstevel@tonic-gate }
90977c478bd9Sstevel@tonic-gate
90987c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to send message to upstream */
90997c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK);
91007c478bd9Sstevel@tonic-gate }
91017c478bd9Sstevel@tonic-gate
91027c478bd9Sstevel@tonic-gate
91037c478bd9Sstevel@tonic-gate /*
91047c478bd9Sstevel@tonic-gate * ohci_handle_intr_td:
91057c478bd9Sstevel@tonic-gate *
91067c478bd9Sstevel@tonic-gate * Handle a interrupt Transfer Descriptor (TD).
91077c478bd9Sstevel@tonic-gate */
91087c478bd9Sstevel@tonic-gate /* ARGSUSED */
91097c478bd9Sstevel@tonic-gate static void
ohci_handle_intr_td(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td,void * tw_handle_callback_value)91107c478bd9Sstevel@tonic-gate ohci_handle_intr_td(
91117c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
91127c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
91137c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
91147c478bd9Sstevel@tonic-gate ohci_td_t *td,
91157c478bd9Sstevel@tonic-gate void *tw_handle_callback_value)
91167c478bd9Sstevel@tonic-gate {
91177c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp =
91187c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
91197c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
91207c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
91217c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs;
91227c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
91237c478bd9Sstevel@tonic-gate
91247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
91257c478bd9Sstevel@tonic-gate "ohci_handle_intr_td: pp=0x%p tw=0x%p td=0x%p"
9126112116d8Sfb209375 "intr_reqp=0%p data=0x%p", (void *)pp, (void *)tw, (void *)td,
9127112116d8Sfb209375 (void *)curr_intr_reqp, (void *)curr_intr_reqp->intr_data);
91287c478bd9Sstevel@tonic-gate
91297c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
91307c478bd9Sstevel@tonic-gate
91317c478bd9Sstevel@tonic-gate /* Get the interrupt xfer attributes */
91327c478bd9Sstevel@tonic-gate attrs = curr_intr_reqp->intr_attributes;
91337c478bd9Sstevel@tonic-gate
91347c478bd9Sstevel@tonic-gate /*
91357c478bd9Sstevel@tonic-gate * For a Interrupt OUT pipe, we just callback and we are done
91367c478bd9Sstevel@tonic-gate */
91377c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
91387c478bd9Sstevel@tonic-gate
91397c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
91407c478bd9Sstevel@tonic-gate "ohci_handle_intr_td: Intr out pipe, intr_reqp=0x%p,"
9141112116d8Sfb209375 "data=0x%p", (void *)curr_intr_reqp,
9142112116d8Sfb209375 (void *)curr_intr_reqp->intr_data);
91437c478bd9Sstevel@tonic-gate
91447c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length,
91457c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress);
91467c478bd9Sstevel@tonic-gate
91477c478bd9Sstevel@tonic-gate /* Do the callback */
91487c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK);
91497c478bd9Sstevel@tonic-gate
91507c478bd9Sstevel@tonic-gate return;
91517c478bd9Sstevel@tonic-gate }
91527c478bd9Sstevel@tonic-gate
91537c478bd9Sstevel@tonic-gate /* Decrement number of interrupt request count */
91547c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--;
91557c478bd9Sstevel@tonic-gate
91567c478bd9Sstevel@tonic-gate /*
91577c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_XFER flag is set
91587c478bd9Sstevel@tonic-gate * and if so, free duplicate request.
91597c478bd9Sstevel@tonic-gate */
91607c478bd9Sstevel@tonic-gate if (attrs & USB_ATTRS_ONE_XFER) {
91617c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(ohcip, tw);
91627c478bd9Sstevel@tonic-gate }
91637c478bd9Sstevel@tonic-gate
91647c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to callback into client */
91657c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK);
91667c478bd9Sstevel@tonic-gate
91677c478bd9Sstevel@tonic-gate /*
91687c478bd9Sstevel@tonic-gate * If interrupt pipe state is still active, insert next Interrupt
91697c478bd9Sstevel@tonic-gate * request into the Host Controller's Interrupt list. Otherwise
91707c478bd9Sstevel@tonic-gate * you are done.
91717c478bd9Sstevel@tonic-gate */
91727c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) {
91737c478bd9Sstevel@tonic-gate return;
91747c478bd9Sstevel@tonic-gate }
91757c478bd9Sstevel@tonic-gate
91767c478bd9Sstevel@tonic-gate if ((error = ohci_allocate_periodic_in_resource(ohcip, pp, tw, 0)) ==
91777c478bd9Sstevel@tonic-gate USB_SUCCESS) {
91787c478bd9Sstevel@tonic-gate curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
91797c478bd9Sstevel@tonic-gate
91807c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp != NULL);
91817c478bd9Sstevel@tonic-gate
91827c478bd9Sstevel@tonic-gate tw->tw_num_tds = 1;
91837c478bd9Sstevel@tonic-gate
918402acac7eSsl147100 if (ohci_tw_rebind_cookie(ohcip, pp, tw) != USB_SUCCESS) {
918502acac7eSsl147100 ohci_deallocate_periodic_in_resource(ohcip, pp, tw);
918602acac7eSsl147100 error = USB_FAILURE;
918702acac7eSsl147100 } else if (ohci_allocate_tds_for_tw(ohcip, tw,
918802acac7eSsl147100 tw->tw_num_tds) != USB_SUCCESS) {
91897c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw);
91907c478bd9Sstevel@tonic-gate error = USB_FAILURE;
91917c478bd9Sstevel@tonic-gate }
91927c478bd9Sstevel@tonic-gate }
91937c478bd9Sstevel@tonic-gate
91947c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) {
91957c478bd9Sstevel@tonic-gate /*
91967c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no
91977c478bd9Sstevel@tonic-gate * resource. Don't insert any more interrupt polling
91987c478bd9Sstevel@tonic-gate * requests.
91997c478bd9Sstevel@tonic-gate */
92007c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING;
92017c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES;
92027c478bd9Sstevel@tonic-gate } else {
92037c478bd9Sstevel@tonic-gate ohci_insert_intr_req(ohcip, pp, tw, 0);
92047c478bd9Sstevel@tonic-gate
92057c478bd9Sstevel@tonic-gate /* Increment number of interrupt request count */
92067c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++;
92077c478bd9Sstevel@tonic-gate
92087c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt ==
92097c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt);
92107c478bd9Sstevel@tonic-gate }
92117c478bd9Sstevel@tonic-gate }
92127c478bd9Sstevel@tonic-gate
92137c478bd9Sstevel@tonic-gate
92147c478bd9Sstevel@tonic-gate /*
92157c478bd9Sstevel@tonic-gate * ohci_handle_one_xfer_completion:
92167c478bd9Sstevel@tonic-gate */
92177c478bd9Sstevel@tonic-gate static void
ohci_handle_one_xfer_completion(ohci_state_t * ohcip,ohci_trans_wrapper_t * tw)92187c478bd9Sstevel@tonic-gate ohci_handle_one_xfer_completion(
92197c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
92207c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
92217c478bd9Sstevel@tonic-gate {
92227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = tw->tw_pipe_private->pp_pipe_handle;
92237c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = tw->tw_pipe_private;
92247c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp =
92257c478bd9Sstevel@tonic-gate (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
92267c478bd9Sstevel@tonic-gate
92277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
9228112116d8Sfb209375 "ohci_handle_one_xfer_completion: tw = 0x%p", (void *)tw);
92297c478bd9Sstevel@tonic-gate
92307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
92317c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER);
92327c478bd9Sstevel@tonic-gate
92337c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE;
92347c478bd9Sstevel@tonic-gate
92357c478bd9Sstevel@tonic-gate /*
92367c478bd9Sstevel@tonic-gate * For one xfer, we need to copy back data ptr
92377c478bd9Sstevel@tonic-gate * and free current request
92387c478bd9Sstevel@tonic-gate */
92397c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))->
92407c478bd9Sstevel@tonic-gate intr_data = ((usb_intr_req_t *)
92417c478bd9Sstevel@tonic-gate (tw->tw_curr_xfer_reqp))->intr_data;
92427c478bd9Sstevel@tonic-gate
92437c478bd9Sstevel@tonic-gate ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL;
92447c478bd9Sstevel@tonic-gate
92457c478bd9Sstevel@tonic-gate /* Now free duplicate current request */
92467c478bd9Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp);
92477c478bd9Sstevel@tonic-gate
92487c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
92497c478bd9Sstevel@tonic-gate ph->p_req_count--;
92507c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
92517c478bd9Sstevel@tonic-gate
92527c478bd9Sstevel@tonic-gate /* Make client's request the current request */
92537c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
92547c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL;
92557c478bd9Sstevel@tonic-gate }
92567c478bd9Sstevel@tonic-gate
92577c478bd9Sstevel@tonic-gate
92587c478bd9Sstevel@tonic-gate /*
92597c478bd9Sstevel@tonic-gate * ohci_handle_isoc_td:
92607c478bd9Sstevel@tonic-gate *
92617c478bd9Sstevel@tonic-gate * Handle an isochronous Transfer Descriptor (TD).
92627c478bd9Sstevel@tonic-gate */
92637c478bd9Sstevel@tonic-gate /* ARGSUSED */
92647c478bd9Sstevel@tonic-gate static void
ohci_handle_isoc_td(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td,void * tw_handle_callback_value)92657c478bd9Sstevel@tonic-gate ohci_handle_isoc_td(
92667c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
92677c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
92687c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
92697c478bd9Sstevel@tonic-gate ohci_td_t *td,
92707c478bd9Sstevel@tonic-gate void *tw_handle_callback_value)
92717c478bd9Sstevel@tonic-gate {
92727c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
92737c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
92747c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp =
92757c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
92767c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
92777c478bd9Sstevel@tonic-gate
92787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
92797c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: pp=0x%p tw=0x%p td=0x%p"
9280112116d8Sfb209375 "isoc_reqp=0%p data=0x%p", (void *)pp, (void *)tw, (void *)td,
9281112116d8Sfb209375 (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
92827c478bd9Sstevel@tonic-gate
92837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
92847c478bd9Sstevel@tonic-gate
92857c478bd9Sstevel@tonic-gate /*
92867c478bd9Sstevel@tonic-gate * Decrement the TDs counter and check whether all the isoc
92877c478bd9Sstevel@tonic-gate * data has been send or received. If TDs counter reaches
92887c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current
92897c478bd9Sstevel@tonic-gate * isoc request. Otherwise wait for completion of other isoc
92907c478bd9Sstevel@tonic-gate * TDs or transactions on this pipe.
92917c478bd9Sstevel@tonic-gate */
92927c478bd9Sstevel@tonic-gate if (--tw->tw_num_tds != 0) {
92937c478bd9Sstevel@tonic-gate
92947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
92957c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: Number of TDs %d", tw->tw_num_tds);
92967c478bd9Sstevel@tonic-gate
92977c478bd9Sstevel@tonic-gate return;
92987c478bd9Sstevel@tonic-gate }
92997c478bd9Sstevel@tonic-gate
93007c478bd9Sstevel@tonic-gate /*
93017c478bd9Sstevel@tonic-gate * If this is a isoc in pipe, return the data to the client.
93027c478bd9Sstevel@tonic-gate * For a isoc out pipe, there is no need to do anything.
93037c478bd9Sstevel@tonic-gate */
93047c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
93057c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
93067c478bd9Sstevel@tonic-gate "ohci_handle_isoc_td: Isoc out pipe, isoc_reqp=0x%p,"
9307112116d8Sfb209375 "data=0x%p", (void *)curr_isoc_reqp,
9308112116d8Sfb209375 (void *)curr_isoc_reqp->isoc_data);
93097c478bd9Sstevel@tonic-gate
93107c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, tw->tw_length,
93117c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress);
93127c478bd9Sstevel@tonic-gate
93137c478bd9Sstevel@tonic-gate /* Do the callback */
93147c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, USB_CR_OK);
93157c478bd9Sstevel@tonic-gate
93167c478bd9Sstevel@tonic-gate return;
93177c478bd9Sstevel@tonic-gate }
93187c478bd9Sstevel@tonic-gate
93197c478bd9Sstevel@tonic-gate /* Decrement number of IN isochronous request count */
93207c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--;
93217c478bd9Sstevel@tonic-gate
93227c478bd9Sstevel@tonic-gate /* Call ohci_sendup_td_message to send message to upstream */
93237c478bd9Sstevel@tonic-gate ohci_sendup_td_message(ohcip, pp, tw, td, USB_CR_OK);
93247c478bd9Sstevel@tonic-gate
93257c478bd9Sstevel@tonic-gate /*
93267c478bd9Sstevel@tonic-gate * If isochronous pipe state is still active, insert next isochronous
93277c478bd9Sstevel@tonic-gate * request into the Host Controller's isochronous list.
93287c478bd9Sstevel@tonic-gate */
93297c478bd9Sstevel@tonic-gate if (pp->pp_state != OHCI_PIPE_STATE_ACTIVE) {
93307c478bd9Sstevel@tonic-gate return;
93317c478bd9Sstevel@tonic-gate }
93327c478bd9Sstevel@tonic-gate
93337c478bd9Sstevel@tonic-gate if ((error = ohci_allocate_periodic_in_resource(ohcip, pp, tw, 0)) ==
93347c478bd9Sstevel@tonic-gate USB_SUCCESS) {
93357c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
93367c478bd9Sstevel@tonic-gate
93377c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL);
93387c478bd9Sstevel@tonic-gate
93397c478bd9Sstevel@tonic-gate tw->tw_num_tds =
93407c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_pkts_count / OHCI_ISOC_PKTS_PER_TD;
93417c478bd9Sstevel@tonic-gate if (curr_isoc_reqp->isoc_pkts_count % OHCI_ISOC_PKTS_PER_TD) {
93427c478bd9Sstevel@tonic-gate tw->tw_num_tds++;
93437c478bd9Sstevel@tonic-gate }
93447c478bd9Sstevel@tonic-gate
934502acac7eSsl147100 if (ohci_tw_rebind_cookie(ohcip, pp, tw) != USB_SUCCESS) {
934602acac7eSsl147100 ohci_deallocate_periodic_in_resource(ohcip, pp, tw);
934702acac7eSsl147100 error = USB_FAILURE;
934802acac7eSsl147100 } else if (ohci_allocate_tds_for_tw(ohcip, tw,
934902acac7eSsl147100 tw->tw_num_tds) != USB_SUCCESS) {
93507c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(ohcip, pp, tw);
93517c478bd9Sstevel@tonic-gate error = USB_FAILURE;
93527c478bd9Sstevel@tonic-gate }
93537c478bd9Sstevel@tonic-gate }
93547c478bd9Sstevel@tonic-gate
93557c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS ||
93567c478bd9Sstevel@tonic-gate ohci_insert_isoc_req(ohcip, pp, tw, 0) != USB_SUCCESS) {
93577c478bd9Sstevel@tonic-gate /*
93587c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no
93597c478bd9Sstevel@tonic-gate * resource. Don't insert any more isoch polling
93607c478bd9Sstevel@tonic-gate * requests.
93617c478bd9Sstevel@tonic-gate */
93627c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_STOP_POLLING;
93637c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES;
93647c478bd9Sstevel@tonic-gate
93657c478bd9Sstevel@tonic-gate } else {
93667c478bd9Sstevel@tonic-gate /* Increment number of IN isochronous request count */
93677c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++;
93687c478bd9Sstevel@tonic-gate
93697c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt ==
93707c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt);
93717c478bd9Sstevel@tonic-gate }
93727c478bd9Sstevel@tonic-gate }
93737c478bd9Sstevel@tonic-gate
93747c478bd9Sstevel@tonic-gate
93757c478bd9Sstevel@tonic-gate /*
937602acac7eSsl147100 * ohci_tw_rebind_cookie:
937702acac7eSsl147100 *
937802acac7eSsl147100 * If the cookie associated with a DMA buffer has been walked, the cookie
937902acac7eSsl147100 * is not usable any longer. To reuse the DMA buffer, the DMA handle needs
938002acac7eSsl147100 * to rebind for cookies.
938102acac7eSsl147100 */
938202acac7eSsl147100 static int
ohci_tw_rebind_cookie(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)938302acac7eSsl147100 ohci_tw_rebind_cookie(
938402acac7eSsl147100 ohci_state_t *ohcip,
938502acac7eSsl147100 ohci_pipe_private_t *pp,
938602acac7eSsl147100 ohci_trans_wrapper_t *tw)
938702acac7eSsl147100 {
938802acac7eSsl147100 usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep;
938902acac7eSsl147100 int rval, i;
939002acac7eSsl147100 uint_t ccount;
939102acac7eSsl147100
939202acac7eSsl147100 USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
939302acac7eSsl147100 "ohci_tw_rebind_cookie:");
939402acac7eSsl147100
939502acac7eSsl147100 ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
939602acac7eSsl147100
939702acac7eSsl147100 if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
939802acac7eSsl147100 ASSERT(tw->tw_num_tds == tw->tw_ncookies);
939902acac7eSsl147100
940002acac7eSsl147100 for (i = 0; i < tw->tw_num_tds; i++) {
940102acac7eSsl147100 if (tw->tw_isoc_bufs[i].ncookies == 1) {
940202acac7eSsl147100
940302acac7eSsl147100 /*
940402acac7eSsl147100 * no need to rebind when there is
940502acac7eSsl147100 * only one cookie in a buffer
940602acac7eSsl147100 */
940702acac7eSsl147100 continue;
940802acac7eSsl147100 }
940902acac7eSsl147100
941002acac7eSsl147100 /* unbind the DMA handle before rebinding */
941102acac7eSsl147100 rval = ddi_dma_unbind_handle(
941202acac7eSsl147100 tw->tw_isoc_bufs[i].dma_handle);
941302acac7eSsl147100 ASSERT(rval == USB_SUCCESS);
941402acac7eSsl147100 tw->tw_isoc_bufs[i].ncookies = 0;
941502acac7eSsl147100
941602acac7eSsl147100 USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
941702acac7eSsl147100 "rebind dma_handle %d", i);
941802acac7eSsl147100
941902acac7eSsl147100 /* rebind the handle to get cookies */
942002acac7eSsl147100 rval = ddi_dma_addr_bind_handle(
942102acac7eSsl147100 tw->tw_isoc_bufs[i].dma_handle, NULL,
942202acac7eSsl147100 (caddr_t)tw->tw_isoc_bufs[i].buf_addr,
942302acac7eSsl147100 tw->tw_isoc_bufs[i].length,
942402acac7eSsl147100 DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
942502acac7eSsl147100 DDI_DMA_DONTWAIT, NULL,
942602acac7eSsl147100 &tw->tw_isoc_bufs[i].cookie, &ccount);
942702acac7eSsl147100
942802acac7eSsl147100 if ((rval == DDI_DMA_MAPPED) &&
942902acac7eSsl147100 (ccount <= OHCI_DMA_ATTR_TD_SGLLEN)) {
943002acac7eSsl147100 tw->tw_isoc_bufs[i].ncookies = ccount;
943102acac7eSsl147100 } else {
943202acac7eSsl147100
943302acac7eSsl147100 return (USB_NO_RESOURCES);
943402acac7eSsl147100 }
943502acac7eSsl147100 }
943602acac7eSsl147100 } else {
943702acac7eSsl147100 if (tw->tw_cookie_idx != 0) {
943802acac7eSsl147100 /* unbind the DMA handle before rebinding */
943902acac7eSsl147100 rval = ddi_dma_unbind_handle(tw->tw_dmahandle);
944002acac7eSsl147100 ASSERT(rval == DDI_SUCCESS);
944102acac7eSsl147100 tw->tw_ncookies = 0;
944202acac7eSsl147100
944302acac7eSsl147100 USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
944402acac7eSsl147100 "rebind dma_handle");
944502acac7eSsl147100
944602acac7eSsl147100 /* rebind the handle to get cookies */
944702acac7eSsl147100 rval = ddi_dma_addr_bind_handle(
944802acac7eSsl147100 tw->tw_dmahandle, NULL,
944902acac7eSsl147100 (caddr_t)tw->tw_buf, tw->tw_length,
945002acac7eSsl147100 DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
945102acac7eSsl147100 DDI_DMA_DONTWAIT, NULL,
945202acac7eSsl147100 &tw->tw_cookie, &ccount);
945302acac7eSsl147100
945402acac7eSsl147100 if (rval == DDI_DMA_MAPPED) {
945502acac7eSsl147100 tw->tw_ncookies = ccount;
945602acac7eSsl147100 tw->tw_dma_offs = 0;
945702acac7eSsl147100 tw->tw_cookie_idx = 0;
945802acac7eSsl147100 } else {
945902acac7eSsl147100
946002acac7eSsl147100 return (USB_NO_RESOURCES);
946102acac7eSsl147100 }
946202acac7eSsl147100 }
946302acac7eSsl147100 }
946402acac7eSsl147100
946502acac7eSsl147100 return (USB_SUCCESS);
946602acac7eSsl147100 }
946702acac7eSsl147100
946802acac7eSsl147100
946902acac7eSsl147100 /*
94707c478bd9Sstevel@tonic-gate * ohci_sendup_td_message:
94717c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback
94727c478bd9Sstevel@tonic-gate */
94737c478bd9Sstevel@tonic-gate static void
ohci_sendup_td_message(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,ohci_td_t * td,usb_cr_t error)94747c478bd9Sstevel@tonic-gate ohci_sendup_td_message(
94757c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
94767c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
94777c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
94787c478bd9Sstevel@tonic-gate ohci_td_t *td,
94797c478bd9Sstevel@tonic-gate usb_cr_t error)
94807c478bd9Sstevel@tonic-gate {
94817c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep;
94827c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
948302acac7eSsl147100 size_t length = 0, skip_len = 0, residue;
94847c478bd9Sstevel@tonic-gate mblk_t *mp;
94857c478bd9Sstevel@tonic-gate uchar_t *buf;
94867c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp;
94877c478bd9Sstevel@tonic-gate
94887c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
94897c478bd9Sstevel@tonic-gate
94907c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
94917c478bd9Sstevel@tonic-gate "ohci_sendup_td_message:");
94927c478bd9Sstevel@tonic-gate
94937c478bd9Sstevel@tonic-gate ASSERT(tw != NULL);
94947c478bd9Sstevel@tonic-gate
94957c478bd9Sstevel@tonic-gate length = tw->tw_length;
94967c478bd9Sstevel@tonic-gate
94977c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
94987c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
94997c478bd9Sstevel@tonic-gate /*
95007c478bd9Sstevel@tonic-gate * Get the correct length, adjust it for the setup size
95017c478bd9Sstevel@tonic-gate * which is not part of the data length in control end
95027c478bd9Sstevel@tonic-gate * points. Update tw->tw_length for future references.
95037c478bd9Sstevel@tonic-gate */
950402acac7eSsl147100 if (((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_wLength) {
950502acac7eSsl147100 tw->tw_length = length = length - OHCI_MAX_TD_BUF_SIZE;
950602acac7eSsl147100 } else {
95077c478bd9Sstevel@tonic-gate tw->tw_length = length = length - SETUP_SIZE;
950802acac7eSsl147100 }
95097c478bd9Sstevel@tonic-gate
95107c478bd9Sstevel@tonic-gate /* Set the length of the buffer to skip */
951102acac7eSsl147100 skip_len = OHCI_MAX_TD_BUF_SIZE;
95127c478bd9Sstevel@tonic-gate
95137c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_ctrl_phase) != OHCI_CTRL_DATA_PHASE) {
95147c478bd9Sstevel@tonic-gate break;
95157c478bd9Sstevel@tonic-gate }
95167c478bd9Sstevel@tonic-gate /* FALLTHRU */
95177c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
95187c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
95197c478bd9Sstevel@tonic-gate /*
95207c478bd9Sstevel@tonic-gate * If error is "data overrun", do not check for the
95217c478bd9Sstevel@tonic-gate * "CurrentBufferPointer" and return whatever data
95227c478bd9Sstevel@tonic-gate * received to the client driver.
95237c478bd9Sstevel@tonic-gate */
95247c478bd9Sstevel@tonic-gate if (error == USB_CR_DATA_OVERRUN) {
95257c478bd9Sstevel@tonic-gate break;
95267c478bd9Sstevel@tonic-gate }
95277c478bd9Sstevel@tonic-gate
95287c478bd9Sstevel@tonic-gate /*
95297c478bd9Sstevel@tonic-gate * If "CurrentBufferPointer" of Transfer Descriptor
95307c478bd9Sstevel@tonic-gate * (TD) is not equal to zero, then we received less
95317c478bd9Sstevel@tonic-gate * data from the device than requested by us. In that
95327c478bd9Sstevel@tonic-gate * case, get the actual received data size.
95337c478bd9Sstevel@tonic-gate */
95347c478bd9Sstevel@tonic-gate if (Get_TD(td->hctd_cbp)) {
953502acac7eSsl147100 residue = ohci_get_td_residue(ohcip, td);
953602acac7eSsl147100 length = Get_TD(td->hctd_xfer_offs) +
953702acac7eSsl147100 Get_TD(td->hctd_xfer_len) - residue - skip_len;
95387c478bd9Sstevel@tonic-gate
95397c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
95407c478bd9Sstevel@tonic-gate "ohci_sendup_qtd_message: requested data %lu "
95417c478bd9Sstevel@tonic-gate "received data %lu", tw->tw_length, length);
95427c478bd9Sstevel@tonic-gate }
95437c478bd9Sstevel@tonic-gate
95447c478bd9Sstevel@tonic-gate break;
95457c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
95467c478bd9Sstevel@tonic-gate default:
95477c478bd9Sstevel@tonic-gate break;
95487c478bd9Sstevel@tonic-gate }
95497c478bd9Sstevel@tonic-gate
95507c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */
95517c478bd9Sstevel@tonic-gate buf = (uchar_t *)tw->tw_buf + skip_len;
95527c478bd9Sstevel@tonic-gate
95537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
95547c478bd9Sstevel@tonic-gate "ohci_sendup_qtd_message: length %lu error %d", length, error);
95557c478bd9Sstevel@tonic-gate
95567c478bd9Sstevel@tonic-gate /* Get the message block */
95577c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
95587c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
95597c478bd9Sstevel@tonic-gate mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data;
95607c478bd9Sstevel@tonic-gate break;
95617c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
95627c478bd9Sstevel@tonic-gate mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data;
95637c478bd9Sstevel@tonic-gate break;
95647c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
95657c478bd9Sstevel@tonic-gate mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data;
95667c478bd9Sstevel@tonic-gate break;
95677c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
95687c478bd9Sstevel@tonic-gate mp = ((usb_isoc_req_t *)curr_xfer_reqp)->isoc_data;
95697c478bd9Sstevel@tonic-gate break;
95707c478bd9Sstevel@tonic-gate }
95717c478bd9Sstevel@tonic-gate
95727c478bd9Sstevel@tonic-gate ASSERT(mp != NULL);
95737c478bd9Sstevel@tonic-gate
95747c478bd9Sstevel@tonic-gate if (length) {
957502acac7eSsl147100 int i;
957602acac7eSsl147100 uchar_t *p = mp->b_rptr;
957702acac7eSsl147100
95787c478bd9Sstevel@tonic-gate /*
95797c478bd9Sstevel@tonic-gate * Update kstat byte counts
95807c478bd9Sstevel@tonic-gate * The control endpoints don't have direction bits so in
95817c478bd9Sstevel@tonic-gate * order for control stats to be counted correctly an in
95827c478bd9Sstevel@tonic-gate * bit must be faked on a control read.
95837c478bd9Sstevel@tonic-gate */
95847c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
95857c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) {
95867c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, length,
95877c478bd9Sstevel@tonic-gate eptd->bmAttributes, USB_EP_DIR_IN);
95887c478bd9Sstevel@tonic-gate } else {
95897c478bd9Sstevel@tonic-gate ohci_do_byte_stats(ohcip, length,
95907c478bd9Sstevel@tonic-gate eptd->bmAttributes, eptd->bEndpointAddress);
95917c478bd9Sstevel@tonic-gate }
95927c478bd9Sstevel@tonic-gate
959302acac7eSsl147100 if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
959402acac7eSsl147100 USB_EP_ATTR_ISOCH) {
959502acac7eSsl147100 for (i = 0; i < tw->tw_ncookies; i++) {
959602acac7eSsl147100 Sync_IO_Buffer(
959702acac7eSsl147100 tw->tw_isoc_bufs[i].dma_handle,
959802acac7eSsl147100 tw->tw_isoc_bufs[i].length);
959902acac7eSsl147100
960002acac7eSsl147100 ddi_rep_get8(tw->tw_isoc_bufs[i].mem_handle,
960102acac7eSsl147100 p, (uint8_t *)tw->tw_isoc_bufs[i].buf_addr,
960202acac7eSsl147100 tw->tw_isoc_bufs[i].length,
960302acac7eSsl147100 DDI_DEV_AUTOINCR);
960402acac7eSsl147100 p += tw->tw_isoc_bufs[i].length;
960502acac7eSsl147100 }
9606b3001defSlg150142 tw->tw_pkt_idx = 0;
960702acac7eSsl147100 } else {
96087c478bd9Sstevel@tonic-gate /* Sync IO buffer */
960902acac7eSsl147100 Sync_IO_Buffer(tw->tw_dmahandle, (skip_len + length));
96107c478bd9Sstevel@tonic-gate
96117c478bd9Sstevel@tonic-gate /* Copy the data into the message */
96127c478bd9Sstevel@tonic-gate ddi_rep_get8(tw->tw_accesshandle,
96137c478bd9Sstevel@tonic-gate mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
961402acac7eSsl147100 }
96157c478bd9Sstevel@tonic-gate
96167c478bd9Sstevel@tonic-gate /* Increment the write pointer */
96177c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length;
96187c478bd9Sstevel@tonic-gate } else {
96197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
96207c478bd9Sstevel@tonic-gate "ohci_sendup_td_message: Zero length packet");
96217c478bd9Sstevel@tonic-gate }
96227c478bd9Sstevel@tonic-gate
96237c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, tw, error);
96247c478bd9Sstevel@tonic-gate }
96257c478bd9Sstevel@tonic-gate
96267c478bd9Sstevel@tonic-gate
96277c478bd9Sstevel@tonic-gate /*
962802acac7eSsl147100 * ohci_get_td_residue:
962902acac7eSsl147100 *
963002acac7eSsl147100 * Calculate the bytes not transfered by the TD
963102acac7eSsl147100 */
963202acac7eSsl147100 size_t
ohci_get_td_residue(ohci_state_t * ohcip,ohci_td_t * td)963302acac7eSsl147100 ohci_get_td_residue(
963402acac7eSsl147100 ohci_state_t *ohcip,
963502acac7eSsl147100 ohci_td_t *td)
963602acac7eSsl147100 {
963702acac7eSsl147100 uint32_t buf_addr, end_addr;
963802acac7eSsl147100 size_t residue;
963902acac7eSsl147100
964002acac7eSsl147100 buf_addr = Get_TD(td->hctd_cbp);
964102acac7eSsl147100 end_addr = Get_TD(td->hctd_buf_end);
964202acac7eSsl147100
964302acac7eSsl147100 if ((buf_addr & 0xfffff000) ==
964402acac7eSsl147100 (end_addr & 0xfffff000)) {
964502acac7eSsl147100 residue = end_addr - buf_addr + 1;
964602acac7eSsl147100 } else {
964702acac7eSsl147100 residue = OHCI_MAX_TD_BUF_SIZE -
964802acac7eSsl147100 (buf_addr & 0x00000fff) +
964902acac7eSsl147100 (end_addr & 0x00000fff) + 1;
965002acac7eSsl147100 }
965102acac7eSsl147100
965202acac7eSsl147100 return (residue);
965302acac7eSsl147100 }
965402acac7eSsl147100
965502acac7eSsl147100
965602acac7eSsl147100 /*
96577c478bd9Sstevel@tonic-gate * Miscellaneous functions
96587c478bd9Sstevel@tonic-gate */
96597c478bd9Sstevel@tonic-gate
96607c478bd9Sstevel@tonic-gate /*
96617c478bd9Sstevel@tonic-gate * ohci_obtain_state:
96627c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
96637c478bd9Sstevel@tonic-gate */
96647c478bd9Sstevel@tonic-gate ohci_state_t *
ohci_obtain_state(dev_info_t * dip)96657c478bd9Sstevel@tonic-gate ohci_obtain_state(dev_info_t *dip)
96667c478bd9Sstevel@tonic-gate {
96677c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
96687c478bd9Sstevel@tonic-gate ohci_state_t *state = ddi_get_soft_state(
96697c478bd9Sstevel@tonic-gate ohci_statep, instance);
96707c478bd9Sstevel@tonic-gate
96717c478bd9Sstevel@tonic-gate ASSERT(state != NULL);
96727c478bd9Sstevel@tonic-gate
96737c478bd9Sstevel@tonic-gate return (state);
96747c478bd9Sstevel@tonic-gate }
96757c478bd9Sstevel@tonic-gate
96767c478bd9Sstevel@tonic-gate
96777c478bd9Sstevel@tonic-gate /*
96787c478bd9Sstevel@tonic-gate * ohci_state_is_operational:
96797c478bd9Sstevel@tonic-gate *
96807c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values.
96817c478bd9Sstevel@tonic-gate */
96827c478bd9Sstevel@tonic-gate int
ohci_state_is_operational(ohci_state_t * ohcip)96837c478bd9Sstevel@tonic-gate ohci_state_is_operational(ohci_state_t *ohcip)
96847c478bd9Sstevel@tonic-gate {
96857c478bd9Sstevel@tonic-gate int val;
96867c478bd9Sstevel@tonic-gate
96877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
96887c478bd9Sstevel@tonic-gate
96897c478bd9Sstevel@tonic-gate switch (ohcip->ohci_hc_soft_state) {
96907c478bd9Sstevel@tonic-gate case OHCI_CTLR_INIT_STATE:
96917c478bd9Sstevel@tonic-gate case OHCI_CTLR_SUSPEND_STATE:
96927c478bd9Sstevel@tonic-gate val = USB_FAILURE;
96937c478bd9Sstevel@tonic-gate break;
96947c478bd9Sstevel@tonic-gate case OHCI_CTLR_OPERATIONAL_STATE:
96957c478bd9Sstevel@tonic-gate val = USB_SUCCESS;
96967c478bd9Sstevel@tonic-gate break;
96977c478bd9Sstevel@tonic-gate case OHCI_CTLR_ERROR_STATE:
96987c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR;
96997c478bd9Sstevel@tonic-gate break;
97007c478bd9Sstevel@tonic-gate default:
97017c478bd9Sstevel@tonic-gate val = USB_FAILURE;
97027c478bd9Sstevel@tonic-gate break;
97037c478bd9Sstevel@tonic-gate }
97047c478bd9Sstevel@tonic-gate
97057c478bd9Sstevel@tonic-gate return (val);
97067c478bd9Sstevel@tonic-gate }
97077c478bd9Sstevel@tonic-gate
97087c478bd9Sstevel@tonic-gate
97097c478bd9Sstevel@tonic-gate /*
97107c478bd9Sstevel@tonic-gate * ohci_do_soft_reset
97117c478bd9Sstevel@tonic-gate *
97127c478bd9Sstevel@tonic-gate * Do soft reset of ohci host controller.
97137c478bd9Sstevel@tonic-gate */
97147c478bd9Sstevel@tonic-gate int
ohci_do_soft_reset(ohci_state_t * ohcip)97157c478bd9Sstevel@tonic-gate ohci_do_soft_reset(ohci_state_t *ohcip)
97167c478bd9Sstevel@tonic-gate {
97177c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number;
97187c478bd9Sstevel@tonic-gate timeout_id_t xfer_timer_id, rh_timer_id;
97197c478bd9Sstevel@tonic-gate ohci_regs_t *ohci_save_regs;
97207c478bd9Sstevel@tonic-gate ohci_td_t *done_head;
97217c478bd9Sstevel@tonic-gate
97227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
97237c478bd9Sstevel@tonic-gate
97247c478bd9Sstevel@tonic-gate /* Increment host controller error count */
97257c478bd9Sstevel@tonic-gate ohcip->ohci_hc_error++;
97267c478bd9Sstevel@tonic-gate
97277c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
97287c478bd9Sstevel@tonic-gate "ohci_do_soft_reset:"
97297c478bd9Sstevel@tonic-gate "Reset ohci host controller 0x%x", ohcip->ohci_hc_error);
97307c478bd9Sstevel@tonic-gate
97317c478bd9Sstevel@tonic-gate /*
97327c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller
97337c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation
97347c478bd9Sstevel@tonic-gate * fails.
97357c478bd9Sstevel@tonic-gate */
97367c478bd9Sstevel@tonic-gate ohci_save_regs = (ohci_regs_t *)
97377c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ohci_regs_t), KM_NOSLEEP);
97387c478bd9Sstevel@tonic-gate
97397c478bd9Sstevel@tonic-gate if (ohci_save_regs == NULL) {
97407c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
97417c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: kmem_zalloc failed");
97427c478bd9Sstevel@tonic-gate
97437c478bd9Sstevel@tonic-gate return (USB_FAILURE);
97447c478bd9Sstevel@tonic-gate }
97457c478bd9Sstevel@tonic-gate
97467c478bd9Sstevel@tonic-gate /* Save current ohci registers */
97477c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_control = Get_OpReg(hcr_control);
97487c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_cmd_status = Get_OpReg(hcr_cmd_status);
97497c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_intr_enable = Get_OpReg(hcr_intr_enable);
97507c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_periodic_strt = Get_OpReg(hcr_periodic_strt);
97517c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_frame_interval = Get_OpReg(hcr_frame_interval);
97527c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_HCCA = Get_OpReg(hcr_HCCA);
97537c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_bulk_head = Get_OpReg(hcr_bulk_head);
97547c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_ctrl_head = Get_OpReg(hcr_ctrl_head);
97557c478bd9Sstevel@tonic-gate
97567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
9757112116d8Sfb209375 "ohci_do_soft_reset: Save reg = 0x%p", (void *)ohci_save_regs);
97587c478bd9Sstevel@tonic-gate
97597c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */
97607c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE |
97617c478bd9Sstevel@tonic-gate HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE)));
97627c478bd9Sstevel@tonic-gate
97637c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_disable, HCR_INTR_SO |
97647c478bd9Sstevel@tonic-gate HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE |
97657c478bd9Sstevel@tonic-gate HCR_INTR_FNO | HCR_INTR_SOF | HCR_INTR_MIE);
97667c478bd9Sstevel@tonic-gate
97677c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */
97687c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT);
97697c478bd9Sstevel@tonic-gate
97707c478bd9Sstevel@tonic-gate /* Root hub interrupt pipe timeout id */
97717c478bd9Sstevel@tonic-gate rh_timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id;
97727c478bd9Sstevel@tonic-gate
97737c478bd9Sstevel@tonic-gate /* Stop the root hub interrupt timer */
97747c478bd9Sstevel@tonic-gate if (rh_timer_id) {
97757c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
97767c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state =
97777c478bd9Sstevel@tonic-gate OHCI_PIPE_STATE_IDLE;
97787c478bd9Sstevel@tonic-gate
97797c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
97807c478bd9Sstevel@tonic-gate (void) untimeout(rh_timer_id);
97817c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
97827c478bd9Sstevel@tonic-gate }
97837c478bd9Sstevel@tonic-gate
97847c478bd9Sstevel@tonic-gate /* Transfer timeout id */
97857c478bd9Sstevel@tonic-gate xfer_timer_id = ohcip->ohci_timer_id;
97867c478bd9Sstevel@tonic-gate
97877c478bd9Sstevel@tonic-gate /* Stop the global transfer timer */
97887c478bd9Sstevel@tonic-gate if (xfer_timer_id) {
97897c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = 0;
97907c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
97917c478bd9Sstevel@tonic-gate (void) untimeout(xfer_timer_id);
97927c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
97937c478bd9Sstevel@tonic-gate }
97947c478bd9Sstevel@tonic-gate
97957c478bd9Sstevel@tonic-gate /* Process any pending HCCA DoneHead */
97967c478bd9Sstevel@tonic-gate done_head = (ohci_td_t *)(uintptr_t)
9797e026ab87Sgc161489 (Get_HCCA(ohcip->ohci_hccap->HccaDoneHead) & HCCA_DONE_HEAD_MASK);
97987c478bd9Sstevel@tonic-gate
9799688b07c5Sgc161489 if (ohci_check_done_head(ohcip, done_head) == USB_SUCCESS) {
98007c478bd9Sstevel@tonic-gate /* Reset the done head to NULL */
98013e1e1e62SToomas Soome Set_HCCA(ohcip->ohci_hccap->HccaDoneHead, 0);
98027c478bd9Sstevel@tonic-gate
98037c478bd9Sstevel@tonic-gate ohci_traverse_done_list(ohcip, done_head);
98047c478bd9Sstevel@tonic-gate }
98057c478bd9Sstevel@tonic-gate
98067c478bd9Sstevel@tonic-gate /* Process any pending hcr_done_head value */
9807e026ab87Sgc161489 done_head = (ohci_td_t *)(uintptr_t)
9808e026ab87Sgc161489 (Get_OpReg(hcr_done_head) & HCCA_DONE_HEAD_MASK);
9809688b07c5Sgc161489 if (ohci_check_done_head(ohcip, done_head) == USB_SUCCESS) {
9810688b07c5Sgc161489
9811688b07c5Sgc161489 ohci_traverse_done_list(ohcip, done_head);
98127c478bd9Sstevel@tonic-gate }
98137c478bd9Sstevel@tonic-gate
98147c478bd9Sstevel@tonic-gate /* Do soft reset of ohci host controller */
98157c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET);
98167c478bd9Sstevel@tonic-gate
98177c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
98187c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Reset in progress");
98197c478bd9Sstevel@tonic-gate
98207c478bd9Sstevel@tonic-gate /* Wait for reset to complete */
98217c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESET_TIMEWAIT);
98227c478bd9Sstevel@tonic-gate
98237c478bd9Sstevel@tonic-gate /* Reset HCCA HcFrameNumber */
98247c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaFrameNo, 0x00000000);
98257c478bd9Sstevel@tonic-gate
98267c478bd9Sstevel@tonic-gate /*
98277c478bd9Sstevel@tonic-gate * Restore previous saved HC register value
98287c478bd9Sstevel@tonic-gate * into the current HC registers.
98297c478bd9Sstevel@tonic-gate */
98307c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_strt, (uint32_t)
98317c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_periodic_strt);
98327c478bd9Sstevel@tonic-gate
98337c478bd9Sstevel@tonic-gate Set_OpReg(hcr_frame_interval, (uint32_t)
98347c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_frame_interval);
98357c478bd9Sstevel@tonic-gate
98367c478bd9Sstevel@tonic-gate Set_OpReg(hcr_done_head, 0x0);
98377c478bd9Sstevel@tonic-gate
98387c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_curr, 0x0);
98397c478bd9Sstevel@tonic-gate
98407c478bd9Sstevel@tonic-gate Set_OpReg(hcr_bulk_head, (uint32_t)
98417c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_bulk_head);
98427c478bd9Sstevel@tonic-gate
98437c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_curr, 0x0);
98447c478bd9Sstevel@tonic-gate
98457c478bd9Sstevel@tonic-gate Set_OpReg(hcr_ctrl_head, (uint32_t)
98467c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_ctrl_head);
98477c478bd9Sstevel@tonic-gate
98487c478bd9Sstevel@tonic-gate Set_OpReg(hcr_periodic_curr, 0x0);
98497c478bd9Sstevel@tonic-gate
98507c478bd9Sstevel@tonic-gate Set_OpReg(hcr_HCCA, (uint32_t)
98517c478bd9Sstevel@tonic-gate ohci_save_regs->hcr_HCCA);
98527c478bd9Sstevel@tonic-gate
98537c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_status, 0x0);
98547c478bd9Sstevel@tonic-gate
98557c478bd9Sstevel@tonic-gate /*
98567c478bd9Sstevel@tonic-gate * Set HcInterruptEnable to enable all interrupts except
98577c478bd9Sstevel@tonic-gate * Root Hub Status change interrupt.
98587c478bd9Sstevel@tonic-gate */
98597c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable,
98607c478bd9Sstevel@tonic-gate HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE |
98617c478bd9Sstevel@tonic-gate HCR_INTR_FNO | HCR_INTR_SOF | HCR_INTR_MIE);
98627c478bd9Sstevel@tonic-gate
98637c478bd9Sstevel@tonic-gate /* Start Control and Bulk list processing */
98647c478bd9Sstevel@tonic-gate Set_OpReg(hcr_cmd_status, (HCR_STATUS_CLF | HCR_STATUS_BLF));
98657c478bd9Sstevel@tonic-gate
98667c478bd9Sstevel@tonic-gate /*
98677c478bd9Sstevel@tonic-gate * Start up Control, Bulk, Periodic and Isochronous lists
98687c478bd9Sstevel@tonic-gate * processing.
98697c478bd9Sstevel@tonic-gate */
98707c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, (uint32_t)
98717c478bd9Sstevel@tonic-gate (ohci_save_regs->hcr_control & (~HCR_CONTROL_HCFS)));
98727c478bd9Sstevel@tonic-gate
98737c478bd9Sstevel@tonic-gate /*
98747c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving
98757c478bd9Sstevel@tonic-gate * HC registers.
98767c478bd9Sstevel@tonic-gate */
98777c478bd9Sstevel@tonic-gate kmem_free((void *) ohci_save_regs, sizeof (ohci_regs_t));
98787c478bd9Sstevel@tonic-gate
98797c478bd9Sstevel@tonic-gate /* Resume the host controller */
98807c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) &
98817c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESUME));
98827c478bd9Sstevel@tonic-gate
98837c478bd9Sstevel@tonic-gate /* Wait for resume to complete */
98847c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_RESUME_TIMEWAIT);
98857c478bd9Sstevel@tonic-gate
98867c478bd9Sstevel@tonic-gate /* Set the Host Controller Functional State to Operational */
98877c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) &
98887c478bd9Sstevel@tonic-gate (~HCR_CONTROL_HCFS)) | HCR_CONTROL_OPERAT));
98897c478bd9Sstevel@tonic-gate
98907c478bd9Sstevel@tonic-gate /* Wait 10ms for HC to start sending SOF */
98917c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT);
98927c478bd9Sstevel@tonic-gate
98937c478bd9Sstevel@tonic-gate /*
98947c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for few
98957c478bd9Sstevel@tonic-gate * milliseconds.
98967c478bd9Sstevel@tonic-gate */
98977c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip);
98987c478bd9Sstevel@tonic-gate
98997c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */
99007c478bd9Sstevel@tonic-gate drv_usecwait(OHCI_TIMEWAIT);
99017c478bd9Sstevel@tonic-gate
99027c478bd9Sstevel@tonic-gate /*
99037c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for few
99047c478bd9Sstevel@tonic-gate * milliseconds.
99057c478bd9Sstevel@tonic-gate */
99067c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip);
99077c478bd9Sstevel@tonic-gate
99087c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
99097c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Before Frm No 0x%llx After Frm No 0x%llx",
9910112116d8Sfb209375 (unsigned long long)before_frame_number,
9911112116d8Sfb209375 (unsigned long long)after_frame_number);
99127c478bd9Sstevel@tonic-gate
99137c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) {
99147c478bd9Sstevel@tonic-gate
99157c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
99167c478bd9Sstevel@tonic-gate "ohci_do_soft_reset: Soft reset failed");
99177c478bd9Sstevel@tonic-gate
99187c478bd9Sstevel@tonic-gate return (USB_FAILURE);
99197c478bd9Sstevel@tonic-gate }
99207c478bd9Sstevel@tonic-gate
99217c478bd9Sstevel@tonic-gate /* Start the timer for the root hub interrupt pipe polling */
99227c478bd9Sstevel@tonic-gate if (rh_timer_id) {
99237c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id =
99247c478bd9Sstevel@tonic-gate timeout(ohci_handle_root_hub_status_change,
99257c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME));
99267c478bd9Sstevel@tonic-gate
99277c478bd9Sstevel@tonic-gate ohcip->ohci_root_hub.
99287c478bd9Sstevel@tonic-gate rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE;
99297c478bd9Sstevel@tonic-gate }
99307c478bd9Sstevel@tonic-gate
99317c478bd9Sstevel@tonic-gate /* Start the global timer */
99327c478bd9Sstevel@tonic-gate if (xfer_timer_id) {
99337c478bd9Sstevel@tonic-gate ohcip->ohci_timer_id = timeout(ohci_xfer_timeout_handler,
99347c478bd9Sstevel@tonic-gate (void *)ohcip, drv_usectohz(1000000));
99357c478bd9Sstevel@tonic-gate }
99367c478bd9Sstevel@tonic-gate
99377c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
99387c478bd9Sstevel@tonic-gate }
99397c478bd9Sstevel@tonic-gate
99407c478bd9Sstevel@tonic-gate
99417c478bd9Sstevel@tonic-gate /*
99427c478bd9Sstevel@tonic-gate * ohci_get_current_frame_number:
99437c478bd9Sstevel@tonic-gate *
99447c478bd9Sstevel@tonic-gate * Get the current software based usb frame number.
99457c478bd9Sstevel@tonic-gate */
99467c478bd9Sstevel@tonic-gate usb_frame_number_t
ohci_get_current_frame_number(ohci_state_t * ohcip)99477c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohci_state_t *ohcip)
99487c478bd9Sstevel@tonic-gate {
99497c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number;
99507c478bd9Sstevel@tonic-gate usb_frame_number_t ohci_fno, frame_number;
99517c478bd9Sstevel@tonic-gate ohci_save_intr_sts_t *ohci_intr_sts =
99527c478bd9Sstevel@tonic-gate &ohcip->ohci_save_intr_sts;
99537c478bd9Sstevel@tonic-gate
99547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
99557c478bd9Sstevel@tonic-gate
99567c478bd9Sstevel@tonic-gate /*
99577c478bd9Sstevel@tonic-gate * Sync HCCA area only if this function
99587c478bd9Sstevel@tonic-gate * is invoked in non interrupt context.
99597c478bd9Sstevel@tonic-gate */
99607c478bd9Sstevel@tonic-gate if (!(ohci_intr_sts->ohci_intr_flag &
99617c478bd9Sstevel@tonic-gate OHCI_INTR_HANDLING)) {
99627c478bd9Sstevel@tonic-gate
99637c478bd9Sstevel@tonic-gate /* Sync HCCA area */
99647c478bd9Sstevel@tonic-gate Sync_HCCA(ohcip);
99657c478bd9Sstevel@tonic-gate }
99667c478bd9Sstevel@tonic-gate
99677c478bd9Sstevel@tonic-gate ohci_fno = ohcip->ohci_fno;
99687c478bd9Sstevel@tonic-gate frame_number = Get_HCCA(ohcip->ohci_hccap->HccaFrameNo);
99697c478bd9Sstevel@tonic-gate
99707c478bd9Sstevel@tonic-gate /*
99717c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number.
99727c478bd9Sstevel@tonic-gate *
99737c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is
99747c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ohci driver
99757c478bd9Sstevel@tonic-gate * gets an FrameNumberOverflow (FNO) interrupt that will
99767c478bd9Sstevel@tonic-gate * adjust Frame higher part.
99777c478bd9Sstevel@tonic-gate *
99787c478bd9Sstevel@tonic-gate * Refer ohci specification 1.0a, section 5.4, page 86.
99797c478bd9Sstevel@tonic-gate */
99807c478bd9Sstevel@tonic-gate usb_frame_number = ((frame_number & 0x7FFF) | ohci_fno) +
99817c478bd9Sstevel@tonic-gate (((frame_number & 0xFFFF) ^ ohci_fno) & 0x8000);
99827c478bd9Sstevel@tonic-gate
99837c478bd9Sstevel@tonic-gate return (usb_frame_number);
99847c478bd9Sstevel@tonic-gate }
99857c478bd9Sstevel@tonic-gate
99867c478bd9Sstevel@tonic-gate
99877c478bd9Sstevel@tonic-gate /*
99887c478bd9Sstevel@tonic-gate * ohci_cpr_cleanup:
99897c478bd9Sstevel@tonic-gate *
99907c478bd9Sstevel@tonic-gate * Cleanup ohci state and other ohci specific informations across
99917c478bd9Sstevel@tonic-gate * Check Point Resume (CPR).
99927c478bd9Sstevel@tonic-gate */
99937c478bd9Sstevel@tonic-gate static void
ohci_cpr_cleanup(ohci_state_t * ohcip)99947c478bd9Sstevel@tonic-gate ohci_cpr_cleanup(ohci_state_t *ohcip)
99957c478bd9Sstevel@tonic-gate {
99967c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
99977c478bd9Sstevel@tonic-gate
99987c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */
99997c478bd9Sstevel@tonic-gate ohcip->ohci_fno = 0;
100007c478bd9Sstevel@tonic-gate
100017c478bd9Sstevel@tonic-gate /* Reset Schedule Overrrun Error Counter */
100027c478bd9Sstevel@tonic-gate ohcip->ohci_so_error = 0;
100037c478bd9Sstevel@tonic-gate
100047c478bd9Sstevel@tonic-gate /* Reset HCCA HcFrameNumber */
100057c478bd9Sstevel@tonic-gate Set_HCCA(ohcip->ohci_hccap->HccaFrameNo, 0x00000000);
100067c478bd9Sstevel@tonic-gate }
100077c478bd9Sstevel@tonic-gate
100087c478bd9Sstevel@tonic-gate
100097c478bd9Sstevel@tonic-gate /*
100107c478bd9Sstevel@tonic-gate * ohci_get_xfer_attrs:
100117c478bd9Sstevel@tonic-gate *
100127c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer.
100137c478bd9Sstevel@tonic-gate */
100147c478bd9Sstevel@tonic-gate static usb_req_attrs_t
ohci_get_xfer_attrs(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)100157c478bd9Sstevel@tonic-gate ohci_get_xfer_attrs(
100167c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
100177c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
100187c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
100197c478bd9Sstevel@tonic-gate {
100207c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep;
100217c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = 0;
100227c478bd9Sstevel@tonic-gate
100237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
100247c478bd9Sstevel@tonic-gate "ohci_get_xfer_attrs:");
100257c478bd9Sstevel@tonic-gate
100267c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
100277c478bd9Sstevel@tonic-gate
100287c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
100297c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
100307c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *)
100317c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes;
100327c478bd9Sstevel@tonic-gate break;
100337c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
100347c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *)
100357c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes;
100367c478bd9Sstevel@tonic-gate break;
100377c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
100387c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *)
100397c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes;
100407c478bd9Sstevel@tonic-gate break;
100417c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
100427c478bd9Sstevel@tonic-gate attrs = ((usb_isoc_req_t *)
100437c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->isoc_attributes;
100447c478bd9Sstevel@tonic-gate break;
100457c478bd9Sstevel@tonic-gate }
100467c478bd9Sstevel@tonic-gate
100477c478bd9Sstevel@tonic-gate return (attrs);
100487c478bd9Sstevel@tonic-gate }
100497c478bd9Sstevel@tonic-gate
100507c478bd9Sstevel@tonic-gate
100517c478bd9Sstevel@tonic-gate /*
100527c478bd9Sstevel@tonic-gate * ohci_allocate_periodic_in_resource
100537c478bd9Sstevel@tonic-gate *
100547c478bd9Sstevel@tonic-gate * Allocate interrupt/isochronous request structure for the
100557c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer.
100567c478bd9Sstevel@tonic-gate */
100577c478bd9Sstevel@tonic-gate static int
ohci_allocate_periodic_in_resource(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw,usb_flags_t flags)100587c478bd9Sstevel@tonic-gate ohci_allocate_periodic_in_resource(
100597c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
100607c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
100617c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
100627c478bd9Sstevel@tonic-gate usb_flags_t flags)
100637c478bd9Sstevel@tonic-gate {
100647c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
100657c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes;
100667c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
100677c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp;
100687c478bd9Sstevel@tonic-gate usb_opaque_t client_periodic_in_reqp;
100697c478bd9Sstevel@tonic-gate size_t length = 0;
100707c478bd9Sstevel@tonic-gate
100717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
100727c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource:"
10073112116d8Sfb209375 "pp = 0x%p tw = 0x%p flags = 0x%x", (void *)pp, (void *)tw, flags);
100747c478bd9Sstevel@tonic-gate
100757c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
100767c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp == NULL);
100777c478bd9Sstevel@tonic-gate
100787c478bd9Sstevel@tonic-gate /* Get the client periodic in request pointer */
100797c478bd9Sstevel@tonic-gate client_periodic_in_reqp = pp->pp_client_periodic_in_reqp;
100807c478bd9Sstevel@tonic-gate
100817c478bd9Sstevel@tonic-gate /*
100827c478bd9Sstevel@tonic-gate * If it a periodic IN request and periodic request is NULL,
100837c478bd9Sstevel@tonic-gate * allocate corresponding usb periodic IN request for the
100847c478bd9Sstevel@tonic-gate * current periodic polling request and copy the information
100857c478bd9Sstevel@tonic-gate * from the saved periodic request structure.
100867c478bd9Sstevel@tonic-gate */
100877c478bd9Sstevel@tonic-gate if ((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
100887c478bd9Sstevel@tonic-gate
100897c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp) {
100907c478bd9Sstevel@tonic-gate
100917c478bd9Sstevel@tonic-gate /* Get the interrupt transfer length */
100927c478bd9Sstevel@tonic-gate length = ((usb_intr_req_t *)
100937c478bd9Sstevel@tonic-gate client_periodic_in_reqp)->intr_len;
100947c478bd9Sstevel@tonic-gate
100957c478bd9Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req(
100967c478bd9Sstevel@tonic-gate ph->p_dip, (usb_intr_req_t *)
100977c478bd9Sstevel@tonic-gate client_periodic_in_reqp, length, flags);
100987c478bd9Sstevel@tonic-gate } else {
100997c478bd9Sstevel@tonic-gate curr_intr_reqp = usb_alloc_intr_req(
101007c478bd9Sstevel@tonic-gate ph->p_dip, length, flags);
101017c478bd9Sstevel@tonic-gate }
101027c478bd9Sstevel@tonic-gate
101037c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
101047c478bd9Sstevel@tonic-gate
101057c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
101067c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource: Interrupt "
101077c478bd9Sstevel@tonic-gate "request structure allocation failed");
101087c478bd9Sstevel@tonic-gate
101097c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
101107c478bd9Sstevel@tonic-gate }
101117c478bd9Sstevel@tonic-gate
101127c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp == NULL) {
101137c478bd9Sstevel@tonic-gate /* For polled mode */
101147c478bd9Sstevel@tonic-gate curr_intr_reqp->
101157c478bd9Sstevel@tonic-gate intr_attributes = USB_ATTRS_SHORT_XFER_OK;
101167c478bd9Sstevel@tonic-gate curr_intr_reqp->
101177c478bd9Sstevel@tonic-gate intr_len = ph->p_ep.wMaxPacketSize;
101187c478bd9Sstevel@tonic-gate } else {
101197c478bd9Sstevel@tonic-gate /* Check and save the timeout value */
101207c478bd9Sstevel@tonic-gate tw->tw_timeout = (curr_intr_reqp->intr_attributes &
101217c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) ?
101227c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_timeout: 0;
101237c478bd9Sstevel@tonic-gate }
101247c478bd9Sstevel@tonic-gate
101257c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)curr_intr_reqp;
101267c478bd9Sstevel@tonic-gate tw->tw_length = curr_intr_reqp->intr_len;
101277c478bd9Sstevel@tonic-gate } else {
101287c478bd9Sstevel@tonic-gate ASSERT(client_periodic_in_reqp != NULL);
101297c478bd9Sstevel@tonic-gate
101307c478bd9Sstevel@tonic-gate curr_isoc_reqp = usba_hcdi_dup_isoc_req(ph->p_dip,
101317c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)client_periodic_in_reqp, flags);
101327c478bd9Sstevel@tonic-gate
101337c478bd9Sstevel@tonic-gate if (curr_isoc_reqp == NULL) {
101347c478bd9Sstevel@tonic-gate
101357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
101367c478bd9Sstevel@tonic-gate "ohci_allocate_periodic_in_resource: Isochronous"
101377c478bd9Sstevel@tonic-gate "request structure allocation failed");
101387c478bd9Sstevel@tonic-gate
101397c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
101407c478bd9Sstevel@tonic-gate }
101417c478bd9Sstevel@tonic-gate
101427c478bd9Sstevel@tonic-gate /*
101437c478bd9Sstevel@tonic-gate * Save the client's isochronous request pointer and
101447c478bd9Sstevel@tonic-gate * length of isochronous transfer in transfer wrapper.
101457c478bd9Sstevel@tonic-gate * The dup'ed request is saved in pp_client_periodic_in_reqp
101467c478bd9Sstevel@tonic-gate */
101477c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp =
101487c478bd9Sstevel@tonic-gate (usb_opaque_t)pp->pp_client_periodic_in_reqp;
101497c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = (usb_opaque_t)curr_isoc_reqp;
101507c478bd9Sstevel@tonic-gate }
101517c478bd9Sstevel@tonic-gate
101527c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
101537c478bd9Sstevel@tonic-gate ph->p_req_count++;
101547c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
101557c478bd9Sstevel@tonic-gate
101567c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_ACTIVE;
101577c478bd9Sstevel@tonic-gate
101587c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
101597c478bd9Sstevel@tonic-gate }
101607c478bd9Sstevel@tonic-gate
101617c478bd9Sstevel@tonic-gate
101627c478bd9Sstevel@tonic-gate /*
101637c478bd9Sstevel@tonic-gate * ohci_wait_for_sof:
101647c478bd9Sstevel@tonic-gate *
101657c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts
101667c478bd9Sstevel@tonic-gate */
101677c478bd9Sstevel@tonic-gate static int
ohci_wait_for_sof(ohci_state_t * ohcip)101687c478bd9Sstevel@tonic-gate ohci_wait_for_sof(ohci_state_t *ohcip)
101697c478bd9Sstevel@tonic-gate {
101707c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number;
101717c478bd9Sstevel@tonic-gate clock_t sof_time_wait;
101727c478bd9Sstevel@tonic-gate int rval, sof_wait_count;
101737c478bd9Sstevel@tonic-gate
101747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
101757c478bd9Sstevel@tonic-gate "ohci_wait_for_sof");
101767c478bd9Sstevel@tonic-gate
101777c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
101787c478bd9Sstevel@tonic-gate
101797c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
101807c478bd9Sstevel@tonic-gate
101817c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
101827c478bd9Sstevel@tonic-gate
101837c478bd9Sstevel@tonic-gate return (rval);
101847c478bd9Sstevel@tonic-gate }
101857c478bd9Sstevel@tonic-gate
101867c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */
101877c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz(OHCI_MAX_SOF_TIMEWAIT * 1000000);
101887c478bd9Sstevel@tonic-gate
101897c478bd9Sstevel@tonic-gate sof_wait_count = 0;
101907c478bd9Sstevel@tonic-gate
101917c478bd9Sstevel@tonic-gate /*
101927c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for the
101937c478bd9Sstevel@tonic-gate * SOF interrupt event.
101947c478bd9Sstevel@tonic-gate */
101957c478bd9Sstevel@tonic-gate before_frame_number = ohci_get_current_frame_number(ohcip);
101967c478bd9Sstevel@tonic-gate
101977c478bd9Sstevel@tonic-gate while (sof_wait_count < MAX_SOF_WAIT_COUNT) {
101987c478bd9Sstevel@tonic-gate /* Enable the SOF interrupt */
101997c478bd9Sstevel@tonic-gate Set_OpReg(hcr_intr_enable, HCR_INTR_SOF);
102007c478bd9Sstevel@tonic-gate
102017c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(hcr_intr_enable) & HCR_INTR_SOF);
102027c478bd9Sstevel@tonic-gate
102037c478bd9Sstevel@tonic-gate /* Wait for the SOF or timeout event */
10204d3d50737SRafael Vanoni rval = cv_reltimedwait(&ohcip->ohci_SOF_cv,
10205d3d50737SRafael Vanoni &ohcip->ohci_int_mutex, sof_time_wait, TR_CLOCK_TICK);
102067c478bd9Sstevel@tonic-gate
102077c478bd9Sstevel@tonic-gate /*
102087c478bd9Sstevel@tonic-gate * Get the current usb frame number after woken up either
102097c478bd9Sstevel@tonic-gate * from SOF interrupt or timer expired event.
102107c478bd9Sstevel@tonic-gate */
102117c478bd9Sstevel@tonic-gate after_frame_number = ohci_get_current_frame_number(ohcip);
102127c478bd9Sstevel@tonic-gate
102137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
102147c478bd9Sstevel@tonic-gate "ohci_wait_for_sof: before 0x%llx, after 0x%llx",
10215112116d8Sfb209375 (unsigned long long)before_frame_number,
10216112116d8Sfb209375 (unsigned long long)after_frame_number);
102177c478bd9Sstevel@tonic-gate
102187c478bd9Sstevel@tonic-gate /*
102197c478bd9Sstevel@tonic-gate * Return failure, if we are woken up becuase of timer expired
102207c478bd9Sstevel@tonic-gate * event and if usb frame number has not been changed.
102217c478bd9Sstevel@tonic-gate */
102227c478bd9Sstevel@tonic-gate if ((rval == -1) &&
102237c478bd9Sstevel@tonic-gate (after_frame_number <= before_frame_number)) {
102247c478bd9Sstevel@tonic-gate
102257c478bd9Sstevel@tonic-gate if ((ohci_do_soft_reset(ohcip)) != USB_SUCCESS) {
102267c478bd9Sstevel@tonic-gate
102277c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS,
102287c478bd9Sstevel@tonic-gate ohcip->ohci_log_hdl, "No SOF interrupts");
102297c478bd9Sstevel@tonic-gate
102307c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */
102317c478bd9Sstevel@tonic-gate ohcip->ohci_hc_soft_state =
102327c478bd9Sstevel@tonic-gate OHCI_CTLR_ERROR_STATE;
102337c478bd9Sstevel@tonic-gate
102347c478bd9Sstevel@tonic-gate return (USB_FAILURE);
102357c478bd9Sstevel@tonic-gate }
102367c478bd9Sstevel@tonic-gate
102377c478bd9Sstevel@tonic-gate /* Get new usb frame number */
102387c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number =
102397c478bd9Sstevel@tonic-gate ohci_get_current_frame_number(ohcip);
102407c478bd9Sstevel@tonic-gate }
102417c478bd9Sstevel@tonic-gate
102427c478bd9Sstevel@tonic-gate ASSERT(after_frame_number >= before_frame_number);
102437c478bd9Sstevel@tonic-gate
102447c478bd9Sstevel@tonic-gate before_frame_number = after_frame_number;
102457c478bd9Sstevel@tonic-gate sof_wait_count++;
102467c478bd9Sstevel@tonic-gate }
102477c478bd9Sstevel@tonic-gate
102487c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
102497c478bd9Sstevel@tonic-gate }
102507c478bd9Sstevel@tonic-gate
102517c478bd9Sstevel@tonic-gate
102527c478bd9Sstevel@tonic-gate /*
102537c478bd9Sstevel@tonic-gate * ohci_pipe_cleanup
102547c478bd9Sstevel@tonic-gate *
102557c478bd9Sstevel@tonic-gate * Cleanup ohci pipe.
102567c478bd9Sstevel@tonic-gate */
102577c478bd9Sstevel@tonic-gate static void
ohci_pipe_cleanup(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)102587c478bd9Sstevel@tonic-gate ohci_pipe_cleanup(
102597c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
102607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
102617c478bd9Sstevel@tonic-gate {
102627c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
102637c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
102647c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
102657c478bd9Sstevel@tonic-gate uint_t pipe_state = pp->pp_state;
102667c478bd9Sstevel@tonic-gate uint_t bit = 0;
102677c478bd9Sstevel@tonic-gate
102687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
10269112116d8Sfb209375 "ohci_pipe_cleanup: ph = 0x%p", (void *)ph);
102707c478bd9Sstevel@tonic-gate
102717c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
102727c478bd9Sstevel@tonic-gate
102737c478bd9Sstevel@tonic-gate switch (pipe_state) {
102747c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_CLOSE:
102757c478bd9Sstevel@tonic-gate if (OHCI_NON_PERIODIC_ENDPOINT(eptd)) {
102767c478bd9Sstevel@tonic-gate
102777c478bd9Sstevel@tonic-gate bit = ((eptd->bmAttributes &
102787c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) ?
102797c478bd9Sstevel@tonic-gate HCR_CONTROL_CLE: HCR_CONTROL_BLE;
102807c478bd9Sstevel@tonic-gate
102817c478bd9Sstevel@tonic-gate Set_OpReg(hcr_control,
102827c478bd9Sstevel@tonic-gate (Get_OpReg(hcr_control) & ~(bit)));
102837c478bd9Sstevel@tonic-gate
102847c478bd9Sstevel@tonic-gate /* Wait for the next SOF */
102857c478bd9Sstevel@tonic-gate (void) ohci_wait_for_sof(ohcip);
102867c478bd9Sstevel@tonic-gate
102877c478bd9Sstevel@tonic-gate break;
102887c478bd9Sstevel@tonic-gate }
102897c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
102907c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_RESET:
102917c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_STOP_POLLING:
102927c478bd9Sstevel@tonic-gate /*
102937c478bd9Sstevel@tonic-gate * Set the sKip bit to stop all transactions on
102947c478bd9Sstevel@tonic-gate * this pipe
102957c478bd9Sstevel@tonic-gate */
102967c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, pp, SET_sKip,
102977c478bd9Sstevel@tonic-gate OHCI_FLAGS_SLEEP | OHCI_FLAGS_DMA_SYNC);
102987c478bd9Sstevel@tonic-gate
102997c478bd9Sstevel@tonic-gate break;
103007c478bd9Sstevel@tonic-gate default:
103017c478bd9Sstevel@tonic-gate return;
103027c478bd9Sstevel@tonic-gate }
103037c478bd9Sstevel@tonic-gate
103047c478bd9Sstevel@tonic-gate /*
103057c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and
103067c478bd9Sstevel@tonic-gate * to send results to upstream.
103077c478bd9Sstevel@tonic-gate */
103087c478bd9Sstevel@tonic-gate ohci_wait_for_transfers_completion(ohcip, pp);
103097c478bd9Sstevel@tonic-gate
103107c478bd9Sstevel@tonic-gate /* Save the data toggle information */
103117c478bd9Sstevel@tonic-gate ohci_save_data_toggle(ohcip, ph);
103127c478bd9Sstevel@tonic-gate
103137c478bd9Sstevel@tonic-gate /*
103147c478bd9Sstevel@tonic-gate * Traverse the list of TD's on this endpoint and
103157c478bd9Sstevel@tonic-gate * these TD's have outstanding transfer requests.
103167c478bd9Sstevel@tonic-gate * Since the list processing is stopped, these tds
103177c478bd9Sstevel@tonic-gate * can be deallocated.
103187c478bd9Sstevel@tonic-gate */
103197c478bd9Sstevel@tonic-gate ohci_traverse_tds(ohcip, ph);
103207c478bd9Sstevel@tonic-gate
103217c478bd9Sstevel@tonic-gate /*
103227c478bd9Sstevel@tonic-gate * If all of the endpoint's TD's have been deallocated,
103237c478bd9Sstevel@tonic-gate * then the DMA mappings can be torn down. If not there
103247c478bd9Sstevel@tonic-gate * are some TD's on the done list that have not been
103257c478bd9Sstevel@tonic-gate * processed. Tag these TD's so that they are thrown
103267c478bd9Sstevel@tonic-gate * away when the done list is processed.
103277c478bd9Sstevel@tonic-gate */
103287c478bd9Sstevel@tonic-gate ohci_done_list_tds(ohcip, ph);
103297c478bd9Sstevel@tonic-gate
103307c478bd9Sstevel@tonic-gate /* Do callbacks for all unfinished requests */
103317c478bd9Sstevel@tonic-gate ohci_handle_outstanding_requests(ohcip, pp);
103327c478bd9Sstevel@tonic-gate
103337c478bd9Sstevel@tonic-gate /* Free DMA resources */
103347c478bd9Sstevel@tonic-gate ohci_free_dma_resources(ohcip, ph);
103357c478bd9Sstevel@tonic-gate
103367c478bd9Sstevel@tonic-gate switch (pipe_state) {
103377c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_CLOSE:
103387c478bd9Sstevel@tonic-gate completion_reason = USB_CR_PIPE_CLOSING;
103397c478bd9Sstevel@tonic-gate break;
103407c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_RESET:
103417c478bd9Sstevel@tonic-gate case OHCI_PIPE_STATE_STOP_POLLING:
103427c478bd9Sstevel@tonic-gate /* Set completion reason */
103437c478bd9Sstevel@tonic-gate completion_reason = (pipe_state ==
103447c478bd9Sstevel@tonic-gate OHCI_PIPE_STATE_RESET) ?
103457c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
103467c478bd9Sstevel@tonic-gate
103477c478bd9Sstevel@tonic-gate /* Restore the data toggle information */
103487c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(ohcip, ph);
103497c478bd9Sstevel@tonic-gate
103507c478bd9Sstevel@tonic-gate /*
103517c478bd9Sstevel@tonic-gate * Clear the sKip bit to restart all the
103527c478bd9Sstevel@tonic-gate * transactions on this pipe.
103537c478bd9Sstevel@tonic-gate */
103547c478bd9Sstevel@tonic-gate ohci_modify_sKip_bit(ohcip, pp,
103557c478bd9Sstevel@tonic-gate CLEAR_sKip, OHCI_FLAGS_NOSLEEP);
103567c478bd9Sstevel@tonic-gate
103577c478bd9Sstevel@tonic-gate /* Set pipe state to idle */
103587c478bd9Sstevel@tonic-gate pp->pp_state = OHCI_PIPE_STATE_IDLE;
103597c478bd9Sstevel@tonic-gate
103607c478bd9Sstevel@tonic-gate break;
103617c478bd9Sstevel@tonic-gate }
103627c478bd9Sstevel@tonic-gate
103637c478bd9Sstevel@tonic-gate ASSERT((Get_ED(pp->pp_ept->hced_tailp) & HC_EPT_TD_TAIL) ==
103647c478bd9Sstevel@tonic-gate (Get_ED(pp->pp_ept->hced_headp) & HC_EPT_TD_HEAD));
103657c478bd9Sstevel@tonic-gate
103667c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head == NULL) && (pp->pp_tw_tail == NULL));
103677c478bd9Sstevel@tonic-gate
103687c478bd9Sstevel@tonic-gate /*
103697c478bd9Sstevel@tonic-gate * Do the callback for the original client
103707c478bd9Sstevel@tonic-gate * periodic IN request.
103717c478bd9Sstevel@tonic-gate */
103727c478bd9Sstevel@tonic-gate if ((OHCI_PERIODIC_ENDPOINT(eptd)) &&
103737c478bd9Sstevel@tonic-gate ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
103747c478bd9Sstevel@tonic-gate USB_EP_DIR_IN)) {
103757c478bd9Sstevel@tonic-gate
103767c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback(
103777c478bd9Sstevel@tonic-gate ohcip, pp, completion_reason);
103787c478bd9Sstevel@tonic-gate }
103797c478bd9Sstevel@tonic-gate }
103807c478bd9Sstevel@tonic-gate
103817c478bd9Sstevel@tonic-gate
103827c478bd9Sstevel@tonic-gate /*
103837c478bd9Sstevel@tonic-gate * ohci_wait_for_transfers_completion:
103847c478bd9Sstevel@tonic-gate *
103857c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and to send results
103867c478bd9Sstevel@tonic-gate * to upstream.
103877c478bd9Sstevel@tonic-gate */
103887c478bd9Sstevel@tonic-gate static void
ohci_wait_for_transfers_completion(ohci_state_t * ohcip,ohci_pipe_private_t * pp)103897c478bd9Sstevel@tonic-gate ohci_wait_for_transfers_completion(
103907c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
103917c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
103927c478bd9Sstevel@tonic-gate {
103937c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *head_tw = pp->pp_tw_head;
103947c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw;
103957c478bd9Sstevel@tonic-gate ohci_td_t *tailp, *headp, *nextp;
103967c478bd9Sstevel@tonic-gate ohci_td_t *head_td, *next_td;
103977c478bd9Sstevel@tonic-gate ohci_ed_t *ept = pp->pp_ept;
103987c478bd9Sstevel@tonic-gate int rval;
103997c478bd9Sstevel@tonic-gate
104007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
10401112116d8Sfb209375 "ohci_wait_for_transfers_completion: pp = 0x%p", (void *)pp);
104027c478bd9Sstevel@tonic-gate
104037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
104047c478bd9Sstevel@tonic-gate
104057c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip,
104067c478bd9Sstevel@tonic-gate Get_ED(ept->hced_headp) & (uint32_t)HC_EPT_TD_HEAD));
104077c478bd9Sstevel@tonic-gate
104087c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip,
104097c478bd9Sstevel@tonic-gate Get_ED(ept->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL));
104107c478bd9Sstevel@tonic-gate
104117c478bd9Sstevel@tonic-gate rval = ohci_state_is_operational(ohcip);
104127c478bd9Sstevel@tonic-gate
104137c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
104147c478bd9Sstevel@tonic-gate
104157c478bd9Sstevel@tonic-gate return;
104167c478bd9Sstevel@tonic-gate }
104177c478bd9Sstevel@tonic-gate
104187c478bd9Sstevel@tonic-gate pp->pp_count_done_tds = 0;
104197c478bd9Sstevel@tonic-gate
104207c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */
104217c478bd9Sstevel@tonic-gate next_tw = head_tw;
104227c478bd9Sstevel@tonic-gate while (next_tw) {
104237c478bd9Sstevel@tonic-gate head_td = (ohci_td_t *)next_tw->tw_hctd_head;
104247c478bd9Sstevel@tonic-gate next_td = head_td;
104257c478bd9Sstevel@tonic-gate
104267c478bd9Sstevel@tonic-gate if (head_td) {
104277c478bd9Sstevel@tonic-gate /*
104287c478bd9Sstevel@tonic-gate * Walk through each TD for this transfer
104297c478bd9Sstevel@tonic-gate * wrapper. If a TD still exists, then it
104307c478bd9Sstevel@tonic-gate * is currently on the done list.
104317c478bd9Sstevel@tonic-gate */
104327c478bd9Sstevel@tonic-gate while (next_td) {
104337c478bd9Sstevel@tonic-gate
104347c478bd9Sstevel@tonic-gate nextp = headp;
104357c478bd9Sstevel@tonic-gate
104367c478bd9Sstevel@tonic-gate while (nextp != tailp) {
104377c478bd9Sstevel@tonic-gate
104387c478bd9Sstevel@tonic-gate /* TD is on the ED */
104397c478bd9Sstevel@tonic-gate if (nextp == next_td) {
104407c478bd9Sstevel@tonic-gate break;
104417c478bd9Sstevel@tonic-gate }
104427c478bd9Sstevel@tonic-gate
104437c478bd9Sstevel@tonic-gate nextp = (ohci_td_t *)
104447c478bd9Sstevel@tonic-gate (ohci_td_iommu_to_cpu(ohcip,
104457c478bd9Sstevel@tonic-gate (Get_TD(nextp->hctd_next_td) &
104467c478bd9Sstevel@tonic-gate HC_EPT_TD_TAIL)));
104477c478bd9Sstevel@tonic-gate }
104487c478bd9Sstevel@tonic-gate
104497c478bd9Sstevel@tonic-gate if (nextp == tailp) {
104507c478bd9Sstevel@tonic-gate pp->pp_count_done_tds++;
104517c478bd9Sstevel@tonic-gate }
104527c478bd9Sstevel@tonic-gate
104537c478bd9Sstevel@tonic-gate next_td = ohci_td_iommu_to_cpu(ohcip,
104547c478bd9Sstevel@tonic-gate Get_TD(next_td->hctd_tw_next_td));
104557c478bd9Sstevel@tonic-gate }
104567c478bd9Sstevel@tonic-gate }
104577c478bd9Sstevel@tonic-gate
104587c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next;
104597c478bd9Sstevel@tonic-gate }
104607c478bd9Sstevel@tonic-gate
104617c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
104627c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: count_done_tds = 0x%x",
104637c478bd9Sstevel@tonic-gate pp->pp_count_done_tds);
104647c478bd9Sstevel@tonic-gate
104657c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_tds) {
104667c478bd9Sstevel@tonic-gate
104677c478bd9Sstevel@tonic-gate return;
104687c478bd9Sstevel@tonic-gate }
104697c478bd9Sstevel@tonic-gate
10470d3d50737SRafael Vanoni (void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &ohcip->ohci_int_mutex,
10471d3d50737SRafael Vanoni drv_usectohz(OHCI_XFER_CMPL_TIMEWAIT * 1000000), TR_CLOCK_TICK);
104727c478bd9Sstevel@tonic-gate
104737c478bd9Sstevel@tonic-gate if (pp->pp_count_done_tds) {
104747c478bd9Sstevel@tonic-gate
104757c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
104767c478bd9Sstevel@tonic-gate "ohci_wait_for_transfers_completion: No transfers "
104777c478bd9Sstevel@tonic-gate "completion confirmation received for 0x%x requests",
104787c478bd9Sstevel@tonic-gate pp->pp_count_done_tds);
104797c478bd9Sstevel@tonic-gate }
104807c478bd9Sstevel@tonic-gate }
104817c478bd9Sstevel@tonic-gate
104827c478bd9Sstevel@tonic-gate
104837c478bd9Sstevel@tonic-gate /*
104847c478bd9Sstevel@tonic-gate * ohci_check_for_transfers_completion:
104857c478bd9Sstevel@tonic-gate *
104867c478bd9Sstevel@tonic-gate * Check whether anybody is waiting for transfers completion event. If so, send
104877c478bd9Sstevel@tonic-gate * this event and also stop initiating any new transfers on this pipe.
104887c478bd9Sstevel@tonic-gate */
104897c478bd9Sstevel@tonic-gate static void
ohci_check_for_transfers_completion(ohci_state_t * ohcip,ohci_pipe_private_t * pp)104907c478bd9Sstevel@tonic-gate ohci_check_for_transfers_completion(
104917c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
104927c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
104937c478bd9Sstevel@tonic-gate {
104947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
10495112116d8Sfb209375 "ohci_check_for_transfers_completion: pp = 0x%p", (void *)pp);
104967c478bd9Sstevel@tonic-gate
104977c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
104987c478bd9Sstevel@tonic-gate
104997c478bd9Sstevel@tonic-gate if ((pp->pp_state == OHCI_PIPE_STATE_STOP_POLLING) &&
105007c478bd9Sstevel@tonic-gate (pp->pp_error == USB_CR_NO_RESOURCES) &&
105017c478bd9Sstevel@tonic-gate (pp->pp_cur_periodic_req_cnt == 0)) {
105027c478bd9Sstevel@tonic-gate
105037c478bd9Sstevel@tonic-gate /* Reset pipe error to zero */
105047c478bd9Sstevel@tonic-gate pp->pp_error = 0;
105057c478bd9Sstevel@tonic-gate
105067c478bd9Sstevel@tonic-gate /* Do callback for original request */
105077c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback(
105087c478bd9Sstevel@tonic-gate ohcip, pp, USB_CR_NO_RESOURCES);
105097c478bd9Sstevel@tonic-gate }
105107c478bd9Sstevel@tonic-gate
105117c478bd9Sstevel@tonic-gate if (pp->pp_count_done_tds) {
105127c478bd9Sstevel@tonic-gate
105137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
105147c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion:"
105157c478bd9Sstevel@tonic-gate "count_done_tds = 0x%x", pp->pp_count_done_tds);
105167c478bd9Sstevel@tonic-gate
105177c478bd9Sstevel@tonic-gate /* Decrement the done td count */
105187c478bd9Sstevel@tonic-gate pp->pp_count_done_tds--;
105197c478bd9Sstevel@tonic-gate
105207c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_tds) {
105217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
105227c478bd9Sstevel@tonic-gate "ohci_check_for_transfers_completion:"
10523112116d8Sfb209375 "Sent transfers completion event pp = 0x%p",
10524112116d8Sfb209375 (void *)pp);
105257c478bd9Sstevel@tonic-gate
105267c478bd9Sstevel@tonic-gate /* Send the transfer completion signal */
105277c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_xfer_cmpl_cv);
105287c478bd9Sstevel@tonic-gate }
105297c478bd9Sstevel@tonic-gate }
105307c478bd9Sstevel@tonic-gate }
105317c478bd9Sstevel@tonic-gate
105327c478bd9Sstevel@tonic-gate
105337c478bd9Sstevel@tonic-gate /*
105347c478bd9Sstevel@tonic-gate * ohci_save_data_toggle:
105357c478bd9Sstevel@tonic-gate *
105367c478bd9Sstevel@tonic-gate * Save the data toggle information.
105377c478bd9Sstevel@tonic-gate */
105387c478bd9Sstevel@tonic-gate static void
ohci_save_data_toggle(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)105397c478bd9Sstevel@tonic-gate ohci_save_data_toggle(
105407c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
105417c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
105427c478bd9Sstevel@tonic-gate {
105437c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
105447c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
105457c478bd9Sstevel@tonic-gate uint_t data_toggle;
105467c478bd9Sstevel@tonic-gate usb_cr_t error = pp->pp_error;
105477c478bd9Sstevel@tonic-gate ohci_ed_t *ed = pp->pp_ept;
105487c478bd9Sstevel@tonic-gate ohci_td_t *headp, *tailp;
105497c478bd9Sstevel@tonic-gate
105507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
10551112116d8Sfb209375 "ohci_save_data_toggle: ph = 0x%p", (void *)ph);
105527c478bd9Sstevel@tonic-gate
105537c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
105547c478bd9Sstevel@tonic-gate
105557c478bd9Sstevel@tonic-gate /* Reset the pipe error value */
105567c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_OK;
105577c478bd9Sstevel@tonic-gate
105587c478bd9Sstevel@tonic-gate /* Return immediately if it is a control or isoc pipe */
105597c478bd9Sstevel@tonic-gate if (((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
105607c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || ((eptd->bmAttributes &
105617c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH)) {
105627c478bd9Sstevel@tonic-gate
105637c478bd9Sstevel@tonic-gate return;
105647c478bd9Sstevel@tonic-gate }
105657c478bd9Sstevel@tonic-gate
105667c478bd9Sstevel@tonic-gate headp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip,
105677c478bd9Sstevel@tonic-gate Get_ED(ed->hced_headp) & (uint32_t)HC_EPT_TD_HEAD));
105687c478bd9Sstevel@tonic-gate
105697c478bd9Sstevel@tonic-gate tailp = (ohci_td_t *)(ohci_td_iommu_to_cpu(ohcip,
105707c478bd9Sstevel@tonic-gate Get_ED(ed->hced_tailp) & (uint32_t)HC_EPT_TD_TAIL));
105717c478bd9Sstevel@tonic-gate
105727c478bd9Sstevel@tonic-gate /*
105737c478bd9Sstevel@tonic-gate * Retrieve the data toggle information either from the endpoint
105747c478bd9Sstevel@tonic-gate * (ED) or from the transfer descriptor (TD) depending on the
105757c478bd9Sstevel@tonic-gate * situation.
105767c478bd9Sstevel@tonic-gate */
105777c478bd9Sstevel@tonic-gate if ((Get_ED(ed->hced_headp) & HC_EPT_Halt) || (headp == tailp)) {
105787c478bd9Sstevel@tonic-gate
105797c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint */
105807c478bd9Sstevel@tonic-gate data_toggle = (Get_ED(ed->hced_headp) &
105817c478bd9Sstevel@tonic-gate HC_EPT_Carry)? DATA1:DATA0;
105827c478bd9Sstevel@tonic-gate } else {
105837c478bd9Sstevel@tonic-gate /*
105847c478bd9Sstevel@tonic-gate * Retrieve the data toggle information depending on the
105857c478bd9Sstevel@tonic-gate * master data toggle information saved in the transfer
105867c478bd9Sstevel@tonic-gate * descriptor (TD) at the head of the endpoint (ED).
105877c478bd9Sstevel@tonic-gate *
105887c478bd9Sstevel@tonic-gate * Check for master data toggle information .
105897c478bd9Sstevel@tonic-gate */
105907c478bd9Sstevel@tonic-gate if (Get_TD(headp->hctd_ctrl) & HC_TD_MS_DT) {
105917c478bd9Sstevel@tonic-gate /* Get the data toggle information from td */
105927c478bd9Sstevel@tonic-gate data_toggle = (Get_TD(headp->hctd_ctrl) &
105937c478bd9Sstevel@tonic-gate HC_TD_DT_1) ? DATA1:DATA0;
105947c478bd9Sstevel@tonic-gate } else {
105957c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint */
105967c478bd9Sstevel@tonic-gate data_toggle = (Get_ED(ed->hced_headp) &
105977c478bd9Sstevel@tonic-gate HC_EPT_Carry)? DATA1:DATA0;
105987c478bd9Sstevel@tonic-gate }
105997c478bd9Sstevel@tonic-gate }
106007c478bd9Sstevel@tonic-gate
106017c478bd9Sstevel@tonic-gate /*
106027c478bd9Sstevel@tonic-gate * If error is STALL, then, set
106037c478bd9Sstevel@tonic-gate * data toggle to zero.
106047c478bd9Sstevel@tonic-gate */
106057c478bd9Sstevel@tonic-gate if (error == USB_CR_STALL) {
106067c478bd9Sstevel@tonic-gate data_toggle = DATA0;
106077c478bd9Sstevel@tonic-gate }
106087c478bd9Sstevel@tonic-gate
106097c478bd9Sstevel@tonic-gate /*
106107c478bd9Sstevel@tonic-gate * Save the data toggle information
106117c478bd9Sstevel@tonic-gate * in the usb device structure.
106127c478bd9Sstevel@tonic-gate */
106137c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
106147c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
106157c478bd9Sstevel@tonic-gate data_toggle);
106167c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
106177c478bd9Sstevel@tonic-gate }
106187c478bd9Sstevel@tonic-gate
106197c478bd9Sstevel@tonic-gate
106207c478bd9Sstevel@tonic-gate /*
106217c478bd9Sstevel@tonic-gate * ohci_restore_data_toggle:
106227c478bd9Sstevel@tonic-gate *
106237c478bd9Sstevel@tonic-gate * Restore the data toggle information.
106247c478bd9Sstevel@tonic-gate */
106257c478bd9Sstevel@tonic-gate static void
ohci_restore_data_toggle(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph)106267c478bd9Sstevel@tonic-gate ohci_restore_data_toggle(
106277c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
106287c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph)
106297c478bd9Sstevel@tonic-gate {
106307c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
106317c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
106327c478bd9Sstevel@tonic-gate uint_t data_toggle = 0;
106337c478bd9Sstevel@tonic-gate
106347c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
10635112116d8Sfb209375 "ohci_restore_data_toggle: ph = 0x%p", (void *)ph);
106367c478bd9Sstevel@tonic-gate
106377c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
106387c478bd9Sstevel@tonic-gate
106397c478bd9Sstevel@tonic-gate /*
106407c478bd9Sstevel@tonic-gate * Return immediately if it is a control or isoc pipe.
106417c478bd9Sstevel@tonic-gate */
106427c478bd9Sstevel@tonic-gate if (((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
106437c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || ((eptd->bmAttributes &
106447c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH)) {
106457c478bd9Sstevel@tonic-gate
106467c478bd9Sstevel@tonic-gate return;
106477c478bd9Sstevel@tonic-gate }
106487c478bd9Sstevel@tonic-gate
106497c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
106507c478bd9Sstevel@tonic-gate
106517c478bd9Sstevel@tonic-gate data_toggle = usba_hcdi_get_data_toggle(ph->p_usba_device,
106527c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress);
106537c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
106547c478bd9Sstevel@tonic-gate 0);
106557c478bd9Sstevel@tonic-gate
106567c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
106577c478bd9Sstevel@tonic-gate
106587c478bd9Sstevel@tonic-gate /*
106597c478bd9Sstevel@tonic-gate * Restore the data toggle bit depending on the
106607c478bd9Sstevel@tonic-gate * previous data toggle information.
106617c478bd9Sstevel@tonic-gate */
106627c478bd9Sstevel@tonic-gate if (data_toggle) {
106637c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
106647c478bd9Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) | HC_EPT_Carry);
106657c478bd9Sstevel@tonic-gate } else {
106667c478bd9Sstevel@tonic-gate Set_ED(pp->pp_ept->hced_headp,
106677c478bd9Sstevel@tonic-gate Get_ED(pp->pp_ept->hced_headp) & (~HC_EPT_Carry));
106687c478bd9Sstevel@tonic-gate }
106697c478bd9Sstevel@tonic-gate }
106707c478bd9Sstevel@tonic-gate
106717c478bd9Sstevel@tonic-gate
106727c478bd9Sstevel@tonic-gate /*
106737c478bd9Sstevel@tonic-gate * ohci_handle_outstanding_requests
106747c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
106757c478bd9Sstevel@tonic-gate *
106767c478bd9Sstevel@tonic-gate * Deallocate interrupt/isochronous request structure for the
106777c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer. Do the callbacks for all
106787c478bd9Sstevel@tonic-gate * unfinished requests.
106797c478bd9Sstevel@tonic-gate */
106807c478bd9Sstevel@tonic-gate void
ohci_handle_outstanding_requests(ohci_state_t * ohcip,ohci_pipe_private_t * pp)106817c478bd9Sstevel@tonic-gate ohci_handle_outstanding_requests(
106827c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
106837c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp)
106847c478bd9Sstevel@tonic-gate {
106857c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
106867c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
106877c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *curr_tw;
106887c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *next_tw;
106897c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
106907c478bd9Sstevel@tonic-gate
106917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
10692112116d8Sfb209375 "ohci_handle_outstanding_requests: pp = 0x%p", (void *)pp);
106937c478bd9Sstevel@tonic-gate
106947c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
106957c478bd9Sstevel@tonic-gate
106967c478bd9Sstevel@tonic-gate /*
106977c478bd9Sstevel@tonic-gate * Deallocate all the pre-allocated interrupt requests
106987c478bd9Sstevel@tonic-gate */
106997c478bd9Sstevel@tonic-gate next_tw = pp->pp_tw_head;
107007c478bd9Sstevel@tonic-gate
107017c478bd9Sstevel@tonic-gate while (next_tw) {
107027c478bd9Sstevel@tonic-gate curr_tw = next_tw;
107037c478bd9Sstevel@tonic-gate next_tw = curr_tw->tw_next;
107047c478bd9Sstevel@tonic-gate
107057c478bd9Sstevel@tonic-gate curr_xfer_reqp = curr_tw->tw_curr_xfer_reqp;
107067c478bd9Sstevel@tonic-gate
107077c478bd9Sstevel@tonic-gate /* Deallocate current interrupt request */
107087c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) {
107097c478bd9Sstevel@tonic-gate
107107c478bd9Sstevel@tonic-gate if ((OHCI_PERIODIC_ENDPOINT(eptd)) &&
107117c478bd9Sstevel@tonic-gate (curr_tw->tw_direction == HC_TD_IN)) {
107127c478bd9Sstevel@tonic-gate
107137c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */
107147c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--;
107157c478bd9Sstevel@tonic-gate
107167c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(
107177c478bd9Sstevel@tonic-gate ohcip, pp, curr_tw);
107187c478bd9Sstevel@tonic-gate } else {
107197c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph,
107207c478bd9Sstevel@tonic-gate curr_tw, USB_CR_FLUSHED);
107217c478bd9Sstevel@tonic-gate }
107227c478bd9Sstevel@tonic-gate }
107237c478bd9Sstevel@tonic-gate }
107247c478bd9Sstevel@tonic-gate }
107257c478bd9Sstevel@tonic-gate
107267c478bd9Sstevel@tonic-gate
107277c478bd9Sstevel@tonic-gate /*
107287c478bd9Sstevel@tonic-gate * ohci_deallocate_periodic_in_resource
107297c478bd9Sstevel@tonic-gate *
107307c478bd9Sstevel@tonic-gate * Deallocate interrupt/isochronous request structure for the
107317c478bd9Sstevel@tonic-gate * interrupt/isochronous IN transfer.
107327c478bd9Sstevel@tonic-gate */
107337c478bd9Sstevel@tonic-gate static void
ohci_deallocate_periodic_in_resource(ohci_state_t * ohcip,ohci_pipe_private_t * pp,ohci_trans_wrapper_t * tw)107347c478bd9Sstevel@tonic-gate ohci_deallocate_periodic_in_resource(
107357c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
107367c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
107377c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw)
107387c478bd9Sstevel@tonic-gate {
107397c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
107407c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes;
107417c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
107427c478bd9Sstevel@tonic-gate
107437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
107447c478bd9Sstevel@tonic-gate "ohci_deallocate_periodic_in_resource: "
10745112116d8Sfb209375 "pp = 0x%p tw = 0x%p", (void *)pp, (void *)tw);
107467c478bd9Sstevel@tonic-gate
107477c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
107487c478bd9Sstevel@tonic-gate
107497c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp;
107507c478bd9Sstevel@tonic-gate
107517c478bd9Sstevel@tonic-gate /* Check the current periodic in request pointer */
107527c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) {
107537c478bd9Sstevel@tonic-gate /*
107547c478bd9Sstevel@tonic-gate * Reset periodic in request usb isoch
107557c478bd9Sstevel@tonic-gate * packet request pointers to null.
107567c478bd9Sstevel@tonic-gate */
107577c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL;
107587c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = NULL;
107597c478bd9Sstevel@tonic-gate
107607c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
107617c478bd9Sstevel@tonic-gate ph->p_req_count--;
107627c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
107637c478bd9Sstevel@tonic-gate
107647c478bd9Sstevel@tonic-gate /*
107657c478bd9Sstevel@tonic-gate * Free pre-allocated interrupt
107667c478bd9Sstevel@tonic-gate * or isochronous requests.
107677c478bd9Sstevel@tonic-gate */
107687c478bd9Sstevel@tonic-gate switch (ep_attr & USB_EP_ATTR_MASK) {
107697c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
107707c478bd9Sstevel@tonic-gate usb_free_intr_req(
107717c478bd9Sstevel@tonic-gate (usb_intr_req_t *)curr_xfer_reqp);
107727c478bd9Sstevel@tonic-gate break;
107737c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
107747c478bd9Sstevel@tonic-gate usb_free_isoc_req(
107757c478bd9Sstevel@tonic-gate (usb_isoc_req_t *)curr_xfer_reqp);
107767c478bd9Sstevel@tonic-gate break;
107777c478bd9Sstevel@tonic-gate }
107787c478bd9Sstevel@tonic-gate }
107797c478bd9Sstevel@tonic-gate }
107807c478bd9Sstevel@tonic-gate
107817c478bd9Sstevel@tonic-gate
107827c478bd9Sstevel@tonic-gate /*
107837c478bd9Sstevel@tonic-gate * ohci_do_client_periodic_in_req_callback
107847c478bd9Sstevel@tonic-gate *
107857c478bd9Sstevel@tonic-gate * Do callback for the original client periodic IN request.
107867c478bd9Sstevel@tonic-gate */
107877c478bd9Sstevel@tonic-gate static void
ohci_do_client_periodic_in_req_callback(ohci_state_t * ohcip,ohci_pipe_private_t * pp,usb_cr_t completion_reason)107887c478bd9Sstevel@tonic-gate ohci_do_client_periodic_in_req_callback(
107897c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
107907c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp,
107917c478bd9Sstevel@tonic-gate usb_cr_t completion_reason)
107927c478bd9Sstevel@tonic-gate {
107937c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
107947c478bd9Sstevel@tonic-gate
107957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
107967c478bd9Sstevel@tonic-gate "ohci_do_client_periodic_in_req_callback: "
10797112116d8Sfb209375 "pp = 0x%p cc = 0x%x", (void *)pp, completion_reason);
107987c478bd9Sstevel@tonic-gate
107997c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
108007c478bd9Sstevel@tonic-gate
108017c478bd9Sstevel@tonic-gate /*
108027c478bd9Sstevel@tonic-gate * Check for Interrupt/Isochronous IN, whether we need to do
108037c478bd9Sstevel@tonic-gate * callback for the original client's periodic IN request.
108047c478bd9Sstevel@tonic-gate */
108057c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) {
108067c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 0);
108077c478bd9Sstevel@tonic-gate ohci_hcdi_callback(ph, NULL, completion_reason);
108087c478bd9Sstevel@tonic-gate }
108097c478bd9Sstevel@tonic-gate }
108107c478bd9Sstevel@tonic-gate
108117c478bd9Sstevel@tonic-gate
108127c478bd9Sstevel@tonic-gate /*
108137c478bd9Sstevel@tonic-gate * ohci_hcdi_callback()
108147c478bd9Sstevel@tonic-gate *
108157c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() other than root hub.
108167c478bd9Sstevel@tonic-gate */
108177c478bd9Sstevel@tonic-gate static void
ohci_hcdi_callback(usba_pipe_handle_data_t * ph,ohci_trans_wrapper_t * tw,usb_cr_t completion_reason)108187c478bd9Sstevel@tonic-gate ohci_hcdi_callback(
108197c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
108207c478bd9Sstevel@tonic-gate ohci_trans_wrapper_t *tw,
108217c478bd9Sstevel@tonic-gate usb_cr_t completion_reason)
108227c478bd9Sstevel@tonic-gate {
108237c478bd9Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
108247c478bd9Sstevel@tonic-gate ph->p_usba_device->usb_root_hub_dip);
108257c478bd9Sstevel@tonic-gate uchar_t attributes = ph->p_ep.bmAttributes &
108267c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK;
108277c478bd9Sstevel@tonic-gate ohci_pipe_private_t *pp = (ohci_pipe_private_t *)ph->p_hcd_private;
108287c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
108297c478bd9Sstevel@tonic-gate uint_t pipe_state = 0;
108307c478bd9Sstevel@tonic-gate
108317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
108327c478bd9Sstevel@tonic-gate "ohci_hcdi_callback: ph = 0x%p, tw = 0x%p, cr = 0x%x",
10833112116d8Sfb209375 (void *)ph, (void *)tw, completion_reason);
108347c478bd9Sstevel@tonic-gate
108357c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
108367c478bd9Sstevel@tonic-gate
108377c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */
108387c478bd9Sstevel@tonic-gate switch (completion_reason) {
108397c478bd9Sstevel@tonic-gate case USB_CR_OK:
108407c478bd9Sstevel@tonic-gate pipe_state = pp->pp_state;
108417c478bd9Sstevel@tonic-gate break;
108427c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
108437c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED:
108447c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
108457c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET:
108467c478bd9Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_IDLE;
108477c478bd9Sstevel@tonic-gate break;
108487c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
108497c478bd9Sstevel@tonic-gate break;
108507c478bd9Sstevel@tonic-gate default:
108517c478bd9Sstevel@tonic-gate /*
108527c478bd9Sstevel@tonic-gate * Set the pipe state to error
108537c478bd9Sstevel@tonic-gate * except for the isoc pipe.
108547c478bd9Sstevel@tonic-gate */
108557c478bd9Sstevel@tonic-gate if (attributes != USB_EP_ATTR_ISOCH) {
108567c478bd9Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_ERROR;
108577c478bd9Sstevel@tonic-gate pp->pp_error = completion_reason;
108587c478bd9Sstevel@tonic-gate }
108597c478bd9Sstevel@tonic-gate break;
108607c478bd9Sstevel@tonic-gate
108617c478bd9Sstevel@tonic-gate }
108627c478bd9Sstevel@tonic-gate
108637c478bd9Sstevel@tonic-gate pp->pp_state = pipe_state;
108647c478bd9Sstevel@tonic-gate
108657c478bd9Sstevel@tonic-gate if (tw && tw->tw_curr_xfer_reqp) {
108667c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp;
108677c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL;
108687c478bd9Sstevel@tonic-gate tw->tw_curr_isoc_pktp = NULL;
108697c478bd9Sstevel@tonic-gate } else {
108707c478bd9Sstevel@tonic-gate ASSERT(pp->pp_client_periodic_in_reqp != NULL);
108717c478bd9Sstevel@tonic-gate
108727c478bd9Sstevel@tonic-gate curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
108737c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL;
108747c478bd9Sstevel@tonic-gate }
108757c478bd9Sstevel@tonic-gate
108767c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL);
108777c478bd9Sstevel@tonic-gate
108787c478bd9Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
108797c478bd9Sstevel@tonic-gate
108807c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
108817c478bd9Sstevel@tonic-gate
108827c478bd9Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
108837c478bd9Sstevel@tonic-gate }
108847c478bd9Sstevel@tonic-gate
108857c478bd9Sstevel@tonic-gate
108867c478bd9Sstevel@tonic-gate /*
108877c478bd9Sstevel@tonic-gate * ohci kstat functions
108887c478bd9Sstevel@tonic-gate */
108897c478bd9Sstevel@tonic-gate
108907c478bd9Sstevel@tonic-gate /*
108917c478bd9Sstevel@tonic-gate * ohci_create_stats:
108927c478bd9Sstevel@tonic-gate *
108937c478bd9Sstevel@tonic-gate * Allocate and initialize the ohci kstat structures
108947c478bd9Sstevel@tonic-gate */
108957c478bd9Sstevel@tonic-gate static void
ohci_create_stats(ohci_state_t * ohcip)108967c478bd9Sstevel@tonic-gate ohci_create_stats(ohci_state_t *ohcip)
108977c478bd9Sstevel@tonic-gate {
108987c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN];
108997c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ohcip->ohci_dip);
109007c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] =
109017c478bd9Sstevel@tonic-gate {"ctrl", "isoch", "bulk", "intr"};
109027c478bd9Sstevel@tonic-gate uint_t instance = ohcip->ohci_instance;
109037c478bd9Sstevel@tonic-gate ohci_intrs_stats_t *isp;
109047c478bd9Sstevel@tonic-gate int i;
109057c478bd9Sstevel@tonic-gate
109067c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip) == NULL) {
109077c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs",
109087c478bd9Sstevel@tonic-gate dname, instance);
109097c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip) = kstat_create("usba", instance,
109107c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED,
109117c478bd9Sstevel@tonic-gate sizeof (ohci_intrs_stats_t) / sizeof (kstat_named_t),
109127c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT);
109137c478bd9Sstevel@tonic-gate
109147c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) {
109157c478bd9Sstevel@tonic-gate isp = OHCI_INTRS_STATS_DATA(ohcip);
109167c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_total,
109177c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64);
109187c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_not_claimed,
109197c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64);
109207c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_so,
109217c478bd9Sstevel@tonic-gate "Schedule Overruns", KSTAT_DATA_UINT64);
109227c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_wdh,
109237c478bd9Sstevel@tonic-gate "Writeback Done Head", KSTAT_DATA_UINT64);
109247c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_sof,
109257c478bd9Sstevel@tonic-gate "Start Of Frame", KSTAT_DATA_UINT64);
109267c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_rd,
109277c478bd9Sstevel@tonic-gate "Resume Detected", KSTAT_DATA_UINT64);
109287c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_ue,
109297c478bd9Sstevel@tonic-gate "Unrecoverable Error", KSTAT_DATA_UINT64);
109307c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_fno,
109317c478bd9Sstevel@tonic-gate "Frame No. Overflow", KSTAT_DATA_UINT64);
109327c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_rhsc,
109337c478bd9Sstevel@tonic-gate "Root Hub Status Change", KSTAT_DATA_UINT64);
109347c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ohci_hcr_intr_oc,
109357c478bd9Sstevel@tonic-gate "Change In Ownership", KSTAT_DATA_UINT64);
109367c478bd9Sstevel@tonic-gate
109377c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip)->ks_private = ohcip;
109387c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip)->ks_update = nulldev;
109397c478bd9Sstevel@tonic-gate kstat_install(OHCI_INTRS_STATS(ohcip));
109407c478bd9Sstevel@tonic-gate }
109417c478bd9Sstevel@tonic-gate }
109427c478bd9Sstevel@tonic-gate
109437c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip) == NULL) {
109447c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total",
109457c478bd9Sstevel@tonic-gate dname, instance);
109467c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS(ohcip) = kstat_create("usba", instance,
109477c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1,
109487c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT);
109497c478bd9Sstevel@tonic-gate
109507c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip)) {
109517c478bd9Sstevel@tonic-gate kstat_install(OHCI_TOTAL_STATS(ohcip));
109527c478bd9Sstevel@tonic-gate }
109537c478bd9Sstevel@tonic-gate }
109547c478bd9Sstevel@tonic-gate
109557c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
109567c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i] == NULL) {
109577c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s",
109587c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]);
109597c478bd9Sstevel@tonic-gate ohcip->ohci_count_stats[i] = kstat_create("usba",
109607c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count",
109617c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
109627c478bd9Sstevel@tonic-gate
109637c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i]) {
109647c478bd9Sstevel@tonic-gate kstat_install(ohcip->ohci_count_stats[i]);
109657c478bd9Sstevel@tonic-gate }
109667c478bd9Sstevel@tonic-gate }
109677c478bd9Sstevel@tonic-gate }
109687c478bd9Sstevel@tonic-gate }
109697c478bd9Sstevel@tonic-gate
109707c478bd9Sstevel@tonic-gate
109717c478bd9Sstevel@tonic-gate /*
109727c478bd9Sstevel@tonic-gate * ohci_destroy_stats:
109737c478bd9Sstevel@tonic-gate *
109747c478bd9Sstevel@tonic-gate * Clean up ohci kstat structures
109757c478bd9Sstevel@tonic-gate */
109767c478bd9Sstevel@tonic-gate static void
ohci_destroy_stats(ohci_state_t * ohcip)109777c478bd9Sstevel@tonic-gate ohci_destroy_stats(ohci_state_t *ohcip)
109787c478bd9Sstevel@tonic-gate {
109797c478bd9Sstevel@tonic-gate int i;
109807c478bd9Sstevel@tonic-gate
109817c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) {
109827c478bd9Sstevel@tonic-gate kstat_delete(OHCI_INTRS_STATS(ohcip));
109837c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS(ohcip) = NULL;
109847c478bd9Sstevel@tonic-gate }
109857c478bd9Sstevel@tonic-gate
109867c478bd9Sstevel@tonic-gate if (OHCI_TOTAL_STATS(ohcip)) {
109877c478bd9Sstevel@tonic-gate kstat_delete(OHCI_TOTAL_STATS(ohcip));
109887c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS(ohcip) = NULL;
109897c478bd9Sstevel@tonic-gate }
109907c478bd9Sstevel@tonic-gate
109917c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
109927c478bd9Sstevel@tonic-gate if (ohcip->ohci_count_stats[i]) {
109937c478bd9Sstevel@tonic-gate kstat_delete(ohcip->ohci_count_stats[i]);
109947c478bd9Sstevel@tonic-gate ohcip->ohci_count_stats[i] = NULL;
109957c478bd9Sstevel@tonic-gate }
109967c478bd9Sstevel@tonic-gate }
109977c478bd9Sstevel@tonic-gate }
109987c478bd9Sstevel@tonic-gate
109997c478bd9Sstevel@tonic-gate
110007c478bd9Sstevel@tonic-gate /*
110017c478bd9Sstevel@tonic-gate * ohci_do_intrs_stats:
110027c478bd9Sstevel@tonic-gate *
110037c478bd9Sstevel@tonic-gate * ohci status information
110047c478bd9Sstevel@tonic-gate */
110057c478bd9Sstevel@tonic-gate static void
ohci_do_intrs_stats(ohci_state_t * ohcip,int val)110067c478bd9Sstevel@tonic-gate ohci_do_intrs_stats(
110077c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
110087c478bd9Sstevel@tonic-gate int val)
110097c478bd9Sstevel@tonic-gate {
110107c478bd9Sstevel@tonic-gate if (OHCI_INTRS_STATS(ohcip)) {
110117c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->ohci_hcr_intr_total.value.ui64++;
110127c478bd9Sstevel@tonic-gate switch (val) {
110137c478bd9Sstevel@tonic-gate case HCR_INTR_SO:
110147c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110157c478bd9Sstevel@tonic-gate ohci_hcr_intr_so.value.ui64++;
110167c478bd9Sstevel@tonic-gate break;
110177c478bd9Sstevel@tonic-gate case HCR_INTR_WDH:
110187c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110197c478bd9Sstevel@tonic-gate ohci_hcr_intr_wdh.value.ui64++;
110207c478bd9Sstevel@tonic-gate break;
110217c478bd9Sstevel@tonic-gate case HCR_INTR_SOF:
110227c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110237c478bd9Sstevel@tonic-gate ohci_hcr_intr_sof.value.ui64++;
110247c478bd9Sstevel@tonic-gate break;
110257c478bd9Sstevel@tonic-gate case HCR_INTR_RD:
110267c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110277c478bd9Sstevel@tonic-gate ohci_hcr_intr_rd.value.ui64++;
110287c478bd9Sstevel@tonic-gate break;
110297c478bd9Sstevel@tonic-gate case HCR_INTR_UE:
110307c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110317c478bd9Sstevel@tonic-gate ohci_hcr_intr_ue.value.ui64++;
110327c478bd9Sstevel@tonic-gate break;
110337c478bd9Sstevel@tonic-gate case HCR_INTR_FNO:
110347c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110357c478bd9Sstevel@tonic-gate ohci_hcr_intr_fno.value.ui64++;
110367c478bd9Sstevel@tonic-gate break;
110377c478bd9Sstevel@tonic-gate case HCR_INTR_RHSC:
110387c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110397c478bd9Sstevel@tonic-gate ohci_hcr_intr_rhsc.value.ui64++;
110407c478bd9Sstevel@tonic-gate break;
110417c478bd9Sstevel@tonic-gate case HCR_INTR_OC:
110427c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110437c478bd9Sstevel@tonic-gate ohci_hcr_intr_oc.value.ui64++;
110447c478bd9Sstevel@tonic-gate break;
110457c478bd9Sstevel@tonic-gate default:
110467c478bd9Sstevel@tonic-gate OHCI_INTRS_STATS_DATA(ohcip)->
110477c478bd9Sstevel@tonic-gate ohci_hcr_intr_not_claimed.value.ui64++;
110487c478bd9Sstevel@tonic-gate break;
110497c478bd9Sstevel@tonic-gate }
110507c478bd9Sstevel@tonic-gate }
110517c478bd9Sstevel@tonic-gate }
110527c478bd9Sstevel@tonic-gate
110537c478bd9Sstevel@tonic-gate
110547c478bd9Sstevel@tonic-gate /*
110557c478bd9Sstevel@tonic-gate * ohci_do_byte_stats:
110567c478bd9Sstevel@tonic-gate *
110577c478bd9Sstevel@tonic-gate * ohci data xfer information
110587c478bd9Sstevel@tonic-gate */
110597c478bd9Sstevel@tonic-gate static void
ohci_do_byte_stats(ohci_state_t * ohcip,size_t len,uint8_t attr,uint8_t addr)110603e1e1e62SToomas Soome ohci_do_byte_stats(ohci_state_t *ohcip, size_t len, uint8_t attr, uint8_t addr)
110617c478bd9Sstevel@tonic-gate {
110627c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK;
110637c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK;
110647c478bd9Sstevel@tonic-gate
110657c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) {
110667c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->reads++;
110677c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->nread += len;
110687c478bd9Sstevel@tonic-gate switch (type) {
110697c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
110707c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->reads++;
110717c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->nread += len;
110727c478bd9Sstevel@tonic-gate break;
110737c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
110747c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->reads++;
110757c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->nread += len;
110767c478bd9Sstevel@tonic-gate break;
110777c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
110787c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->reads++;
110797c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->nread += len;
110807c478bd9Sstevel@tonic-gate break;
110817c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
110827c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->reads++;
110837c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->nread += len;
110847c478bd9Sstevel@tonic-gate break;
110857c478bd9Sstevel@tonic-gate }
110867c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) {
110877c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->writes++;
110887c478bd9Sstevel@tonic-gate OHCI_TOTAL_STATS_DATA(ohcip)->nwritten += len;
110897c478bd9Sstevel@tonic-gate switch (type) {
110907c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
110917c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->writes++;
110927c478bd9Sstevel@tonic-gate OHCI_CTRL_STATS(ohcip)->nwritten += len;
110937c478bd9Sstevel@tonic-gate break;
110947c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
110957c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->writes++;
110967c478bd9Sstevel@tonic-gate OHCI_BULK_STATS(ohcip)->nwritten += len;
110977c478bd9Sstevel@tonic-gate break;
110987c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
110997c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->writes++;
111007c478bd9Sstevel@tonic-gate OHCI_INTR_STATS(ohcip)->nwritten += len;
111017c478bd9Sstevel@tonic-gate break;
111027c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
111037c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->writes++;
111047c478bd9Sstevel@tonic-gate OHCI_ISOC_STATS(ohcip)->nwritten += len;
111057c478bd9Sstevel@tonic-gate break;
111067c478bd9Sstevel@tonic-gate }
111077c478bd9Sstevel@tonic-gate }
111087c478bd9Sstevel@tonic-gate }
111097c478bd9Sstevel@tonic-gate
111107c478bd9Sstevel@tonic-gate
111117c478bd9Sstevel@tonic-gate /*
111127c478bd9Sstevel@tonic-gate * ohci_print_op_regs:
111137c478bd9Sstevel@tonic-gate *
111147c478bd9Sstevel@tonic-gate * Print Host Controller's (HC) Operational registers.
111157c478bd9Sstevel@tonic-gate */
111167c478bd9Sstevel@tonic-gate static void
ohci_print_op_regs(ohci_state_t * ohcip)111177c478bd9Sstevel@tonic-gate ohci_print_op_regs(ohci_state_t *ohcip)
111187c478bd9Sstevel@tonic-gate {
111197c478bd9Sstevel@tonic-gate uint_t i;
111207c478bd9Sstevel@tonic-gate
111217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111227c478bd9Sstevel@tonic-gate "\n\tOHCI%d Operational Registers\n",
111237c478bd9Sstevel@tonic-gate ddi_get_instance(ohcip->ohci_dip));
111247c478bd9Sstevel@tonic-gate
111257c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111267c478bd9Sstevel@tonic-gate "\thcr_revision: 0x%x \t\thcr_control: 0x%x",
111277c478bd9Sstevel@tonic-gate Get_OpReg(hcr_revision), Get_OpReg(hcr_control));
111287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111297c478bd9Sstevel@tonic-gate "\thcr_cmd_status: 0x%x \t\thcr_intr_enable: 0x%x",
111307c478bd9Sstevel@tonic-gate Get_OpReg(hcr_cmd_status), Get_OpReg(hcr_intr_enable));
111317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111327c478bd9Sstevel@tonic-gate "\thcr_intr_disable: 0x%x \thcr_HCCA: 0x%x",
111337c478bd9Sstevel@tonic-gate Get_OpReg(hcr_intr_disable), Get_OpReg(hcr_HCCA));
111347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111357c478bd9Sstevel@tonic-gate "\thcr_periodic_curr: 0x%x \t\thcr_ctrl_head: 0x%x",
111367c478bd9Sstevel@tonic-gate Get_OpReg(hcr_periodic_curr), Get_OpReg(hcr_ctrl_head));
111377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111387c478bd9Sstevel@tonic-gate "\thcr_ctrl_curr: 0x%x \t\thcr_bulk_head: 0x%x",
111397c478bd9Sstevel@tonic-gate Get_OpReg(hcr_ctrl_curr), Get_OpReg(hcr_bulk_head));
111407c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111417c478bd9Sstevel@tonic-gate "\thcr_bulk_curr: 0x%x \t\thcr_done_head: 0x%x",
111427c478bd9Sstevel@tonic-gate Get_OpReg(hcr_bulk_curr), Get_OpReg(hcr_done_head));
111437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111447c478bd9Sstevel@tonic-gate "\thcr_frame_interval: 0x%x "
111457c478bd9Sstevel@tonic-gate "\thcr_frame_remaining: 0x%x", Get_OpReg(hcr_frame_interval),
111467c478bd9Sstevel@tonic-gate Get_OpReg(hcr_frame_remaining));
111477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111487c478bd9Sstevel@tonic-gate "\thcr_frame_number: 0x%x \thcr_periodic_strt: 0x%x",
111497c478bd9Sstevel@tonic-gate Get_OpReg(hcr_frame_number), Get_OpReg(hcr_periodic_strt));
111507c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111517c478bd9Sstevel@tonic-gate "\thcr_transfer_ls: 0x%x \t\thcr_rh_descriptorA: 0x%x",
111527c478bd9Sstevel@tonic-gate Get_OpReg(hcr_transfer_ls), Get_OpReg(hcr_rh_descriptorA));
111537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111547c478bd9Sstevel@tonic-gate "\thcr_rh_descriptorB: 0x%x \thcr_rh_status: 0x%x",
111557c478bd9Sstevel@tonic-gate Get_OpReg(hcr_rh_descriptorB), Get_OpReg(hcr_rh_status));
111567c478bd9Sstevel@tonic-gate
111577c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111587c478bd9Sstevel@tonic-gate "\tRoot hub port status");
111597c478bd9Sstevel@tonic-gate
111607c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_OpReg(hcr_rh_descriptorA) & HCR_RHA_NDP); i++) {
111617c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
111627c478bd9Sstevel@tonic-gate "\thcr_rh_portstatus 0x%x: 0x%x ", i,
111637c478bd9Sstevel@tonic-gate Get_OpReg(hcr_rh_portstatus[i]));
111647c478bd9Sstevel@tonic-gate }
111657c478bd9Sstevel@tonic-gate }
111667c478bd9Sstevel@tonic-gate
111677c478bd9Sstevel@tonic-gate
111687c478bd9Sstevel@tonic-gate /*
111697c478bd9Sstevel@tonic-gate * ohci_print_ed:
111707c478bd9Sstevel@tonic-gate */
111717c478bd9Sstevel@tonic-gate static void
ohci_print_ed(ohci_state_t * ohcip,ohci_ed_t * ed)111727c478bd9Sstevel@tonic-gate ohci_print_ed(
111737c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
111747c478bd9Sstevel@tonic-gate ohci_ed_t *ed)
111757c478bd9Sstevel@tonic-gate {
111767c478bd9Sstevel@tonic-gate uint_t ctrl = Get_ED(ed->hced_ctrl);
111777c478bd9Sstevel@tonic-gate
111787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111797c478bd9Sstevel@tonic-gate "ohci_print_ed: ed = 0x%p", (void *)ed);
111807c478bd9Sstevel@tonic-gate
111817c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111827c478bd9Sstevel@tonic-gate "\thced_ctrl: 0x%x %s", ctrl,
111837c478bd9Sstevel@tonic-gate ((Get_ED(ed->hced_headp) & HC_EPT_Halt) ? "halted": ""));
111847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111857c478bd9Sstevel@tonic-gate "\ttoggle carry: 0x%x", Get_ED(ed->hced_headp) & HC_EPT_Carry);
111867c478bd9Sstevel@tonic-gate
111877c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111887c478bd9Sstevel@tonic-gate "\tctrl: 0x%x", Get_ED(ed->hced_ctrl));
111897c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111907c478bd9Sstevel@tonic-gate "\ttailp: 0x%x", Get_ED(ed->hced_tailp));
111917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111927c478bd9Sstevel@tonic-gate "\theadp: 0x%x", Get_ED(ed->hced_headp));
111937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111947c478bd9Sstevel@tonic-gate "\tnext: 0x%x", Get_ED(ed->hced_next));
111957c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111967c478bd9Sstevel@tonic-gate "\tprev: 0x%x", Get_ED(ed->hced_prev));
111977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
111987c478bd9Sstevel@tonic-gate "\tnode: 0x%x", Get_ED(ed->hced_node));
111997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112007c478bd9Sstevel@tonic-gate "\treclaim_next: 0x%x", Get_ED(ed->hced_reclaim_next));
112017c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112027c478bd9Sstevel@tonic-gate "\treclaim_frame: 0x%x", Get_ED(ed->hced_reclaim_frame));
112037c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112047c478bd9Sstevel@tonic-gate "\tstate: 0x%x", Get_ED(ed->hced_state));
112057c478bd9Sstevel@tonic-gate }
112067c478bd9Sstevel@tonic-gate
112077c478bd9Sstevel@tonic-gate
112087c478bd9Sstevel@tonic-gate /*
112097c478bd9Sstevel@tonic-gate * ohci_print_td:
112107c478bd9Sstevel@tonic-gate */
112117c478bd9Sstevel@tonic-gate static void
ohci_print_td(ohci_state_t * ohcip,ohci_td_t * td)112127c478bd9Sstevel@tonic-gate ohci_print_td(
112137c478bd9Sstevel@tonic-gate ohci_state_t *ohcip,
112147c478bd9Sstevel@tonic-gate ohci_td_t *td)
112157c478bd9Sstevel@tonic-gate {
112167c478bd9Sstevel@tonic-gate uint_t i;
112177c478bd9Sstevel@tonic-gate uint_t ctrl = Get_TD(td->hctd_ctrl);
112187c478bd9Sstevel@tonic-gate
112197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112207c478bd9Sstevel@tonic-gate "ohci_print_td: td = 0x%p", (void *)td);
112217c478bd9Sstevel@tonic-gate
112227c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112237c478bd9Sstevel@tonic-gate "\tPID: 0x%x ", ctrl & HC_TD_PID);
112247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112257c478bd9Sstevel@tonic-gate "\tDelay Intr: 0x%x ", ctrl & HC_TD_DI);
112267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112277c478bd9Sstevel@tonic-gate "\tData Toggle: 0x%x ", ctrl & HC_TD_DT);
112287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112297c478bd9Sstevel@tonic-gate "\tError Count: 0x%x ", ctrl & HC_TD_EC);
112307c478bd9Sstevel@tonic-gate
112317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112327c478bd9Sstevel@tonic-gate "\tctrl: 0x%x ", Get_TD(td->hctd_ctrl));
112337c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112347c478bd9Sstevel@tonic-gate "\tcbp: 0x%x ", Get_TD(td->hctd_cbp));
112357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112367c478bd9Sstevel@tonic-gate "\tnext_td: 0x%x ", Get_TD(td->hctd_next_td));
112377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112387c478bd9Sstevel@tonic-gate "\tbuf_end: 0x%x ", Get_TD(td->hctd_buf_end));
112397c478bd9Sstevel@tonic-gate
112407c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) {
112417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112427c478bd9Sstevel@tonic-gate "\toffset[%d]: 0x%x ", i, Get_TD(td->hctd_offsets[i]));
112437c478bd9Sstevel@tonic-gate }
112447c478bd9Sstevel@tonic-gate
112457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112467c478bd9Sstevel@tonic-gate "\ttrans_wrapper: 0x%x ", Get_TD(td->hctd_trans_wrapper));
112477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112487c478bd9Sstevel@tonic-gate "\tstate: 0x%x ", Get_TD(td->hctd_state));
112497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112507c478bd9Sstevel@tonic-gate "\ttw_next_td: 0x%x ", Get_TD(td->hctd_tw_next_td));
112517c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ohcip->ohci_log_hdl,
112527c478bd9Sstevel@tonic-gate "\tctrl_phase: 0x%x ", Get_TD(td->hctd_ctrl_phase));
112537c478bd9Sstevel@tonic-gate }
1125419397407SSherry Moore
1125519397407SSherry Moore /*
1125619397407SSherry Moore * quiesce(9E) entry point.
1125719397407SSherry Moore *
1125819397407SSherry Moore * This function is called when the system is single-threaded at high
1125919397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be
1126019397407SSherry Moore * blocked.
1126119397407SSherry Moore *
1126219397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
1126319397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen.
112645321cfb7Spengcheng chen - Sun Microsystems - Beijing China *
112655321cfb7Spengcheng chen - Sun Microsystems - Beijing China * define as a wrapper for sparc, or warlock will complain.
1126619397407SSherry Moore */
112675321cfb7Spengcheng chen - Sun Microsystems - Beijing China #ifdef __sparc
112685321cfb7Spengcheng chen - Sun Microsystems - Beijing China int
ohci_quiesce(dev_info_t * dip)112695321cfb7Spengcheng chen - Sun Microsystems - Beijing China ohci_quiesce(dev_info_t *dip)
112705321cfb7Spengcheng chen - Sun Microsystems - Beijing China {
112715321cfb7Spengcheng chen - Sun Microsystems - Beijing China return (ddi_quiesce_not_supported(dip));
112725321cfb7Spengcheng chen - Sun Microsystems - Beijing China }
112735321cfb7Spengcheng chen - Sun Microsystems - Beijing China #else
1127419397407SSherry Moore int
ohci_quiesce(dev_info_t * dip)1127519397407SSherry Moore ohci_quiesce(dev_info_t *dip)
1127619397407SSherry Moore {
1127719397407SSherry Moore ohci_state_t *ohcip = ohci_obtain_state(dip);
1127819397407SSherry Moore
1127919397407SSherry Moore if (ohcip == NULL)
1128019397407SSherry Moore return (DDI_FAILURE);
1128119397407SSherry Moore
1128234c852b0Szhigang lu - Sun Microsystems - Beijing China #ifndef lint
1128334c852b0Szhigang lu - Sun Microsystems - Beijing China _NOTE(NO_COMPETING_THREADS_NOW);
1128434c852b0Szhigang lu - Sun Microsystems - Beijing China #endif
1128534c852b0Szhigang lu - Sun Microsystems - Beijing China
1128619397407SSherry Moore if (ohcip->ohci_flags & OHCI_INTR) {
1128719397407SSherry Moore
1128819397407SSherry Moore /* Disable all HC ED list processing */
1128919397407SSherry Moore Set_OpReg(hcr_control,
1129019397407SSherry Moore (Get_OpReg(hcr_control) & ~(HCR_CONTROL_CLE |
1129119397407SSherry Moore HCR_CONTROL_BLE | HCR_CONTROL_PLE | HCR_CONTROL_IE)));
1129219397407SSherry Moore
1129319397407SSherry Moore /* Disable all HC interrupts */
1129419397407SSherry Moore Set_OpReg(hcr_intr_disable,
1129519397407SSherry Moore (HCR_INTR_SO | HCR_INTR_WDH | HCR_INTR_RD | HCR_INTR_UE));
1129619397407SSherry Moore
1129719397407SSherry Moore /* Disable Master and SOF interrupts */
1129819397407SSherry Moore Set_OpReg(hcr_intr_disable, (HCR_INTR_MIE | HCR_INTR_SOF));
1129919397407SSherry Moore
1130019397407SSherry Moore /* Set the Host Controller Functional State to Reset */
1130119397407SSherry Moore Set_OpReg(hcr_control, ((Get_OpReg(hcr_control) &
1130219397407SSherry Moore (~HCR_CONTROL_HCFS)) | HCR_CONTROL_RESET));
1130319397407SSherry Moore
1130419397407SSherry Moore /*
1130519397407SSherry Moore * Workaround for ULI1575 chipset. Following OHCI Operational
1130619397407SSherry Moore * Memory Registers are not cleared to their default value
1130719397407SSherry Moore * on reset. Explicitly set the registers to default value.
1130819397407SSherry Moore */
1130919397407SSherry Moore if (ohcip->ohci_vendor_id == PCI_ULI1575_VENID &&
1131019397407SSherry Moore ohcip->ohci_device_id == PCI_ULI1575_DEVID) {
1131119397407SSherry Moore Set_OpReg(hcr_control, HCR_CONTROL_DEFAULT);
1131219397407SSherry Moore Set_OpReg(hcr_intr_enable, HCR_INT_ENABLE_DEFAULT);
1131319397407SSherry Moore Set_OpReg(hcr_HCCA, HCR_HCCA_DEFAULT);
1131419397407SSherry Moore Set_OpReg(hcr_ctrl_head, HCR_CONTROL_HEAD_ED_DEFAULT);
1131519397407SSherry Moore Set_OpReg(hcr_bulk_head, HCR_BULK_HEAD_ED_DEFAULT);
1131619397407SSherry Moore Set_OpReg(hcr_frame_interval,
1131719397407SSherry Moore HCR_FRAME_INTERVAL_DEFAULT);
1131819397407SSherry Moore Set_OpReg(hcr_periodic_strt,
1131919397407SSherry Moore HCR_PERIODIC_START_DEFAULT);
1132019397407SSherry Moore }
1132119397407SSherry Moore
1132219397407SSherry Moore ohcip->ohci_hc_soft_state = OHCI_CTLR_SUSPEND_STATE;
1132319397407SSherry Moore }
1132419397407SSherry Moore
1132519397407SSherry Moore /* Unmap the OHCI registers */
1132619397407SSherry Moore if (ohcip->ohci_regs_handle) {
1132719397407SSherry Moore /* Reset the host controller */
1132819397407SSherry Moore Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET);
1132919397407SSherry Moore }
1133019397407SSherry Moore
1133134c852b0Szhigang lu - Sun Microsystems - Beijing China #ifndef lint
1133234c852b0Szhigang lu - Sun Microsystems - Beijing China _NOTE(COMPETING_THREADS_NOW);
1133334c852b0Szhigang lu - Sun Microsystems - Beijing China #endif
1133419397407SSherry Moore return (DDI_SUCCESS);
1133519397407SSherry Moore }
1133619397407SSherry Moore #endif /* __sparc */
11337