/**HEADER********************************************************************
* 
* Copyright (c) 2008, 2013 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
*************************************************************************** 
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: usb_host_cdc.h$
* $Version : 
* $Date    : 
*
* Comments:
*
*   This file defines a template structure for Class Drivers.
*
*END************************************************************************/
#ifndef __usb_host_cdc_h__
#define __usb_host_cdc_h__

#ifdef __cplusplus
extern "C" {
#endif

#define USB_CDC_SET_LINE_CODING              0x20
#define USB_CDC_GET_LINE_CODING              0x21

/*
** FILE STRUCTURE
**
** This structure defines the information kept in order to implement
** ANSI 'C' standard I/O stream.
*/
typedef struct file_struct
{
	
	/* The address of the Device for this stream */
	struct cdc_io_device_struct * DEV_PTR;

	/* Device Driver specific information */
	void *		 DEV_DATA_PTR;

	/* General control flags for this stream */
	uint32_t	 FLAGS;
	
	/* The current error for this stream */
	uint32_t	 ERROR;

	/* The current position in the stream */
	uint32_t	LOCATION;

	/* The current size of the file */
	uint32_t	SIZE;

	/* The following 2 implement undelete */
	bool	   HAVE_UNGOT_CHARACTER;
	uint32_t	  UNGOT_CHARACTER;

} FILE_CDC, * FILE_CDC_PTR;  

typedef struct cdc_queue_element_struct
{

   /* next element in queue, MUST BE FIRST FIELD */
   struct queue_element_struct * NEXT;

   /* previous element in queue, MUST BE SECOND FIELD */
   struct queue_element_struct * PREV;

} CDC_QUEUE_ELEMENT_STRUCT, * CDC_QUEUE_ELEMENT_STRUCT_PTR;

/*
**
** IO DEVICE STRUCT
**
** This is the structure used to store device information for an
** installed I/O driver
*/
typedef struct cdc_io_device_struct
{

   /* Used to link io_device_structs together */
   CDC_QUEUE_ELEMENT_STRUCT QUEUE_ELEMENT;

   /*
   ** A string that identifies the device.  This string is matched
   ** by fopen, then the other information is used to initialize a
   ** FILE struct for standard I/O.  This string is also provided in
   ** the kernel initialization record for the default I/O channel
   */
   char *             IDENTIFIER;
  
   /* The I/O init function */
   int32_t (_CODE_PTR_ IO_OPEN)(FILE_CDC_PTR, char *, char *);

   /* The I/O deinit function */
   int32_t (_CODE_PTR_ IO_CLOSE)(FILE_CDC_PTR);

   /* The I/O read function */
   int32_t (_CODE_PTR_ IO_READ)(FILE_CDC_PTR, char *, int32_t);

   /* The I/O write function */
   int32_t (_CODE_PTR_ IO_WRITE)(FILE_CDC_PTR, char *, int32_t);

   /* The I/O ioctl function */
   int32_t (_CODE_PTR_ IO_IOCTL)(FILE_CDC_PTR, uint32_t, void *);
   
   /* The function to call when uninstalling this device */
   int32_t (_CODE_PTR_ IO_UNINSTALL)(struct cdc_io_device_struct *);
   
   /* The I/O channel specific initialization data */
   void *              DRIVER_INIT_PTR;

    /* Type of driver for this device */
    uint32_t           DRIVER_TYPE;

} CDC_IO_DEVICE_STRUCT, * CDC_IO_DEVICE_STRUCT_PTR;
/* The following struct is for storing a class's validity-check
** code with the pointer to the data.  The address of one such
** struct is passed as a pointer to select-interface calls,
** where values for that interface get initialized.  Then the
** struct should be passed to class calls using the interface. */
typedef struct class_call_struct
{
   usb_class_intf_handle         class_intf_handle;
   uint32_t                       code_key;
   void *                         next;   /* Used by class driver or app, usually pointer to next CDC_CLASS_CALL_STRUCT */
   void *                         anchor; /* Used by class driver or app, usually pointer to first CDC_CLASS_CALL_STRUCT */
}  CDC_CLASS_CALL_STRUCT, * CDC_CLASS_CALL_STRUCT_PTR;

typedef struct {
    uint32_t      baudrate;
    uint8_t       stopbits; /* 1 ~ 1bit, 2 ~ 2bits, 3 ~ 1.5bit */
    uint8_t       parity;   /* 1 ~ even, -1 ~ odd, 0 ~ no parity */
    uint8_t       databits;
} USB_CDC_UART_CODING, * USB_CDC_UART_CODING_PTR;

/* set ouput pin state */
#define USB_CDC_SET_CTRL_LINE_STATE          0x22
typedef struct {
#define USB_ACM_LINE_STATE_DTR               0x01
#define USB_ACM_LINE_STATE_RTS               0x02
    uint16_t      state;
} USB_CDC_CTRL_STATE, * USB_CDC_CTRL_STATE_PTR;

/* receive interrupt state */
typedef struct {
    uint8_t       reservedA[8];
#define USB_ACM_STATE_RX_CARRIER             0x01
#define USB_ACM_STATE_TX_CARRIER             0x02
#define USB_ACM_STATE_BREAK                  0x04
#define USB_ACM_STATE_RING_SIGNAL            0x08
#define USB_ACM_STATE_FRAMING                0x10
#define USB_ACM_STATE_PARITY                 0x20
#define USB_ACM_STATE_OVERRUN                0x40
    uint8_t       bmStates;
uint8_t		 reservedB[1];
uint8_t		 reservedC[2]; /* To be removed, fix 4B align issue */
} USB_CDC_ACM_STATE, * USB_CDC_ACM_STATE_PTR;

#define USB_DESC_SUBTYPE_CS_HEADER           0x00
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
    uint8_t   bcdCDC[2];
} USB_CDC_DESC_HEADER, * USB_CDC_DESC_HEADER_PTR;

#define USB_DESC_SUBTYPE_CS_CM               0x01
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
#define USB_ACM_CM_CAP_HANDLE_MANAGEMENT     0x01
#define USB_ACM_CM_CAP_DATA_CLASS            0x02
    uint8_t   bmCapabilities;
    uint8_t   bDataInterface;
} USB_CDC_DESC_CM, * USB_CDC_DESC_CM_PTR;

#define USB_DESC_SUBTYPE_CS_ACM              0x02
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
#define USB_ACM_CAP_COMM_FEATURE             0x01
#define USB_ACM_CAP_LINE_CODING              0x02
#define USB_ACM_CAP_SEND_BREAK               0x04
#define USB_ACM_CAP_NET_NOTIFY               0x08
    uint8_t   bmCapabilities;
} USB_CDC_DESC_ACM, * USB_CDC_DESC_ACM_PTR;

#define USB_DESC_SUBTYPE_CS_DL               0x03
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
    uint8_t   bmCapabilities;
} USB_CDC_DESC_DL, * USB_CDC_DESC_DL_PTR;

#define USB_DESC_SUBTYPE_CS_TR               0x04
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
    uint8_t   bRingerVolSteps;
    uint8_t   bNumRingerPatterns;
} USB_CDC_DESC_TR, * USB_CDC_DESC_TR_PTR;

#define USB_DESC_SUBTYPE_CS_TCS              0x05
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
    uint8_t   bmCapabilities[4];
} USB_CDC_DESC_TCS, * USB_CDC_DESC_TCS_PTR;

#define USB_DESC_SUBTYPE_CS_UNION            0x06
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
    uint8_t   bMasterInterface;
    uint8_t   bSlaveInterface[];
} USB_CDC_DESC_UNION, * USB_CDC_DESC_UNION_PTR;

#define USB_DESC_SUBTYPE_CS_TOM              0x08
typedef struct {
    uint8_t   bFunctionLength;
    uint8_t   bDescriptorType;
    uint8_t   bDescriptorSubtype;
    uint8_t   bmCapabilities;
} USB_CDC_DESC_TOM, * USB_CDC_DESC_TOM_PTR;

typedef union {
    USB_CDC_DESC_HEADER         header;
    USB_CDC_DESC_CM             cm;
    USB_CDC_DESC_ACM            acm;
    USB_CDC_DESC_DL             dl;
    USB_CDC_DESC_TR             tr;
    USB_CDC_DESC_TCS            tcs;
    USB_CDC_DESC_TOM            tom;
    USB_CDC_DESC_UNION          uni;
} USB_CDC_FUNC_DESC, * USB_CDC_FUNC_DESC_PTR;

/*
** CDC Class Interface structure. This structure will be passed to
** all commands to this class driver.
*/
typedef struct {
    /* Each CDC subclass must start with a USB_CDC_GENERAL_CLASS struct */
    /*USB_CDC_GENERAL_CLASS                     CDC_G;*/
    USB_CDC_DESC_ACM_PTR                      acm_desc;
    USB_CDC_DESC_CM_PTR                       cm_desc;
    USB_CDC_DESC_HEADER_PTR                   header_desc;
    USB_CDC_DESC_UNION_PTR                    union_desc;
   
    USB_CDC_UART_CODING                       uart_coding;

    usb_pipe_handle                          interrupt_pipe;
    USB_CDC_ACM_STATE                         interrupt_buffer;
    
    USB_CDC_CTRL_STATE                        ctrl_state;

#define USB_ACM_DETACH           0x01
#define USB_ACM_CTRL_PIPE_FREE   0x02
#define USB_ACM_INT_PIPE_FREE    0x04
    OS_Event_handle                           acm_event;
	usb_host_handle				          host_handle; 
	usb_device_instance_handle 	          dev_handle;
	usb_interface_descriptor_handle          intf_handle;
	uint8_t                                   intf_num;
    OS_Mutex_handle                           mutex;
} USB_ACM_CLASS_INTF_STRUCT, * USB_ACM_CLASS_INTF_STRUCT_PTR;
typedef void (*_usb_cdc_callback)(void * param);
typedef struct {
    /* Each CDC subclass must start with a USB_CDC_GENERAL_CLASS struct */
    /*USB_CDC_GENERAL_CLASS                     CDC_G;*/
    /* Address of bound control interface */
    CDC_CLASS_CALL_STRUCT_PTR                     BOUND_CONTROL_INTERFACE;

    uint8_t *                                  RX_BUFFER;
    uint8_t *                                  RX_BUFFER_DRV;
    uint8_t *                                  RX_BUFFER_APP;
    uint32_t                                   RX_BUFFER_SIZE;
    uint32_t                                   RX_READ;
    
    uint32_t                                   TX_SENT;

    usb_pipe_handle                           in_pipe;
    usb_pipe_handle                           out_pipe;
   
    char *                                  device_name;

#define USB_DATA_DETACH            0x01
#define USB_DATA_READ_COMPLETE     0x02
#define USB_DATA_READ_PIPE_FREE    0x04
#define USB_DATA_SEND_COMPLETE     0x08
#define USB_DATA_SEND_PIPE_FREE    0x10
    OS_Event_handle                        data_event;
	usb_host_handle						  host_handle; 
	usb_device_instance_handle 			  dev_handle;
	usb_interface_descriptor_handle		  intf_handle;
	uint8_t                                   intf_num;
    OS_Mutex_handle                           mutex;
	tr_callback                               ctrl_callback;
	void *                                    ctrl_callback_param;
	_usb_cdc_callback                         data_tx_cb;
	_usb_cdc_callback                         data_rx_cb;
} USB_DATA_CLASS_INTF_STRUCT, * USB_DATA_CLASS_INTF_STRUCT_PTR;

typedef struct {
    CDC_CLASS_CALL_STRUCT_PTR   CLASS_PTR;
    tr_callback             CALLBACK_FN;
    void *                 CALLBACK_PARAM;
} CDC_COMMAND, * CDC_COMMAND_PTR;

typedef struct cdc_serial_init {
#define USB_UART_BLOCKING          (0x0000)
#define USB_UART_NO_BLOCKING       (0x0001)
/* NOTE!!!
** HW control flow has one weakness: we dont know exactly when DCD signal got log. 0 or
** log.1. This is because interrupts pipe is polled in time intervals in some milliseconds.
** HW flow control is here only just for compatibility purposes.
** As for output pins, we set always DTR and RTS signal for HW flow control. The user can
** still use usb_class_cdc_set_acm_ctrl_state to control those signals manually.
** Note also, that additional HW control flow is done on USB,
** which implies from USB specification (NAK responding).
*/
#define USB_UART_HW_FLOW           (0x0002)
    uint32_t               FLAGS;
} CDC_SERIAL_INIT, * CDC_SERIAL_INIT_PTR;

/* Mutex handling */
#define USB_CDC_ACM_lock()                OS_Mutex_lock(((USB_ACM_CLASS_INTF_STRUCT_PTR)if_acm_ptr)->mutex)
#define USB_CDC_ACM_unlock()              OS_Mutex_unlock(((USB_ACM_CLASS_INTF_STRUCT_PTR)if_acm_ptr)->mutex)
#define USB_CDC_DATA_lock()               OS_Mutex_lock(((USB_DATA_CLASS_INTF_STRUCT_PTR)if_data_ptr)->mutex)
#define USB_CDC_DATA_unlock()             OS_Mutex_unlock(((USB_DATA_CLASS_INTF_STRUCT_PTR)if_data_ptr)->mutex)
/* Class specific functions exported by CDC class driver */
extern usb_status usb_class_cdc_acm_init(usb_device_instance_handle, usb_interface_descriptor_handle, class_handle*);
extern usb_status usb_class_cdc_acm_deinit(class_handle);
extern usb_status usb_class_cdc_acm_pre_deinit(class_handle);
extern usb_status usb_class_cdc_acm_use_lwevent(CDC_CLASS_CALL_STRUCT_PTR, OS_Event_handle);
extern usb_status usb_class_cdc_data_init(usb_device_instance_handle, usb_interface_descriptor_handle, class_handle*);
extern usb_status usb_class_cdc_data_deinit(class_handle);
extern usb_status usb_class_cdc_data_pre_deinit(class_handle);
extern usb_status usb_class_cdc_data_use_lwevent(CDC_CLASS_CALL_STRUCT_PTR, OS_Event_handle);

extern CDC_CLASS_CALL_STRUCT_PTR usb_class_cdc_get_ctrl_interface(void *);
extern CDC_CLASS_CALL_STRUCT_PTR usb_class_cdc_get_data_interface(void *);
extern usb_status usb_class_cdc_get_acm_line_coding(CDC_CLASS_CALL_STRUCT_PTR, USB_CDC_UART_CODING_PTR);
extern usb_status usb_class_cdc_set_acm_line_coding(CDC_CLASS_CALL_STRUCT_PTR, USB_CDC_UART_CODING_PTR);
extern usb_status usb_class_cdc_set_acm_ctrl_state(CDC_CLASS_CALL_STRUCT_PTR, uint8_t, uint8_t);
extern usb_status usb_class_cdc_get_acm_descriptors(usb_device_instance_handle, usb_interface_descriptor_handle, USB_CDC_DESC_ACM_PTR *, USB_CDC_DESC_CM_PTR *, USB_CDC_DESC_HEADER_PTR *, USB_CDC_DESC_UNION_PTR *);
extern usb_status usb_class_cdc_set_acm_descriptors(CDC_CLASS_CALL_STRUCT_PTR, USB_CDC_DESC_ACM_PTR, USB_CDC_DESC_CM_PTR, USB_CDC_DESC_HEADER_PTR, USB_CDC_DESC_UNION_PTR);
extern usb_status usb_class_cdc_get_ctrl_descriptor(usb_device_instance_handle, usb_interface_descriptor_handle, interface_descriptor_t* *);
extern usb_status usb_class_cdc_bind_data_interfaces(usb_device_instance_handle, CDC_CLASS_CALL_STRUCT_PTR);
extern usb_status usb_class_cdc_unbind_data_interfaces(CDC_CLASS_CALL_STRUCT_PTR);
extern usb_status usb_class_cdc_bind_acm_interface(CDC_CLASS_CALL_STRUCT_PTR, interface_descriptor_t*);
extern usb_status usb_class_cdc_unbind_acm_interface(CDC_CLASS_CALL_STRUCT_PTR);
extern usb_status usb_class_cdc_init_ipipe(CDC_CLASS_CALL_STRUCT_PTR);

#ifdef __cplusplus
}
#endif

#endif
