#ifndef serial_rdc_A9610_H
#define serial_rdc_A9610_H

struct pci_driver_data;
struct pci_board;

struct pci_board {
    // derived form 8250_pci. we combine it with pci_serial_quirk.
    // we use this structure to do specific process of the different borads.
    
    
    unsigned int    vendor;
    unsigned int    device;
    unsigned int    subvendor;
    unsigned int    subdevice;
    
    // use the following callback to init/setup/exit for differnt multiple serial boards.
    int             (*init)(struct pci_dev *, struct pci_driver_data *);
    int             (*setup)(struct pci_dev *, struct pci_driver_data *, irq_handler_t handler);
                    // allocate resoures - io, mem, irq

    void            (*exit)(struct pci_dev *, struct pci_driver_data *);
                    // free resoures - io, mem, irq
    
    // serial information
    unsigned int    BaseBarForUart; // Use BAR as base io address for uart.
    unsigned int    num_ports;
    unsigned int    base_baud;
    unsigned int    uart_offset;
    unsigned int    reg_shift;
    unsigned int    first_offset;
    unsigned int    uartconfigtype;
    
    unsigned int    PID;           // Project ID
    unsigned int    BaseBarForDMA; // none if 255
    
    // parallel port information
    unsigned int    num_parports;
    unsigned int    BaseBarForParport_io;
    unsigned int    BaseBarForParport_iohi;
};


//--------
// This replaces serial_uart_config in include/linux/serial.h
#define PORT_UNKNOWN            0
#define EUART_232_V1            1
#define EUART_422485_V1         2
#define EUART_A9610_232_V1      3
#define EUART_A9610_422485_V1   4
struct uart_config {
    const char          *name;
    unsigned int        fifo_size;
    unsigned int        tx_loadsz;
        // also as TransmissionUnit see MTU.
    
    unsigned int        capabilities;   // reserved for specific hardware.
                                        // the capability of the 422, 485 is not equal to 232.
                                        // 422, 485 dont have rts/cts flow control.
                                        // 485 dont have xon/xoff flow control, because it is Half Duplex.
};

// Module function

int __init Module_init(void);
void __exit Module_exit(void);

//----
//  Driver Data
//

#define PCI_NUM_BAR_RESOURCES   5
#define max_uart_port_minor     16
#define max_parport             2
#define not_assign              (-1)

struct pci_driver_data {
    // data for pci device
    struct pci_dev *            pcidev;
    struct pci_board *          this_board;
    
    // resource allocated
    struct resource *           hresource[PCI_NUM_BAR_RESOURCES];
    unsigned int                BaseAddressSpace[PCI_NUM_BAR_RESOURCES];    // 0: memory space, 1: io space
    unsigned long               BaseAddress[PCI_NUM_BAR_RESOURCES];
    unsigned long               BaseAddressLength[PCI_NUM_BAR_RESOURCES];
    void *                      MappedBaseAddress[PCI_NUM_BAR_RESOURCES];
    
    int                         irq;
    
    int                         uart_port_minor[max_uart_port_minor];
                                    // the value -1 indicate that the port dont assign(allocate) a uart_port_device.
                                    
    struct parport *            hparport[max_parport];
};

#define InterruptQueue_MaxCount     10
typedef struct _INTERRUPT_EXTENSION
{
    // DpcQueue; // Queue size depend on the frequency of interrupt.
                        // Dont let the queue be full
    // the following code should be modify with my ideal plans.
    // current code is a simple plan.
    HwdEUARTInterrupt           losInterrupt[InterruptQueue_MaxCount];
    HwdEUARTVolatileInfo        losVolatileInfo[InterruptQueue_MaxCount];
    ULONG                       Interrupt_Start;
    ULONG                       Interrupt_End;
    ULONG                       Interrupt_Count;        // number of interrupts
    ULONG                       Interrupt_Overrun;
    
    ULONG   dummy;
} INTERRUPT_EXTENSION, *PINTERRUPT_EXTENSION;

//--------
// define my uart port device derived from the uart_port of the serial core.

struct uart_port_device {
    struct uart_port    port;               
        // put to the first location of structure member to be derived from the uart_port.
        // struct uart_port_device *uartportdevice = (struct uart_port_device *)uartport;
    // data for pci device
    struct pci_dev *    pcidev;             // null means this device is unused.
                                            // this_driver_data = pci_get_drvdata(pcidev);
                                            
    unsigned int        portid;             // zero based, on multiple port card.
    unsigned int        minor;              // minor number.
    struct list_head    shared_irq_entry;   /* IRQ entry on this port */
    
    MappedBusAddress    sMappedRegisters_uart;
    MappedBusAddress    sMappedRegisters_DMA;
    HwdEUART            sHwdEUART;
    PHwdEUART           hHwdEUART;
    
    unsigned int        ClockRate;
    unsigned int        ClockDIV;
    unsigned int        MinBaudRateDivisor;
    unsigned int        DMAEnable;
    
    unsigned int        bops_stop_rx;
    unsigned int        bops_stop_tx;
    
    unsigned int        uartconfigtype;     // uart_config type.
    unsigned int        tx_loadsz;          /* transmit fifo load size */
    
    
    // DPCRoutine should use tasklet mechanism to handle interrupt & event, because tasklet can not sleep.
    // If a tasklet is scheduled again before it has a chance to run, it runs only once.
    // However, if it is scheduled while it runs, it runs again after it completes;
    // This behavior also allows a tasklet to reschedule itself.
    struct tasklet_struct       ISRDPCTasklet;
    
    // ISRDPC Queue and Rountine
    spinlock_t                  spinlock_ISRDPCQueue;
    INTERRUPT_EXTENSION         sInterruptExtension;
    
    
    //struct timer_list   timer;          /* "no irq" timer */
        // we dont support no irq handle for our multiple serail card port.
    
    //unsigned short      capabilities;   /* port capabilities */
        // we dont use this variable to do(keep, note) a specific uart port.
        // like auto hardware flow contorl.
        // see 8250.h
        
    //unsigned short      bugs;           /* port bugs */
        // we dont use this variable to do(keep, note) bugs for a specific uart port.
        // see 8250.h
    
    
        
    
    
    //unsigned char       acr;
        // this is the 16C950 Additional Control Register.
        // we dont support it.
    
    unsigned char       last_ier;
    unsigned char       last_lcr;
    unsigned char       last_mcr;
        // we use those variables to keep the last upated register.
        
    //unsigned char       mcr_mask;       /* mask of user bits */
    //unsigned char       mcr_force;      /* mask of forced bits */
        // legacy variables, we dont use them.
    
    /*
    * Some bits in registers are cleared on a read, so they must
    * be saved whenever the register is read but the bits will not
    * be immediately processed.
    */
//#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
    //unsigned char       lsr_saved_flags;
//#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
    //unsigned char       msr_saved_flags;
    
    /*
    * We provide a per-port pm hook.
    */
    void                (*pm)(struct uart_port *uartport, unsigned int state, unsigned int oldstate);
};

// callback function for pci_driver

irqreturn_t
IRQHandler(
            int                 irq,
            void *              devicedata
    );

void
ISRDPCRoutine(
            UINTPTR             data
    );

int
pcidevice_probe(
            struct pci_dev *                pcidev, // this_pci_dev
            const struct pci_device_id *    this_device_id
    );
    
void
pcidevice_remove(
            struct pci_dev *                pcidev  // this_pci_dev
    );

int
pcidevice_suspend(
            struct pci_dev *                pcidev, // this_pci_dev
            pm_message_t                    state
    );
    
int
pcidevice_resume(
            struct pci_dev *                pcidev  // this_pci_dev
    );

int
pci_default_init(
    struct pci_dev *            pcidev,
    struct pci_driver_data *    this_driver_data
    );

int
pci_default_setup(
    struct pci_dev *            pcidev,
    struct pci_driver_data *    this_driver_data,
    irq_handler_t               handler
    );

void
pci_default_exit(
    struct pci_dev *            pcidev,
    struct pci_driver_data *    this_driver_data
    );

unsigned int
uart_serial_in(
    struct uart_port *          uartport,
    int                         offset
    );

void
uart_serial_out(
    struct uart_port *          uartport,
    int                         offset,
    int                         value
    );

int
uart_ops_request_port(
    struct uart_port *          uartport
    );

void
uart_ops_release_port(
    struct uart_port *          uartport
    );

void
uart_ops_config_port(
    struct uart_port *          uartport,
    int                         flags
    );

const char *
uart_ops_type(
    struct uart_port *          uartport
    );
    
int
uart_ops_startup(
    struct uart_port *          uartport
    );

void
uart_ops_shutdown(
    struct uart_port *          uartport
    );

void
uart_ops_pm(
    struct uart_port *          uartport,
    unsigned int                state,
    unsigned int                oldstate
    );

void
uart_ops_set_termios(
    struct uart_port *          uartport,
    struct ktermios *           termios,
    struct ktermios *           oldtermios
    );

void
uart_ops_set_mctrl(
    struct uart_port *          uartport,
    unsigned int                mctrl
    );

unsigned int
uart_ops_get_mctrl(
    struct uart_port *          uartport
    );

unsigned int
uart_ops_tx_empty(
    struct uart_port *          uartport
    );    

void
uart_ops_start_tx(
    struct uart_port *          uartport
    );

void
uart_ops_stop_tx(
    struct uart_port *          uartport
    );
    
void
uart_ops_stop_rx(
    struct uart_port *          uartport
    );

void
uart_ops_enable_ms(
    struct uart_port *          uartport
    );

void
uart_ops_break_ctl(
    struct uart_port *          uartport,
    int                         break_state
    );

VOID
PCIConfigure_A9610(
    IN      ULONG               BusNumber,
    IN      ULONG               DeviceNumber,
    IN      ULONG               FunctionNumber,
    IN      ULONG               PortID,
    IN      ULONG               UARTSpeedMode
    );

int
uart_ops_ioctl(
    struct uart_port *          uartport,
    unsigned int                cmd,
    unsigned long               arg
    );



#endif

