MosChip?/NetMos MCS99xx Serial Cards
The
MosChip? MCS9900 series are PCI Express I/O cards, including the 9904 tested here with 4 serial ports and other chips providing different configurations of serial and parallel ports. The cards are compatible with a standard 16450/16550/16650 UART, but do not work with the default serial driver for some reason. A driver from
MosChip? for Linux is available but unfortunately it does not compile on newer kernels (after about 2.6.32) due to changes in the core serial code.
Device Information
Sample of
lspci -v output (there will be multiple chips/functions shown on each card for the different ports available):
05:00.0 Serial controller: NetMos Technology Device 9904 (prog-if 02 [16550])
Subsystem: Device a000:1000
Flags: bus master, fast devsel, latency 0, IRQ 17
I/O ports at ece0 [size=8]
Memory at dfbf0000 (32-bit, non-prefetchable) [size=4K]
Memory at dfbf2000 (32-bit, non-prefetchable) [size=4K]
Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [78] Power Management version 3
Capabilities: [80] Express Legacy Endpoint, MSI 00
Capabilities: [100] Virtual Channel
Capabilities: [800] Advanced Error Reporting
Kernel driver in use: saturn
saturn is the driver provided by the
99xx kernel module. This card requires the "non-cascade" driver.
Driver
The driver published by
MosChip? is GPL2 and based on the stock 8250 driver. It can be downloaded from
http://moschip.com/file_download.php?folder=MCS9900&fileid=MCS9900_Linux.tar.gz after registering for an account.
Patch
--- MCS9900_Linux/MCS9900_NonCascade/MCS99XX_V_1.0.0.0/99xx.c 2010-02-09 06:40:28.000000000 -0500
+++ MCS9900_Linux-new/MCS9900_NonCascade/MCS99XX_V_1.0.0.0/99xx.c 2011-07-28 10:46:15.733197673 -0400
@@ -495,7 +495,11 @@ static void serial99xx_start_tx(struct u
#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;
@@ -608,7 +612,11 @@ static _INLINE_ void check_modem_status(
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__);
}
@@ -622,8 +630,10 @@ static _INLINE_ void receive_chars(struc
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26))
struct tty_struct *tty = up->port.info->tty;
-#else
+#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;
@@ -710,7 +720,12 @@ ignore_char:
//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__);
@@ -758,7 +773,12 @@ static _INLINE_ void transmit_chars(stru
//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
@@ -774,7 +794,12 @@ static void transmit_chars_dma_stop_done
//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)
{
- struct circ_buf *xmit = &(up->port.info->xmit);
+#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__);
@@ -859,8 +884,10 @@ static void receive_chars_dma_done(struc
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26))
struct tty_struct *tty = up->port.info->tty;
-#else
+#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,rxdma_done=0;
@@ -969,11 +996,12 @@ static inline void serial99xx_handle_por
u8 status = serial_in(up, UART_LSR);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26))
- struct tty_struct *tty=up->port.info->tty;
-#else
+ 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);
@@ -1862,7 +1890,7 @@ int serial99xx_match_port(struct uart_po
return 0;
}
-static DECLARE_MUTEX(serial99xx_sem);
+static DEFINE_SEMAPHORE(serial99xx_sem);
static struct uart_driver starex_serial_driver = {
.owner = THIS_MODULE,
This has been tested against 2.6.38.
--
StephenCavilia - 28 Jul 2011