root/usr/src/uts/common/sys/usb/usba/usba_ugend.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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_USBA_UGEND_H
#define _SYS_USBA_UGEND_H


/*
 * UGEN - USB Generic Driver Support
 * This file contains the UGEN specific data structure definitions
 * and UGEN specific macros.
 */
#include <sys/usb/usba/usbai_private.h>

#ifdef  __cplusplus
extern "C" {
#endif

/* ugen handle passed to client drivers as an opaque token */
typedef struct {
        dev_info_t      *hdl_dip;
        uint_t          hdl_flags;
        dev_t           hdl_minor_node_ugen_bits_mask;
        uint_t          hdl_minor_node_ugen_bits_shift;
        uint_t          hdl_minor_node_ugen_bits_limit;

        dev_t           hdl_minor_node_instance_mask;
        uint_t          hdl_minor_node_instance_shift;
        uint_t          hdl_minor_node_instance_limit;

        struct ugen_state *hdl_ugenp;
        char            *hdl_log_name;
        uint_t          hdl_log_name_length;
} usb_ugen_hdl_impl_t;

_NOTE(SCHEME_PROTECTS_DATA("stable data", usb_ugen_hdl_impl_t))

/* devt lookup support */
typedef struct ugen_devt_list_entry {
        struct ugen_devt_list_entry     *list_next;
        struct ugen_devt_list_entry     *list_prev;
        dev_t                           list_dev;
        struct ugen_state               *list_state;
} ugen_devt_list_entry_t;

typedef struct ugen_devt_cache_entry  {
        dev_t                           cache_dev;
        struct ugen_state               *cache_state;
        uint_t                          cache_hit;
} ugen_devt_cache_entry_t;

#define UGEN_DEVT_CACHE_SIZE 10

/* minor node definition */
#ifdef _LP64
#define UGEN_MINOR_NODE_SIZE            32
#else
#define UGEN_MINOR_NODE_SIZE            18
#endif

#define UGEN_MINOR_INSTANCE_MASK(ugenp) \
                (ugenp)->ug_hdl->hdl_minor_node_instance_mask
#define UGEN_MINOR_INSTANCE_LIMIT(ugenp) \
                (ugenp)->ug_hdl->hdl_minor_node_instance_limit
#define UGEN_MINOR_INSTANCE_SHIFT(ugenp) \
                (ugenp)->ug_hdl->hdl_minor_node_instance_shift

#define UGEN_MINOR_IDX_SHIFT(ugenp) \
                (ugenp)->ug_hdl->hdl_minor_node_ugen_bits_shift
#define UGEN_MINOR_IDX_LIMIT(ugenp) \
                (ugenp)->ug_hdl->hdl_minor_node_ugen_bits_limit

#define UGEN_MINOR_GET_IDX(ugenp, dev) \
                ((getminor(dev) >> UGEN_MINOR_IDX_SHIFT(ugenp)) & \
                (ugenp)->ug_hdl->hdl_minor_node_ugen_bits_mask)

#define UGEN_MINOR_INSTANCE(ugenp, dev) \
        (getminor(dev) & UGEN_MINOR_INSTANCE_MASK(ugenp))


#define UGEN_N_ENDPOINTS                32

/* UGEN specific macros */
#define UGEN_SETUP_PKT_SIZE             8       /* Ctrl xfer Setup token sz */

/*
 * minor node is contructed as follows for ugen driver (other client
 * drivers that export a ugen interface may have a different layout):
 *
 * 17                    9                      0
 * +---------------------+----------------------+
 * | minor index         |      instance        |
 * +---------------------+----------------------+
 *
 * Note that only 512 endpoint minor nodes can be supported (each
 * endpoint requires a status endpoint as well so we can only support
 * 256 endpoints)
 *
 * the real minor node is:
 *
 * 47     40      32      24     16       8       0
 * +-------+-------+-------+------+-------+-------+
 * | cfgval| cfgidx| iface | alt  |epidx  | type  |
 * +-------+-------+-------+------+-------+-------+
 *
 * We get from the minor code to minor number thru ugen_minor_node_table
 */
typedef uint64_t ugen_minor_t;

#define UGEN_MINOR_DEV_STAT_NODE        0x00
#define UGEN_MINOR_EP_XFER_NODE         0x01
#define UGEN_MINOR_EP_STAT_NODE         0x02
#define UGEN_OWNS_DEVICE                0x04

#define UGEN_MINOR_EPIDX_SHIFT          8
#define UGEN_MINOR_ALT_SHIFT            16
#define UGEN_MINOR_IF_SHIFT             24
#define UGEN_MINOR_CFGIDX_SHIFT         32
#define UGEN_MINOR_CFGVAL_SHIFT         40

#define UGEN_MINOR_TYPE(ugenp, dev) \
        (ugen_devt2minor((ugenp), (dev)) & 0x3)
#define UGEN_MINOR_EPIDX(ugenp, dev) \
        ((ugen_devt2minor((ugenp), (dev)) >> UGEN_MINOR_EPIDX_SHIFT) & 0xFF)

#define UGEN_MINOR_ALT(ugenp, dev) \
        ((ugen_devt2minor((ugenp), (dev)) >> UGEN_MINOR_ALT_SHIFT) & 0xFF)

#define UGEN_MINOR_IF(ugenp, dev) \
        ((ugen_devt2minor((ugenp), (dev)) >> UGEN_MINOR_IF_SHIFT) & 0xFF)

#define UGEN_MINOR_CFGIDX(ugenp, dev) \
        ((ugen_devt2minor((ugenp), (dev)) >> UGEN_MINOR_CFGIDX_SHIFT) & 0xFF)

#define UGEN_MINOR_CFGVAL(ugenp, dev) \
        ((ugen_devt2minor((ugenp), (dev)) >> UGEN_MINOR_CFGVAL_SHIFT) & 0xFF)


/*
 * According to usb2.0 spec (table 9-13), for all ep, bits 10..0 specify the
 * max pkt size; for high speed ISOC/INTR ep, bits 12..11 specify the number of
 * additional transaction opportunities per microframe.
 */
#define UGEN_PKT_SIZE(pktsize)  (pktsize & 0x07ff) * (1 + ((pktsize >> 11) & 3))


/*
 * Structure for holding isoc data packets information
 */
typedef struct ugen_isoc_pkt_info {
        ushort_t        isoc_pkts_count;
        uint_t          isoc_pkts_length;
        ugen_isoc_pkt_descr_t    *isoc_pkt_descr; /* array of pkt descr */
} ugen_isoc_pkt_info_t;

/*
 * Endpoint structure
 * Holds all the information needed to manage the endpoint
 */
typedef struct ugen_ep {
        uint_t          ep_state;       /* Endpoint state, see below */
        usb_ep_descr_t  ep_descr;       /* Endpoint descriptor */
        usb_ep_xdescr_t ep_xdescr;      /* Extended endpoint descriptor */
        uchar_t         ep_cfgidx;      /* cfg index */
        uchar_t         ep_if;          /* Interface # */
        uchar_t         ep_alt;         /* alternate # */
        uchar_t         ep_done;        /* cmd is done */
        boolean_t       ep_one_xfer;    /* use one xfer on intr IN eps */
        uint_t          ep_lcmd_status; /* last cmd status */
        int             ep_xfer_oflag;  /* open flag */
        int             ep_stat_oflag;  /* open flag */
        size_t          ep_buf_limit;   /* one second of data */
        usb_pipe_handle_t ep_ph;        /* Endpoint pipe handle */
        usb_pipe_policy_t ep_pipe_policy;
        kmutex_t        ep_mutex;       /* Mutex protecting ugen_ep */
        kcondvar_t      ep_wait_cv;     /* block for completion */
        usb_serialization_t ep_ser_cookie;      /* one xfer at the time */
        mblk_t          *ep_data;       /* IN data (ctrl & intr) */
        struct buf      *ep_bp;         /* save current buf ptr */
        struct pollhead ep_pollhead;    /* for polling  */
        ugen_isoc_pkt_info_t ep_isoc_info;      /* for isoc eps */
        int             ep_isoc_in_inited;      /* isoc IN init flag */
} ugen_ep_t;

_NOTE(MUTEX_PROTECTS_DATA(ugen_ep::ep_mutex, ugen_ep))

/* endpoints descriptor access */
#define UGEN_XFER_TYPE(epp) ((epp)->ep_descr.bmAttributes & USB_EP_ATTR_MASK)
#define UGEN_XFER_DIR(epp) ((epp)->ep_descr.bEndpointAddress & USB_EP_DIR_IN)
#define UGEN_XFER_ADDR(epp) ((epp)->ep_descr.bEndpointAddress)

#define UGEN_INTR_BUF_LIMIT     4096

/* endpoint xfer/stat states */
#define UGEN_EP_STATE_NONE              0x00
#define UGEN_EP_STATE_ACTIVE            0x01
#define UGEN_EP_STATE_XFER_OPEN         0x02
#define UGEN_EP_STATE_STAT_OPEN         0x04
#define UGEN_EP_STATE_XS_OPEN           (UGEN_EP_STATE_XFER_OPEN | \
                                            UGEN_EP_STATE_STAT_OPEN)
#define UGEN_EP_STATE_INTR_IN_POLLING_ON                0x10
#define UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED        0x20
#define UGEN_EP_STATE_INTR_IN_POLL_PENDING              0x40

#define UGEN_EP_STATE_ISOC_IN_POLLING_ON        0x100
#define UGEN_EP_STATE_ISOC_IN_POLLING_IS_STOPPED        0x200
#define UGEN_EP_STATE_ISOC_IN_POLL_PENDING      0x400

_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_ep::ep_ph))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_ep::ep_descr))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_ep::ep_ser_cookie))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_ep::ep_if))

_NOTE(SCHEME_PROTECTS_DATA("USBA", usb_ctrl_req))
_NOTE(SCHEME_PROTECTS_DATA("USBA", usb_bulk_req))
_NOTE(SCHEME_PROTECTS_DATA("USBA", usb_intr_req))

typedef struct ugen_dev_stat {
        int                     dev_oflag;      /* open flag */
        uint_t                  dev_stat;       /* internal status */
        uint_t                  dev_state;      /* exported state */
        kcondvar_t              dev_wait_cv;    /* block for change */
        struct pollhead         dev_pollhead;   /* for polling */
} ugen_dev_stat_t;

/* dev_stat */
#define UGEN_DEV_STATUS_INACTIVE        0x0
#define UGEN_DEV_STATUS_ACTIVE          0x1
#define UGEN_DEV_STATUS_POLL_PENDING    0x2
#define UGEN_DEV_STATUS_CHANGED         0x4

/* Power Management support */
typedef struct ugen_power  {
        uint_t                  pwr_states;
        int                     pwr_busy;               /* busy accounting */
        uint8_t                 pwr_wakeup_enabled;
        uint8_t                 pwr_current;
} ugen_power_t;

/* UGEN state structure */
typedef struct ugen_state {
        usb_ugen_hdl_impl_t     *ug_hdl;                /* pointer to handle */
        dev_info_t              *ug_dip;                /* Dev info */
        uint_t                  ug_instance;            /* Instance number */
        uint_t                  ug_dev_state;
        uint_t                  ug_dev_stat_state;
        uint_t                  ug_open_count;
        uint_t                  ug_pending_cmds;
        uint_t                  ug_initial_cfgidx;

        /* locks */
        kmutex_t                ug_mutex;               /* Instance mutex */
        usb_serialization_t     ug_ser_cookie;          /* access */

        /* USB debugging system support */
        usb_log_handle_t        ug_log_hdl;

        /* registration data */
        usb_client_dev_data_t   *ug_dev_data;

        /* Endpoint management list */
        ugen_ep_t               ug_ep[UGEN_N_ENDPOINTS];

        /* encoding minor numbers as we only have 8 bits in the minor # */
        ugen_minor_t            *ug_minor_node_table;
        int                     ug_minor_node_table_index;
        size_t                  ug_minor_node_table_size;

        /* device status management */
        ugen_dev_stat_t         ug_ds;

        /* PM Support */
        ugen_power_t            *ug_pm;

        /* Maximum transfer size for bulk endpoints */
        size_t                  ug_max_bulk_xfer_sz;

        /* Used to deallocate allocated resources */
        ushort_t                ug_cleanup_flags;
} ugen_state_t;

_NOTE(SCHEME_PROTECTS_DATA("unshared", buf))

_NOTE(MUTEX_PROTECTS_DATA(ugen_state::ug_mutex, ugen_state))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_log_hdl))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_hdl))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_ser_cookie))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_dip))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_pm))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_instance))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_minor_node_table))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_minor_node_table_index))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_max_bulk_xfer_sz))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_dev_data))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ugen_state::ug_cleanup_flags))


/* ugen_cleanup_flags */
#define UGEN_INIT_LOCKS                 0x01

/* additional USB device states */
#define USB_UGEN_DEV_UNAVAILABLE_RESUME         0x90
#define USB_UGEN_DEV_UNAVAILABLE_RECONNECT      0x91

/* Debugging information */
#define UGEN_PRINT_ATTA         0x1
#define UGEN_PRINT_CBOPS        0x2
#define UGEN_PRINT_CPR          0x4
#define UGEN_PRINT_POLL         0x8
#define UGEN_PRINT_XFER         0x10
#define UGEN_PRINT_HOTPLUG      0x20
#define UGEN_PRINT_STAT         0x40
#define UGEN_PRINT_PM           0x80
#define UGEN_PRINT_ALL          0xFFFFFFFF

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_USBA_UGEND_H */