Facebook Social Icon Twitter Social Icon YouTube Social Icon

Using Moxa NPort 5450 Serial to IP Server with Linux Kernel Version 3.8.0 (tested with Ubuntu 13.04)

From M.Eng. René Schwarz, Bremen/Merseburg
Jump to: navigation, search

Unfortunately, Moxa's NPort Real TTY Driver for Linux is currently (version 1.18, released 2012/03/20) not compatible with Linux kernel 3.8.0. When I tried to install this driver for the NPort 5450 Serial to IP Server on my Ubuntu 13.04 machine (currently with kernel 3.8.0-27), the driver didn't compile. It turned out, that it is possible to patch the driver source code in order to get it work with Linux kernel 3.8.0 – here is a short documentation what I did.


Building the Patched Driver

  1. Download the NPort Real TTY Driver for Linux in version 1.18.7 Build 13050317 from this forum post (unofficial build, Russian forum)
  2. Prepare the code base for compilation:
    user@ubuntu:~$ tar -xzvf npreal2_1.18.7_Build_13050317.tgz -C /tmp
    user@ubuntu:~$ cd /tmp/moxa
    user@ubuntu:/tmp/moxa$ wget https://downloads.rene-schwarz.com/download/npreal2.c_1-18-7_b13050317.patch
    user@ubuntu:/tmp/moxa$ patch < npreal2.c_1-18-7_b13050317.patch
    • Extract the driver source code to /tmp (line 1).
    • Download the patch for npreal2.c from here (lines 2 et seq.).
    • Patch the C source file npreal2.c (line 4).
  3. You are now ready to compile and install the driver (root privileges required):
    user@ubuntu:/tmp/moxa$ sudo ./mxinst
  4. The driver should compile now without any errors. If so, the driver should be properly installed now and you can configure it (please refer to /tmp/moxa/README.TXT).


Changes for Linux Kernel 3.8.0

The changes that were necessary to let the driver compile against the Linux kernel 3.8.0 are the following (identical to the patch provided above):

--- npreal2.c	Fri May 03 11:52:43 2013
+++ npreal2.c	Tue Aug 06 16:58:36 2013
@@ -426,6 +426,39 @@
 static struct semaphore 	npvar_tmp_buf_sem = MUTEX;
 #endif
 
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+struct n_tty_data {
+	unsigned int column;
+	unsigned long overrun_time;
+	int num_overrun;
+
+	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+	unsigned char echo_overrun:1;
+
+	DECLARE_BITMAP(process_char_map, 256);
+	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
+
+	char *read_buf;
+	int read_head;
+	int read_tail;
+	int read_cnt;
+	int minimum_to_wake;
+
+	unsigned char *echo_buf;
+	unsigned int echo_pos;
+	unsigned int echo_cnt;
+
+	int canon_data;
+	unsigned long canon_head;
+	unsigned int canon_column;
+
+	struct mutex atomic_read_lock;
+	struct mutex output_lock;
+	struct mutex echo_lock;
+	raw_spinlock_t read_lock;
+};
+#endif
+
 #if (LINUX_VERSION_CODE < VERSION_CODE(2,4,0))
 static struct inode_operations npreal_net_iops;
 #endif
@@ -3436,7 +3469,21 @@
 }
 #endif
 
-#if ((LINUX_VERSION_CODE > VERSION_CODE(2,6,15)) || ((LINUX_VERSION_CODE == VERSION_CODE(2,6,15)) && defined(FEDORA)))
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+    /* Dumb strategy for now - should keep some stats */
+    /* 	printk("Flip dispose %p\n", b); */
+    if (b->size >= 512)
+        kfree(b);
+    else
+    {
+        b->next = tty->port->buf.free;
+        tty->port->buf.free = b;
+    }
+}
+#endif
+#if ((LINUX_VERSION_CODE > VERSION_CODE(2,6,15) && LINUX_VERSION_CODE < VERSION_CODE(3,8,0)) || ((LINUX_VERSION_CODE == VERSION_CODE(2,6,15)) && defined(FEDORA)))
 static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
 {
     /* Dumb strategy for now - should keep some stats */
@@ -3514,11 +3561,20 @@
         tty->ldisc.receive_buf(tty, cp, fp, count);
         //DBGPRINT(MX_DEBUG_TRACE, "flush %d bytes\n", count);
 #else
-        spin_lock_irqsave(&tty->buf.lock, flags);
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+        spin_lock_irqsave(&tty->port->buf.lock, flags);
+	head = tty->port->buf.head;
+#else
+        spin_lock_irqsave(&tty->port->buf.lock, flags);
         head = tty->buf.head;
+#endif
         if (head != NULL)
         {
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+            tty->port->buf.head = NULL;
+#else
             tty->buf.head = NULL;
+#endif
             for (;;)
             {
                 count = head->commit - head->read;
@@ -3545,17 +3601,29 @@
                 cp = head->char_buf_ptr + head->read;
                 fp = head->flag_buf_ptr + head->read;
                 head->read += count;
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+                spin_unlock_irqrestore(&tty->port->buf.lock, flags);
+#else
                 spin_unlock_irqrestore(&tty->buf.lock, flags);
+#endif
 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,27))
                 disc->ops->receive_buf(tty, cp, fp, count);
 #else
                 disc->receive_buf(tty, cp, fp, count);
 #endif
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+                spin_lock_irqsave(&tty->port->buf.lock, flags);
+            }
+            tty->port->buf.head = head;
+        }
+        spin_unlock_irqrestore(&tty->port->buf.lock, flags);
+#else
                 spin_lock_irqsave(&tty->buf.lock, flags);
             }
             tty->buf.head = head;
         }
         spin_unlock_irqrestore(&tty->buf.lock, flags);
+#endif
         tty_ldisc_deref(disc);
 #endif
     }
@@ -4303,6 +4371,7 @@
     int cnt;
     struct npreal_struct *info;
     struct tty_struct *	tty;
+    struct n_tty_data *ldata;
 
     /*
      *  Get the node pointer, and quit if it doesn't exist.
@@ -4350,6 +4419,10 @@
         up(&info->rx_semaphore);
         goto done;
     }
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+    ldata = tty->disc_data;
+#endif
+
 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
 #if 1
     if(!info->tty->low_latency)
@@ -4392,8 +4465,11 @@
         	* that erase characters will be handled.  Other excess
         	* characters will be beeped.
         	*/
-
-        if (!tty->icanon || tty->canon_data)
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+	if (!ldata->icanon || ldata->canon_data)
+#else
+	if (!tty->icanon || tty->canon_data)
+#endif
         {
 #if (LINUX_VERSION_CODE <  VERSION_CODE(2,1,0))
             if (!set_bit(TTY_THROTTLED,&tty->flags))
@@ -4408,9 +4484,15 @@
         up(&info->rx_semaphore);
         goto done;
     }
+#if (LINUX_VERSION_CODE >= VERSION_CODE(3,8,0))
+    if (!ldata->icanon || ldata->canon_data)
+    {
+        if ((cnt = MIN(cnt,(N_TTY_BUF_SIZE-1) - ldata->read_cnt )) <= 0)
+#else
     if (!tty->icanon || tty->canon_data)
     {
         if ((cnt = MIN(cnt,(N_TTY_BUF_SIZE-1) - tty->read_cnt )) <= 0)
+#endif
         {
 
             /*


Driver Support for Other Moxa Products

This driver should also work for other Moxa products, namely the following ones:

  • CN2510 Series
  • CN2610/2650 Series
  • MiiNePort E1 Series
  • MiiNePort E2 Series
  • MiiNePort E3 Series
  • MiiNePort W1 Series
  • NE-4000T/NE-4000T-ST
  • NE-4100T
  • NE-4110A
  • NE-4110S
  • NE-4120A
  • NE-4120S
  • NPort 5110/5130/5150 Series
  • NPort 5110A/5130A/5150A Series
  • NPort 5130
  • NPort 5150
  • NPort 5150AI-M12/5250AI-M12/5450AI-M12 Series
  • NPort 5210/5230/5232 Series
  • NPort 5210A/5230A/5250A Series
  • NPort 5230 Series
  • NPort 5410/5430/5450 Series
  • NPort 5430 Series
  • NPort 5450 Series
  • NPort 5600-8-DT/5650-8-DT Series
  • NPort 5610/5630 Series
  • NPort 5610-8-DTL/5650-8-DTL Series
  • NPort 5650 Series
  • NPort 6150 Series
  • NPort 6250 Series
  • NPort 6450 Series
  • NPort 6610/6650 Series
  • NPort DE-311M
  • NPort Express DE-211
  • NPort Express DE-311
  • NPort IA5150/5250 Series
  • NPort IA5150A/IA5250A/IA5450A Series
  • NPort P5150A Series
  • NPort S8455/S8458 Series
  • NPort Server Lite DE-301/302/304/331/332/334
  • NPort Server Pro DE-303, DE-308
  • NPort W2004 Series
  • NPort W2150/2250 Plus
  • NPort W2150A/W2250A
  • NPort W2250/2150
  • WE-2100T


References