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

Topic attachments
I Attachment Action Size Date Who Comment
99xx-uart.patchpatch 99xx-uart.patch manage 4 K 28 Jul 2011 - 14:52 StephenCavilia Patch for 99xx.c in non-cascade driver
MCS9900_Linux.tar.gzgz MCS9900_Linux.tar.gz manage 36 K 28 Jul 2011 - 14:51 StephenCavilia original MCS9900 driver version 1.0.0.0
Topic revision: r1 - 28 Jul 2011, StephenCavilia
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding CodenamePending? Send feedback