root/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_USB_OHCID_H
#define _SYS_USB_OHCID_H

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * Open Host Controller Driver (OHCI)
 *
 * The USB Open Host Controller driver is a software driver which interfaces
 * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
 * The interface to USB Open Host Controller is defined by the OpenHCI  Host
 * Controller Interface.
 *
 * This header file describes the data structures required for the USB Open
 * Host Controller Driver to maintain state of USB Open Host Controller, to
 * perform different USB transfers and for the bandwidth allocations.
 */

#include <sys/usb/hcd/openhci/ohci.h>
#include <sys/usb/hcd/openhci/ohci_hub.h>

/*
 * OpenHCI interrupt status information structure
 *
 * The Host Controller Driver (HCD) has to maintain two different sets of
 * Host Controller (HC) state information that includes HC registers, the
 * interrupt tables etc.. for the normal and polled modes.  In  addition,
 * suppose if we switched to polled mode while ohci  interrupt handler is
 * executing in the normal mode then we need to save the interrupt status
 * information that includes interrupts for which ohci interrupt  handler
 * is called and HCCA done head list in the polled mode. This infromation
 * will be used later in normal mode to  service those missed interrupts.
 * This will avoid race conditions like missing of normal mode's ohci SOF
 * and WriteDoneHead interrupts because of this polled switch.
 */
typedef struct ohci_save_intr_sts {
        /*
         * The following field has set of flags & these flags will be set
         * in the ohci interrupt handler to indicate that currently  ohci
         * interrupt handler is in execution and also while critical code
         * execution within the ohci interrupt handler.  These flags will
         * be verified in polled mode while saving the normal mode's ohci
         * interrupt status information.
         */
        uint_t          ohci_intr_flag;         /* Intr handler flags */

        /*
         * The following fields will be used to save the interrupt status
         * and the HCCA done head list that the ohci interrupt handler is
         * currently handling.
         */
        uint_t          ohci_curr_intr_sts;     /* Current interrupts */
        ohci_td_t       *ohci_curr_done_lst;    /* Current done head  */

        /*
         * The following fields will be used to save the interrupt status
         * and the HCCA done list currently being handled by the critical
         * section of the ohci interrupt handler..
         */
        uint_t          ohci_critical_intr_sts; /* Critical interrupts */
        ohci_td_t       *ohci_critical_done_lst; /* Critical done head */

        /*
         * The following fields will be used to save the interrupt status
         * and HCCA done head list by the polled code if an  interrupt is
         * pending when polled code is entered. These missed interrupts &
         * done list will be serviced either in current  normal mode ohci
         * interrupt handler execution or during the next  ohci interrupt
         * handler execution.
         */
        uint_t          ohci_missed_intr_sts;   /* Missed interrupts */
        ohci_td_t       *ohci_missed_done_lst;  /* Missed done head  */
} ohci_save_intr_sts_t;

/*
 * These flags will be set in the the normal mode ohci  interrupt handler
 * to indicate that currently ohci interrupt handler is in  execution and
 * also while critical code  execution within the ohci interrupt handler.
 * These flags will be verified in the polled mode while saving the normal
 * mode's ohci interrupt status infromation.
 */
#define         OHCI_INTR_HANDLING      0x01    /* Handling ohci intrs */
#define         OHCI_INTR_CRITICAL      0x02    /* Critical intr code  */


/*
 * OpenHCI Host Controller state structure
 *
 * The Host Controller Driver (HCD) maintains the state of Host Controller
 * (HC). There is an ohci_state structure per instance  of the OpenHCI
 * host controller.
 */

typedef struct ohci_state {
        dev_info_t              *ohci_dip;              /* Dip of HC */
        uint_t                  ohci_instance;
        usba_hcdi_ops_t         *ohci_hcdi_ops;         /* HCDI structure */
        uint_t                  ohci_flags;             /* Used for cleanup */
        uint16_t                ohci_vendor_id;         /* chip vendor */
        uint16_t                ohci_device_id;         /* chip device */
        uint8_t                 ohci_rev_id;            /* chip revison */

        ohci_regs_t             *ohci_regsp;            /* Host ctlr regs */
        ddi_acc_handle_t        ohci_regs_handle;       /* Reg handle */

        ddi_acc_handle_t        ohci_config_handle;     /* Config space hndle */
        uint_t                  ohci_frame_interval;    /* Frme inter reg */
        ddi_dma_attr_t          ohci_dma_attr;          /* DMA attributes */

        ddi_intr_handle_t       *ohci_htable;           /* intr handle */
        int                     ohci_intr_type;         /* intr type used */
        int                     ohci_intr_cnt;          /* # of intrs inuse */
        uint_t                  ohci_intr_pri;          /* intr priority */
        int                     ohci_intr_cap;          /* intr capabilities */
        boolean_t               ohci_msi_enabled;       /* default to true */
        kmutex_t                ohci_int_mutex;         /* Mutex for struct */

        /* HCCA area */
        ohci_hcca_t             *ohci_hccap;            /* Virtual HCCA ptr */
        ddi_dma_cookie_t        ohci_hcca_cookie;       /* DMA cookie */
        ddi_dma_handle_t        ohci_hcca_dma_handle;   /* DMA handle */
        ddi_acc_handle_t        ohci_hcca_mem_handle;   /* Memory handle */

        /*
         * There are two pools of memory. One pool contains the memory for
         * the transfer descriptors and other pool contains the memory for
         * the endpoint descriptors. The advantage of the pools is that it's
         * easy to go back and forth between the iommu and the cpu addresses.
         *
         * The pools are protected by the ohci_int_mutex because the memory
         * in the pools may be accessed by either the host controller or the
         * host controller driver.
         */

        /* General transfer descriptor pool */
        ohci_td_t               *ohci_td_pool_addr;     /* Start of the pool */
        ddi_dma_cookie_t        ohci_td_pool_cookie;    /* DMA cookie */
        ddi_dma_handle_t        ohci_td_pool_dma_handle;        /* DMA hndle */
        ddi_acc_handle_t        ohci_td_pool_mem_handle;        /* Mem hndle */

        /* Endpoint descriptor pool */
        ohci_ed_t               *ohci_ed_pool_addr;     /* Start of the pool */
        ddi_dma_cookie_t        ohci_ed_pool_cookie;    /* DMA cookie */
        ddi_dma_handle_t        ohci_ed_pool_dma_handle;        /* DMA handle */
        ddi_acc_handle_t        ohci_ed_pool_mem_handle;        /* Mem handle */
        uint_t                  ohci_dma_addr_bind_flag;        /* DMA flag */

        /* Condition variables */
        kcondvar_t              ohci_SOF_cv;            /* SOF variable */

        /* Semaphore to serialize opens and closes */
        ksema_t                 ohci_ocsem;

        /*
         * Bandwidth fields
         *
         * The ohci_bandwidth array keeps track of the allocated bandwidth
         * for this host controller. The total bandwidth allocated for least
         * allocated list out of the 32 periodic lists is represented by the
         * ohci_periodic_minimum_bandwidth field.
         */
        uint_t                  ohci_periodic_minimum_bandwidth;
        uint_t                  ohci_periodic_bandwidth[NUM_INTR_ED_LISTS];

        /* Different transfer open pipe counts */
        uint_t                  ohci_open_pipe_count;
        uint_t                  ohci_open_ctrl_pipe_count;
        uint_t                  ohci_open_bulk_pipe_count;
        uint_t                  ohci_open_periodic_pipe_count;
        uint_t                  ohci_open_isoch_pipe_count;
        /*
         * Endpoint Reclamation List
         *
         * The interrupt or isochronous list processing cannot be stopped
         * when a periodic endpoint is removed from the list. The endpoints
         * are detached from the interrupt lattice tree and put on to the
         * reclaimation list. On next SOF interrupt all those endpoints,
         * which are on the reclaimation list will be deallocated.
         */
        ohci_ed_t               *ohci_reclaim_list;     /* Reclaimation list */

        ohci_root_hub_t         ohci_root_hub;          /* Root hub info */

        /*
         * Global transfer timeout handling & this transfer timeout handling
         * will be per USB Host Controller.
         */
        struct ohci_trans_wrapper *ohci_timeout_list;   /* Timeout List */
        timeout_id_t            ohci_timer_id;          /* Timer id  */

        /* Frame number overflow information */
        usb_frame_number_t      ohci_fno;

        /* For Schedule Overrun error counter */
        uint_t                  ohci_so_error;

        /* For host controller error counter */
        uint_t                  ohci_hc_error;

        /* For SOF interrupt event */
        boolean_t               ohci_sof_flag;

        /* Openhci Host Controller Software State information */
        uint_t                  ohci_hc_soft_state;

        /*
         * ohci_save_intr_stats is used to save the normal mode interrupt
         * status information while executing interrupt handler & also by
         * the polled code if an interrupt is pending for the normal mode
         * when polled code is entered.
         */
        ohci_save_intr_sts_t    ohci_save_intr_sts;

        /*
         * Saved copy of the ohci registers of the normal mode & change
         * required ohci registers values for the polled mode operation.
         * Before returning from the polled mode to normal mode replace
         * the required current registers with this saved ohci registers
         * copy.
         */
        ohci_regs_t     ohci_polled_save_regs;

        /*
         * Saved copy of the interrupt table used in normal ohci mode and
         * replace this table by another interrupt table that used in the
         * POLLED mode.
         */
        ohci_ed_t       *ohci_polled_save_IntTble[NUM_INTR_ED_LISTS];

        /* ohci polled mode enter counter for the input devices */
        uint_t                  ohci_polled_enter_count;

        /*
         * Counter for polled mode and used in suspend mode to see if
         * there is a input device connected.
         */
        uint_t                  ohci_polled_kbd_count;

        /* Done list for the Polled mode */
        ohci_td_t               *ohci_polled_done_list;

        /* Log handle for debug, console, log messages */
        usb_log_handle_t        ohci_log_hdl;

        /* Kstat structures */
        kstat_t                 *ohci_intrs_stats;
        kstat_t                 *ohci_total_stats;
        kstat_t                 *ohci_count_stats[USB_N_COUNT_KSTATS];
} ohci_state_t;

typedef struct ohci_intrs_stats {
        struct kstat_named      ohci_hcr_intr_so;
        struct kstat_named      ohci_hcr_intr_wdh;
        struct kstat_named      ohci_hcr_intr_sof;
        struct kstat_named      ohci_hcr_intr_rd;
        struct kstat_named      ohci_hcr_intr_ue;
        struct kstat_named      ohci_hcr_intr_fno;
        struct kstat_named      ohci_hcr_intr_rhsc;
        struct kstat_named      ohci_hcr_intr_oc;
        struct kstat_named      ohci_hcr_intr_not_claimed;
        struct kstat_named      ohci_hcr_intr_total;
} ohci_intrs_stats_t;

/*
 * ohci kstat defines
 */
#define OHCI_INTRS_STATS(ohci)  ((ohci)->ohci_intrs_stats)
#define OHCI_INTRS_STATS_DATA(ohci)     \
        ((ohci_intrs_stats_t *)OHCI_INTRS_STATS((ohci))->ks_data)

#define OHCI_TOTAL_STATS(ohci)  ((ohci)->ohci_total_stats)
#define OHCI_TOTAL_STATS_DATA(ohci)     (KSTAT_IO_PTR((ohci)->ohci_total_stats))
#define OHCI_CTRL_STATS(ohci)   \
        (KSTAT_IO_PTR((ohci)->ohci_count_stats[USB_EP_ATTR_CONTROL]))
#define OHCI_BULK_STATS(ohci)   \
        (KSTAT_IO_PTR((ohci)->ohci_count_stats[USB_EP_ATTR_BULK]))
#define OHCI_INTR_STATS(ohci)   \
        (KSTAT_IO_PTR((ohci)->ohci_count_stats[USB_EP_ATTR_INTR]))
#define OHCI_ISOC_STATS(ohci)   \
        (KSTAT_IO_PTR((ohci)->ohci_count_stats[USB_EP_ATTR_ISOCH]))

/* warlock directives, stable data */
_NOTE(MUTEX_PROTECTS_DATA(ohci_state_t::ohci_int_mutex, ohci_state_t))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_intr_pri))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_dip))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_regsp))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_instance))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_vendor_id))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_device_id))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_rev_id))

/* this may not be stable data in the future */
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_td_pool_addr))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_td_pool_mem_handle))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_ed_pool_addr))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_ed_pool_mem_handle))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_td_pool_cookie))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_ed_pool_cookie))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_hcca_mem_handle))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_hccap))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_dma_addr_bind_flag))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ohci_state_t::ohci_log_hdl))

_NOTE(LOCK_ORDER(ohci_state::ohci_int_mutex \
                usba_pipe_handle_data::p_mutex \
                usba_device::usb_mutex \
                usba_ph_impl::usba_ph_mutex))

/*
 * Host Contoller Software States
 *
 * OHCI_CTLR_INIT_STATE:
 *      The host controller soft state will be set to this during the
 *      ohci_attach.
 *
 * OHCI_CTLR_SUSPEND_STATE:
 *      The host controller soft state will be set to this during the
 *      ohci_cpr_suspend.
 *
 * OHCI_CTLR_OPERATIONAL_STATE:
 *      The host controller soft state will be set to this after moving
 *      host controller to operational state and host controller start
 *      generating SOF successfully.
 *
 * OHCI_CTLR_ERROR_STATE:
 *      The host controller soft state will be set to this during the
 *      no SOF or UE error conditions.
 *
 *      Under this state or condition, only pipe stop polling, pipe reset
 *      and pipe close are allowed. But all other entry points like  pipe
 *      open, get/set pipe policy, cotrol send/receive, bulk send/receive
 *      isoch send/receive, start polling etc. will fail.
 *
 * State Diagram for the host controller software state
 *
 *
 * ohci_attach->[INIT_STATE]
 *      |
 *      |       -------->----[ERROR_STATE]--<-----------<---
 *      |      |      Failure (UE/no SOF condition)         |
 *      |      ^                                            ^
 *      V      |      Success                               |
 * ohci_init_ctlr--->--------[OPERATIONAL_STATE]------>-ohci_send/recv/polling
 *      ^                                           |
 *      |                                           |
 *      |                                           V
 *      -<-ohci_cpr_resume--[SUSPEND_STATE]-<-ohci_cpr_suspend
 */
#define OHCI_CTLR_INIT_STATE            0       /* Initilization state */
#define OHCI_CTLR_SUSPEND_STATE         1       /* Suspend state */
#define OHCI_CTLR_OPERATIONAL_STATE     2       /* Operational state */
#define OHCI_CTLR_ERROR_STATE           3       /* Ue error or no sof state */

/*
 * Define all ohci's Vendor-id and Device-id Here
 */
#define RIO_VENDOR      0x108e
#define RIO_DEVICE      0x1103
#define OHCI_IS_RIO(ohcip)      (ohcip->ohci_vendor_id == RIO_VENDOR)

/*
 * Periodic and non-periodic macros
 */
#define OHCI_PERIODIC_ENDPOINT(endpoint) (((endpoint->bmAttributes &\
                                USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) ||\
                                ((endpoint->bmAttributes &\
                                USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH))

#define OHCI_NON_PERIODIC_ENDPOINT(endpoint) (((endpoint->bmAttributes &\
                                USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) ||\
                                ((endpoint->bmAttributes &\
                                USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK))

/*
 * OHCI ED and TD Pool sizes.
 */
#define OHCI_ED_POOL_SIZE       100
#define OHCI_TD_POOL_SIZE       200

/*
 * ohci_dma_addr_bind_flag values
 *
 * This flag indicates if the various DMA addresses allocated by the OHCI
 * have been bound to their respective handles. This is needed to recover
 * without errors from ohci_cleanup when it calls ddi_dma_unbind_handle()
 */
#define OHCI_TD_POOL_BOUND      0x01    /* For TD pools  */
#define OHCI_ED_POOL_BOUND      0x02    /* For ED pools  */
#define OHCI_HCCA_DMA_BOUND     0x04    /* For HCCA area */

/*
 * Maximum SOF wait count
 */
#define MAX_SOF_WAIT_COUNT      2       /* Wait for maximum SOF frames */


/*
 * Pipe private structure
 *
 * There is an instance of this structure per pipe.  This structure holds
 * HCD specific pipe information.  A pointer to this structure is kept in
 * the USBA pipe handle (usba_pipe_handle_data_t).
 */
typedef struct ohci_pipe_private {
        usba_pipe_handle_data_t *pp_pipe_handle;        /* Back ptr to handle */
        ohci_ed_t               *pp_ept;                /* Pipe's ept */

        /* State of the pipe */
        uint_t                  pp_state;               /* See below */

        /* Local copy of the pipe policy */
        usb_pipe_policy_t       pp_policy;

        /* For Periodic Pipes Only */
        uint_t                  pp_node;                /* Node in lattice */
        uint_t                  pp_cur_periodic_req_cnt; /* Curr req count */
        uint_t                  pp_max_periodic_req_cnt; /* Max req count */

        /* For isochronous pipe only */
        usb_frame_number_t      pp_next_frame_number;   /* Next frame no */

        /*
         * Each pipe may have multiple transfer wrappers. Each transfer
         * wrapper represents a USB transfer on the bus.  A transfer is
         * made up of one or more transactions.
         */
        struct ohci_trans_wrapper *pp_tw_head;  /* Head of the list */
        struct ohci_trans_wrapper *pp_tw_tail;  /* Tail of the list */

        /* Done td count */
        uint_t                  pp_count_done_tds;      /* Done td count */

        /* Errors */
        usb_cr_t                pp_error;               /* Pipe error */

        /* Flags */
        uint_t                  pp_flag;                /* Flags */

        /* Condition variable for transfers completion event */
        kcondvar_t              pp_xfer_cmpl_cv;        /* Xfer completion */

        /*
         * HCD gets Interrupt/Isochronous IN polling request only once and
         * it has to insert next polling requests after completion of first
         * request until either stop polling/pipe close is called. So  HCD
         * has to take copy of the original Interrupt/Isochronous IN request.
         */
        usb_opaque_t            pp_client_periodic_in_reqp;
} ohci_pipe_private_t;

/* warlock directives, stable data */
_NOTE(MUTEX_PROTECTS_DATA(ohci_state_t::ohci_int_mutex, ohci_pipe_private_t))

/*
 * Pipe states
 *
 * ohci pipe states will be similar to usba. Refer usbai.h.
 */
#define OHCI_PIPE_STATE_IDLE            1       /* Pipe is in ready state */
#define OHCI_PIPE_STATE_ACTIVE          2       /* Pipe is in busy state */
#define OHCI_PIPE_STATE_ERROR           3       /* Pipe is in error state */

/* Additional ohci pipe states for the ohci_pipe_cleanup */
#define OHCI_PIPE_STATE_CLOSE           4       /* Pipe close */
#define OHCI_PIPE_STATE_RESET           5       /* Pipe reset */
#define OHCI_PIPE_STATE_STOP_POLLING    6       /* Pipe stop polling */

/*
 * Pipe specific Flags
 */
#define OHCI_ISOC_XFER_CONTINUE 1       /* For isoc transfers */

/*
 * The maximum allowable usb isochronous data transfer size or maximum
 * number of isochronous data packets.
 *
 * Each usb isochronous request must not exceed multiples of isochronous
 * endpoint packet size and OHCI_MAX_ISOC_PKTS_PER_XFER.
 *
 * Ex: usb isochronous endpoint maximum packet size is 64 bytes
 *     maximum usb isochronous request will be OHCI_MAX_ISOC_PKTS_PER_XFER
 *     * 64 bytes
 */
#define         OHCI_MAX_ISOC_PKTS_PER_XFER     256     /* Max pkts per req */

/*
 * The ohci supports maximum of eight isochronous data packets per transfer
 * descriptor.
 */
#define         OHCI_ISOC_PKTS_PER_TD           8       /* Packets per TD */

/*
 * USB frame offset
 *
 * Add appropriate frame offset to the current usb frame number and use it
 * as a starting frame number for a given usb isochronous request.
 */
#define         OHCI_FRAME_OFFSET               2       /* Frame offset */

/*
 * Default usb isochronous receive packets per request before ohci will do
 * callback.
 */
#define         OHCI_DEFAULT_ISOC_RCV_PKTS      1       /* isoc pkts per req */

/*
 * Different interrupt polling intervals supported
 */
#define         INTR_1MS_POLL   1
#define         INTR_2MS_POLL   2
#define         INTR_4MS_POLL   4
#define         INTR_8MS_POLL   8
#define         INTR_16MS_POLL  16
#define         INTR_32MS_POLL  32

/*
 * Number of interrupt/isochronous transfer requests that should
 * be maintained on the interrupt/isochronous endpoint corresponding
 * to different polling intervals supported.
 */
#define         INTR_1MS_REQS   4       /* 1ms polling interval */
#define         INTR_2MS_REQS   2       /* 2ms polling interval */
#define         INTR_XMS_REQS   1       /* Between 4ms and 32ms */

/* Function prototype */
typedef void (*ohci_handler_function_t)(
        ohci_state_t                    *ohcip,
        ohci_pipe_private_t             *pp,
        struct ohci_trans_wrapper       *tw,
        ohci_td_t                       *td,
        void                            *ohci_handle_callback_value);


/*
 * Transfer wrapper
 *
 * The transfer wrapper represents a USB transfer on the bus and there
 * is one instance per USB transfer.  A transfer is made up of one or
 * more transactions. OHCI uses one TD for one transaction. So one
 * transfer wrapper may have one or more TDs associated.
 *
 * Control and bulk pipes will have one transfer wrapper per transfer
 * and where as Isochronous and Interrupt pipes will only have one
 * transfer wrapper. The transfers wrapper are continually reused for
 * the Interrupt and Isochronous pipes as those pipes are polled.
 *
 * Control, bulk and interrupt transfers will have one DMA buffer per
 * transfer. The data to be transferred are contained in the DMA buffer
 * which is virtually contiguous but physically discontiguous. When
 * preparing the TDs for a USB transfer, the DMA cookies contained in
 * the buffer need to be walked through to retrieve the DMA addresses.
 *
 * Isochronous transfers may have multiple DMA buffers per transfer
 * with each isoc TD having a DMA buffer. And one isoc TD may hold up to
 * eight isoc packets, but two cookies at most.
 */
typedef struct ohci_trans_wrapper {
        struct ohci_trans_wrapper       *tw_next;       /* Next wrapper */
        ohci_pipe_private_t             *tw_pipe_private; /* Back ptr */
        ddi_dma_handle_t                tw_dmahandle;   /* DMA handle */
        ddi_acc_handle_t                tw_accesshandle; /* Acc hndle */
        ddi_dma_cookie_t                tw_cookie;      /* DMA cookie */
        uint32_t                        tw_id;          /* 32bit ID */
        size_t                          tw_length;      /* Txfer length */
        char                            *tw_buf;        /* Buffer for Xfer */
        uint_t                          tw_ncookies;    /* DMA cookie count */
        uint_t                          tw_cookie_idx;  /* DMA cookie index */
        size_t                          tw_dma_offs;    /* DMA buffer offset */
        usb_flags_t                     tw_flags;       /* Flags */
        uint_t                          tw_num_tds;     /* Number of TDs */
        ohci_td_t                       *tw_hctd_head;  /* Head TD */
        ohci_td_t                       *tw_hctd_tail;  /* Tail TD */
        uint_t                          tw_direction;   /* Direction of TD */
        uint_t                          tw_pkt_idx;     /* packet index */

        /* We preallocate all the td's for each tw and place them here */
        ohci_td_t                       *tw_hctd_free_list;

        /* Current transfer request pointer */
        usb_opaque_t                    tw_curr_xfer_reqp;

        /* Current isochronous packet descriptor pointer */
        usb_isoc_pkt_descr_t            *tw_curr_isoc_pktp;

        /* Isochronous DMA handlers and buffer pointers are stored here */
        ohci_isoc_buf_t                 *tw_isoc_bufs;
        size_t                          tw_isoc_strtlen;

        /* Transfer timeout information */
        uint_t                          tw_timeout;     /* Timeout value */
        struct ohci_trans_wrapper       *tw_timeout_next; /* Xfer Timeout Q */

        /*
         * This is the function to call when this td is done. This way
         * we don't have to look in the td to figure out what kind it is.
         */
        ohci_handler_function_t         tw_handle_td;

        /*
         * This is the callback value used when processing a done td.
         */
        usb_opaque_t                    tw_handle_callback_value;
} ohci_trans_wrapper_t;

_NOTE(MUTEX_PROTECTS_DATA(ohci_state_t::ohci_int_mutex, ohci_trans_wrapper))


/*
 * Time waits for the different OHCI specific operations.
 * These timeout values are specified in terms of microseconds.
 */
#define OHCI_RESET_TIMEWAIT     10000   /* HC reset waiting time */
#define OHCI_RESUME_TIMEWAIT    40000   /* HC resume waiting time */
#define OHCI_TIMEWAIT           10000   /* HC any other waiting time */

/* These timeout values are specified in seconds */
#define OHCI_DEFAULT_XFER_TIMEOUT       5 /* Default transfer timeout */
#define OHCI_MAX_SOF_TIMEWAIT           3 /* Maximum SOF waiting time */
#define OHCI_XFER_CMPL_TIMEWAIT         3 /* Xfers completion timewait */

/* OHCI flags for general use */
#define OHCI_FLAGS_NOSLEEP      0x000   /* Don't wait for SOF */
#define OHCI_FLAGS_SLEEP        0x100   /* Wait for SOF */
#define OHCI_FLAGS_DMA_SYNC     0x200   /* Call ddi_dma_sync */

/*
 * Maximum allowable data transfer  size per transaction as supported
 * by OHCI is 8k. (See Open Host Controller Interface Spec rev 1.0a)
 */
#define OHCI_MAX_TD_XFER_SIZE   0x2000  /* Maxmum data per transaction */

/*
 * One OHCI TD allows two physically discontiguous pages. The page size
 * is 4k.
 */
#define OHCI_MAX_TD_BUF_SIZE    0x1000

/*
 * The maximum allowable bulk data transfer size. It can be different
 * from OHCI_MAX_TD_XFER_SIZE and if it is more then ohci driver will
 * take care of  breaking a bulk data request into  multiples of ohci
 * OHCI_MAX_TD_XFER_SIZE  until request is satisfied.  Currently this
 * value is set to 256k bytes.
 */
#define OHCI_MAX_BULK_XFER_SIZE 0x40000 /* Maximum bulk transfer size */

/*
 * Timeout flags
 *
 * These flags will be used to stop the timer before timeout handler
 * gets executed.
 */
#define OHCI_REMOVE_XFER_IFLAST 1       /* Stop the timer if  it is last TD */
#define OHCI_REMOVE_XFER_ALWAYS 2       /* Stop the timer without condition */


/*
 * Bandwidth allocation
 *
 * The following definitions are  used during  bandwidth calculations
 * for a given endpoint maximum packet size.
 */
#define MAX_USB_BUS_BANDWIDTH   1500    /* Up to 1500 bytes per frame */
#define MAX_POLL_INTERVAL       255     /* Maximum polling interval */
#define MIN_POLL_INTERVAL       1       /* Minimum polling interval */
#define SOF                     6       /* Length in bytes of SOF */
#define EOF                     4       /* Length in bytes of EOF */
#define TREE_HEIGHT             5       /* Log base 2 of 32 */

/*
 * Minimum polling interval for low speed endpoint
 *
 * According USB Specifications, a full-speed endpoint can specify
 * a desired polling interval 1ms to 255ms and a low speed endpoints
 * are limited to specifying only 10ms to 255ms. But some old keyboards
 * and mice uses polling interval of 8ms. For compatibility purpose,
 * we are using polling interval between 8ms and 255ms for low speed
 * endpoints. But ohci driver will reject any low speed endpoints which
 * request polling interval less than 8ms.
 */
#define MIN_LOW_SPEED_POLL_INTERVAL     8

/*
 * For non-periodic transfers, reserve atleast for one low-speed device
 * transaction. According to USB Bandwidth Analysis white paper and also
 * as per OHCI Specification 1.0a, section 7.3.5, page 123, one low-speed
 * transaction takes 0x628h full speed bits (197 bytes), which comes to
 * around 13% of USB frame time.
 *
 * The periodic transfers will  get around 87% of USB frame time.
 */
#define MAX_NON_PERIODIC_BANDWIDTH      197
#define MAX_PERIODIC_BANDWIDTH          (MAX_USB_BUS_BANDWIDTH - SOF - \
                                        EOF - MAX_NON_PERIODIC_BANDWIDTH)

/*
 * The USB periodic transfers like interrupt and isochronous transfers
 * after completion of SOF and USB non-periodic transfers.
 */
#define PERIODIC_XFER_STARTS            (MAX_USB_BUS_BANDWIDTH - \
                                        SOF - MAX_NON_PERIODIC_BANDWIDTH)

/* Number of Bits Per Byte */
#define BITS_PER_BYTE                   8

/*
 * The following are the protocol overheads in terms of Bytes for the
 * different transfer types.  All these protocol overhead  values are
 * derived from the 5.9.3 section of USB Specification  and  with the
 * help of Bandwidth Analysis white paper which is posted on the  USB
 * developer forum.
 */
#define FS_NON_ISOC_PROTO_OVERHEAD      14
#define FS_ISOC_INPUT_PROTO_OVERHEAD    11
#define FS_ISOC_OUTPUT_PROTO_OVERHEAD   10
#define LOW_SPEED_PROTO_OVERHEAD        97
#define HUB_LOW_SPEED_PROTO_OVERHEAD    01

/*
 * The Host Controller (HC) delays are the USB host controller specific
 * delays. The value shown below is the host  controller delay for  the
 * RIO USB host controller.  This value was calculated and  given by the
 * Sun USB hardware people.
 */
#define HOST_CONTROLLER_DELAY           18

/*
 * The low speed clock below represents that to transmit one low-speed
 * bit takes eight times more than one full speed bit time.
 */
#define LOW_SPEED_CLOCK                 8


/*
 * Macros for setting/getting information
 */
#define Get_ED(addr)            ddi_get32(ohcip->ohci_ed_pool_mem_handle, \
                                        (uint32_t *)&addr)

#define Set_ED(addr, val)       ddi_put32(ohcip->ohci_ed_pool_mem_handle,  \
                                        ((uint32_t *)&addr), \
                                        ((int32_t)(val)))

#define Get_TD(addr)            ddi_get32(ohcip->ohci_td_pool_mem_handle, \
                                        (uint32_t *)&addr)

#define Set_TD(addr, val)       ddi_put32(ohcip->ohci_td_pool_mem_handle, \
                                        ((uint32_t *)&addr), \
                                        ((uint32_t)(uintptr_t)(val)))

#define Get_HCCA(addr)          ddi_get32(ohcip->ohci_hcca_mem_handle, \
                                        (uint32_t *)&addr)

#define Set_HCCA(addr, val)     ddi_put32(ohcip->ohci_hcca_mem_handle, \
                                        ((uint32_t *)&addr), \
                                        ((int32_t)(val)))

#define Get_OpReg(addr)         ddi_get32(ohcip->ohci_regs_handle, \
                                        (uint32_t *)&ohcip->ohci_regsp->addr)

#define Set_OpReg(addr, val)    ddi_put32(ohcip->ohci_regs_handle, \
                                ((uint32_t *)&ohcip->ohci_regsp->addr), \
                                        ((int32_t)(val)))

#define Sync_HCCA(ohcip)        (void) ddi_dma_sync( \
                                ohcip->ohci_hcca_dma_handle, \
                                0, sizeof (ohci_hcca_t), \
                                DDI_DMA_SYNC_FORCPU);

#define Sync_ED_TD_Pool(ohcip)  (void) ddi_dma_sync( \
                                ohcip->ohci_ed_pool_dma_handle, \
                                0, OHCI_ED_POOL_SIZE * sizeof (ohci_ed_t), \
                                DDI_DMA_SYNC_FORCPU); \
                                (void) ddi_dma_sync( \
                                ohcip->ohci_td_pool_dma_handle, \
                                0, OHCI_TD_POOL_SIZE * sizeof (ohci_td_t), \
                                DDI_DMA_SYNC_FORCPU);

#define Sync_IO_Buffer(dma_handle, length) \
                                (void) ddi_dma_sync(dma_handle, \
                                0, length, DDI_DMA_SYNC_FORCPU);
#define Sync_IO_Buffer_for_device(dma_handle, length) \
                                (void) ddi_dma_sync(dma_handle, \
                                0, length, DDI_DMA_SYNC_FORDEV);

/*
 * Macros to speed handling of 32bit IDs
 */
#define OHCI_GET_ID(x)          id32_alloc((void *)(x), KM_SLEEP)
#define OHCI_LOOKUP_ID(x)       id32_lookup((x))
#define OHCI_FREE_ID(x)         id32_free((x))


/*
 * Miscellaneous definitions.
 */

/* Data toggle bits */
#define DATA0           0
#define DATA1           1

/* sKip bit actions */
#define CLEAR_sKip      0
#define SET_sKip        1

typedef uint_t          skip_bit_t;

/*
 * Setup Packet
 */
typedef struct setup_pkt {
        uchar_t bmRequestType;
        uchar_t bRequest;
        ushort_t wValue;
        ushort_t wIndex;
        ushort_t wLength;
}setup_pkt_t;

#define SETUP_SIZE              8       /* Setup packet is always 8 bytes */

#define REQUEST_TYPE_OFFSET     0
#define REQUEST_OFFSET          1
#define VALUE_OFFSET            2
#define INDEX_OFFSET            4
#define LENGTH_OFFSET           6

#define TYPE_DEV_TO_HOST        0x80000000
#define DEVICE                  0x00000001
#define CONFIGURATION           0x00000002

/*
 * The following are used in attach to   indicate
 * what has been succesfully allocated, so detach
 * can remove them.
 */
#define OHCI_ATTACH             0x01    /* ohci driver initilization */
#define OHCI_ZALLOC             0x02    /* Memory for ohci state structure */
#define OHCI_INTR               0x04    /* Interrupt handler registered */
#define OHCI_USBAREG            0x08    /* USBA registered */
#define OHCI_RHREG              0x10    /* Root hub driver loaded */

#define OHCI_UNIT(dev)  (getminor((dev)) & ~HUBD_IS_ROOT_HUB)

/*
 * Debug printing
 * Masks
 */
#define PRINT_MASK_ATTA         0x00000001      /* Attach time */
#define PRINT_MASK_LISTS        0x00000002      /* List management */
#define PRINT_MASK_ROOT_HUB     0x00000004      /* Root hub stuff */
#define PRINT_MASK_ALLOC        0x00000008      /* Alloc/dealloc descr */
#define PRINT_MASK_INTR         0x00000010      /* Interrupt handling */
#define PRINT_MASK_BW           0x00000020      /* Bandwidth */
#define PRINT_MASK_CBOPS        0x00000040      /* CB-OPS */
#define PRINT_MASK_HCDI         0x00000080      /* HCDI entry points */
#define PRINT_MASK_DUMPING      0x00000100      /* Dump ohci info */
#define PRINT_MASK_ALL          0xFFFFFFFF


/* Polling support */
int             ohci_hcdi_polled_input_init(
                                usba_pipe_handle_data_t *ph,
                                uchar_t                 **polled_buf,
                                usb_console_info_impl_t *info);
int             ohci_hcdi_polled_input_enter(
                                usb_console_info_impl_t *info);
int             ohci_hcdi_polled_read(
                                usb_console_info_impl_t *info,
                                uint_t                  *num_characters);
int             ohci_hcdi_polled_input_exit(
                                usb_console_info_impl_t *info);
int             ohci_hcdi_polled_input_fini(
                                usb_console_info_impl_t *info);

int             ohci_hcdi_polled_output_init(
                                usba_pipe_handle_data_t *ph,
                                usb_console_info_impl_t *console_output_info);
int             ohci_hcdi_polled_output_enter(
                                usb_console_info_impl_t *info);
int             ohci_hcdi_polled_write(
                                usb_console_info_impl_t *info,
                                uchar_t *buf,
                                uint_t num_characters,
                                uint_t *num_characters_written);
int             ohci_hcdi_polled_output_exit(
                                usb_console_info_impl_t *info);
int             ohci_hcdi_polled_output_fini(
                                usb_console_info_impl_t *info);

/* Root hub related functions */
int             ohci_init_root_hub(
                                ohci_state_t            *ohcip);
int             ohci_load_root_hub_driver(
                                ohci_state_t            *ohcip);
int             ohci_unload_root_hub_driver(
                                ohci_state_t            *ohcip);
int             ohci_handle_root_hub_pipe_open(
                                usba_pipe_handle_data_t *ph,
                                usb_flags_t             flags);
int             ohci_handle_root_hub_pipe_close(
                                usba_pipe_handle_data_t *ph);
int             ohci_handle_root_hub_pipe_reset(
                                usba_pipe_handle_data_t *ph,
                                usb_flags_t             flags);
int             ohci_handle_root_hub_request(
                                ohci_state_t            *ohcip,
                                usba_pipe_handle_data_t *ph,
                                usb_ctrl_req_t          *ctrl_reqp);
int             ohci_handle_root_hub_pipe_start_intr_polling(
                                usba_pipe_handle_data_t *ph,
                                usb_intr_req_t          *intr_reqp,
                                usb_flags_t             flags);
void            ohci_handle_root_hub_pipe_stop_intr_polling(
                                usba_pipe_handle_data_t *ph,
                                usb_flags_t             flags);
void            ohci_handle_root_hub_status_change(void *arg);

/* Endpoint Descriptor (ED) related functions */
ohci_ed_t       *ohci_alloc_hc_ed(
                                ohci_state_t            *ohcip,
                                usba_pipe_handle_data_t *ph);
void            ohci_deallocate_ed(
                                ohci_state_t            *ohcip,
                                ohci_ed_t               *old_ed);
uint32_t        ohci_ed_cpu_to_iommu(
                                ohci_state_t            *ohcip,
                                ohci_ed_t               *addr);

/* Transfer Descriptor (TD) related functions */
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);
void            ohci_traverse_tds(
                                ohci_state_t            *ohcip,
                                usba_pipe_handle_data_t *ph);
void            ohci_deallocate_td(
                                ohci_state_t            *ohcip,
                                ohci_td_t               *old_td);
uint32_t        ohci_td_cpu_to_iommu(
                                ohci_state_t            *ohcip,
                                ohci_td_t               *addr);
ohci_td_t       *ohci_td_iommu_to_cpu(
                                ohci_state_t            *ohcip,
                                uintptr_t               addr);
size_t          ohci_get_td_residue(
                                ohci_state_t            *ohcip,
                                ohci_td_t               *td);
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);

/* Transfer Wrapper (TW) functions */
void            ohci_deallocate_tw_resources(
                                ohci_state_t            *ohcip,
                                ohci_pipe_private_t     *pp,
                                ohci_trans_wrapper_t    *tw);

/* Interrupt Handling functions */
void            ohci_handle_frame_number_overflow(
                                ohci_state_t            *ohcip);

/* Miscillaneous functions */
ohci_state_t    *ohci_obtain_state(
                                dev_info_t              *dip);
int             ohci_state_is_operational(
                                ohci_state_t            *ohcip);
int             ohci_do_soft_reset(
                                ohci_state_t            *ohcip);
usb_frame_number_t ohci_get_current_frame_number(
                                ohci_state_t            *ohcip);
void            ohci_handle_outstanding_requests(
                                ohci_state_t            *ohcip,
                                ohci_pipe_private_t     *pp);
int     ohci_allocate_tds_for_tw(
                                ohci_state_t            *ohcip,
                                ohci_trans_wrapper_t    *tw,
                                size_t                  td_count);

#ifdef __cplusplus
}
#endif

#endif /* _SYS_USB_OHCID_H */