tty: Add termiox
authorAlan Cox <alan@redhat.com>
Mon, 13 Oct 2008 09:38:18 +0000 (10:38 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Oct 2008 16:51:40 +0000 (09:51 -0700)
We need a way to describe the various additional modes and flow control
features that random weird hardware shows up and software such as wine
wants to emulate as Windows supports them.

TCGETX/TCSETX and the termiox ioctl are a SYS5 extension that we might as
well adopt. This patches adds the structures and the basic ioctl interfaces
when the TCGETX etc defines are added for an architecture. Drivers wishing
to use this stuff need to add new methods.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/char/tty_ioctl.c
include/asm-x86/ioctls.h
include/linux/termios.h
include/linux/tty.h
include/linux/tty_driver.h

index bf34e45974212fc46df349416646779d2e7d78dd..93bfa1d6cc92301e38cca48dbf99086a6dce2e78 100644 (file)
@@ -579,6 +579,50 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio)
        return 0;
 }
 
+
+#ifdef TCGETX
+
+/**
+ *     set_termiox     -       set termiox fields if possible
+ *     @tty: terminal
+ *     @arg: termiox structure from user
+ *     @opt: option flags for ioctl type
+ *
+ *     Implement the device calling points for the SYS5 termiox ioctl
+ *     interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct termiox tnew;
+       struct tty_ldisc *ld;
+
+       if (tty->termiox == NULL)
+               return -EINVAL;
+       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+               return -EFAULT;
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       mutex_lock(&tty->termios_mutex);
+       if (tty->ops->set_termiox)
+               tty->ops->set_termiox(tty, &tnew);
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+#endif
+
 static unsigned long inq_canon(struct tty_struct *tty)
 {
        int nr, head, tail;
@@ -936,6 +980,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                        return -EFAULT;
                        return 0;
 #endif
+#ifdef TCGETX
+       case TCGETX:
+               if (real_tty->termiox == NULL)
+                       return -EINVAL;
+               if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
+                       return -EFAULT;
+               return 0;
+       case TCSETX:
+               return set_termiox(real_tty, p, 0);
+       case TCSETXW:
+               return set_termiox(real_tty, p, TERMIOS_WAIT);
+       case TCSETXF:
+               return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif         
        case TIOCGSOFTCAR:
                /* FIXME: for correctness we may need to take the termios
                   lock here - review */
index 1a8ac45b28be69af883b602911bae29b2f9fa692..06752a649044d2029c4c555f006635ff41d6b9f5 100644 (file)
 #define TIOCGPTN       _IOR('T', 0x30, unsigned int)
                                /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK     _IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX         0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX         0x5433
+#define TCSETXF                0x5434
+#define TCSETXW                0x5435
 
 #define FIONCLEX       0x5450
 #define FIOCLEX                0x5451
index 478662889f487db6fb1b8f6abba1bd781831a445..2acd0c1f8a2a305c8c7fc23895a6cba3cdd35ea8 100644 (file)
@@ -4,4 +4,19 @@
 #include <linux/types.h>
 #include <asm/termios.h>
 
+#define NFF    5
+
+struct termiox
+{
+       __u16   x_hflag;
+       __u16   x_cflag;
+       __u16   x_rflag[NFF];
+       __u16   x_sflag;
+};
+
+#define        RTSXOFF         0x0001          /* RTS flow control on input */
+#define        CTSXON          0x0002          /* CTS flow control on output */
+#define        DTRXOFF         0x0004          /* DTR flow control on input */
+#define DSRXON         0x0008          /* DCD flow control on output */
+
 #endif
index b6e6c26883ee789463eb04f10b6a3424dc9142c5..b64d10b66548141e05cebae006ea5e24fef0360d 100644 (file)
@@ -219,6 +219,7 @@ struct tty_struct {
        spinlock_t ctrl_lock;
        /* Termios values are protected by the termios mutex */
        struct ktermios *termios, *termios_locked;
+       struct termiox *termiox;        /* May be NULL for unsupported */
        char name[64];
        struct pid *pgrp;               /* Protected by ctrl lock */
        struct pid *session;
index 16d27944c3211af2f954fa6fff4950d3c3591812..ac6e58e26b73f4f9d55ab5e32a188c783dd9d3c5 100644 (file)
  *     not force errors here if they are not resizable objects (eg a serial
  *     line). See tty_do_resize() if you need to wrap the standard method
  *     in your own logic - the usual case.
+ *
+ * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
+ *
+ *     Called when the device receives a termiox based ioctl. Passes down
+ *     the requested data from user space. This method will not be invoked
+ *     unless the tty also has a valid tty->termiox pointer.
+ *
+ *     Optional: Called under the termios lock
  */
 
 #include <linux/fs.h>
@@ -220,6 +228,7 @@ struct tty_operations {
                        unsigned int set, unsigned int clear);
        int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
                                struct winsize *ws);
+       int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
 #ifdef CONFIG_CONSOLE_POLL
        int (*poll_init)(struct tty_driver *driver, int line, char *options);
        int (*poll_get_char)(struct tty_driver *driver, int line);