#1 Le 19/07/2016, à 21:01
- Aurel05
Installation Carte 2*ports COM et 1*Port Parallèle ASIX Electronics Co
Bonjour à tous;
Ayant (encore ) 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
, 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"
.
Je ne parviens pas à avoir de détail et je ne comprends pas ce qui bloque.
Si quelqu'un a une idée, merci
Contenu du readme :
The Following files will be there with the tar of the Driver:
99xx.c
99xx.h
Makefile
README
mcs99xx
ioctl.c
ioctl.h
99xx_ReleaseNotesBuilding the Driver:
--------------------
Change to the folder with the Starex source files. And run the following Command:
$ makeOnce 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 installUninstalling the Driver:
------------------------To un-install the driver use the following command:
make uninstallFeatures 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 characterAn 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:
$ makeOnce 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, à 22: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, à 00: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 ). 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, à 01: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, à 01: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, à 05:57)
Hors ligne
#6 Le 20/07/2016, à 23: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 20/07/2016, à 23:44)
Hors ligne
#7 Le 21/07/2016, à 01: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, à 15:49)
Hors ligne