Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 19/07/2016, à 22:01

Aurel05

Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

Bonjour à tous;
Ayant (encore tongue) besoin des interfaces série et parallèle, j'ai été contraint d'utiliser une carte PCI, la carte maman ne proposant pas ce genre de chose. J'ai retenu ce modèle : https://www.amazon.fr/StarTech-com-PEX2 … B0041UEFXI. une fois l’installation effectuée coté Windows, et après quelques écrans bleus lol, je teste avec succès le matériel (shunt rx et tx et envoi de trames). Vient le tour d'Ubuntu, une 16.04 Xenial Xerus fraîchement installée. Je déballe le mini DVD et me dirige vers le dossier Linux, et, après lecture du readme, je lance la compilation du module comme indiqué. C'est précisément là (en faisant le make) que je rencontre l'erreur "La recette de la cible à échouée" mad.
Je ne parviens pas à avoir de détail et je ne comprends pas ce qui bloque.
Si quelqu'un a une idée, merci big_smile

Contenu du readme :

StarTech a écrit :

The Following files will be there with the tar of the Driver:

    99xx.c
    99xx.h
    Makefile
    README   
    mcs99xx
    ioctl.c
    ioctl.h
    99xx_ReleaseNotes

Building the Driver:
--------------------
    Change to the folder with the Starex source files. And run the following Command:
        $ make

    Once the driver is compliles the loadable module 99xx.ko will be created in the same folder.

    **  '$' --this symbol represent the shell prompt on linux

To build driver on kernels from v3.1.0 till latest:
----------------------------------------------------
  Since the device ID 99XX is included (as built-in) with kernel versions
    starts from v3.1.0 and above, the following procedure is required to
    follow to detect MCS9865 devices.

  a) Go to the path,
        "/usr/src/linux-x.y.z/drivers/tty/serial" in v3.1.0
        $ cd /usr/src/linux-x.y.z/drivers/tty/serial/

        "/usr/src/linux-x.y.z/drivers/tty/serial/8250" from v3.3.0 to latest
        $ cd /usr/src/linux-x.y.z/drivers/tty/serial/8250/

  b) Open file "8250_pci.c".
    - find for the macro PCI_DEVICE_ID_NETMOS_9901, PCI_DEVICE_ID_NETMOS_9912,
             PCI_DEVICE_ID_NETMOS_9922, PCI_DEVICE_ID_NETMOS_9904,
             PCI_DEVICE_ID_NETMOS_9900, It will be found in two places,

        1) In the struct definition "serial_pci_tbl[]"
          - Comment the below lines,

        "
        {    PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
            0xA000, 0x1000,
            0, 0, pbn_b0_1_115200 },

        {    PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922,
            0xA000, 0x1000,
            0, 0, pbn_b0_1_115200 },

        {    PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904,
            0xA000, 0x1000,
            0, 0, pbn_b0_1_115200 },

        {    PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
            0xA000, 0x1000,
            0, 0, pbn_b0_1_115200 },

        {    PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
            0xA000, 0x3002,
            0, 0, pbn_NETMOS9900_2s_115200 },
        "

        2) In the routine "pci_netmos_init"
          - No need do any action, as we already done (a).

  c) Re-compile the Linux kernel.           

Loading the Driver:
-------------------
   
    To load the driver use the following command:
        $ insmod 99xx.ko

    **  '$' --this symbol represent the shell prompt on linux           

Unloading the Driver:
---------------------

    To unload the driver use the following command:
        $rmmod 99xx

    **  '$' --this symbol represent the shell prompt on linux           

Installing the Driver:
----------------------

    To install the driver use the following command:
       
        make install

Uninstalling the Driver:
------------------------

    To un-install the driver use the following command:
       
        make uninstall

Features Supported:
-------------------

    The driver supports all the features supported by the MCS99XX serial device.
        Note: only baud rates upto 3.0Mbps are implemented in the current driver.
   
Feature Configuration:
----------------------

    This driver comes with a static array uart_99xx_contxts[ ] for all the 16 ports features in the 99xx.c file.
    Where u can set the features like:
        -DMA in RX
        -DMA in TX
        -enable/disable Flow control
        -Flow control type
        -RX fifo trigger level
        -TX fifo trigger level
        -x-on character
        -x-off character

    An example array setting for PORT 0 which will be recognised as /dev/ttyF0:           

    //Port 0    --**This represents that this setting is for port 0 which will be recognised as /dev/ttyF0
    {
        .rx_dma_en    = 0,
        .tx_dma_en    = 0,
        .uart_mode    = MCS99XX_RS232_MODE,
        .en_flow_control    = 0,
        .flow_ctrl_type     = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
        .rxfifotrigger    = 64,
        .txfifotrigger    = 64,       
        .x_on        = SERIAL_DEF_XON,
        .x_off        = SERIAL_DEF_XOFF,
    },

To change the port to different modes for uart_mode settings use the following,

MCS99XX_RS422_MODE           (422 mode)
MCS99XX_RS485_HALF_DUPLEX    (485 half duplex)
MCS99XX_RS485_FULL_DUPLEX    (485 full duplex)

Kernels:
--------

    This driver is currently developed and tested on 2.6.15 linux kernel and above     

Limitations:
------------

    This driver supports a maximum of 16 serial devices. This can be modified as required       
   

Steps for setting parallel port :
---------------------------------
        1. rmmod lp
        2. rmmod parport_pc
        2. insmod /usr/lib/modules/2.6.15/kernel/drivers/parport/parport_pc io=0xb000 irq=10.

Note: Here, the io and irq should be noted from lspci -v.

Steps for setting cascade serial ports:
----------------------------------------
 
  Building the Driver:
  --------------------
        Change to the folder with the Starex source files. And run the following Command:
                $ make

        Once the driver is compliles the loadable module 99xx.ko will be created in the same folder.

        **  '$' --this symbol represent the shell prompt on linux


  Installing the Driver:
  ----------------------

        To install the driver use the following command:

                make install

   Note:
   -----
    Before installing the driver the following steps need to follow when
working with a multifunction board in cascade mode.
     
      1.Go to install script of Makefile.
     
      2.Observe the line "modprobe 99xx nr_funs=4" at the end of the script,
here our driver by default works with a device having 8 ports.In order to
make our driver to work with a device having 4 ports then change the line
from "modprobe 99xx nr_funs=4" to "modprobe 99xx nr_funs=2".   

     

  Uninstalling the Driver:
  ------------------------

        To un-install the driver use the following command:

                make uninstall


~


99xx.c :

/*
 *  linux/drivers/serial/99xx.c
 *
 *  Based on drivers/serial/8250.c by Russell King.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This code is modified to support moschip 99xx series serial devices by ravikanthg@moschip.com
 */

#include <linux/version.h>

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
#include <linux/config.h>
#endif

#if defined(CONFIG_SERIAL_99xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
#include <linux/sysrq.h>

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
#include <linux/mca.h>
#endif

#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/nmi.h>
#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "99xx.h"

#include <linux/ioctl.h>
#include "ioctl.h"

#define NORMAL_MODE 1
#define CASCADE_MODE 2
#define UART99xx_NR  16

//All transactions are with memory mapped registers
#define MEM_AXS 1

/*
 * Definitions for PCI support.
 */
#define FL_BASE_MASK		0x0007
#define FL_BASE0			0x0000
#define FL_BASE1			0x0001
#define FL_BASE2			0x0002
#define FL_BASE3			0x0003
#define FL_BASE4			0x0004
#define FL_GET_BASE(x)		(x & FL_BASE_MASK)

#if 0
#define DEBUG(fmt...)	printk(fmt)
#else
#define DEBUG(fmt...)	do { } while (0)
#endif
//choose mode either as NORMAL_MODE or CASCADE_MODE
int mode = CASCADE_MODE;//NORMAL_MODE  


struct uart_99xx_port {
	struct uart_port	port;
	spinlock_t		lock_99xx;			//Per port lock
	int			serialise_txdma;				//Variable to serialise the start_tx calls in dma mode
	unsigned int 		dma_tx;				//TX DMA enable or not
	unsigned int 		dma_rx;				//RX DMA enable or not
	u8			ier; 				//Interrupt Enable Register
	u8 			lcr;				//Line Control Register
	u8			mcr;				//Modem Control Register 
	u8 			acr;				//Additional Control Register
	unsigned int		capabilities;			//port capabilities
	int			rxfifotrigger;		
	int 			txfifotrigger;
	u32			dma_tx_cnt;			//Amount of data to be DMA in TX
	u32			dma_rx_cnt;			//Amount of data to be DMA in RX
	char 	*		dma_tx_buf_v;			//Virtual Address of DMA Buffer for TX
	dma_addr_t 		dma_tx_buf_p;			//Physical Address of DMA Buffer for TX
	char	*		dma_rx_buf_v;			//Virtual Address of DMA Buffer for RX
	dma_addr_t		dma_rx_buf_p;			//Physical Address of DMA Buffer for TX
	u32			part_done_recv_cnt;		//RX DMA CIRC buffer Read index
	int 			rx_dma_done_cnt;	
	int			uart_mode;			//SERIAL TYPE
	int			flow_control;			//Flow control is enabled or not
	int			flow_ctrl_type;			//Type of Flow control
	u8 			x_on;				//X-ON Character
	u8 			x_off;				//X-OFF Character
	u32 			ser_dcr_din_reg;		//Device control register
	u32 			ser_ven_reg;			//Vendor register
	struct uart_99xx_port   *next_port;
	struct uart_99xx_port   *prev_port;

	int 			dma_start_offset;

	int 			custom_setting;
	int			custom_baud;
};

static struct uart_99xx_port serial99xx_ports[UART99xx_NR];

static int nr_funs = 4;

struct uart_99xx_contxt{
	int rx_dma_en;		
				//0-I/O mode of RX
				//1 -DMA mode of RX
	int tx_dma_en;		
				//0-I/O mode of TX 
				//1 -DMA mode of TX
	int  uart_mode;		
				//MCS99XX_RS232_MODE
				//MCS99XX_RS422_MODE
				//MCS99XX_RS485_HALF_DUPLEX
				//MCS99XX_RS485_FULL_DUPLEX
	int en_flow_control;  
				//0 - No H/W Flow Control	 
				//1 - H/W Flow Control
	int  flow_ctrl_type;	
				//MCS99XX_DTR_DSR_HW_FLOWCONTROL
				//MCS99XX_XON_XOFF_HW_FLOWCONTROL
				//MCS99XX_RTS_CTS_HW_FLOWCONTROL
	int rxfifotrigger;	//0-127
	int txfifotrigger;	//0-127
	int x_on;
	int x_off;
};

static struct uart_99xx_contxt uart_99xx_contxts[] = {
	//Port 0
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on	= SERIAL_DEF_XON,
		.x_off	= SERIAL_DEF_XOFF,
	},
	//Port 1
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger  = 64,
		.txfifotrigger  = 64,		
		.x_on=  SERIAL_DEF_XON,
		.x_off= SERIAL_DEF_XOFF,
	},
	//Port 2
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 3
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 4
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 5
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 6
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 7
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 8
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 9
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 10
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 11
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 12
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 13
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 14
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
	//Port 15
	{
		.rx_dma_en	= 0,
		.tx_dma_en	= 0,
		.uart_mode	= MCS99XX_RS232_MODE,
		.en_flow_control= 0,
		.flow_ctrl_type = MCS99XX_XON_XOFF_HW_FLOWCONTROL,
		.rxfifotrigger	= 64,
		.txfifotrigger	= 64,		
		.x_on=SERIAL_DEF_XON,
		.x_off=SERIAL_DEF_XOFF,
	},
};

/*
 * Here we define the default xmit fifo size used for each type of UART.
 */
static const struct serial99xx_config uart_config[] = {
	[PORT_UNKNOWN] = {
		.fifo_size	= 1,
		.tx_loadsz	= 1,
	},
	[PORT_16450] = {
		.fifo_size	= 1,
		.tx_loadsz	= 1,
	},
	[PORT_16550] = {
		.fifo_size	= 16,
		.tx_loadsz	= 14,
	},
	[PORT_16550A] = {
		.fifo_size	= 256,
		.tx_loadsz	= 128,
		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
		.flags		= UART_CAP_FIFO,
	},
	[PORT_16650] = {
		.fifo_size	= 128,
		.tx_loadsz	= 128,
		.flags		= UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
	},
	[PORT_16750] = {
		.fifo_size	= 64,
		.tx_loadsz	= 64,
		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |UART_FCR7_64BYTE,
		.flags		= UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
	},
	[PORT_16850] = {
		.fifo_size	= 128,
		.tx_loadsz	= 128,
		.fcr		= UART_FCR_ENABLE_FIFO,
		.flags		= UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
	},
	[PORT_16C950] = {
		.fifo_size	= 128,
		.tx_loadsz	= 128,
		.fcr		= UART_FCR_ENABLE_FIFO,
		.flags		= UART_CAP_FIFO,
	},
	[PORT_ENHANCED]= {
		.fifo_size	= 256,
		.tx_loadsz 	= 128,
		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | UART_FCR_R_TRIG_01,
		.flags		= UART_CAP_FIFO,
	},
};


//helper function for IO type read
static _INLINE_ u8 serial_in(struct uart_99xx_port *up, int offset)
{
#if MEM_AXS
        u8 tmp1;
        tmp1=readl(up->port.membase+0x280+(offset*4));
        return tmp1;
#else
	return inb(up->port.iobase + offset);
#endif
}

//helper function for IO type write
static _INLINE_ void serial_out(struct uart_99xx_port *up, int offset, int value)
{
#if MEM_AXS
        writel(value, up->port.membase+0x280+(offset*4));
#else
	outb(value, up->port.iobase + offset);
#endif
}

//Helper function to write to index control register
static void serial_icr_write(struct uart_99xx_port *up, int offset, int value)
{
	DEBUG("UART_LCR=0x%x\n",serial_in(up,UART_LCR));
        serial_out(up, UART_SCR, offset);
        serial_out(up, UART_ICR, value);
}

//Helper function to read from index control register
static unsigned int serial_icr_read(struct uart_99xx_port *up, int offset)
{
	unsigned int value;
	serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
	serial_out(up, UART_SCR, offset);
	value = inb(up->port.iobase+UART_ICR);
	serial_icr_write(up, UART_ACR, up->acr);
	return value;
}

//Helper function to set the 950 mode
void setserial_ENHANC_mode(struct uart_99xx_port *up)
{
	u8 lcr,efr;
	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);

	lcr=serial_in(up,UART_LCR);
	serial_out(up, UART_LCR, 0xBF);

	efr=serial_in(up,UART_EFR);
	efr |= UART_EFR_ECB;
	serial_out(up, UART_EFR,efr);

	serial_out(up, UART_LCR, lcr);	

	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
}

// Helper function to clear the FIFO
static inline void serial99xx_clear_fifos(struct uart_99xx_port *p)
{
	if (p->capabilities & UART_CAP_FIFO) {
		serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
		serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
			       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
		serial_out(p, UART_FCR, 0);
	}
}

//Helper function to set the the UART to sleep mode
static inline void serial99xx_set_sleep(struct uart_99xx_port *p, int sleep)
{
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	if (p->capabilities & UART_CAP_SLEEP) {
		if (p->capabilities & UART_CAP_EFR) {
			serial_out(p, UART_LCR, 0xBF);
			serial_out(p, UART_EFR, UART_EFR_ECB);
			serial_out(p, UART_LCR, 0);
		}
		serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
		if (p->capabilities & UART_CAP_EFR) {
			serial_out(p, UART_LCR, 0xBF);
			serial_out(p, UART_EFR, 0);
			serial_out(p, UART_LCR, 0);
		}
	}
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}

//Member function of the port operations to stop the data transfer
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
static void serial99xx_stop_tx(struct uart_port *port, unsigned int tty_stop)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
static void serial99xx_stop_tx(struct uart_port *port)
#endif
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	if(up->dma_tx){
		up->serialise_txdma=0;
	}else{	//IO mode
		if (up->ier & UART_IER_THRI) {
			up->ier &= ~UART_IER_THRI;
			serial_out(up, UART_IER, up->ier);
		}
	}

	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}

//Member function of the port operations to start the data transfer
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
static void serial99xx_start_tx(struct uart_port *port, unsigned int tty_start)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
static void serial99xx_start_tx(struct uart_port *port)
#endif
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
	struct circ_buf *xmit = &up->port.info->xmit;
#else
	struct circ_buf *xmit = &up->port.state->xmit;
#endif
	u32	length=0,len2end;
	int tail,head;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);

	if(up->dma_tx && (up->serialise_txdma == 0)){
		DEBUG(" I WAS IN DMA OF START_TX\n");

		//CALCULATING THE AMOUNT OF DATA AVAILABLE FOR THE NEXT TRANSFER
		//AND COPYING THE DATA TO THE DMA BUFFER
		length = uart_circ_chars_pending(xmit);

		if (length == 0) {
			DEBUG("In %s TX length = 0\n",__FUNCTION__);
			return;
		}

		head=xmit->head;
		tail=xmit->tail;
		len2end = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE);
		DEBUG("In %s -------------------xmit->tail=%d, xmit->head=%d,length=%d,length2end=%d\n",__FUNCTION__,tail,head,length,len2end);

		if(tail < head){
			if(length <= DMA_TX_BUFFER_SZ){
				DEBUG("In %s normal circ buffer\n",__FUNCTION__);
				memcpy(up->dma_tx_buf_v,&xmit->buf[tail],length);  //xmit->buf + xmit->tail
				up->dma_tx_cnt = length;
			}else{
				memcpy(up->dma_tx_buf_v,&xmit->buf[tail],DMA_TX_BUFFER_SZ);
				up->dma_tx_cnt = DMA_TX_BUFFER_SZ;
			}
		}else{
			if(length <= DMA_TX_BUFFER_SZ){
				DEBUG("In %s 2 mode circ buffer\n",__FUNCTION__);
				memcpy(up->dma_tx_buf_v, &xmit->buf[tail], len2end);
				memcpy(up->dma_tx_buf_v+len2end, xmit->buf, head);
				up->dma_tx_cnt = length;
			}else{
				if(len2end <= DMA_TX_BUFFER_SZ){
					memcpy(up->dma_tx_buf_v,&xmit->buf[tail],len2end);
					memcpy(up->dma_tx_buf_v+len2end, xmit->buf, DMA_TX_BUFFER_SZ-len2end);
					up->dma_tx_cnt = len2end;
				}else{
					memcpy(up->dma_tx_buf_v,&xmit->buf[tail],DMA_TX_BUFFER_SZ);
					up->dma_tx_cnt = DMA_TX_BUFFER_SZ;
				}
			}
		}

		up->serialise_txdma++;	//variable to serialise the DMA tx calls
		DEBUG("In %s up->dma_tx_cnt=%d\n",__FUNCTION__,up->dma_tx_cnt);
		DEBUG("IN %s length=%d and data in dma->buf is: %s\n",__FUNCTION__,length,up->dma_tx_buf_v);

		spin_lock(&up->lock_99xx);
		writel(up->dma_tx_buf_p,up->port.membase + REG_TX_DMA_START_ADDRESS_LOW);
		writel(0,up->port.membase + REG_TX_DMA_START_ADDRESS_HIGH);
		writel(up->dma_tx_cnt,up->port.membase+REG_TX_DMA_LENGTH);
		writel(TX_DMA_START_BIT, up->port.membase + REG_TX_DMA_START);
		spin_unlock(&up->lock_99xx);
	
		DEBUG("In %s programmed registers\n",__FUNCTION__);
	}else{
		if (!(up->ier & UART_IER_THRI)) {
			up->ier |= UART_IER_THRI;
			serial_out(up, UART_IER, up->ier);
		}
	}
	 
 	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}

//Member function of the port operations to stop receiving the data
static void serial99xx_stop_rx(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	u32	value=0;
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	if(up->dma_rx){
		value |= RX_DMA_STOP_BIT;
		writel(value, up->port.membase + REG_RX_DMA_STOP);		
	}else{
		up->ier &= ~UART_IER_RLSI;
		up->port.read_status_mask &= ~UART_LSR_DR;
		serial_out(up, UART_IER, up->ier);
	}	
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}


//Member function of the port operations to enable modem status change interrupt
static void serial99xx_enable_ms(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];

	DEBUG("In %s --------------------------------------- START\n",__FUNCTION__);
	up->ier |= UART_IER_MSI;
	serial_out(up, UART_IER, up->ier);
}

//Function to check modem statuss
static _INLINE_ void check_modem_status(struct uart_99xx_port *up)
{
	u8 status;	

	DEBUG("In %s -------------------- START\n",__FUNCTION__);
	status = serial_in(up, UART_MSR);

	if ((status & UART_MSR_ANY_DELTA) == 0)
		return;

	if (status & UART_MSR_TERI)
		up->port.icount.rng++;
	if (status & UART_MSR_DDSR)
		up->port.icount.dsr++;
	if (status & UART_MSR_DDCD)
		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
	if (status & UART_MSR_DCTS)
		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
	wake_up_interruptible(&up->port.info->delta_msr_wait);
#else
	wake_up_interruptible(&up->port.state->port.delta_msr_wait);
#endif
	DEBUG("In %s -------------------- END\n",__FUNCTION__);
}

//Helper function used in ISR to receive the the charecters from the UART
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
static _INLINE_ void receive_chars(struct uart_99xx_port *up, u8 *status)
#else
static _INLINE_ void receive_chars(struct uart_99xx_port *up, u8 *status, struct pt_regs *regs)
#endif
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26))
	struct tty_struct *tty = up->port.info->tty;
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
	struct tty_struct *tty = up->port.info->port.tty;
#else
	struct tty_struct *tty = up->port.state->port.tty;
#endif

	u8 ch,lsr = *status;
	int max_count = 256;
	unsigned int flag;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	do {
		/* The following is not allowed by the tty layer and
		   unsafe. It should be fixed ASAP */
		#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
			if (tty->low_latency) {
				spin_unlock(&up->port.lock);
				tty_flip_buffer_push(tty);
				spin_lock(&up->port.lock);
			}
			/*
			 * If this failed then we will throw away the
			 * bytes but must do so to clear interrupts
			 */
		}
		#endif
		ch = serial_in(up, UART_RX);
		flag = TTY_NORMAL;
		up->port.icount.rx++;

		if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |UART_LSR_FE | UART_LSR_OE))) {
			/*
			 * For statistics only
			 */
			if (lsr & UART_LSR_BI) {
				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
				up->port.icount.brk++;
				/*
				 * We do the SysRQ and SAK checking
				 * here because otherwise the break
				 * may get masked by ignore_status_mask
				 * or read_status_mask.
				 */
				if (uart_handle_break(&up->port))
					goto ignore_char;
			} else if (lsr & UART_LSR_PE)
				up->port.icount.parity++;
			else if (lsr & UART_LSR_FE)
				up->port.icount.frame++;
			if (lsr & UART_LSR_OE)
				up->port.icount.overrun++;

			/*
			 * Mask off conditions which should be ignored.
			 */
			lsr &= up->port.read_status_mask;

			if (lsr & UART_LSR_BI) {
				DEBUG("handling break....");
				flag = TTY_BREAK;
			}else if (lsr & UART_LSR_PE)
				flag = TTY_PARITY;
			else if (lsr & UART_LSR_FE)
				flag = TTY_FRAME;
		}
		#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
			if (uart_handle_sysrq_char(&up->port, ch, regs))
				goto ignore_char;
		#else
			if (uart_handle_sysrq_char(&up->port, ch))
				goto ignore_char;
		#endif

		uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);

ignore_char:

		lsr = serial_in(up, UART_LSR);
	} while ((lsr & UART_LSR_DR) && (max_count-- > 0));
	spin_unlock(&up->port.lock);
	tty_flip_buffer_push(tty);
	spin_lock(&up->port.lock);
	*status = lsr;
	DEBUG("In %s -------------------------------------END\n",__FUNCTION__);
}


//Helper function used in ISR to send the data to the UART
static _INLINE_ void transmit_chars(struct uart_99xx_port *up)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
	struct circ_buf *xmit = &up->port.info->xmit;
#else
	struct circ_buf *xmit = &up->port.state->xmit;
#endif
	int count;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	if (up->port.x_char) {
		serial_out(up, UART_TX, up->port.x_char);
		up->port.icount.tx++;
		up->port.x_char = 0;
		return;
	}

	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
		#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
		serial99xx_stop_tx(&up->port, 0);
		#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
		serial99xx_stop_tx(&up->port);
		#endif		
		return;
	}

	count = uart_config[up->port.type].tx_loadsz;
	DEBUG("In %s-----------up->port.type=%d,tx_loadsz=%d\n",__FUNCTION__,up->port.type,count);
	do {
		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
		up->port.icount.tx++;
		if (uart_circ_empty(xmit))
			break;
	} while (--count > 0);

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(&up->port);

	if (uart_circ_empty(xmit)){
		#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
		serial99xx_stop_tx(&up->port, 0);
		#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
		serial99xx_stop_tx(&up->port);
		#endif
	}
	DEBUG("In %s --------------------------------------2END\n",__FUNCTION__);
}

//Helper function to stop the characters transmission in DMA mode
/*
static void transmit_chars_dma_stop_done(struct uart_99xx_port * up)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
        struct circ_buf *xmit = &up->port.info->xmit;
#else
        struct circ_buf *xmit = &up->port.state->xmit;
#endif

		long int transferred;
		DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
		//UPDATING THE TRANSMIT FIFO WITH THE AMOUNT OF DATA TRANSFERRED
		transferred=readl(up->port.membase+REG_TX_BYTES_TRANSFERRED);
		xmit->tail=((xmit->tail)+transferred) & (UART_XMIT_SIZE-1);
		up->port.icount.tx += transferred;
		up->serialise_txdma=0;
		
		memset(up->dma_tx_buf_v,0,DMA_TX_BUFFER_SZ);
		DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}
*/

//Helper function to do the necessary action upon the successful completion of data transfer in DMA mode
static int transmit_chars_dma_done(struct uart_99xx_port * up)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
	struct circ_buf *xmit = &up->port.info->xmit;
#else
	struct circ_buf *xmit = &up->port.state->xmit;
#endif
	int length,tobe_transferred,transferred,len2end;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	
	//UPDATING THE xmit FIFO WITH THE AMOUNT OF DATA TRANSFERRED
	tobe_transferred=readl(up->port.membase+REG_TX_BYTES_TRANSFERRED);
	transferred = (up->dma_tx_cnt - tobe_transferred);
	DEBUG("In %s -------------transferred=%d--------------------------START\n",__FUNCTION__,transferred);
	xmit->tail = ((xmit->tail) + transferred) & (UART_XMIT_SIZE-1);
	
	up->port.icount.tx += transferred;			
	length = uart_circ_chars_pending(xmit); 
	DEBUG("In %s circ_buf lenght=%d after\n",__FUNCTION__,length); 
	memset(up->dma_tx_buf_v,0,DMA_TX_BUFFER_SZ);
	
	DEBUG("In %s up->dma_tx_buf_v=0x%x ---------------------------------------START\n",__FUNCTION__,(unsigned int)up->dma_tx_buf_v);
		
	if (uart_circ_empty(xmit) ||uart_tx_stopped(&up->port)){
		up->serialise_txdma=0;	
		if (length < WAKEUP_CHARS)
			uart_write_wakeup(&up->port);
		return 0;		
	}

	//CALCULATING THE AMOUNT OF DATA AVAILABLE FOR THE NEXT TRANSFER 
	//AND COPYING THE DATA TO THE DMA BUFFER
	
	length = uart_circ_chars_pending(xmit);
	len2end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); 
	DEBUG("In %s -------------------xmit->tail=%d, xmit->head=%d,length=%d,length2end=%d\n",__FUNCTION__,xmit->tail,xmit->head,length,len2end);

	if(xmit->tail < xmit->head){	
		if(length <= DMA_TX_BUFFER_SZ){
			memcpy(up->dma_tx_buf_v,&xmit->buf[xmit->tail],length);  //xmit->buf + xmit->tail
			up->dma_tx_cnt = length;
			DEBUG("In %s Normal mode\n",__FUNCTION__); 
		}else{
			memcpy(up->dma_tx_buf_v,&xmit->buf[xmit->tail],DMA_TX_BUFFER_SZ);
			up->dma_tx_cnt = DMA_TX_BUFFER_SZ;
		}	
	}else{
		if(length <= DMA_TX_BUFFER_SZ){
			DEBUG("In %s 2nd mode\n",__FUNCTION__); 
			memcpy(up->dma_tx_buf_v,&xmit->buf[xmit->tail],len2end);
			memcpy(up->dma_tx_buf_v+len2end,xmit->buf,xmit->head);
			up->dma_tx_cnt = length;
		}else{
			if(len2end <= DMA_TX_BUFFER_SZ){
				memcpy(up->dma_tx_buf_v,&xmit->buf[xmit->tail],len2end);
				memcpy(up->dma_tx_buf_v+len2end, xmit->buf, DMA_TX_BUFFER_SZ-len2end);
				up->dma_tx_cnt = len2end;
			}else{
				memcpy(up->dma_tx_buf_v,&xmit->buf[xmit->tail],DMA_TX_BUFFER_SZ);
				up->dma_tx_cnt = DMA_TX_BUFFER_SZ;
			}	
		}
	}


	DEBUG("In %s length=%d\n",__FUNCTION__,length);
		
	//INITIATING THE NEXT TRANSFER
		
	//Writing the source address to the TX DMA 
	writel(up->dma_tx_buf_p,up->port.membase+REG_TX_DMA_START_ADDRESS_LOW);
	//Writing the source address to the TX DMA 
	writel(0,up->port.membase+REG_TX_DMA_START_ADDRESS_HIGH);			
	
	//Writing the length of data to the TX DMA Length register
	//writel(length,up->port.membase+REG_TX_DMA_LENGTH);
	writel(up->dma_tx_cnt,up->port.membase+REG_TX_DMA_LENGTH);						

	//Start the DMA data transfer
	writel(TX_DMA_START_BIT,up->port.membase+REG_TX_DMA_START);
		
	// Requesting more data to send out from the TTY layer to the driver
	if (length < WAKEUP_CHARS)
		uart_write_wakeup(&up->port);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return 0;
}

//Helper function to do the necessary action upon the successful completion of data receive in DMA mode
static void receive_chars_dma_done(struct uart_99xx_port * up, int iirg)
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26))
	struct tty_struct *tty = up->port.info->tty;
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
        struct tty_struct *tty = up->port.info->port.tty;
#else
	struct tty_struct *tty = up->port.state->port.tty;
#endif

	int i;
	int rxdma_done=0;
	u16 received_bytes;
	u32 need2recv;
	u8 status = serial_in(up, UART_LSR);
	
	DEBUG("In %s ---------iirg=0x%x------------------------------START\n",__FUNCTION__,iirg);
	//checking for the flip buffer size and asking to clear it upon some threshold
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
	if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
		if (tty->low_latency) {
			spin_unlock(&up->port.lock);
			tty_flip_buffer_push(tty);
			spin_lock(&up->port.lock);
		}
	}
#endif
	if ((iirg & SPINTR_RXDMA_PARTDONE) || (iirg & SPINTR_RXDMA_DONE)){
		//checking for the number of bytes received 
		need2recv=readl(up->port.membase + REG_RX_BYTES_NEED_TO_RECV);
		DEBUG("In %s --------Receive DMA Part Done need2recv=%d\n",__FUNCTION__,need2recv);
	
		if ((iirg & SPINTR_RXDMA_DONE) || (need2recv == 0)) {
			DEBUG("In %s --------Receive DMA Done\n",__FUNCTION__);
			DEBUG("In %s --------up->rx_dma_done_cnt=%d\n",__FUNCTION__,up->rx_dma_done_cnt);
			
			if (up->rx_dma_done_cnt == 0) 
				up->dma_start_offset = DMA_RX_SZ;
			else
				up->dma_start_offset = 0;
			
			//Reinitialise the DMA
			writel(up->dma_rx_buf_p + up->dma_start_offset, up->port.membase + REG_RX_DMA_START_ADDRESS_LOW);
			writel(0,up->port.membase+REG_RX_DMA_START_ADDRESS_HIGH);
			writel(DMA_RX_SZ,up->port.membase+REG_RX_DMA_LENGTH);
			writel(RX_DMA_START_BIT,up->port.membase+REG_RX_DMA_START);	
			DEBUG("REG_RX_DMA_START_ADDRESS_LOW:0x%x\n",readl(up->port.membase+REG_RX_DMA_START_ADDRESS_LOW));
			DEBUG("REG_RX_DMA_START_ADDRESS_HIGH:0x%x\n",readl(up->port.membase+REG_RX_DMA_START_ADDRESS_HIGH));
			DEBUG("REG_RX_DMA_LENGTH:0x%x\n",readl(up->port.membase+REG_RX_DMA_LENGTH));
			rxdma_done=1;
		}
	
		if (up->rx_dma_done_cnt == 0) 
			received_bytes=(DMA_RX_SZ -(need2recv + up->part_done_recv_cnt));
		else
			received_bytes=(DMA_RX_BUFFER_SZ -(need2recv + up->part_done_recv_cnt));
	
		if(rxdma_done){
			up->rx_dma_done_cnt++;
			rxdma_done=0;
		}
		if (up->rx_dma_done_cnt == (DMA_RX_BUFFER_SZ/DMA_RX_SZ))
			up->rx_dma_done_cnt=0;
				
		DEBUG("In %s --------Receive DMA Part Done received_bytes=%d\n part_recv_cnt=%d\n",__FUNCTION__,received_bytes,up->part_done_recv_cnt);
		//copiying the recived bytes to the TTY layers flip buffer
		
		if (tty){
			DEBUG("received_bytes=%d and up->part_done_recv_cnt=%d\n",received_bytes,up->part_done_recv_cnt);
			for (i = 1; i <= received_bytes; i++){
				/* if we insert more than TTY_FLIPBUF_SIZE characters, tty layer will drop them. */
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
				if(tty->flip.count >= TTY_FLIPBUF_SIZE){
					tty_flip_buffer_push(tty);
				}
#endif
				/* this doesn't actually push the data through unless tty->low_latency is set */
				uart_insert_char(&up->port, status, UART_LSR_OE, up->dma_rx_buf_v[ up->part_done_recv_cnt], TTY_NORMAL);
				up->part_done_recv_cnt++;
				DEBUG("char=%c \n",up->dma_rx_buf_v[up->part_done_recv_cnt]);
				if(up->part_done_recv_cnt == DMA_RX_BUFFER_SZ)
					up->part_done_recv_cnt = 0;
	            }
				tty_flip_buffer_push(tty);
		}
		
		up->port.icount.rx += received_bytes;

#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,11)
		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
			if (tty->low_latency) {
				spin_unlock(&up->port.lock);
				tty_flip_buffer_push(tty);
				spin_lock(&up->port.lock);
			}
		}
#endif
	}
}



//This handles the interrupt from a port in IO mode.
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
static inline void serial99xx_handle_port(struct uart_99xx_port *up)
#else
static inline void serial99xx_handle_port(struct uart_99xx_port *up, struct pt_regs *regs)
#endif
{
	u8 status = serial_in(up, UART_LSR);

#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26))
	struct tty_struct *tty=up->port.info->tty;
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
	struct tty_struct *tty = up->port.info->port.tty;
#else
	struct tty_struct *tty = up->port.state->port.tty;
#endif

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	DEBUG("UART_LSR = %x...", status);

	if((status & UART_LSR_DR) && !up->dma_rx){
		DEBUG("RECEIVE_CHARS\n");
	#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
		receive_chars(up, &status);
	#else
		receive_chars(up, &status, regs);
	#endif
	
	}

	check_modem_status(up);
	
	if ((status & UART_LSR_THRE) && !up->dma_tx){
		DEBUG("TRANSMIT_CHARS\n");
		transmit_chars(up);
	}

	if(up->dma_rx){
		if (status & (UART_LSR_BI | UART_LSR_PE |UART_LSR_FE | UART_LSR_OE)){
			//For statistics only
			if (status & UART_LSR_BI) {
				status &= ~(UART_LSR_FE | UART_LSR_PE);
				up->port.icount.brk++;
				/*
				 * We do the SysRQ and SAK checking
				 * here because otherwise the break
				 * may get masked by ignore_status_mask
				 * or read_status_mask.
				 */
				if (uart_handle_break(&up->port))
					return;
			}else if (status & UART_LSR_PE)
				up->port.icount.parity++;
			else if (status & UART_LSR_FE)
				up->port.icount.frame++;
			if (status & UART_LSR_OE)
				up->port.icount.overrun++;
	
				//Mask off conditions which should be ignored.
				status &= up->port.read_status_mask;		
			}
		if (status & ~up->port.ignore_status_mask & UART_LSR_OE)
			tty_insert_flip_char(tty, 0, TTY_OVERRUN);	
	}
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);	
}


// This is the 99xx type serial driver's interrupt routine.
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
static irqreturn_t serial99xx_cascade_interrupt(int irq, void *dev_id)
#else
static irqreturn_t serial99xx_cascade_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
{
	struct uart_99xx_port *up = dev_id;
	u32 iirg=0;
	u8 iir;
	int handled=0;

	iirg= readl(up->port.membase+ REG_GLBL_ISR);
	if(!(iirg & 0xFE))
	{
		up = up->next_port;
		iirg= readl(up->port.membase+ REG_GLBL_ISR);

	}

	if(iirg & 0xFE){
		
		DEBUG("In %s ---GLobal Interrupt iirg=0x%x--------------------------START\n",__FUNCTION__,iirg);
		
		spin_lock(&up->port.lock);
		writel(0xFFFFFFFE,up->port.membase+REG_GLBL_ICLR);
		
		if(iirg & SPINTR_TXDMA_DONE){
			transmit_chars_dma_done(up);
			handled=1;
		}
//		if((iirg & SPINTR_TXDMA_STOP_DONE) ||(iirg & SPINTR_TXDMA_ABORT_DONE)){
//			handled=1;
//			transmit_chars_dma_stop_done(up);
		if(iirg & (SPINTR_RXDMA_DONE | SPINTR_RXDMA_PARTDONE)){
			receive_chars_dma_done(up,iirg);
			handled=1;
		}
		if(iirg & SPINTR_RXDMA_STOP_DONE){
			DEBUG("In %s SPINTR_RXDMA_STOP_DONE is Handled\n",__FUNCTION__);
			handled=1;
		}
		if(iirg & SPINTR_RXDMA_ABORT_DONE){
			DEBUG("In %s SPINTR_RXDMA_ABORT_DONE is Handled\n",__FUNCTION__);
			handled=1;
		}
		spin_unlock(&up->port.lock);
	}
	if(up->prev_port == NULL)
	{	
		DEBUG("control is in normal port\n");
		iir = serial_in(up, UART_IIR);
		DEBUG("device structure id for port%d is %u\n",up->port.line,up);
		DEBUG("IIR value is 0x%x\n",iir);
		if(iir & UART_IIR_NO_INT){
			if(up->next_port!=NULL)
			{
				up = up->next_port;
				DEBUG("device structure id of next_port for port%d is %u\n",up->port.line,up);
				iir = serial_in(up, UART_IIR);
				DEBUG("IIR value of next_port is 0x%x\n",iir);
			}
		}
	}
	else
        {
		DEBUG("control is in cascade port\n");
		iir = serial_in(up, UART_IIR);
		DEBUG("device structure id for port%d is %u\n",up->port.line,up);
		DEBUG("IIR value is 0x%x\n",iir);
		if(iir & UART_IIR_NO_INT){
			if(up->prev_port!=NULL)
			{
				up = up->prev_port;
				DEBUG("device structure id of prev_port for port%d is %u\n",up->port.line,up);
				iir = serial_in(up, UART_IIR);
				DEBUG("IIR value of prev_port is 0x%x\n",iir);
			}
		}
	}	
	DEBUG("In %s up->port.line= %d\n",__FUNCTION__,up->port.line);

	if (!(iir & UART_IIR_NO_INT)) {
		DEBUG("In %s IIR=0x%x UART_SCR=0x%x\n",__FUNCTION__,iir,serial_in(up,UART_SCR));
		spin_lock(&up->port.lock);
	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
		serial99xx_handle_port(up);
	#else
		serial99xx_handle_port(up, regs);
	#endif	
		spin_unlock(&up->port.lock);
		handled = 1;
	} 
	return IRQ_RETVAL(handled);
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
static irqreturn_t serial99xx_nocascade_interrupt(int irq, void *dev_id)
#else
static irqreturn_t serial99xx_nocascade_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
{
	struct uart_99xx_port *up = dev_id;
	u32 iirg=0;
	u8 iir;
	int handled=0;

	iirg= readl(up->port.membase+ REG_GLBL_ISR);

	if(iirg & 0xFE){
		
		DEBUG("In %s ---GLobal Interrupt iirg=0x%x--------------------------START\n",__FUNCTION__,iirg);
		
		spin_lock(&up->port.lock);
		writel(0xFFFFFFFE,up->port.membase+REG_GLBL_ICLR);
		
		if(iirg & SPINTR_TXDMA_DONE){
			transmit_chars_dma_done(up);
			handled=1;
		}
//		if((iirg & SPINTR_TXDMA_STOP_DONE) ||(iirg & SPINTR_TXDMA_ABORT_DONE)){
//			handled=1;
//			transmit_chars_dma_stop_done(up);
		if(iirg & (SPINTR_RXDMA_DONE | SPINTR_RXDMA_PARTDONE)){
			receive_chars_dma_done(up,iirg);
			handled=1;
		}
		if(iirg & SPINTR_RXDMA_STOP_DONE){
			DEBUG("In %s SPINTR_RXDMA_STOP_DONE is Handled\n",__FUNCTION__);
			handled=1;
		}
		if(iirg & SPINTR_RXDMA_ABORT_DONE){
			DEBUG("In %s SPINTR_RXDMA_ABORT_DONE is Handled\n",__FUNCTION__);
			handled=1;
		}
		spin_unlock(&up->port.lock);
	}

	iir = serial_in(up, UART_IIR);

	if((!(iir & UART_IIR_NO_INT)) || (iirg & 0xFE)){
		DEBUG("In %s up->port.line= %d\n",__FUNCTION__,up->port.line);
	}	

	if (!(iir & UART_IIR_NO_INT)) {

		DEBUG("In %s IIR=0x%x UART_SCR=0x%x\n",__FUNCTION__,iir,serial_in(up,UART_SCR));
		spin_lock(&up->port.lock);
	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
		serial99xx_handle_port(up);
	#else
		serial99xx_handle_port(up, regs);
	#endif	
		spin_unlock(&up->port.lock);
		handled = 1;
	} 
	return IRQ_RETVAL(handled);
}

//This is a port ops helper function to verify whether the transmitter is empty of not
static unsigned int serial99xx_tx_empty(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	unsigned long flags;
	unsigned int ret;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	spin_lock_irqsave(&up->lock_99xx, flags);
	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
	spin_unlock_irqrestore(&up->lock_99xx, flags);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	
	return ret;
}

//This is a port ops helper function to find the current state of the modem control
static unsigned int serial99xx_get_mctrl(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	unsigned long flags;
	u8 status;
	unsigned int ret;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	spin_lock_irqsave(&up->lock_99xx, flags);
	status = serial_in(up, UART_MSR);
	spin_unlock_irqrestore(&up->lock_99xx, flags);

	ret = 0;
	if (status & UART_MSR_DCD)
		ret |= TIOCM_CAR;
	if (status & UART_MSR_RI)
		ret |= TIOCM_RNG;
	if (status & UART_MSR_DSR)
		ret |= TIOCM_DSR;
	if (status & UART_MSR_CTS)
		ret |= TIOCM_CTS;
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	
	return ret;
}

//This is a port ops helper function to set the modem control lines
static void serial99xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	u8 mcr = 0;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	if (mctrl & TIOCM_RTS)
		mcr |= UART_MCR_RTS;
	if (mctrl & TIOCM_DTR)
		mcr |= UART_MCR_DTR;
	if (mctrl & TIOCM_OUT1)
		mcr |= UART_MCR_OUT1;
	if (mctrl & TIOCM_OUT2)
		mcr |= UART_MCR_OUT2;
	if (mctrl & TIOCM_LOOP)
		mcr |= UART_MCR_LOOP;
	
	mcr |= up->mcr;
	serial_out(up, UART_MCR, mcr);

	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}

//This is a port ops helper function to control the transmission of a break signal
static void serial99xx_break_ctl(struct uart_port *port, int break_state)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	unsigned long flags;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	spin_lock_irqsave(&up->lock_99xx, flags);
	if (break_state == -1)
		up->lcr |= UART_LCR_SBC;
	else
		up->lcr &= ~UART_LCR_SBC;
	serial_out(up, UART_LCR, up->lcr);
	spin_unlock_irqrestore(&up->lock_99xx, flags);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
}

//This is a port ops helper function to enable the port for reception
static int serial99xx_startup(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	unsigned long flags;
	u8 fcr=0,efr=0,efr1=0,lcr=0,cks=0,acr=0,mcr=0;
	u32 tmp,ser_dcr_din_val=0,ser_ven_val=0;
	int uart_mode=0;
	

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	DEBUG("Device structure address id %x\n",up);
	DEBUG(" In startup port->line is %d\n",up->port.line);
	DEBUG("membase is 0x%x\n",up->port.membase);
	DEBUG("mapbase is 0x%x\n",up->port.mapbase);
	DEBUG("iobase is 0x%x\n",up->port.iobase);
	DEBUG("port.type is %d\n",up->port.type);
	DEBUG("fifo size is %d \n",uart_config[up->port.type].fifo_size);

	port->fifosize = uart_config[up->port.type].fifo_size;

	up->capabilities = uart_config[up->port.type].flags;
	up->mcr = 0;
	up->part_done_recv_cnt = 0;	
	up->rx_dma_done_cnt = 0;
	up->dma_start_offset = 0;
	/*
	 * Clear the FIFO buffers and disable them.
	 * (they will be reeanbled in set_termios())
	 */
	serial99xx_clear_fifos(up);

	/*
	 * Clear the interrupt registers.
	 */
	if(up->dma_tx || up->dma_rx)
		(void) readl(up->port.membase+REG_GLBL_ISR);
		
	(void) serial_in(up, UART_LSR);
	(void) serial_in(up, UART_RX);
	(void) serial_in(up, UART_IIR);
	(void) serial_in(up, UART_MSR);
	/*
	 * Now, initialize the UART
	 */
	serial_out(up, UART_LCR, UART_LCR_WLEN8);

	spin_lock_irqsave(&up->lock_99xx, flags);

	up->port.mctrl |= TIOCM_OUT2;

	serial99xx_set_mctrl(&up->port, up->port.mctrl);
	spin_unlock_irqrestore(&up->lock_99xx, flags);


	//Rx data transfer Interrupts
	up->ier = UART_IER_RLSI | UART_IER_RDI;
	serial_out(up, UART_IER, up->ier);

	if(up->port.type == PORT_16550A){
		DEBUG("In %s 550EX mode\n",__FUNCTION__);
		ser_dcr_din_val=readl(up->port.membase+SER_DCR_DIN_REG);
		ser_dcr_din_val |= COM_550EX_MODE_EN;
		writel(ser_dcr_din_val,up->port.membase+SER_DCR_DIN_REG);
		DEBUG("In %s 550EX mode SER_DCR_DIN_REG=0x%x\n",__FUNCTION__,readl(up->port.membase+SER_DCR_DIN_REG));
	
		if(up->flow_control){
			DEBUG("Enabled the Auto Hardware Flowcontrol\n");
			mcr = serial_in(up,UART_MCR);
			DEBUG("In %s mcr=0x%x and up->port.mctrl=0x%x\n",__FUNCTION__,mcr,up->port.mctrl);
			
			up->mcr |= UART_MCR_AFE;
			serial99xx_set_mctrl(&up->port,up->port.mctrl);	
			mcr = serial_in(up,UART_MCR);
			DEBUG("In %s mcr=0x%x and up->port.mctrl=0x%x\n",__FUNCTION__,mcr,up->port.mctrl);
		}	

		if (up->capabilities & UART_CAP_FIFO && uart_config[port->type].fifo_size > 1) {
				fcr = uart_config[up->port.type].fcr;
				serial_out(up,UART_FCR,fcr);
		}
	}

	if((up->port.type == PORT_ENHANCED) || (up->custom_setting == 1)){
		//Setting the Enhanced Mode Features
		setserial_ENHANC_mode(up);	

		if (up->capabilities & UART_CAP_FIFO && uart_config[port->type].fifo_size > 1) {
				fcr = uart_config[up->port.type].fcr;
				serial_out(up,UART_FCR,fcr);
		}

		
		switch(up->uart_mode){

			case MCS99XX_RS485_HALF_DUPLEX:
				//Commset Registers Offset 0
				//0x0008 0000  -19thBit -1 SwRS 485 enable
				//0x0000 0000  -17thBit -0 swFD enable RS485
				//0x0000 2000  -13thBit -1 RS485 RTS enable
 				//0x0000 0000  -14thBit -0 SwRTS enable

				DEBUG("TranceiverMode MCS99XX_RS485_MODE - RS485_HALF_DUPLEX\n");
				uart_mode=1;	
				ser_dcr_din_val = readl(up->port.membase+SER_DCR_DIN_REG);
				ser_dcr_din_val &= 0xfff00fff;
				ser_dcr_din_val |= 0x00080000;

				//Commset Registers Offset 1
				//0xff00 0000  -[31-24] ff
				ser_ven_val = readl(up->port.membase+SER_VEN_REG);
				ser_ven_val &= 0x00ffffff;
				ser_ven_val |= 0x00000000;

				//CKS - 0x00
				//serial_icr_write(up,UART_CKS,0x00);
				cks=serial_icr_read(up,UART_CKS);
				cks |= 0x00;

				//ACR - [4:3]-10 -> 0x10, 
				acr = 0x10;
				break;
				
			case MCS99XX_RS485_HALF_DUPLEX_ECHO:
				//Commset Registers Offset 0
				//0x0008 0000  -19thBit -1 SwRS 485 enable
				//0x0004 0000  -18thBit -1 SwEcho Rs485 enable
				//0x0000 0000  -17thBit -0 swFD enable RS485
				//0x0000 2000  -13thBit -1 RS485 RTS enable
				//0x0000 4000  -14thBit -1 SwRTS enable
				DEBUG("TranceiverMode MCS99XX_RS485_MODE - RS485_HALF_DUPLEX_ECHO\n");
				uart_mode=1;
				ser_dcr_din_val = readl(up->port.membase+SER_DCR_DIN_REG);
				ser_dcr_din_val &= 0xfff00fff;
				ser_dcr_din_val |= 0x000C6000;

				//Commset Registers Offset 1
				//0xff00 0000  -[31-24] ff
				ser_ven_val = readl(up->port.membase+SER_VEN_REG);
				ser_ven_val &= 0x00ffffff;
				ser_ven_val |= 0xff000000;

				//CKS - 0x00
				cks = serial_icr_read(up,UART_CKS);
				cks |= 0x00;

				//ACR - [4:3]-11 -> 0x18, 
				acr = 0x18;
				
				break;

			case MCS99XX_RS485_FULL_DUPLEX:
			case MCS99XX_RS422_MODE:

				//Commset Registers Offset 0
				//0x0008 0000  -19thBit - SwRS 485 enable
				//0x0002 0000  -17thBit - SwFD enable RS485
				//0x0000 0000  -13thBit - RS485 RTS enable(should be 0)
				//0x0000 4000  -14thBit - SwRTS enable
				DEBUG("TranceiverMode MCS99XX_RS485_MODE - RS485_FULL_DUPLEX\n");
				uart_mode=1;
				ser_dcr_din_val = readl(up->port.membase+SER_DCR_DIN_REG);
				ser_dcr_din_val &= 0xfff00fff;
				ser_dcr_din_val |= 0x000A4000;

				//Commset Registers Offset 1
				//0xff00 0000  -[31-24] ff
				ser_ven_val = readl(up->port.membase+SER_VEN_REG);
				ser_ven_val &= 0x00ffffff;
				ser_ven_val |= 0xff000000;

				//CKS - 0x00
				cks = serial_icr_read(up,UART_CKS);
				cks |= 0x00;

				//ACR - 0x10, 
				acr = 0x10;
				break;
			default:
				DEBUG("Tranceiver RS_232 mode\n");
				break;
		}

		if(uart_mode){	
			up->acr = up->acr|acr;

			writel(ser_dcr_din_val,up->port.membase+SER_DCR_DIN_REG);
			writel(ser_ven_val,up->port.membase+SER_VEN_REG);
			serial_icr_write(up,UART_CKS,cks);
			serial_icr_write(up,UART_ACR,up->acr);
			
			DEBUG("SER_DCR_DIN_REG=0x%x   SER_VEN_REG=0x%x   UART_CKS=0x%x   UART_ACR=0x%x\n",readl(up->port.membase+SER_DCR_DIN_REG),readl(up->port.membase+SER_VEN_REG),cks,up->acr);
			uart_mode = 0;
		}

		//Setting the trigger Levels
		serial_icr_write(up,UART_TTL,up->txfifotrigger);
		serial_icr_write(up,UART_RTL,up->rxfifotrigger);
		up->acr |= UART_ACR_TLENB;
		serial_icr_write(up,UART_ACR,up->acr);

		//If Hardware Flow Control is to be enabled. The RTS/CTS, DTR/DTS is possible only in 232 mode. 
		if(up->flow_control){
			
			//Setting the auto hardware flow control trigger levels
			serial_icr_write(up,UART_FCL,16);
			serial_icr_write(up,UART_FCH,240);

			//Setting the hw Flow control
			switch(up->flow_ctrl_type){
				case MCS99XX_DTR_DSR_HW_FLOWCONTROL:
					if(up->uart_mode == MCS99XX_RS232_MODE){
						DEBUG("H/W Flow Control MCS99XX_DTR_DSR_HW_FLOWCONTROL enabled\n");
						DEBUG("UART_ACR=0x%x and up->acr=0x%x\n",serial_icr_read(up,UART_ACR),up->acr);
						up->acr |= 0x0C;
						serial_icr_write(up, UART_ACR, up->acr);
						
						break;
					}else{
						DEBUG("No flow control enabled\n");
						break;
					}			
						
					
				case MCS99XX_XON_XOFF_HW_FLOWCONTROL:
					DEBUG("Enabled HwFlowControl MCS99XX_XON_XOFF_HW_FLOWCONTROL\n");
					lcr = serial_in(up,UART_LCR);

					serial_out(up,UART_LCR,0xBF);

					efr=serial_in(up,UART_EFR);
					efr1 = efr;
					efr |= 0x1A;
					serial_out(up,UART_EFR,efr);
					serial_out(up,UART_XON1,up->x_on);
					serial_out(up,UART_XOFF1,up->x_off);											
					serial_out(up,UART_XON2,up->x_on);
					serial_out(up,UART_XOFF2,up->x_off);
					serial_out(up,UART_EFR,efr1);
					serial_out(up,UART_LCR,lcr);
					break;

				case MCS99XX_RTS_CTS_HW_FLOWCONTROL:
				default:
					if(up->uart_mode == MCS99XX_RS232_MODE){
						DEBUG("H/W Flow Control MCS99XX_RTS_CTS_HW_FLOWCONTROL enabled\n");
						lcr = serial_in(up,UART_LCR);
						serial_out(up,UART_LCR,0xBF);	
						efr=serial_in(up,UART_EFR);
						efr |= 0xD0;
						serial_out(up,UART_EFR,efr);									
						serial_out(up,UART_LCR,lcr);	
						break;	
					}else{
						DEBUG("No H/W flow control enabled\n");
					}

			}
		}
	}
	
	/*
	 * Finally, enable interrupts.  Note: Modem status interrupts
	 * are set via set_termios(), which will be occurring imminently
	 * anyway, so we don't enable them here.
	 */
	if(up->dma_rx || up->dma_tx){
		writel(0xFFFFFFFF,up->port.membase+REG_GLBL_IER);
		tmp=readl(up->port.membase+REG_GLBL_IER);
		DEBUG("REG_GLBL_IER=0x%x, up->port.membase=0x%x\n",tmp,(unsigned int)up->port.membase+REG_GLBL_IER);	

		if(up->dma_rx){
			//Set the comset DMA register to enable DMA
			DEBUG("DMA bit in DCR register was set ");
			ser_dcr_din_val=readl(up->port.membase+SER_DCR_DIN_REG);
			ser_dcr_din_val |= COM_DMA_MODE_EN;
			writel(ser_dcr_din_val,up->port.membase+SER_DCR_DIN_REG);
			DEBUG("SER_DCR_DIN_REG=0x%x\n",readl(up->port.membase+SER_DCR_DIN_REG));	
		}

		if (up->dma_tx && !up->dma_rx) {
			serial_out(up,UART_IER, UART_IER_RDI | UART_IER_RLSI | UART_IER_MSI);
		} else if (!up->dma_tx && up->dma_rx) {
			serial_out(up,UART_IER, UART_IER_RDI | UART_IER_RLSI | UART_IER_MSI | UART_IER_THRI);
		} else {
			serial_out(up,UART_IER, UART_IER_RDI | UART_IER_RLSI | UART_IER_MSI);
		}

		if(up->dma_rx){
			DEBUG("RX_DMA engine started\n");
			writel(up->dma_rx_buf_p,up->port.membase+REG_RX_DMA_START_ADDRESS_LOW);
			writel(0,up->port.membase+REG_RX_DMA_START_ADDRESS_HIGH);
			writel(DMA_RX_SZ,up->port.membase+REG_RX_DMA_LENGTH);
			writel(RX_DMA_START_BIT,up->port.membase+REG_RX_DMA_START);	
		}
	}

	/*
	 * And clear the interrupt generating registers again for luck.
	 */
	(void) serial_in(up, UART_LSR);
	(void) serial_in(up, UART_RX);
	(void) serial_in(up, UART_IIR);
	(void) serial_in(up, UART_MSR);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);

	return 0;
}

//This is a port ops helper function to disable the port, disable any break condition that may be in
//effect, and free any interrupt resources.
static void serial99xx_shutdown(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	unsigned long flags;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	DEBUG("up= %x up->prev_port :%x and up->next_port :%x\n" ,up,up->prev_port,up->next_port);
	DEBUG("Device structure address for port%d id %u\n",port->line,up);
	DEBUG("membase is 0x%x\n",up->port.membase);
        DEBUG("mapbase is 0x%x\n",up->port.mapbase);
        DEBUG("iobase is 0x%x\n",up->port.iobase);

	printk("No of Errors In ttyF%d brake=%d frame=%d parity=%d overrun=%d\n",
		port->line, 
		port->icount.brk,
		port->icount.frame,
		port->icount.parity,
		port->icount.overrun);

	/*
	 * Disable interrupts from this port
	 */
	up->ier = 0;
	serial_out(up, UART_IER, 0);

	spin_lock_irqsave(&up->lock_99xx, flags);
	up->port.mctrl &= ~TIOCM_OUT2;

	serial99xx_set_mctrl(&up->port, up->port.mctrl);
	spin_unlock_irqrestore(&up->lock_99xx, flags);

	/*
	 * Disable break condition and FIFOs
	 */
	serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
	serial99xx_clear_fifos(up);

	/*
	 * Read data port to reset things
	 */
	(void) serial_in(up, UART_LSR);
       	//(void) serial_in(up, UART_RX);
        (void) serial_in(up, UART_IIR);
        (void) serial_in(up, UART_MSR);
	(void) serial_in(up, UART_RX);

	up->lcr = 0;
	up->mcr = 0;
	up->ser_dcr_din_reg = 0;
	up->ser_ven_reg = 0;

	//Reset the UART upon port close
	if(up->port.type == PORT_ENHANCED){

		DEBUG("In ENHANCED MODE\n");
		DEBUG("up= %x up->prev_port :%x and up->next_port :%x\n" ,up,up->prev_port,up->next_port);
		DEBUG("membase is 0x%x\n",up->port.membase);
	        DEBUG("mapbase is 0x%x\n",up->port.mapbase);
        	DEBUG("iobase is 0x%x\n",up->port.iobase);
		up->acr = 0x00;
	
		// ENHANC Mode reset
		serial_icr_write(up, UART_CSR, 0x00);
		serial_icr_write(up, UART_CSR, 0xFF);
		
		// Serial soft reset
		writel(0x01,up->port.membase+SER_SOFT_RESET_REG);
	}else{
		// Serial soft reset
		writel(0x01,up->port.membase+SER_SOFT_RESET_REG);
	}

	DEBUG("In %s --------------------------------------END\n",__FUNCTION__);
}

//This is a port ops helper function to return the divsor (baud_base / baud) for the selected baud rate 
//	specified by termios.
static unsigned int serial99xx_get_divisor(struct uart_port *port, unsigned int baud)
{
	unsigned int quot;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);

	quot = uart_get_divisor(port, baud);

	DEBUG("In %s quot=%u----baud=%u-----------------------------END\n",__FUNCTION__,quot,baud);
	return quot;	
}

//This is a port ops function to set the terminal settings.
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
static void serial99xx_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
#else
static void serial99xx_set_termios(struct uart_port *port, struct termios *termios, struct termios *old)
#endif

{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	u8 cval,fcr=0;
	unsigned long flags;
	unsigned int baud, quot;
	u32 clk_sel_val=0,ser_ven_val=0;
	unsigned int sampling_clock = 0; // 0:use default 16 bits sampling clock


	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	switch (termios->c_cflag & CSIZE) {
	case CS5:
		cval = 0x00;
		break;
	case CS6:
		cval = 0x01;
		break;
	case CS7:
		cval = 0x02;
		break;
	default:
	case CS8:
		cval = 0x03;
		break;
	}

	if (termios->c_cflag & CSTOPB)
		cval |= UART_LCR_STOP;
	if (termios->c_cflag & PARENB)
		cval |= UART_LCR_PARITY;
	if (!(termios->c_cflag & PARODD))
		cval |= UART_LCR_EPAR;
#ifdef CMSPAR
	if (termios->c_cflag & CMSPAR)
		cval |= UART_LCR_SPAR;
#endif

	/*
	 * Ask the core to calculate the divisor for us.
	 */
	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
	DEBUG("In %s -------------------baud=%u\n",__FUNCTION__,baud);

	if (up->custom_setting == 1)
		baud = up->custom_baud;
	else
		port->uartclk = DEFAULT99xx_BAUD * 16;

	if(baud > 115200) {
		quot = 1;

		switch (baud) {
		case 230400:
			port->uartclk = 3686400;
			clk_sel_val=0x10;
			break;
		case 403200:
			port->uartclk = 6451200;
			clk_sel_val=0x20;
			break;
		case 460800:
			port->uartclk = 7372800;
			clk_sel_val=0x30;
			break;
		case 806400:
			port->uartclk = 12902400;
			clk_sel_val=0x40;
			break;
		case 921600:
			port->uartclk = 14745600;
			clk_sel_val=0x50; 
			break;
		case 1500000:
			port->uartclk = 24000000;
			clk_sel_val=0x60;
			break;
		case 3000000:
			port->uartclk = 48000000;
			clk_sel_val=0x70; 
			break;
		case 6000000:
			port->uartclk = 96000000;
			break;
		case 6400000:
			port->uartclk = 96000000;
			sampling_clock = 15; 
			break;
		case 8000000:
			port->uartclk = 96000000;
			sampling_clock = 12; 
			break;
		case 9600000:
			port->uartclk = 96000000;
			sampling_clock = 10; 
			break;
		case 12000000:
			port->uartclk = 96000000;
			sampling_clock = 8; 
			break;
		case 16000000:
			port->uartclk = 96000000;
			sampling_clock = 6; 
			break;
		default:
			break;
		}

	} else
		quot = serial99xx_get_divisor(port, baud);
	
	if (up->capabilities & UART_CAP_FIFO && uart_config[port->type].fifo_size > 1) {
		if (baud < 2400)
			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
		else
			fcr = uart_config[up->port.type].fcr;
	}
	
	/*
	 * MCR-based auto flow control.  When AFE is enabled, RTS will be
	 * deasserted when the receive FIFO contains more characters than
	 * the trigger, or the MCR RTS bit is cleared.  In the case where
	 * the remote UART is not using CTS auto flow control, we must
	 * have sufficient FIFO entries for the latency of the remote
	 * UART to respond.  IOW, at least 32 bytes of FIFO.
	 */
	if (up->capabilities & UART_CAP_AFE && uart_config[port->type].fifo_size >= 32) {
		up->mcr &= ~UART_MCR_AFE;
		if (termios->c_cflag & CRTSCTS)
			up->mcr |= UART_MCR_AFE;
	}

	/*
	 * Ok, we're now changing the port state.  Do it with
	 * interrupts disabled.
	 */
	spin_lock_irqsave(&up->lock_99xx, flags);

	/*
	 * Update the per-port timeout.
	 */
	uart_update_timeout(port, termios->c_cflag, baud);

	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
	if (termios->c_iflag & INPCK)
		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
	if (termios->c_iflag & (BRKINT | PARMRK))
		up->port.read_status_mask |= UART_LSR_BI;

	/*
	 * Characteres to ignore
	 */
	up->port.ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
	if (termios->c_iflag & IGNBRK) {
		up->port.ignore_status_mask |= UART_LSR_BI;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
		 */
		if (termios->c_iflag & IGNPAR)
			up->port.ignore_status_mask |= UART_LSR_OE;
	}

	/*
	 * ignore all characters if CREAD is not set
	 */
	if ((termios->c_cflag & CREAD) == 0)
		up->port.ignore_status_mask |= UART_LSR_DR;

	/*
	 * CTS flow control flag and modem status interrupts
	 */
	up->ier &= ~UART_IER_MSI;
	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
		up->ier |= UART_IER_MSI;
	serial_out(up, UART_IER, up->ier);
	if (up->capabilities & UART_CAP_EFR) {
		unsigned char efr = 0;
		/*
		 * TI16C752/Startech hardware flow control.  FIXME:
		 * - TI16C752 requires control thresholds to be set.
		 * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
		 */
		if (termios->c_cflag & CRTSCTS)
			efr |= UART_EFR_CTS;

		serial_out(up, UART_LCR, 0xBF);
		serial_out(up, UART_EFR, efr);
	}


	//reset clk sel val 
	ser_ven_val = readl(up->port.membase+SER_VEN_REG);
	ser_ven_val = 0;
	writel(ser_ven_val, up->port.membase + SER_VEN_REG);
	DEBUG("In %s SER_VEN_REG=0x%x\n",__FUNCTION__,readl(up->port.membase+SER_VEN_REG));

	//for baud rates of 2x to 3Mbps
	ser_ven_val = readl(up->port.membase+SER_VEN_REG);
	ser_ven_val |= clk_sel_val;
	writel(ser_ven_val, up->port.membase + SER_VEN_REG);
	DEBUG("In %s SER_VEN_REG=0x%x\n",__FUNCTION__,readl(up->port.membase+SER_VEN_REG));

	//clock prescaling is used for higher baudrates than 3mbps
	if(baud > 3145728){ 
		writel(5, up->port.membase+SP_CLK_SELECT_REG); 
		DEBUG("   In %s SP_CLK_SELECT_REG=0x%x\n",__FUNCTION__,readl(up->port.membase+SP_CLK_SELECT_REG));
	} else { 
		writel(0, up->port.membase+SP_CLK_SELECT_REG); 
		DEBUG("In %s SP_CLK_SELECT_REG=0x%x\n",__FUNCTION__,readl(up->port.membase+SP_CLK_SELECT_REG));
	}

	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */

	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */
	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */

	serial_out(up, UART_LCR, cval);		/* reset DLAB */

	up->lcr = cval;				/* Save LCR */

	if (up->port.type != PORT_16750) {
		if (fcr & UART_FCR_ENABLE_FIFO) {
			/* emulated UARTs (Lucent Venus 167x) need two steps */
			serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
			
		}
		serial_out(up,UART_FCR,fcr);		/* set fcr */
		DEBUG("In %s UART_FCR is written with fcr=0x%x\n",__FUNCTION__,fcr);	
	}

	serial_icr_write(up, UART_TCR, sampling_clock);

	serial99xx_set_mctrl(&up->port, up->port.mctrl);
	spin_unlock_irqrestore(&up->lock_99xx, flags);
	DEBUG("In %s ------------------------------END\n",__FUNCTION__);
}

static void serial99xx_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
{
	struct uart_99xx_port *p = &serial99xx_ports[port->line];
	serial99xx_set_sleep(p, state != 0);
}

//Helper function to relase the kernel resources used by the port
static void serial99xx_release_port(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);
	
	iounmap(up->port.membase);
	
	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
}

//Helper function to get the necessary kernel resources for the port
static int serial99xx_request_port(struct uart_port *port)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];
	int ret = 0,size=8,mem_size=4096;

	//TODO:the mem_size and the mem2_size are not yet known properly
	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);
	if(!request_region(up->port.iobase, size, "saturn")){
		ret = -EBUSY;
		goto release1;
	}
	
	if(!request_mem_region(up->port.mapbase, mem_size, "saturn")){
		ret = -EBUSY;
		goto release2;
	}
	
	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
	return ret;
	
release2:
	release_region(up->port.iobase,size);
release1:
	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
	return ret;
}

static const char *serial99xx_type(struct uart_port *port)
{
	return "saturn";
}

static int serial99xx_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
{
	struct uart_99xx_port *up = &serial99xx_ports[port->line];

	switch (cmd) {
	case IOCTL_GET_CUSTOM:
		__put_user(up->custom_baud, (int __user*)arg);
		break;
        case IOCTL_SET_CUSTOM:
		if (arg == 0) {
			up->custom_setting = 0;
			up->custom_baud = 0;

		} else {
			up->custom_setting = 1;
			up->custom_baud = arg;
		}
		break;
	default:
		return -ENOIOCTLCMD;	
	}

	return 0;
}

static struct uart_ops serial99xx_pops = {
	.tx_empty	= serial99xx_tx_empty,
	.set_mctrl	= serial99xx_set_mctrl,
	.get_mctrl	= serial99xx_get_mctrl,
	.stop_tx	= serial99xx_stop_tx,
	.start_tx	= serial99xx_start_tx,
	.stop_rx	= serial99xx_stop_rx,
	.enable_ms	= serial99xx_enable_ms,
	.break_ctl	= serial99xx_break_ctl,
	.startup	= serial99xx_startup,
	.shutdown	= serial99xx_shutdown,
	.set_termios	= serial99xx_set_termios,
	.pm		= serial99xx_pm,
	.type		= serial99xx_type,
	.release_port	= serial99xx_release_port,
	.request_port	= serial99xx_request_port,
	.ioctl		= serial99xx_ioctl,

};

//Initialising the global per port context array to the default values
static void serial99xx_init_port(struct uart_99xx_port *up)
{
	spin_lock_init(&up->port.lock);
	spin_lock_init(&up->lock_99xx);
	up->port.ops 	= &serial99xx_pops;
	up->port.iotype = UPIO_PORT;
	up->port.type 	= PORT_16550A;
	up->port.flags |= UPF_SHARE_IRQ;
}

//Initialising the maximum allowed per port Structures with the default values
static void __init serial99xx_init_ports(void)
{
	int i;
	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);

	memset(serial99xx_ports, 0, UART99xx_NR * sizeof(struct uart_99xx_port));
	for (i = 0; i < UART99xx_NR; i++) {
		serial99xx_init_port(&serial99xx_ports[i]);
		serial99xx_ports[i].port.line = i;
	}
	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
}

/*
 *	Are the two ports equivalent?
 */
int serial99xx_match_port(struct uart_port *port1, struct uart_port *port2)
{
	if (port1->iotype != port2->iotype)
		return 0;

	if ((port1->iobase == port2->iobase) && (port1->membase == port2->membase)){
		return 1;
	}
	else
		return 0;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
static DECLARE_MUTEX(serial99xx_sem);
#else
static DEFINE_SEMAPHORE(serial99xx_sem);
#endif

static struct uart_driver starex_serial_driver = {
        .owner                  = THIS_MODULE,
        .driver_name            = "saturn",
        .dev_name               = "ttyF",//E",//D",
        .major                  = 200,
        .minor                  = 0,
        .nr                     = UART99xx_NR,
        .cons                   = NULL,
};

int serial99xx_find_match_or_unused(struct uart_port *port)
{
	int i;
	
	/*
	 * We didn't find a matching entry, so look for the first
	 * free entry.  We look for one which hasn't been previously
	 * used (indicated by zero iobase).
	 */
	for (i = 0; i < UART99xx_NR; i++){
		if (serial99xx_ports[i].port.iobase == 0){
			return i;
			}
	}	

	/*
	 * That also failed.  Last resort is to find any entry which
	 * doesn't have a real port associated with it.
	 */
	for (i = 0; i < UART99xx_NR; i++){
		if (serial99xx_ports[i].port.type == PORT_UNKNOWN){
			return i;
			}	
	}		
	return -1;
}

int serial99xx_cascade_register_port(struct uart_port *port,int index,int port_context,struct pci_dev *dev)
{
	//unsigned long base, len;
	int ret = -ENOSPC;
	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);
	if (port->uartclk == 0)
		return -EINVAL;

	//down(&serial99xx_sem);

	//index = serial99xx_find_match_or_unused(port);
	if (index >= 0) {

		serial99xx_ports[index].port.iobase   = port->iobase;
		serial99xx_ports[index].port.membase  = port->membase;
		serial99xx_ports[index].port.uartclk  = port->uartclk;
		serial99xx_ports[index].port.fifosize = port->fifosize;
		serial99xx_ports[index].port.regshift = port->regshift;
		serial99xx_ports[index].port.iotype   = port->iotype;
		serial99xx_ports[index].port.flags    = port->flags;
		serial99xx_ports[index].port.mapbase  = port->mapbase;
		serial99xx_ports[index].port.line = index;
		//This is the default value
		serial99xx_ports[index].port.type = PORT_16550A;

		serial99xx_ports[index].custom_setting = 0;
		serial99xx_ports[index].custom_baud = 0;
	
		if(port_context == 0)
			serial99xx_ports[index].port.irq = port->irq;
		if (port->dev)
			serial99xx_ports[index].port.dev = NULL;

		ret = uart_add_one_port(&starex_serial_driver,&serial99xx_ports[index].port);
		if(ret<0)
			DEBUG("uart_add_one_port ----------failed\n");
		if (ret == 0)
			ret = serial99xx_ports[index].port.line;

		if(uart_99xx_contxts[index].tx_dma_en == 1){
			serial99xx_ports[index].dma_tx=1;
			serial99xx_ports[index].dma_tx_buf_v=(char *)pci_alloc_consistent(dev,DMA_TX_BUFFER_SZ,&serial99xx_ports[index].dma_tx_buf_p);
			serial99xx_ports[index].serialise_txdma=0;
			DEBUG("dma_tx_buf_v=0x%x\n dma_tx_buf_p=0x%x\n",(unsigned int)serial99xx_ports[index].dma_tx_buf_v, (unsigned int)serial99xx_ports[index].dma_tx_buf_p);
		}else{
			serial99xx_ports[index].dma_tx=0;
			serial99xx_ports[index].dma_tx_buf_v=NULL;
		}
		
		if(uart_99xx_contxts[index].rx_dma_en == 1){
			serial99xx_ports[index].dma_rx=1;
			serial99xx_ports[index].dma_rx_buf_v=(char *)pci_alloc_consistent(dev,DMA_RX_BUFFER_SZ,&serial99xx_ports[index].dma_rx_buf_p);
			serial99xx_ports[index].part_done_recv_cnt=0;	
			serial99xx_ports[index].rx_dma_done_cnt=0;
			DEBUG("dma_rx_buf_v=0x%x\n dma_rx_buf_p=0x%x\n",(unsigned int)serial99xx_ports[index].dma_rx_buf_v, (unsigned int)serial99xx_ports[index].dma_rx_buf_p);
		}else{
			serial99xx_ports[index].dma_rx=0;
			serial99xx_ports[index].dma_rx_buf_v=NULL;
		}

		serial99xx_ports[index].uart_mode = uart_99xx_contxts[index].uart_mode;
		serial99xx_ports[index].flow_control = uart_99xx_contxts[index].en_flow_control;
		serial99xx_ports[index].flow_ctrl_type = uart_99xx_contxts[index].flow_ctrl_type;
		serial99xx_ports[index].x_on = uart_99xx_contxts[index].x_on;
		serial99xx_ports[index].x_off = uart_99xx_contxts[index].x_off;
		serial99xx_ports[index].ser_dcr_din_reg = 0;
		serial99xx_ports[index].ser_ven_reg = 0;
		serial99xx_ports[index].acr = 0;
		serial99xx_ports[index].lcr = 0;
		serial99xx_ports[index].mcr = 0;
		
		if(uart_99xx_contxts[index].uart_mode == MCS99XX_RS485_FULL_DUPLEX || \
  			uart_99xx_contxts[index].uart_mode == MCS99XX_RS485_HALF_DUPLEX || \
			uart_99xx_contxts[index].uart_mode == MCS99XX_RS485_HALF_DUPLEX_ECHO|| \
			uart_99xx_contxts[index].uart_mode == MCS99XX_RS422_MODE || \
			uart_99xx_contxts[index].uart_mode == MCS99XX_IRDA_MODE){
			
			serial99xx_ports[index].port.type = PORT_ENHANCED;
			serial99xx_ports[index].rxfifotrigger = uart_99xx_contxts[index].rxfifotrigger;
			serial99xx_ports[index].txfifotrigger = uart_99xx_contxts[index].txfifotrigger;			
		}
		
		if(serial99xx_ports[index].flow_control){
			if (uart_99xx_contxts[index].flow_ctrl_type == MCS99XX_DTR_DSR_HW_FLOWCONTROL || \
				uart_99xx_contxts[index].flow_ctrl_type == MCS99XX_XON_XOFF_HW_FLOWCONTROL){
				serial99xx_ports[index].port.type = PORT_ENHANCED;
				serial99xx_ports[index].rxfifotrigger = uart_99xx_contxts[index].rxfifotrigger;
				serial99xx_ports[index].txfifotrigger = uart_99xx_contxts[index].txfifotrigger;		
			}
		}

	}
	//up(&serial99xx_sem);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return ret;
}

int serial99xx_nocascade_register_port(struct uart_port *port,struct pci_dev *dev)
{
	//unsigned long base, len;
	int index,ret = -ENOSPC;
	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);
	if (port->uartclk == 0)
		return -EINVAL;

	down(&serial99xx_sem);

	index = serial99xx_find_match_or_unused(port);
	if (index >= 0) {

		serial99xx_ports[index].port.iobase   = port->iobase;
		serial99xx_ports[index].port.membase  = port->membase;
		serial99xx_ports[index].port.irq      = port->irq;
		serial99xx_ports[index].port.uartclk  = port->uartclk;
		serial99xx_ports[index].port.fifosize = port->fifosize;
		serial99xx_ports[index].port.regshift = port->regshift;
		serial99xx_ports[index].port.iotype   = port->iotype;
		serial99xx_ports[index].port.flags    = port->flags;
		serial99xx_ports[index].port.mapbase  = port->mapbase;
		serial99xx_ports[index].port.line = index;
		//This is the default value
		serial99xx_ports[index].port.type = PORT_16550A;

		serial99xx_ports[index].custom_setting = 0;
		serial99xx_ports[index].custom_baud = 0;

		if (port->dev)
			serial99xx_ports[index].port.dev = port->dev;

		ret = uart_add_one_port(&starex_serial_driver,&serial99xx_ports[index].port);
		if(ret<0)
			DEBUG("uart_add_one_port ----------failed\n");
		if (ret == 0)
			ret = serial99xx_ports[index].port.line;

		if(uart_99xx_contxts[index].tx_dma_en == 1){
			serial99xx_ports[index].dma_tx=1;
			serial99xx_ports[index].dma_tx_buf_v=(char *)pci_alloc_consistent(dev,DMA_TX_BUFFER_SZ,&serial99xx_ports[index].dma_tx_buf_p);
			serial99xx_ports[index].serialise_txdma=0;
			DEBUG("dma_tx_buf_v=0x%x\n dma_tx_buf_p=0x%x\n",(unsigned int)serial99xx_ports[index].dma_tx_buf_v,serial99xx_ports[index].dma_tx_buf_p);
		}else{
			serial99xx_ports[index].dma_tx=0;
			serial99xx_ports[index].dma_tx_buf_v=NULL;
		}
		
		if(uart_99xx_contxts[index].rx_dma_en == 1){
			serial99xx_ports[index].dma_rx=1;
			serial99xx_ports[index].dma_rx_buf_v=(char *)pci_alloc_consistent(dev,DMA_RX_BUFFER_SZ,&serial99xx_ports[index].dma_rx_buf_p);
			serial99xx_ports[index].part_done_recv_cnt=0;	
			serial99xx_ports[index].rx_dma_done_cnt=0;
			DEBUG("dma_rx_buf_v=0x%x\n dma_rx_buf_p=0x%x\n",(unsigned int)serial99xx_ports[index].dma_rx_buf_v,serial99xx_ports[index].dma_rx_buf_p);
		}else{
			serial99xx_ports[index].dma_rx=0;
			serial99xx_ports[index].dma_rx_buf_v=NULL;
		}

		serial99xx_ports[index].uart_mode = uart_99xx_contxts[index].uart_mode;
		serial99xx_ports[index].flow_control = uart_99xx_contxts[index].en_flow_control;
		serial99xx_ports[index].flow_ctrl_type = uart_99xx_contxts[index].flow_ctrl_type;
		serial99xx_ports[index].x_on = uart_99xx_contxts[index].x_on;
		serial99xx_ports[index].x_off = uart_99xx_contxts[index].x_off;
		serial99xx_ports[index].ser_dcr_din_reg = 0;
		serial99xx_ports[index].ser_ven_reg = 0;
		serial99xx_ports[index].acr = 0;
		serial99xx_ports[index].lcr = 0;
		serial99xx_ports[index].mcr = 0;
		
		if(uart_99xx_contxts[index].uart_mode == MCS99XX_RS485_FULL_DUPLEX || \
  			uart_99xx_contxts[index].uart_mode == MCS99XX_RS485_HALF_DUPLEX || \
			uart_99xx_contxts[index].uart_mode == MCS99XX_RS485_HALF_DUPLEX_ECHO|| \
			uart_99xx_contxts[index].uart_mode == MCS99XX_RS422_MODE || \
			uart_99xx_contxts[index].uart_mode == MCS99XX_IRDA_MODE){
			
			serial99xx_ports[index].port.type = PORT_ENHANCED;
			serial99xx_ports[index].rxfifotrigger = uart_99xx_contxts[index].rxfifotrigger;
			serial99xx_ports[index].txfifotrigger = uart_99xx_contxts[index].txfifotrigger;			
		}
		
		if(serial99xx_ports[index].flow_control){
			if (uart_99xx_contxts[index].flow_ctrl_type == MCS99XX_DTR_DSR_HW_FLOWCONTROL || \
				uart_99xx_contxts[index].flow_ctrl_type == MCS99XX_XON_XOFF_HW_FLOWCONTROL){
				serial99xx_ports[index].port.type = PORT_ENHANCED;
				serial99xx_ports[index].rxfifotrigger = uart_99xx_contxts[index].rxfifotrigger;
				serial99xx_ports[index].txfifotrigger = uart_99xx_contxts[index].txfifotrigger;		
			}
		}

	}
	up(&serial99xx_sem);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return ret;
}

static struct pci_device_id serial99xx_pci_tbl[] = {
	//{PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_NOCASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_NOCASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9950, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_NOCASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_NOCASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_NOCASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_NOCASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_CASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_CASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9950, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_CASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_CASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_CASCADE, 0, 0, 0},
	{PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912, PCI_SUBDEV_ID_MCS99XX, PCI_SUBVEN_ID_MCS99XX_CASCADE, 0, 0, 0},
	{0, },
};

static void __devexit serial99xx_cascade_remove_one(struct pci_dev *dev)
{
	int i,port_context,ret;
	unsigned long base;
	struct uart_99xx_port *uart=NULL;
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);

        for(port_context = 0;port_context < mode; port_context++) {
		base = pci_resource_start(dev, FL_BASE0 + (port_context * 0x0003));

		for (i = 0; i < UART99xx_NR; i++){
			if(serial99xx_ports[i].port.iobase == base){
				uart=&serial99xx_ports[i];
				break;
			}
		}

		if(uart){
			//Free the IRQ
			if(port_context == 0){
				free_irq(uart->port.irq,uart);
			}
			DEBUG("value at address 3FC is %x\n",readl(uart->port.membase + 0x3FC));
		        writel(1,uart->port.membase + 0x3FC);
		        DEBUG("value at address 3FC after configuring is %x\n",readl(uart->port.membase + 0x3FC));
		
			down(&serial99xx_sem);
			ret = uart_remove_one_port(&starex_serial_driver, &uart->port);
			uart->next_port = NULL;
			uart->prev_port = NULL;	
			up(&serial99xx_sem);
		
			pci_free_consistent(dev,DMA_TX_BUFFER_SZ,uart->dma_tx_buf_v,uart->dma_tx_buf_p);
			pci_free_consistent(dev,DMA_RX_BUFFER_SZ,uart->dma_rx_buf_v,uart->dma_rx_buf_p);

			//Initialise the uart_99xx_port arrays port specific element to the default state
			serial99xx_init_port(&serial99xx_ports[uart->port.line]);
		}
	}

	pci_disable_device(dev);

	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
}

static void __devexit serial99xx_nocascade_remove_one(struct pci_dev *dev)
{
	int i;
	unsigned long base;
	struct uart_99xx_port *uart=NULL;
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	base = pci_resource_start(dev, FL_BASE0);

	for (i = 0; i < UART99xx_NR; i++){
		if(serial99xx_ports[i].port.iobase == base){
			uart=&serial99xx_ports[i];
			break;
		}
	}

	if(uart){
		//Free the IRQ
		free_irq(uart->port.irq,uart);
		DEBUG("value at address 3FC is %x\n",readl(uart->port.membase + 0x3FC));
	        writel(1,uart->port.membase + 0x3FC);
        	DEBUG("value at address 3FC after configuring is %x\n",readl(uart->port.membase + 0x3FC));
	
		down(&serial99xx_sem);
		uart_remove_one_port(&starex_serial_driver, &uart->port);
		uart->port.dev = NULL;		
		up(&serial99xx_sem);
		
		pci_free_consistent(dev,DMA_TX_BUFFER_SZ,uart->dma_tx_buf_v,uart->dma_tx_buf_p);
		pci_free_consistent(dev,DMA_RX_BUFFER_SZ,uart->dma_rx_buf_v,uart->dma_rx_buf_p);
		pci_disable_device(dev);

		//Initialise the uart_99xx_port arrays port specific element to the default state
		serial99xx_init_port(&serial99xx_ports[uart->port.line]);
	}
	DEBUG("In %s---------------------------------------END\n",__FUNCTION__);
}

//PCI driver remove function. Rlease the resources used by the port
static void __devexit serial99xx_remove_one(struct pci_dev *dev)
{
	if (dev->subsystem_device == PCI_SUBVEN_ID_MCS99XX_CASCADE) {
		serial99xx_cascade_remove_one(dev);
	} else if  (dev->subsystem_device == PCI_SUBVEN_ID_MCS99XX_NOCASCADE) {
		serial99xx_nocascade_remove_one(dev);
	} else {
		dev_err(&dev->dev, "Not 99XX cascade or non-cascade device when remove!\n");		
	}
}

static int __devinit serial99xx_cascade_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
	int retval;
	unsigned long base, len;
	struct uart_port serial_port;
	int index=0,port_context,fun_no=0;
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);

	//To verify whether it is a serial communication hardware
/*	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
		((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
		(dev->class & 0xff) > 6){
		DEBUG("Not a serial communication hardware\n");
		retval = -ENODEV;
		goto disable;
	}
*/

	//To verify whether it is a MCS99XX type BARs
	if(((pci_resource_flags(dev,FL_BASE0) & BAR_FMT) ^ BAR_IO) ||
			((pci_resource_flags(dev,FL_BASE1) & BAR_FMT) ^ BAR_MEM) ||
			((pci_resource_flags(dev,FL_BASE4) & BAR_FMT) ^ BAR_MEM)) {
		DEBUG("Not a MCS99XX type device\n");
		retval = -ENOMEM;
		goto disable;
	}

	pci_set_master(dev);	

	memset(&serial_port, 0, sizeof(struct uart_port));

	index = serial99xx_find_match_or_unused(&serial_port);
	DEBUG("index is %d\n",index);

	for(port_context = 0;port_context < mode; port_context++) {	

		DEBUG("In for loop\n");
	        if(port_context == (CASCADE_MODE-1))
			index = index + nr_funs;
		DEBUG("index in for loop %d\n",index);	
		memset(&serial_port, 0, sizeof(struct uart_port));
		serial_port.flags = UPF_SHARE_IRQ |UPF_SKIP_TEST;
		serial_port.uartclk = DEFAULT99xx_BAUD * 16;
		serial_port.irq = dev->irq;
		//serial_port.dev = &dev->dev;
		len =  pci_resource_len(dev, (FL_BASE1 + (port_context * 0x0003)));
		base = pci_resource_start(dev, (FL_BASE1 + (port_context * 0x0003)));
		serial_port.mapbase = base;
		serial_port.membase = ioremap(base,len);
		DEBUG("membase=0x%x\n mapbase=0x%x\n",(unsigned int)serial_port.membase,(unsigned int)serial_port.mapbase);
		DEBUG("value at address 3FC is %x\n",readl(serial_port.membase + 0x3FC));
	        writel(0,serial_port.membase + 0x3FC);
        	DEBUG("value at address 3FC after configuring is %x\n",readl(serial_port.membase + 0x3FC));
		base = pci_resource_start(dev,(FL_BASE0 + (port_context * 0x0003)));
		serial_port.iobase = base;
		DEBUG("iobase=0x%x\n",(unsigned int)serial_port.iobase);
		retval = serial99xx_cascade_register_port(&serial_port,index,port_context,dev);
		if (retval < 0){
			DEBUG(KERN_WARNING "Couldn't register serial port %s, retval=%d: \n", pci_name(dev),retval);
			goto disable;	
		}
		DEBUG("serial99xx_ports[index] : %x\n",&serial99xx_ports[index]);	

		if(port_context == 0) {
                        fun_no = index;
			DEBUG("index in is %d\n",index);
                        serial99xx_ports[index].next_port = NULL;
			serial99xx_ports[index].prev_port = NULL;
                } else {
			DEBUG("fun_no and index are %d %d\n",fun_no,index);
			
			serial99xx_ports[index].next_port = NULL;
			serial99xx_ports[index].prev_port =  &serial99xx_ports[fun_no];
                        serial99xx_ports[fun_no].next_port = &serial99xx_ports[index];
			DEBUG("serial99xx_ports[index] :%x serial99xx_ports[index].prev_port :%x and serial99xx_ports[fun_no].next_port :%x\n",
							&serial99xx_ports[index],serial99xx_ports[index].prev_port,serial99xx_ports[fun_no].next_port);
		}
	
		DEBUG("-------------serial port no is %d----------------\n",retval);
		DEBUG("Device structure for port %d is %u\n",index,&serial99xx_ports[index]);
	}
		
	DEBUG("IRQ value is %d\n",dev->irq);
	DEBUG("fun no is %d\n",fun_no);

//Register an ISR
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
	if ((retval = request_irq(dev->irq, serial99xx_cascade_interrupt, SA_SHIRQ,"saturn", &serial99xx_ports[fun_no]))) 
		goto disable;
#else
	if ((retval = request_irq(dev->irq, serial99xx_cascade_interrupt, IRQF_SHARED, "saturn", &serial99xx_ports[fun_no]))) 
		goto disable;
#endif

	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return 0;	
	 
disable:
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return retval;
}

static int __devinit serial99xx_nocascade_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
	int retval;
	unsigned long base, len;
	struct uart_port serial_port;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);

	//To verify whether it is a serial communication hardware
	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
		((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
		(dev->class & 0xff) > 6){
		DEBUG("Not a serial communication hardware\n");
		retval = -ENODEV;
		goto disable;
	}

	//To verify whether it is a MCS99XX type BARs
	if(((pci_resource_flags(dev,FL_BASE0) & BAR_FMT) ^ BAR_IO) ||
			((pci_resource_flags(dev,FL_BASE2) & BAR_FMT) ^ BAR_MEM) ||
			((pci_resource_flags(dev,FL_BASE4) & BAR_FMT) ^ BAR_MEM)) {
		DEBUG("Not a MCS99XX type device\n");
		retval = -ENOMEM;
		goto disable;
	}

	pci_set_master(dev);	

	memset(&serial_port, 0, sizeof(struct uart_port));

	serial_port.flags = UPF_SHARE_IRQ |UPF_SKIP_TEST;
	serial_port.uartclk = DEFAULT99xx_BAUD * 16;
	serial_port.irq = dev->irq;
	serial_port.dev = &dev->dev;
	len =  pci_resource_len(dev, FL_BASE1);
	base = pci_resource_start(dev, FL_BASE1);
	serial_port.mapbase = base;
	serial_port.membase = ioremap(base,len);
	DEBUG("membase=0x%x\n mapbase=0x%x\n",(unsigned int)serial_port.membase,(unsigned int)serial_port.mapbase);
	DEBUG("value at address 3FC is %x\n",readl(serial_port.membase + 0x3FC));
	writel(0,serial_port.membase + 0x3FC);
	DEBUG("value at address 3FC after configuring is %x\n",readl(serial_port.membase + 0x3FC));
	base = pci_resource_start(dev,FL_BASE0);
	serial_port.iobase = base;

	retval = serial99xx_nocascade_register_port(&serial_port,dev);
	if (retval < 0){
		DEBUG(KERN_WARNING "Couldn't register serial port %s, retval=%d: \n", pci_name(dev),retval);
		goto disable;	
	}	

//Register an ISR
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
	if ((retval = request_irq(dev->irq, serial99xx_nocascade_interrupt,SA_SHIRQ,"saturn",&serial99xx_ports[retval]))) 
		goto disable;
#else
	if ((retval = request_irq(dev->irq, serial99xx_nocascade_interrupt,IRQF_SHARED,"saturn",&serial99xx_ports[retval]))) 
		goto disable;
#endif

	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return 0;	
	 
disable:
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return retval;
}

//PCI drivers probe function
static int __devinit serial99xx_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
	int retval;

	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);

	retval = pci_enable_device(dev);
	
	if (retval) {
		dev_err(&dev->dev, "Device enable FAILED\n");
                return retval;
	}

	if (dev->subsystem_device == PCI_SUBVEN_ID_MCS99XX_CASCADE) {
		return serial99xx_cascade_probe(dev, ent);
	} else if  (dev->subsystem_device == PCI_SUBVEN_ID_MCS99XX_NOCASCADE) {
		return serial99xx_nocascade_probe(dev, ent);
	} else {
		pci_disable_device(dev);
		dev_err(&dev->dev, "Not 99XX cascade or non-cascade device!\n");		
		DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
		return retval;
	}
	
}

	
static struct pci_driver starex_pci_driver = {
	.name		= "saturn",
	.probe		= serial99xx_probe,
	.remove		= __devexit_p(serial99xx_remove_one),
	.id_table	= serial99xx_pci_tbl,
};


//Drivers entry function. register with the pci core and the serial core
static int __init serial99xx_init(void)
{
	int ret;

	DEBUG("In %s---------------------------------------START\n",__FUNCTION__);
	serial99xx_init_ports();
	ret = uart_register_driver(&starex_serial_driver);

	if (ret){
		DEBUG("In %s uart_register_driver FAILED\n",__FUNCTION__);
		return ret;
	}	

	ret = pci_register_driver(&starex_pci_driver);
	if (ret < 0){
		DEBUG("In %s pci_register_driver FAILED\n",__FUNCTION__);
		uart_unregister_driver(&starex_serial_driver);
	}	
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);
	return ret;
}

//Drivers exit function. Unregister with the PCI core as well as serial core
static void __exit serial99xx_exit(void)
{
	DEBUG("In %s ---------------------------------------START\n",__FUNCTION__);
	pci_unregister_driver(&starex_pci_driver);
	uart_unregister_driver(&starex_serial_driver);
	DEBUG("In %s ---------------------------------------END\n",__FUNCTION__);	
}

module_param(nr_funs,int,0);

module_init(serial99xx_init);
module_exit(serial99xx_exit);

MODULE_DESCRIPTION("moschip 99xx serial driver module");
MODULE_SUPPORTED_DEVICE("moschip serial 99xx");
MODULE_LICENSE("GPL");

99xx.h :

/*
 *  linux/drivers/serial/99xx.h
 *
 *  Based on drivers/serial/8250.c by Russell King.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This code is modified to support moschip 99xx series serial devices
 */

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
#include <linux/config.h>
#endif


struct old_serial_port {
	unsigned int 	uart;
	unsigned int 	baud_base;
	unsigned int	 port;
	unsigned int	 irq;
	unsigned int 	flags;
	unsigned char 	hub6;
	unsigned char 	io_type;
	unsigned char 	*iomem_base;
	unsigned short 	iomem_reg_shift;
};

struct serial99xx_config {
	unsigned short	fifo_size;
	unsigned short	tx_loadsz;
	unsigned char		fcr;
	unsigned int		flags;
};

#define DIV 1

#define UART_CAP_FIFO	(1 << 8)	/* UART has FIFO */
#define UART_CAP_EFR	(1 << 9)	/* UART has EFR */
#define UART_CAP_SLEEP	(1 << 10)	/* UART has IER sleep */
#define UART_CAP_AFE	(1 << 11)	/* MCR-based hw flow control */
#define UART_CAP_UUE	(1 << 12)	/* UART needs IER bit 6 set (Xscale) */

#define REG_TX_DMA_START_ADDRESS_LOW	((0x80)/DIV)
#define REG_TX_DMA_START_ADDRESS_HIGH	((0x84)/DIV)
#define REG_TX_DMA_LENGTH				((0x88)/DIV)
#define REG_TX_DMA_START				((0x8C)/DIV)
#define REG_TX_DMA_STOP					((0x90)/DIV)
#define REG_TX_DMA_STOP_DONE			((0x94)/DIV)
#define REG_TX_BYTES_TRANSFERRED		((0x98)/DIV)
#define REG_TX_DMA_BUSY					((0x9C)/DIV)
#define REG_TX_DMA_DONE					((0xA0)/DIV)
#define REG_TX_RDY_1					((0xA4)/DIV)

#define REG_RX_DMA_START_ADDRESS_LOW	((0x100)/DIV)
#define REG_RX_DMA_START_ADDRESS_HIGH	((0x104)/DIV)
#define REG_RX_DMA_LENGTH				((0x108)/DIV)
#define REG_RX_DMA_START				((0x10C)/DIV)
#define REG_RX_DMA_STOP					((0x110)/DIV)
#define REG_RX_TRIG_LVL					((0x114)/DIV)
#define REG_RX_DMA_STOP_DONE			((0x118)/DIV)
#define REG_RX_BYTES_NEED_TO_RECV		((0x11C)/DIV)
#define REG_RX_DMA_BUSY					((0x120)/DIV)
#define REG_RX_DMA_DONE					((0x124)/DIV)
#define REG_RX_RDY_1					((0x128)/DIV)
#define REG_RX_MEM_4K_LMT				((0x12C)/DIV)


#define REG_GLBL_ISR			((0x3A0)/DIV)
#define REG_GLBL_ICLR			((0x3A4)/DIV)
#define REG_GLBL_IER			((0x3A8)/DIV)

#define TX_DMA_START_BIT		1<<0
#define TX_DMA_STOP_BIT			1<<0
#define TX_DMA_STOP_DONE_BIT 	1<<0
#define TX_DMA_DONE				1<<0
#define TX_DMA_BUSY				1<<0
#define TX_DMA_RDY				1<<0

#define RX_DMA_START_BIT		1<<0
#define RX_DMA_STOP_BIT			1<<0
#define RX_DMA_STOP_DONE_BIT 	1<<0
#define RX_DMA_DONE				1<<0
#define RX_DMA_BUSY				1<<0
#define RX_DMA_RDY				1<<0

#define SPINTR_DMA					0x01
#define SPINTR_TXDMA_ABORT_DONE		0x02
#define SPINTR_TXDMA_STOP_DONE		0x04
#define SPINTR_TXDMA_DONE 			0x08
#define SPINTR_RXDMA_ABORT_DONE 	0x10
#define SPINTR_RXDMA_STOP_DONE		0x20
#define SPINTR_RXDMA_DONE			0x40
#define SPINTR_RXDMA_PARTDONE		0x80

#define SERIAL_450MODE		0x5470
#define SERIAL_550MODE		0x5471
#define SERIAL_550AMODE		0x5472
#define SERIAL_650MODE		0x5473
#define SERIAL_750MODE		0x5474
#define SERIAL_850MODE		0x5475
#define SERIAL_950MODE		0x5476

// Default xon/xoff characters.
#define SERIAL_DEF_XON		0x11
#define SERIAL_DEF_XOFF		0x13

// UART mode
#define MCS99XX_RS232_MODE					0
#define MCS99XX_RS422_MODE					1
#define MCS99XX_RS485_HALF_DUPLEX			2
#define MCS99XX_RS485_HALF_DUPLEX_ECHO		4
#define MCS99XX_RS485_FULL_DUPLEX			5
#define MCS99XX_DTR_DSR_HW_FLOWCONTROL 		6
#define MCS99XX_XON_XOFF_HW_FLOWCONTROL		7
#define MCS99XX_RTS_CTS_HW_FLOWCONTROL		8
#define MCS99XX_IRDA_MODE					9

#define PORT_ENHANCED			14

//CommSet Registers
//Common Registers Set (memory mapped)
#define SER_DCR_DIN_REG			((0x200)/DIV)
#define SER_VEN_REG				((0x204)/DIV)
#define SP_SIGNAL_VALID_REG		((0x208)/DIV)
#define SP_IO_CONTROL_ENABLE_REG	((0x20C)/DIV)
#define SP_OUTPUT_REG_VALID		((0x210)/DIV)
#define SP_TX_TRIGGER_LVL		((0x21C)/DIV)
#define SP_CLK_SELECT_REG		((0x214)/DIV)
#define PP_DIV_REG				((0x250)/DIV)
#define PP_RX_TRIG_LEVEL		((0x254)/DIV)
#define PP_TX_TRIG_LEVEL		((0x258)/DIV)
#define PP_PERI_HOST_HIGH_REG	((0x25C)/DIV)
#define SER_TFL_REG				((0x220)/DIV) 
#define SER_RFL_REG				((0x224)/DIV) 
#define SER_SOFT_RESET_REG		((0x238)/DIV) 

#define COM_DMA_MODE_EN			0x10000000
#define COM_550EX_MODE_EN		0x00001000


#define SER_TFL_REG				((0x220)/DIV)
#define SER_RFL_REG				((0x224)/DIV)
#define SER_SOFT_RESET_REG		((0x238)/DIV)


//Old set
#define PCI_DEVICE_ID_NETMOS_9950 0x9950 //VGA + serial
#define PCI_SUBVEN_ID_MCS99XX_NOCASCADE	0x1000
#define PCI_SUBVEN_ID_MCS99XX_CASCADE  	0x3002
#define PCI_SUBDEV_ID_MCS99XX	  0xa000	


//New Set
#define PCI_DEVICE_ID_NETMOS_9901 0x9901
#define PCI_DEVICE_ID_NETMOS_9900 0x9900 //Serial
#define PCI_DEVICE_ID_NETMOS_9904 0x9904 //non Cascade 4 serial
#define PCI_DEVICE_ID_NETMOS_9922 0x9922 //non Cascade 2 serial
#define PCI_DEVICE_ID_NETMOS_9912 0x9912 //non Cascade 2 serial 1 parallel


#define BAR_IO		0x001
#define BAR_MEM 	0x000
#define BAR_FMT  	0x001

#define DMA_TX_BUFFER_SZ 	4096
#define DMA_RX_SZ 		4096
#define DMA_RX_BUFFER_SZ 	DMA_RX_SZ * 2


#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
#define _INLINE_ inline
#else
#define _INLINE_
#endif

#define DEFAULT99xx_BAUD 115200

static unsigned int serial99xx_get_mctrl(struct uart_port *);

ioctl.c :

/* INCLUDE FILE DECLARATIONS */
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <linux/sockios.h>
#include <linux/types.h>
#include <pthread.h>
#include "ioctl.h"

/* LOCAL VARIABLES DECLARATIONS */

int main(int argc, char* argv[])
{

	char dev[16];
	int  select;
	int  custom_baud;

	int devfd;

	while (1) {

		printf("Please input the port of MCS99xx. (ex. /dev/ttyF0):");
		scanf("%s", dev);

		if (memcmp(dev, "/dev/ttyF", 9) != 0)
			printf("Wrong input!!\n");
		else
			break;
	}

	devfd = open(dev, O_RDWR);
	
	if (devfd == -1) {
		printf("Can't open %s\n", dev);
		return 0;
	}

	if (ioctl(devfd, IOCTL_GET_CUSTOM, &custom_baud) < 0) {
		printf("IOCTL_GET_CUSTOM failed!!!\n");
		return 0;	
	}

	if (custom_baud == 0)
		printf("\nPort %s support standard baud rate\n", dev);
	else
		printf("\nPort %s support custom baud rate:%d\n", dev, custom_baud);

	while (1) {

		printf("\nPlease specift the baud rate of %s.\n", dev);
		printf("0  : Standard baud rate\n");
		printf("1  : 230400\n");
		printf("2  : 403200\n");
		printf("3  : 460800\n");
		printf("4  : 806400\n");
		printf("5  : 921600\n");
		printf("6  : 1500000\n");
		printf("7  : 3000000\n");
		printf("8  : 6000000\n");
		printf("9  : 6400000\n");
		printf("10 : 8000000\n");
		printf("11 : 9600000\n");
		printf("12 : 12000000\n");
		printf("13 : 16000000\n");
		printf("99 : Exit\n");
		printf(":");
		scanf("%d", &select);


		if (select == 1) {
			custom_baud = 230400;
			break;
		} else if (select == 2) {	
			custom_baud = 403200;
			break;
		} else if (select == 3) {
			custom_baud = 460800;
			break;
		} else if (select == 4) {	
			custom_baud = 806400;
			break;
		} else if (select == 5) {	
			custom_baud = 921600;
			break;
		} else if (select == 6) {	
			custom_baud = 1500000;
			break;
		} else if (select == 7) {	
			custom_baud = 3000000;
			break;
		} else if (select == 8) {	
			custom_baud = 6000000;
			break;
		} else if (select == 9) {	
			custom_baud = 6400000;
			break;
		} else if (select == 10) {	
			custom_baud = 8000000;
			break;
		} else if (select == 11) {	
			custom_baud = 9600000;
			break;
		} else if (select == 12) {	
			custom_baud = 12000000;
			break;
		} else if (select == 13) {	
			custom_baud = 16000000;
			break;
		} else if (select == 0) {	
			custom_baud = 0;
			break;
		} else if (select == 99) {
			return 0;
		}
	}

	if (ioctl(devfd, IOCTL_SET_CUSTOM, custom_baud) < 0) {
		printf("IOCTL_SET_CUSTOM failed!!!\n");
		return 0;	
	}

	printf("The %s will operating in custom baud rate after open(re-open) it.\n", dev);

exit:

	printf("\n");

	return 0;
}

ioctl.h

/* Definition for IOCTL */
#define IOCTL_SET_CUSTOM		_IOW(0xD0, 11, int)
#define IOCTL_GET_CUSTOM		_IOR(0xD0, 12, int)

Le makefile :

KDIR:=/lib/modules/$(shell  uname -r)/build/ 

DEBIAN_VERSION_FILE:=/etc/debian_version
DEBIAN_DISTRO:=$(wildcard $(DEBIAN_VERSION_FILE))
CURRENT=$(shell uname -r)
MAJORVERSION=$(shell uname -r | cut -d '.' -f 1)
MINORVERSION=$(shell uname -r | cut -d '.' -f 2)
SUBLEVEL=$(shell uname -r | cut -d '.' -f 3)

ifeq ($(MAJORVERSION),3)
MDIR=drivers/tty/serial
else
ifeq ($(MAJORVERSION),2)
ifneq (,$(filter $(SUBLEVEL),38 39))
MDIR=drivers/tty/serial
else
MDIR=drivers/serial
endif
else
MDIR=drivers/serial
endif
endif

obj-m +=99xx.o

default:
	$(RM) *.mod.c *.o *.ko .*.cmd *.symvers
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
	gcc -pthread ioctl.c -o ioctl

install:
	cp 99xx.ko  /lib/modules/$(shell uname -r)/kernel/$(MDIR)
	depmod -A
	chmod +x mcs99xx
	cp mcs99xx /etc/init.d/
ifeq ($(DEBIAN_DISTRO), $(DEBIAN_VERSION_FILE))
	ln -s /etc/init.d/mcs99xx /etc/rcS.d/Smcs99xx || true
else
	ln -s /etc/init.d/mcs99xx /etc/rc.d/rc3.d/Smcs99xx || true  	
	ln -s /etc/init.d/mcs99xx /etc/rc.d/rc5.d/Smcs99xx || true
endif
	modprobe 99xx

uninstall:
	modprobe -r 99xx
	rm -f /lib/modules/$(shell uname -r)/kernel/$(MDIR)/99xx.*
	depmod -A
	rm -f /etc/init.d/mcs99xx
ifeq ($(DEBIAN_DISTRO), $(DEBIAN_VERSION_FILE))
	rm -f /etc/init.d/mcs99xx /etc/rcS.d/Smcs99xx || true
else
	rm -f /etc/rc.d/rc3.d/Smcs99xx
	rm -f /etc/rc.d/rc5.d/Smcs99xx
endif

clean:
	$(RM) *.mod.c *.o *.ko .*.cmd *.symvers
	rm -rf .tmp_version*
	rm -rf Module.markers modules.*
	rm -f ioctl

Hors ligne

#2 Le 19/07/2016, à 23:38

MicP

Re : Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

…besoin des interfaces série et parallèle…

Je ne sais pas ce qui va être connecté à ces ports, mais je voulais te dire qu'il existe des adaptateurs USB <-> RS232 et USB <-> parallèle (IEEE 1284) qui fonctionnent très bien, qui ne coûtent vraiment pas cher du tout (moins de 5€) et qui sont parfaitement reconnu sans aucun pilote spécifique par les systèmes Linux.

Hors ligne

#3 Le 20/07/2016, à 01:13

Aurel05

Re : Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

je sais, j'utilise notamment des FT232 que j'intègre au besoin J'ai utilisé il y a peu, quelques modems 56k, pour la communication distante avec certains automates via le RTC (en mode teletext minitel pour les plus vieux lol). En effet, il n'y a rien de plus fiable et simple d'utilisation qu'un port COM.

Hors ligne

#4 Le 20/07/2016, à 02:10

Aurel05

Re : Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

Je n'ai pas trouvé le "8250_pci.c". C'est normal ?
Voici ce que donne le make :

rm -f *.mod.c *.o *.ko .*.cmd *.symvers
make -C /lib/modules/4.4.0-31-generic/build/  SUBDIRS=/home/Extension_2Series_1Parallele/LINUX modules
make[1] : on entre dans le répertoire « /usr/src/linux-headers-4.4.0-31-generic »
  CC [M]  /home/Extension_2Series_1Parallele/LINUX/99xx.o
/home/Extension_2Series_1Parallele/LINUX/99xx.c: In function ‘receive_chars’:
/home/Extension_2Series_1Parallele/LINUX/99xx.c:739:23: warning: passing argument 1 of ‘tty_flip_buffer_push’ from incompatible pointer type [-Wincompatible-pointer-types]
  tty_flip_buffer_push(tty);
                       ^
In file included from /home/Extension_2Series_1Parallele/LINUX/99xx.c:42:0:
include/linux/tty_flip.h:13:13: note: expected ‘struct tty_port *’ but argument is of type ‘struct tty_struct *’
 extern void tty_flip_buffer_push(struct tty_port *port);
             ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c: In function ‘receive_chars_dma_done’:
/home/Extension_2Series_1Parallele/LINUX/99xx.c:993:26: warning: passing argument 1 of ‘tty_flip_buffer_push’ from incompatible pointer type [-Wincompatible-pointer-types]
     tty_flip_buffer_push(tty);
                          ^
In file included from /home/Extension_2Series_1Parallele/LINUX/99xx.c:42:0:
include/linux/tty_flip.h:13:13: note: expected ‘struct tty_port *’ but argument is of type ‘struct tty_struct *’
 extern void tty_flip_buffer_push(struct tty_port *port);
             ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c: In function ‘serial99xx_handle_port’:
/home/Extension_2Series_1Parallele/LINUX/99xx.c:1074:25: warning: passing argument 1 of ‘tty_insert_flip_char’ from incompatible pointer type [-Wincompatible-pointer-types]
    tty_insert_flip_char(tty, 0, TTY_OVERRUN); 
                         ^
In file included from /home/Extension_2Series_1Parallele/LINUX/99xx.c:42:0:
include/linux/tty_flip.h:16:19: note: expected ‘struct tty_port *’ but argument is of type ‘struct tty_struct *’
 static inline int tty_insert_flip_char(struct tty_port *port,
                   ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c: At top level:
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2357:23: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘serial99xx_cascade_remove_one’
 static void __devexit serial99xx_cascade_remove_one(struct pci_dev *dev)
                       ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2402:23: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘serial99xx_nocascade_remove_one’
 static void __devexit serial99xx_nocascade_remove_one(struct pci_dev *dev)
                       ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2440:23: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘serial99xx_remove_one’
 static void __devexit serial99xx_remove_one(struct pci_dev *dev)
                       ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2451:22: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘serial99xx_cascade_probe’
 static int __devinit serial99xx_cascade_probe(struct pci_dev *dev, const struct pci_device_id *ent)
                      ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2553:22: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘serial99xx_nocascade_probe’
 static int __devinit serial99xx_nocascade_probe(struct pci_dev *dev, const struct pci_device_id *ent)
                      ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2622:22: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘serial99xx_probe’
 static int __devinit serial99xx_probe(struct pci_dev *dev, const struct pci_device_id *ent)
                      ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2651:12: error: ‘serial99xx_probe’ undeclared here (not in a function)
  .probe  = serial99xx_probe,
            ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2652:13: error: implicit declaration of function ‘__devexit_p’ [-Werror=implicit-function-declaration]
  .remove  = __devexit_p(serial99xx_remove_one),
             ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:2652:25: error: ‘serial99xx_remove_one’ undeclared here (not in a function)
  .remove  = __devexit_p(serial99xx_remove_one),
                         ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:1082:20: warning: ‘serial99xx_cascade_interrupt’ defined but not used [-Wunused-function]
 static irqreturn_t serial99xx_cascade_interrupt(int irq, void *dev_id)
                    ^
/home/Extension_2Series_1Parallele/LINUX/99xx.c:1177:20: warning: ‘serial99xx_nocascade_interrupt’ defined but not used [-Wunused-function]
 static irqreturn_t serial99xx_nocascade_interrupt(int irq, void *dev_id)
                    ^
cc1: some warnings being treated as errors
scripts/Makefile.build:264 : la recette pour la cible « /home/Extension_2Series_1Parallele/LINUX/99xx.o » a échouée
make[2]: *** [/home/Extension_2Series_1Parallele/LINUX/99xx.o] Erreur 1
Makefile:1403 : la recette pour la cible « _module_/home/Extension_2Series_1Parallele/LINUX » a échouée
make[1]: *** [_module_/home/Extension_2Series_1Parallele/LINUX] Erreur 2
make[1] : on quitte le répertoire « /usr/src/linux-headers-4.4.0-31-generic »
Makefile:27 : la recette pour la cible « default » a échouée
make: *** [default] Erreur 2

Hors ligne

#5 Le 20/07/2016, à 02:36

MicP

Re : Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

Depuis mon répertoire personnel, je viens de télécharger et décompresser le fichier accessible par le lien web suivant : ASIX : MCS99xx_LINUX_Driver_v3.1.0_Source.tar.gz (25,1KB)

$ wget --quiet --output-document=- http://www.asix.com.tw/FrootAttach/driver/MCS99xx_LINUX_Driver_v3.1.0_Source.tar.gz | tar -zxvf -

La décompression a créé un sous-répertoire ~/MCS99xx_LINUX_Driver_v3.1.0_Source/

Ensuite je me suis positionné dans ce répertoire pour exécuter la commande make

$ cd ~/MCS99xx_LINUX_Driver_v3.1.0_Source/ && make
rm -f *.mod.c *.o *.ko .*.cmd *.symvers
make -C /lib/modules/3.16.0-4-amd64/build/  SUBDIRS=/home/michel/MCS99xx_LINUX_Driver_v3.1.0_Source modules
make[1]: Entering directory '/usr/src/linux-headers-3.16.0-4-amd64'
Makefile:10: *** mixed implicit and normal rules: deprecated syntax
make[1]: Entering directory `/usr/src/linux-headers-3.16.0-4-amd64'
  CC [M]  /home/michel/MCS99xx_LINUX_Driver_v3.1.0_Source/99xx.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/michel/MCS99xx_LINUX_Driver_v3.1.0_Source/99xx.mod.o
  LD [M]  /home/michel/MCS99xx_LINUX_Driver_v3.1.0_Source/99xx.ko
make[1]: Leaving directory '/usr/src/linux-headers-3.16.0-4-amd64'
gcc -pthread select_BR.c -o select_BR
gcc -pthread advanced_BR.c -o advanced_BR
gcc -pthread gpio_99xx.c -o gpio_99xx

la commande make s'est déroulée sans aucune erreur,
et les fichiers suivants ont été créés dans le répertoire  ~/MCS99xx_LINUX_Driver_v3.1.0_Source/

-rwxr-xr-x 1 michel michel   9864 juil. 20 02:16 gpio_99xx
-rwxr-xr-x 1 michel michel  11400 juil. 20 02:16 advanced_BR
-rwxr-xr-x 1 michel michel   9368 juil. 20 02:16 select_BR
-rw-r--r-- 1 michel michel 421872 juil. 20 02:16 99xx.ko
-rw-r--r-- 1 michel michel  67176 juil. 20 02:16 99xx.mod.o
-rw-r--r-- 1 michel michel   3451 juil. 20 02:16 99xx.mod.c
-rw-r--r-- 1 michel michel      0 juil. 20 02:16 Module.symvers
-rw-r--r-- 1 michel michel     63 juil. 20 02:16 modules.order
-rw-r--r-- 1 michel michel 359648 juil. 20 02:16 99xx.o

=======
Mais bon… j'utilise debian version 8.5 (jessie) :

$ uname -srv
Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-2+deb8u3 (2016-07-02)

alors que tu utilise la version 4.4.0-31-generic du noyau Linux.

Je n'ai pas trouvé de version plus récente des sources de ce pilote
et je ne sais pas quelle version tu as utilisé comme source,
mais AMHA tu devrais faire un test en utilisant la version que j'ai téléchargé
car je pense que la version qui est fournie dans le CD n'est pas forcement à jour (=> version 2.0.0 au lieu de 3.1.0)

Dernière modification par MicP (Le 20/07/2016, à 06:57)

Hors ligne

#6 Le 21/07/2016, à 00:44

Aurel05

Re : Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

Ok donc j'ai téléchargé le driver indiqué, réussi la compilation, installé puis chargé le module.
Après un set serial, j'ouvre deux invite de commande. Dans l'une un

cat /dev/ttyS0

et dans l'autre un

echo a >> /dev/ttyS0

Quand je shunt le cat ne m'affiche rien. Aussi je doute que le driver fonctionne. Je vais essayer de faire d'autres test.
Merci

Dernière modification par Aurel05 (Le 21/07/2016, à 00:44)

Hors ligne

#7 Le 21/07/2016, à 02:09

MicP

Re : Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co

Bonjour

Content que tu ais réussi la compilation des fichiers sources.

Il est possible que le système ait besoin d'être réinitialisé pour que les ports puissent êtres utilisables.
Ce doit aussi être faisable à chaud, mais un système qui démarre fera sans doute mieux le travail.

Il reste aussi à vérifier les droits et privilèges d'accès à ces fichiers de périphériques qui dépendent du système et bien sûr de l'appartenance de l'utilisateur au groupe (en général, c'est dialout ) ce qui lui permettra d'y accéder.
la commande id te permettra de connaître les groupes auxquels ton compte utilisateur appartiens,
et si besoin :

sudo /usr/bin/usermod -G dialout $USER

te permettra d'ajouter ton compte utilisateur au groupe dialout.

Il faudra  sans doute initialiser ces ports RS232 pour qu'ils puissent communiquer (baud, parité, Nbr bits, bit de stop, contrôle de flux…etc.)
Pour ça, j'aimais bien minicom  : Son interface texte est très conviviale, mais un simple terminal fait aussi bien l'affaire quand on connaît son matériel, sa configuration, et les différentes commandes nécessaires

Ça fait très longtemps que je n'ai pas utilisé un port RS232, et les systèmes Linux ont beaucoup changé ces derniers temps (cgroups, systemd, etc.)…

Dernière modification par MicP (Le 21/07/2016, à 16:49)

Hors ligne