Passing tty cflag to serial implementation.
authorFlorian Pose <fp@igh-essen.com>
Thu, 21 Jan 2010 17:53:40 +0100
changeset 1779 9fab229d6ca9
parent 1778 94dbb44884ec
child 1780 11f452ca4d7a
Passing tty cflag to serial implementation.
examples/tty/serial.c
include/ectty.h
tty/module.c
--- a/examples/tty/serial.c	Thu Jan 21 16:41:41 2010 +0100
+++ b/examples/tty/serial.c	Thu Jan 21 17:53:40 2010 +0100
@@ -29,6 +29,7 @@
 
 #include <linux/module.h>
 #include <linux/err.h>
+#include <linux/termios.h>
 
 #include "../../include/ecrt.h" // EtherCAT realtime interface
 #include "../../include/ectty.h" // EtherCAT TTY interface
@@ -200,12 +201,45 @@
 
 /****************************************************************************/
 
+int el6002_cflag_changed(void *data, unsigned short cflag)
+{
+    el6002_t *ser = (el6002_t *) data;
+    int cs = 0, stop, par;
+
+    printk(KERN_INFO PFX "%s(data=%p, cflag=%x).\n", __func__, ser, cflag);
+
+    switch (cflag & CSIZE) {
+        case CS7:
+            cs = 7;
+            break;
+        case CS8:
+            cs = 8;
+            break;
+        default: /* CS5 or CS6 */
+            return -EINVAL; // not supported
+    }
+
+    stop = (cflag & CSTOPB) ? 2 : 1;
+
+    if (cflag & PARENB) {
+        par = (cflag & PARODD) ? 1 : 2;
+    } else {
+        par = 0;
+    }
+
+    printk(KERN_INFO PFX "CS%u stopb=%u par=%i.\n", cs, stop, par);
+
+    return 0;
+}
+
+/****************************************************************************/
+
 int el6002_init(el6002_t *ser, ec_master_t *master, u16 position,
         ec_domain_t *domain)
 {
     int ret = 0;
 
-    ser->tty = ectty_create();
+    ser->tty = ectty_create(el6002_cflag_changed, ser);
     if (IS_ERR(ser->tty)) {
         printk(KERN_ERR PFX "Failed to create tty.\n");
         ret = PTR_ERR(ser->tty);
--- a/include/ectty.h	Thu Jan 21 16:41:41 2010 +0100
+++ b/include/ectty.h	Thu Jan 21 17:53:40 2010 +0100
@@ -54,10 +54,19 @@
  *****************************************************************************/
 
 /** Create a virtual TTY interface.
- * 
+ *
+ * \param cflag_cb This callback function is called when the serial settings
+ * shall be changed. The \a cb_data argument is the same as the \a cb_data
+ * given on device creation, while the \a cflag argument contains the new
+ * settings.
+ * \param cb_data Arbitrary data to pass to callbacks.
+ *
  * \return Pointer to the interface object, otherwise an ERR_PTR value.
  */
-ec_tty_t *ectty_create(void);
+ec_tty_t *ectty_create(
+        int (*cflag_cb)(void *cb_data, unsigned short cflag),
+        void *cb_data
+        );
 
 /******************************************************************************
  * TTY interface methods
--- a/tty/module.c	Thu Jan 21 16:41:41 2010 +0100
+++ b/tty/module.c	Thu Jan 21 17:53:40 2010 +0100
@@ -107,6 +107,9 @@
 
     struct timer_list timer;
     struct tty_struct *tty;
+
+    int (*cflag_cb)(void *, unsigned short);
+    void *cb_data;
 };
 
 static const struct tty_operations ec_tty_ops; // see below
@@ -242,10 +245,10 @@
         unsigned char *cbuf;
         int space = tty_prepare_flip_string(tty->tty, &cbuf, to_recv);
 
-		if (space < to_recv) {
-			printk(KERN_WARNING PFX "Insufficient space to_recv=%d space=%d\n",
+        if (space < to_recv) {
+            printk(KERN_WARNING PFX "Insufficient space to_recv=%d space=%d\n",
                     to_recv, space);
-		}
+        }
 
         if (space < 0) {
             to_recv = 0;
@@ -266,7 +269,7 @@
             }
             tty_flip_buffer_push(tty->tty);
         }
-	}
+    }
     
     tty->timer.expires += 1;
     add_timer(&tty->timer);
@@ -274,7 +277,8 @@
 
 /*****************************************************************************/
 
-int ec_tty_init(ec_tty_t *tty, int minor)
+int ec_tty_init(ec_tty_t *tty, int minor,
+        int (*cflag_cb)(void *, unsigned short), void *cb_data)
 {
     tty->minor = minor;
     tty->tx_read_idx = 0;
@@ -284,6 +288,8 @@
     tty->rx_write_idx = 0;
     init_timer(&tty->timer);
     tty->tty = NULL;
+    tty->cflag_cb = cflag_cb;
+    tty->cb_data = cb_data;
 
     tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
     if (IS_ERR(tty->dev)) {
@@ -310,17 +316,17 @@
 
 int ec_tty_get_serial_info(ec_tty_t *tty, struct serial_struct *data)
 {
-	struct serial_struct tmp;
-  
-	if (!data)
-		return -EFAULT;
-
-	memset(&tmp, 0, sizeof(tmp));
-    
-	if (copy_to_user(data, &tmp, sizeof(*data))) {
+    struct serial_struct tmp;
+
+    if (!data)
         return -EFAULT;
-    }
-	return 0;
+
+    memset(&tmp, 0, sizeof(tmp));
+
+    if (copy_to_user(data, &tmp, sizeof(*data))) {
+        return -EFAULT;
+    }
+    return 0;
 }
 
 /******************************************************************************
@@ -336,8 +342,8 @@
     printk(KERN_INFO PFX "Opening line %i.\n", line);
 #endif
 
-	if (line < 0 || line >= EC_TTY_MAX_DEVICES) {
-		return -ENXIO;
+    if (line < 0 || line >= EC_TTY_MAX_DEVICES) {
+        return -ENXIO;
     }
 
     t = ttys[line];
@@ -474,7 +480,7 @@
 /*****************************************************************************/
 
 static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
-		    unsigned int cmd, unsigned long arg)
+        unsigned int cmd, unsigned long arg)
 {
     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
     int ret = -ENOTTY;
@@ -487,8 +493,8 @@
 #endif
 
     switch (cmd) {
-		case TIOCGSERIAL:
-			if (access_ok(VERIFY_WRITE,
+        case TIOCGSERIAL:
+            if (access_ok(VERIFY_WRITE,
                         (void *) arg, sizeof(struct serial_struct))) {
                 ret = ec_tty_get_serial_info(t, (struct serial_struct *) arg);
             } else {
@@ -513,9 +519,10 @@
 /*****************************************************************************/
 
 static void ec_tty_set_termios(struct tty_struct *tty,
-			   struct ktermios *old_termios)
-{
-    //ec_tty_t *t = (ec_tty_t *) tty->driver_data;
+        struct ktermios *old_termios)
+{
+    ec_tty_t *t = (ec_tty_t *) tty->driver_data;
+    int ret;
 
 #if EC_TTY_DEBUG >= 2
     printk(KERN_INFO PFX "%s().\n", __func__);
@@ -528,6 +535,13 @@
     printk(KERN_INFO "cflag changed from %x to %x.\n",
             old_termios->c_cflag, tty->termios->c_cflag);
 #endif
+
+    ret = t->cflag_cb(t->cb_data, tty->termios->c_cflag);
+    if (ret) {
+        printk(KERN_ERR PFX "ERROR: cflag 0x%x not accepted.\n",
+                tty->termios->c_cflag);
+        tty->termios->c_cflag = old_termios->c_cflag;
+    }
 }
 
 /*****************************************************************************/
@@ -598,25 +612,25 @@
     .open = ec_tty_open,
     .close = ec_tty_close,
     .write = ec_tty_write,
-	.put_char = ec_tty_put_char,
-	.write_room = ec_tty_write_room,
-	.chars_in_buffer = ec_tty_chars_in_buffer,
-	.flush_buffer = ec_tty_flush_buffer,
-	.ioctl = ec_tty_ioctl,
-	.set_termios = ec_tty_set_termios,
-	.stop = ec_tty_stop,
-	.start = ec_tty_start,
-	.hangup = ec_tty_hangup,
-	.break_ctl = ec_tty_break,
-	.send_xchar = ec_tty_send_xchar,
-	.wait_until_sent = ec_tty_wait_until_sent,
+    .put_char = ec_tty_put_char,
+    .write_room = ec_tty_write_room,
+    .chars_in_buffer = ec_tty_chars_in_buffer,
+    .flush_buffer = ec_tty_flush_buffer,
+    .ioctl = ec_tty_ioctl,
+    .set_termios = ec_tty_set_termios,
+    .stop = ec_tty_stop,
+    .start = ec_tty_start,
+    .hangup = ec_tty_hangup,
+    .break_ctl = ec_tty_break,
+    .send_xchar = ec_tty_send_xchar,
+    .wait_until_sent = ec_tty_wait_until_sent,
 };
 
 /******************************************************************************
  * Public functions and methods
  *****************************************************************************/
 
-ec_tty_t *ectty_create(void)
+ec_tty_t *ectty_create(int (*cflag_cb)(void *, unsigned short), void *cb_data)
 {
     ec_tty_t *tty;
     int minor, ret;
@@ -636,7 +650,7 @@
                 return ERR_PTR(-ENOMEM);
             }
 
-            ret = ec_tty_init(tty, minor);
+            ret = ec_tty_init(tty, minor, cflag_cb, cb_data);
             if (ret) {
                 up(&tty_sem);
                 kfree(tty);