/*
* @file hv_drv_UsbCoreCommonUsb.h
* @brief Header file of usb common.
*
* @author HiView SoC Software Team
* @version 1.0.0
* @date 2022-06-15
*/

#ifndef __HV_DRV_USB_CORE_COMMON_USB_H
#define __HV_DRV_USB_CORE_COMMON_USB_H

#include "hv_drv_UsbCh9.h"
#include "hv_drv_UsbCoreCh11.h"
#include "hv_drv_UsbCoreDevice.h"

struct usb_driver;
struct usb_device;
struct urb;

/**
 * struct usb_host_endpoint - host-side endpoint descriptor and queue
 * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
 * @list_head: urbs queued to this endpoint; maintained by usbcore
 * @xfer_urb: current active urb (for SINGLE device)
 * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
 *  with one more transfer descriptors (TDs) per urb
 * @extra: descriptors following this endpoint in the configuration
 * @extralen: how many bytes of extea are valid
 * @enabled: urbs may be submitted to this endpoint
 */

struct usb_host_endpoint {
    struct usb_endpoint_descriptor        desc;
    struct usb_ss_ep_comp_descriptor    ss_ep_comp;
    struct urb *xfer_urb;

    struct list_head        urb_list;
    void                *hcpriv;

    unsigned char *extra;   /* Extra descriptors */
    int extralen;
    int enabled;
    int streams;
};


/* host-side wrapper for one interface setting's parsed descriptors */
struct usb_host_interface {
    struct usb_interface_descriptor desc;

    /* array of desc.bNumEndpoint endpoints associated with this
     * interface setting.  these will be in no particular order.
     */
    struct usb_host_endpoint *endpoint;

    unsigned char *extra;
    int extralen;

    char *string;
};

enum usb_interface_condition {
    USB_INTERFACE_UNBOUND = 0,
    USB_INTERFACE_BINDING,
    USB_INTERFACE_BOUND,
    USB_INTERFACE_UNBINDING,
};

/**
 * struct usb_interface - what usb device drivers talk to
 */
struct usb_interface {
    /* array of alternate settings for this interface,
     * stored in no particular order */
    struct usb_host_interface *altsetting;
    unsigned num_altsetting; /* number of alternate settings */

    /* the currently active alternate setting */
    struct usb_host_interface *cur_altsetting;

    enum usb_interface_condition condition;
    int minor;  /* OPTIMIZATION: seems no use */

    struct device dev;  /* interface specific device info */
    struct device *usb_dev;  /* belongs to this device */

    unsigned needs_altsetting0:1;   /* switch to altsetting 0 is pending */
    unsigned needs_binding:1;   /* needs delayed unbind/rebind */
    unsigned unregistering:1;   /* unregistration is in progress */
    unsigned reset_running:1;
    unsigned resetting_device:1;    /* true: bandwidth alloc after reset */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)

INLINE void *usb_get_intfdata(struct usb_interface *intf) {
    return dev_get_drvdata(&intf->dev);
}

INLINE void usb_set_intfdata(struct usb_interface *intf, void *data) {
    dev_set_drvdata(&intf->dev, data);
}


/* this maximum is arbitrary */
#define USB_MAXINTERFACES   32
#define USB_MAXIADS     (USB_MAXINTERFACES/2)

struct usb_interface_cache {
    unsigned num_altsetting;    /* number of alternate settings */

    /* variable-length array of alternate settings for this interface,
     * stored in no particular order */
    struct usb_host_interface altsetting[0];
};

#define altsetting_to_usb_interface_cache(a) \
        container_of(a, struct usb_interface_cache, altsetting[0])

int __usb_get_extra_descriptor(char *buffer, unsigned size,
                               unsigned char type, void **ptr);
#define usb_get_extra_descriptor(ifpoint, type, ptr) \
                __usb_get_extra_descriptor((ifpoint)->extra, \
                (ifpoint)->extralen, \
                type, (void **)ptr)

/**
 * struct usb_host_config - representation of a device's configuration
 */
struct usb_host_config {
    struct usb_config_descriptor desc;

    char *string;       /* iConfiguration string, if present */

    /* List of any Interface Association Descriptors in this
     * configuration. */
    struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];

    /* the interfaces associated with this configuration,
     * stored in no particular order */
    struct usb_interface *interface[USB_MAXINTERFACES];

    /* Interface information available even when this is not the
     * active configuration */
    struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];

    unsigned char *extra;   /* Extra descriptors */
    int extralen;
};

/* usb device number allocation bitmap */
struct usb_devmap {
    unsigned long devicemap[128 / (8*sizeof(unsigned long))];
};

struct usb_bus {
    const char *bus_name;
    struct device *controller; /* host side hardware <musb> */

    int devnum_next;                /* next open device number */
    struct usb_devmap devmap;       /* device address allocation map */
    struct usb_device *root_hub;    /* root hub. may have none */
    u8 is_b_host:1;                 /* true during some HNP roleswitches */
    u8  hc_needreset:1;             /* host controller need reset */
};

/**
 * struct usb_device
 * @devnum: device number; address on a bus
 * @portnum: parent port number (origin 1)
 * @maxchild: number of ports if hub
 */
struct usb_device {
    int devnum;
    enum usb_device_state state;
    enum usb_device_speed speed;

    unsigned int toggle[2];

    struct usb_device *parent;
    struct usb_bus *bus;
    struct device dev;

    struct usb_host_endpoint ep0;
    struct usb_ctrlrequest ctrl_rq;

    struct usb_device_descriptor descriptor;

    struct usb_host_config *config;

    struct usb_host_config *actconfig;

    char **rawdescriptors;

    struct usb_host_endpoint *ep_in[16];
    struct usb_host_endpoint *ep_out[16];

    u8      portnum;
    u8      level;

    u16 can_submit:1;
    u16 persist_enabled:1;
    u16 have_langid:1;
    u16 authorized:1;
    u16 authenticated:1;
    u16 wusb:1;   /* do not support. */
    u16 is_init:1;
    u16 is_connect:1;
    int string_langid;
    unsigned long removable;

    u32     quirks;

    /* static strings from the device */
    char *product;
    char *manufacturer;
    char *serial;
    int maxchild;
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
#define interface_to_usbdev(intf)   to_usb_device(intf->dev.parent)

enum usb_device_removable {
    USB_DEVICE_REMOVABLE_UNKNOWN = 0,
    USB_DEVICE_REMOVABLE,
    USB_DEVICE_FIXED,
};

enum usb_port_connect_type {
    USB_PORT_CONNECT_TYPE_UNKNOWN = 0,
    USB_PORT_CONNECT_TYPE_HOT_PLUG,
    USB_PORT_CONNECT_TYPE_HARD_WIRED,
    USB_PORT_NOT_USED,
};


struct usbdrv_wrap {
    struct device_driver driver;
    int for_devices;
};

struct usb_device_id {
    /* which fields to match against? */
    u16       match_flags;

    /* Used for product specific matches; range is inclusive */
    u16       idVendor;
    u16       idProduct;
    u16       bcdDevice_lo;
    u16       bcdDevice_hi;

    /* Used for device class matches */
    u8        bDeviceClass;
    u8        bDeviceSubClass;
    u8        bDeviceProtocol;

    /* Used for interface class matches */
    u8        bInterfaceClass;
    u8        bInterfaceSubClass;
    u8        bInterfaceProtocol;

    /* Used for vendor-specific interface matches */
    u8        bInterfaceNumber;
    u32       driver_info;
};

struct usb_dynids {
    struct list_head list;
};

struct usb_dynid {
    struct list_head node;
    struct usb_device_id id;
};

struct usb_driver {
    const char *name;

    int (*probe) (struct usb_interface *intf, const struct usb_device_id *id);
    void (*disconnect) (struct usb_interface *intf);

    int (*pre_reset)(struct usb_interface *intf);
    int (*post_reset)(struct usb_interface *intf);

    const struct usb_device_id *id_table;
    struct usb_dynids dynids;
    struct usbdrv_wrap drvwrap;
    unsigned    soft_unbind:1;
    
    int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
            void *buf);

    int (*resume) (struct usb_interface *intf);

};
#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)

struct usb_device_driver {
    const char *name;

    int (*probe) (struct usb_device *udev);
    void (*disconnect) (struct usb_device *udev);

    struct usbdrv_wrap drvwrap;
};
#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, drvwrap.driver)

/* USB device locking */
#define usb_lock_device(udev)       //device_lock(&(udev)->dev)
#define usb_unlock_device(udev)     //device_unlock(&(udev)->dev)
#define usb_trylock_device(udev)    //device_trylock(&(udev)->dev)

/* USB port reset for device reinitialization */
extern int usb_reset_device(struct usb_device *dev);

extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
        unsigned ifnum);
extern struct usb_host_interface *usb_altnum_to_altsetting(
    const struct usb_interface *intf, unsigned int altnum);

extern void usb_init_urb(struct urb *urb);
extern struct urb *usb_alloc_urb(void);
extern void usb_free_urb(struct urb *urb);
#define usb_put_urb usb_free_urb
extern int usb_submit_urb(struct urb *urb);
extern int usb_unlink_urb(struct urb *urb);
extern int usb_kill_urb(struct urb *urb);
extern void usb_poison_urb(struct urb *urb);
extern void usb_unpoison_urb(struct urb *urb);
extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
                                        struct usb_bus *bus, unsigned port1);
/* ----------------------------------------------------------------------- */

#define URB_SHORT_NOT_OK        0x0001  /* report short reads as errors */
#define URB_ISO_ASAP            0x0002  /* iso-only, urb->start_frame
                     * ignored */
#define URB_NO_TRANSFER_DMA_MAP 0x0004  /* urb->transfer_dma valid on submit */
#define URB_NAK_LIMITED         0x0008
#define URB_NO_FSBR             0x0020  /* UHCI-specific */
#define URB_ZERO_PACKET         0x0040  /* Finish bulk OUT with short packet */
#define URB_NO_INTERRUPT        0x0080  /* HINT: no non-error interrupt
                     * needed */
#define URB_FREE_BUFFER         0x0100  /* Free transfer buffer with the URB */

/* The following flags are used internally by usbcore and HCDs */
#define URB_DIR_IN              0x0200  /* Transfer from device to host */
#define URB_DIR_OUT             0
#define URB_DIR_MASK            URB_DIR_IN

#define URB_DMA_MAP_SINGLE      0x00010000  /* Non-scatter-gather mapping */
#define URB_DMA_MAP_PAGE        0x00020000  /* HCD-unsupported S-G */
#define URB_DMA_MAP_SG          0x00040000  /* HCD-supported S-G */
#define URB_MAP_LOCAL           0x00080000  /* HCD-local-memory mapping */
#define URB_SETUP_MAP_SINGLE    0x00100000  /* Setup packet DMA mapped */
#define URB_SETUP_MAP_LOCAL     0x00200000  /* HCD-local setup packet */
#define URB_DMA_SG_COMBINED     0x00400000  /* S-G entries were combined */


struct usb_iso_packet_descriptor {
    unsigned int offset;
    unsigned int length;        /* expected length */
    unsigned int actual_length;
    int status;
};


typedef void (*usb_complete_t)(struct urb *);

#define dma_addr_t u32
struct urb {
    /* private: usb core and host controller only fields in the urb */
    void        *hcpriv;       /* private data for host controller */
    atomic_t    use_count;     /* concurrent submissions counter */
    atomic_t    reject;        /* submissions will fail */
    int         unlinked;      /* unlink error code */

    /* public: documented fields in the urb that can be used by drivers */
    struct usb_device        *dev;      /* (in) pointer to associated device */
    struct usb_host_endpoint *ep;       /* (internal) pointer to endpoint */
    unsigned int    pipe;               /* (in) pipe information */
    int             status;             /* (return) non-ISO status */
    unsigned int    transfer_flags;     /* (in) URB_SHORT_NOT_OK | ...*/
    void            *transfer_buffer;   /* (in) associated data buffer */
    dma_addr_t      transfer_dma;       /* (in) dma addr for transfer_buffer */
    u32             transfer_buffer_length; /* (in) data buffer length */
    u32             actual_length;      /* (return) actual transfer length */
    unsigned char   *setup_packet;      /* (in) setup packet (control only) */
    dma_addr_t      setup_dma;          /* (in) dma addr for setup_packet */

    void            *context;           /* (in) context for completion */
    usb_complete_t  complete;           /* (in) completion routine */

    int             start_frame;        /* (modify) start frame (ISO) */
    int             number_of_packets;      /* (in) number of ISO packets */
    int             interval;           /* (modify) transfer interval * (INT/ISO) */
    u8              preferable;
    int             error_count;        /* (return) number of ISO errors */
    struct usb_iso_packet_descriptor iso_frame_desc[0];
};


INLINE int usb_urb_dir_in(struct urb *urb) {
    return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN;
}

INLINE int usb_urb_dir_out(struct urb *urb) {
    return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
}

/*-------------------------------------------------------------------*
 *                         SYNCHRONOUS CALL SUPPORT                  *
 *-------------------------------------------------------------------*/

extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
                           u8 request, u8 requesttype, u16 value, u16 index,
                           void *data, u16 size, int timeout);
extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
                             void *data, int len, int *actual_length, int timeout);

/* wrappers around usb_control_msg() for the most common standard requests */
extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
                              unsigned char descindex, void *buf, int size);
extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size);
extern int usb_get_status(struct usb_device *dev,
                          int type, int target, void *data);
extern int usb_string(struct usb_device *dev, int index,
                      char *buf, size_t size);
extern char *usb_cache_string(struct usb_device *udev, int index);

/* wrappers that also update important state inside usbcore */
extern int usb_clear_halt(struct usb_device *dev, int pipe);
extern int usb_reset_configuration(struct usb_device *dev);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);

/* this request isn't really synchronous, but it belongs with the others */
extern int usb_driver_set_configuration(struct usb_device *udev, int config);
extern void usb_device_disconnect(void);

extern int usb_choose_configuration(struct usb_device *udev);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_forced_unbind_intf(struct usb_interface *intf);

/* ----------------------------------------------------------------------- */

INLINE void usb_fill_control_urb(struct urb *urb,
                                 struct usb_device *dev,
                                 unsigned int pipe,
                                 unsigned char *setup_packet,
                                 void *transfer_buffer,
                                 int buffer_length,
                                 usb_complete_t complete_fn,
                                 void *context) {
    urb->dev = dev;
    urb->pipe = pipe;
    urb->setup_packet = setup_packet;
    urb->transfer_buffer = transfer_buffer;
    urb->transfer_buffer_length = buffer_length;
    urb->complete = complete_fn;
    urb->context = context;
    urb->actual_length = 0;
}

INLINE void usb_fill_bulk_urb(struct urb *urb,
                              struct usb_device *dev,
                              unsigned int pipe,
                              void *transfer_buffer,
                              int buffer_length,
                              usb_complete_t complete_fn,
                              void *context) {
    urb->dev = dev;
    urb->pipe = pipe;
    urb->transfer_buffer = transfer_buffer;
    urb->transfer_buffer_length = buffer_length;
    urb->complete = complete_fn;
    urb->context = context;
    urb->hcpriv = NULL;
}

INLINE void usb_fill_int_urb(struct urb *urb,
                             struct usb_device *dev,
                             unsigned int pipe,
                             void *transfer_buffer,
                             int buffer_length,
                             usb_complete_t complete_fn,
                             void *context,
                             int interval) {
    urb->dev = dev;
    urb->pipe = pipe;
    urb->transfer_buffer = transfer_buffer;
    urb->transfer_buffer_length = buffer_length;
    urb->complete = complete_fn;
    urb->context = context;

    if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
        interval = interval < 1 ? 1 : (interval > 16) ? 16 : interval;
        urb->interval = 1 << (interval - 1);
    } else {
        urb->interval = interval;
    }

    
    urb->start_frame = 1;
}

/*-------------------------------------------------------------------------*/

/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_VENDOR          0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT         0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO          0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI          0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS       0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS    0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL    0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS       0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS    0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL    0x0200
#define USB_DEVICE_ID_MATCH_INT_NUMBER      0x0400

#define USB_DEVICE_ID_MATCH_DEVICE \
        (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
#define USB_DEVICE_ID_MATCH_DEV_RANGE \
        (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)
#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION \
        (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)
#define USB_DEVICE_ID_MATCH_DEV_INFO \
        (USB_DEVICE_ID_MATCH_DEV_CLASS | \
        USB_DEVICE_ID_MATCH_DEV_SUBCLASS | \
        USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
#define USB_DEVICE_ID_MATCH_INT_INFO \
        (USB_DEVICE_ID_MATCH_INT_CLASS | \
        USB_DEVICE_ID_MATCH_INT_SUBCLASS | \
        USB_DEVICE_ID_MATCH_INT_PROTOCOL)


#define USB_DEVICE(vend, prod) \
    .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
    .idVendor = (vend), \
    .idProduct = (prod)

#define USB_DEVICE_VER(vend, prod, lo, hi) \
    .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
    .idVendor = (vend), \
    .idProduct = (prod), \
    .bcdDevice_lo = (lo), \
    .bcdDevice_hi = (hi)


#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \
    .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
               USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
    .idVendor = (vend), \
    .idProduct = (prod), \
    .bInterfaceProtocol = (pr)


#define USB_DEVICE_INFO(cl, sc, pr) \
    .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
    .bDeviceClass = (cl), \
    .bDeviceSubClass = (sc), \
    .bDeviceProtocol = (pr)

#define USB_INTERFACE_INFO(cl, sc, pr) \
    USB_DEVICE_ID_MATCH_INT_INFO, /* u16 match_flags; */ \
    0,        /* u16      idVendor; */        \
    0,       /* u16       idProduct; */        \
    0,       /* u16       bcdDevice_lo; */    \
    0,       /* u16       bcdDevice_hi; */    \
    0,       /* u8        bDeviceClass; */    \
    0,       /* u8        bDeviceSubClass; */    \
    0,       /* u8        bDeviceProtocol; */    \
    (cl),    /* u8        bInterfaceClass; */ \
    (sc),    /* u8        bInterfaceSubClass; */    \
    (pr),    /* u8        bInterfaceProtocol; */    \
    0,       /* u8        bInterfaceNumber; */    \
    0,       /* u32       driver_info; */


#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
    .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
        | USB_DEVICE_ID_MATCH_DEVICE, \
    .idVendor = (vend), \
    .idProduct = (prod), \
    .bInterfaceClass = (cl), \
    .bInterfaceSubClass = (sc), \
    .bInterfaceProtocol = (pr)

/*
 * timeouts, in milliseconds, used for sending/receiving control messages
 * they typically complete within a few frames (msec) after they're issued
 * USB identifies 5 second timeouts, maybe more in a few cases, and a few
 * slow devices (like some MGE Ellipse UPSes) actually push that limit.
 */
#define USB_CTRL_GET_TIMEOUT    50
#define USB_CTRL_SET_TIMEOUT    50
#define USB_STOR_CTRL_TIMEOUT   300
#define USB_STOR_BULK_TIMEOUT   300

/* ----------------------------------------------------------------------- */

/* NOTE:  these are not the standard USB_ENDPOINT_XFER_* values!! */
/* (yet ... they're the values used by usbfs) */
#define PIPE_ISOCHRONOUS        0
#define PIPE_INTERRUPT          1
#define PIPE_CONTROL            2
#define PIPE_BULK               3

#define usb_pipein(pipe)        ((pipe) & USB_DIR_IN)
#define usb_pipeout(pipe)       (!usb_pipein(pipe))

#define usb_pipedevice(pipe)    (((pipe) >> 8) & 0x7f)
#define usb_pipeendpoint(pipe)  (((pipe) >> 15) & 0xf)

#define usb_pipetype(pipe)      (((pipe) >> 30) & 3)
#define usb_pipeisoc(pipe)      (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe)       (usb_pipetype((pipe)) == PIPE_INTERRUPT)
#define usb_pipecontrol(pipe)   (usb_pipetype((pipe)) == PIPE_CONTROL)
#define usb_pipebulk(pipe)      (usb_pipetype((pipe)) == PIPE_BULK)

#define usb_sndaddr0pipe()      (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe()      ((PIPE_CONTROL << 30) | USB_DIR_IN)

INLINE unsigned int __create_pipe(struct usb_device *dev,
                                  unsigned int endpoint) {
    return (dev->devnum << 8) | (endpoint << 15);
}

/* Create various pipes... */
#define usb_sndctrlpipe(dev, endpoint)  \
    ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
#define usb_rcvctrlpipe(dev, endpoint)  \
    ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev, endpoint)  \
    ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
#define usb_rcvisocpipe(dev, endpoint)  \
    ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev, endpoint)  \
    ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
#define usb_rcvbulkpipe(dev, endpoint)  \
    ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev, endpoint)   \
    ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
#define usb_rcvintpipe(dev, endpoint)   \
    ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)

INLINE struct usb_host_endpoint *
usb_pipe_endpoint(struct usb_device *dev, unsigned int pipe) {
    struct usb_host_endpoint **eps;

    eps = usb_pipein(pipe) ? dev->ep_in : dev->ep_out;

    return eps[usb_pipeendpoint(pipe)];
}

/*-------------------------------------------------------------------------*/

INLINE u16
usb_maxpacket(struct usb_device *udev, int pipe, int is_out) {
    struct usb_host_endpoint *ep;
    unsigned epnum = usb_pipeendpoint(pipe);

    if (is_out) {
        ep = udev->ep_out[epnum];
    } else {
        ep = udev->ep_in[epnum];
    }
    if (!ep)
        return 0;

    /* NOTE:  only 0x07ff bits are for packet size... */
    return (ep->desc.wMaxPacketSize);
}

/* ----------------------------------------------------------------------- */

/* Events from the usb core */
#define USB_DEVICE_ADD      0x0001
#define USB_DEVICE_REMOVE   0x0002
#define USB_BUS_ADD         0x0003
#define USB_BUS_REMOVE      0x0004

#define usb_endpoint_out(ep_dir)    (!((ep_dir) & USB_DIR_IN))

const char *usb_str_request(u8 request);

const char *usb_str_request_type(u8 requesttype);

#endif
