root/drivers/char/tty_ioctl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wait_until_sent
  2. unset_locked_termios
  3. set_termios_2
  4. set_termios
  5. get_termio
  6. set_termio
  7. inq_canon
  8. n_tty_ioctl

   1 /*
   2  *  linux/kernel/drivers/char/tty_ioctl.c
   3  *
   4  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   5  *
   6  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
   7  * which can be dynamically activated and de-activated by the line
   8  * discipline handling modules (like SLIP).
   9  */
  10 
  11 #include <linux/types.h>
  12 #include <linux/termios.h>
  13 #include <linux/errno.h>
  14 #include <linux/sched.h>
  15 #include <linux/config.h>
  16 #include <linux/kernel.h>
  17 #include <linux/major.h>
  18 #include <linux/tty.h>
  19 #include <linux/fcntl.h>
  20 #include <linux/string.h>
  21 
  22 #include <asm/io.h>
  23 #include <asm/bitops.h>
  24 #include <asm/segment.h>
  25 #include <asm/system.h>
  26 
  27 #undef  DEBUG
  28 #ifdef DEBUG
  29 # define        PRINTK(x)       printk (x)
  30 #else
  31 # define        PRINTK(x)       /**/
  32 #endif
  33 
  34 extern int session_of_pgrp(int pgrp);
  35 extern int kill_pg(int pgrp, int sig, int priv);
  36 
  37 void wait_until_sent(struct tty_struct * tty, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         struct wait_queue wait = { current, NULL };
  40 
  41         if (!tty->driver.chars_in_buffer ||
  42             !tty->driver.chars_in_buffer(tty))
  43                 return;
  44         add_wait_queue(&tty->write_wait, &wait);
  45         current->counter = 0;   /* make us low-priority */
  46         if (timeout)
  47                 current->timeout = timeout + jiffies;
  48         else
  49                 current->timeout = (unsigned) -1;
  50         do {
  51                 current->state = TASK_INTERRUPTIBLE;
  52                 if (current->signal & ~current->blocked)
  53                         break;
  54                 if (!tty->driver.chars_in_buffer(tty))
  55                         break;
  56                 schedule();
  57         } while (current->timeout);
  58         current->state = TASK_RUNNING;
  59         remove_wait_queue(&tty->write_wait, &wait);
  60 }
  61 
  62 static void unset_locked_termios(struct termios *termios,
     /* [previous][next][first][last][top][bottom][index][help] */
  63                                  struct termios *old,
  64                                  struct termios *locked)
  65 {
  66         int     i;
  67         
  68 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
  69 
  70         if (!locked) {
  71                 printk("Warning?!? termios_locked is NULL.\n");
  72                 return;
  73         }
  74 
  75         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  76         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  77         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  78         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  79         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
  80         for (i=0; i < NCCS; i++)
  81                 termios->c_cc[i] = locked->c_cc[i] ?
  82                         old->c_cc[i] : termios->c_cc[i];
  83 }
  84 
  85 static int set_termios_2(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87         struct termios old_termios = *tty->termios;
  88         int canon_change;
  89 
  90         cli();
  91         *tty->termios = *termios;
  92         unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
  93         canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
  94         if (canon_change) {
  95                 memset(&tty->read_flags, 0, sizeof tty->read_flags);
  96                 tty->canon_head = tty->read_tail;
  97                 tty->canon_data = 0;
  98                 tty->erasing = 0;
  99         }
 100         sti();
 101         if (canon_change && !L_ICANON(tty) && tty->read_cnt)
 102                 /* Get characters left over from canonical mode. */
 103                 wake_up_interruptible(&tty->read_wait);
 104 
 105         /* see if packet mode change of state */
 106 
 107         if (tty->link && tty->link->packet) {
 108                 int old_flow = ((old_termios.c_iflag & IXON) &&
 109                                 (old_termios.c_cc[VSTOP] == '\023') &&
 110                                 (old_termios.c_cc[VSTART] == '\021'));
 111                 int new_flow = (I_IXON(tty) &&
 112                                 STOP_CHAR(tty) == '\023' &&
 113                                 START_CHAR(tty) == '\021');
 114                 if (old_flow != new_flow) {
 115                         tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
 116                         if (new_flow)
 117                                 tty->ctrl_status |= TIOCPKT_DOSTOP;
 118                         else
 119                                 tty->ctrl_status |= TIOCPKT_NOSTOP;
 120                         wake_up_interruptible(&tty->link->read_wait);
 121                 }
 122         }
 123 
 124         if (tty->driver.set_termios)
 125                 (*tty->driver.set_termios)(tty, &old_termios);
 126 
 127         if (tty->ldisc.set_termios)
 128                 (*tty->ldisc.set_termios)(tty, &old_termios);
 129                 
 130         return 0;
 131 }
 132 
 133 static int set_termios(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         struct termios tmp_termios;
 136 
 137         memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
 138         return set_termios_2(tty, &tmp_termios);
 139 }
 140 
 141 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         int i;
 144         struct termio tmp_termio;
 145 
 146         i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
 147         if (i)
 148                 return i;
 149         tmp_termio.c_iflag = tty->termios->c_iflag;
 150         tmp_termio.c_oflag = tty->termios->c_oflag;
 151         tmp_termio.c_cflag = tty->termios->c_cflag;
 152         tmp_termio.c_lflag = tty->termios->c_lflag;
 153         tmp_termio.c_line = tty->termios->c_line;
 154         for(i=0 ; i < NCC ; i++)
 155                 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
 156         memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
 157         return 0;
 158 }
 159 
 160 static int set_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         struct termio tmp_termio;
 163         struct termios tmp_termios;
 164 
 165         tmp_termios = *tty->termios;
 166         memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
 167 
 168 #define SET_LOW_BITS(x,y)       ((x) = (0xffff0000 & (x)) | (y))
 169 
 170         SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
 171         SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
 172         SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
 173         SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
 174         memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
 175 
 176 #undef SET_LOW_BITS
 177 
 178         return set_termios_2(tty, &tmp_termios);
 179 }
 180 
 181 static unsigned long inq_canon(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 182 {
 183         int nr, head, tail;
 184 
 185         if (!tty->canon_data || !tty->read_buf)
 186                 return 0;
 187         head = tty->canon_head;
 188         tail = tty->read_tail;
 189         nr = (head - tail) & (N_TTY_BUF_SIZE-1);
 190         /* Skip EOF-chars.. */
 191         while (head != tail) {
 192                 if (test_bit(tail, &tty->read_flags) &&
 193                     tty->read_buf[tail] == __DISABLED_CHAR)
 194                         nr--;
 195                 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
 196         }
 197         return nr;
 198 }
 199 
 200 int n_tty_ioctl(struct tty_struct * tty, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 201                        unsigned int cmd, unsigned long arg)
 202 {
 203         struct tty_struct * real_tty;
 204         int retval;
 205 
 206         if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 207             tty->driver.subtype == PTY_TYPE_MASTER)
 208                 real_tty = tty->link;
 209         else
 210                 real_tty = tty;
 211 
 212         switch (cmd) {
 213                 case TCGETS:
 214                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 215                                              sizeof (struct termios));
 216                         if (retval)
 217                                 return retval;
 218                         memcpy_tofs((struct termios *) arg,
 219                                     real_tty->termios,
 220                                     sizeof (struct termios));
 221                         return 0;
 222                 case TCSETSF:
 223                 case TCSETSW:
 224                 case TCSETS:
 225                         retval = tty_check_change(real_tty);
 226                         if (retval)
 227                                 return retval;
 228                         if (cmd == TCSETSF || cmd == TCSETSW) {
 229                                 if (cmd == TCSETSF &&
 230                                     real_tty->ldisc.flush_buffer)
 231                                         real_tty->ldisc.flush_buffer(real_tty);
 232                                 wait_until_sent(real_tty, 0);
 233                         }
 234                         return set_termios(real_tty,
 235                                            (struct termios *) arg);
 236                 case TCGETA:
 237                         return get_termio(real_tty,(struct termio *) arg);
 238                 case TCSETAF:
 239                 case TCSETAW:
 240                 case TCSETA:
 241                         retval = tty_check_change(real_tty);
 242                         if (retval)
 243                                 return retval;
 244                         if (cmd == TCSETAF || cmd == TCSETAW) {
 245                                 if (cmd == TCSETAF &&
 246                                     real_tty->ldisc.flush_buffer)
 247                                         real_tty->ldisc.flush_buffer(real_tty);
 248                                 wait_until_sent(real_tty, 0);
 249                         }
 250                         return set_termio(real_tty, (struct termio *) arg);
 251                 case TCXONC:
 252                         retval = tty_check_change(tty);
 253                         if (retval)
 254                                 return retval;
 255                         switch (arg) {
 256                         case TCOOFF:
 257                                 stop_tty(tty);
 258                                 break;
 259                         case TCOON:
 260                                 start_tty(tty);
 261                                 break;
 262                         case TCIOFF:
 263                                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
 264                                         tty->driver.write(tty, 0,
 265                                                           &STOP_CHAR(tty), 1);
 266                                 break;
 267                         case TCION:
 268                                 if (START_CHAR(tty) != __DISABLED_CHAR)
 269                                         tty->driver.write(tty, 0,
 270                                                           &START_CHAR(tty), 1);
 271                                 break;
 272                         default:
 273                                 return -EINVAL;
 274                         }
 275                         return 0;
 276                 case TCFLSH:
 277                         retval = tty_check_change(tty);
 278                         if (retval)
 279                                 return retval;
 280                         switch (arg) {
 281                         case TCIFLUSH:
 282                                 if (tty->ldisc.flush_buffer)
 283                                         tty->ldisc.flush_buffer(tty);
 284                                 break;
 285                         case TCIOFLUSH:
 286                                 if (tty->ldisc.flush_buffer)
 287                                         tty->ldisc.flush_buffer(tty);
 288                                 /* fall through */
 289                         case TCOFLUSH:
 290                                 if (tty->driver.flush_buffer)
 291                                         tty->driver.flush_buffer(tty);
 292                                 break;
 293                         default:
 294                                 return -EINVAL;
 295                         }
 296                         return 0;
 297                 case TIOCOUTQ:
 298                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 299                                              sizeof (unsigned long));
 300                         if (retval)
 301                                 return retval;
 302                         if (tty->driver.chars_in_buffer)
 303                                 put_fs_long(tty->driver.chars_in_buffer(tty),
 304                                             (unsigned long *) arg);
 305                         else
 306                                 put_fs_long(0, (unsigned long *) arg);
 307                         return 0;
 308                 case TIOCINQ:
 309                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 310                                              sizeof (unsigned long));
 311                         if (retval)
 312                                 return retval;
 313                         if (L_ICANON(tty))
 314                                 put_fs_long(inq_canon(tty),
 315                                         (unsigned long *) arg);
 316                         else
 317                                 put_fs_long(tty->read_cnt,
 318                                             (unsigned long *) arg);
 319                         return 0;
 320                 case TIOCGLCKTRMIOS:
 321                         arg = get_fs_long((unsigned long *) arg);
 322                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 323                                              sizeof (struct termios));
 324                         if (retval)
 325                                 return retval;
 326                         memcpy_tofs((struct termios *) arg,
 327                                     &real_tty->termios_locked,
 328                                     sizeof (struct termios));
 329                         return 0;
 330                 case TIOCSLCKTRMIOS:
 331                         if (!suser())
 332                                 return -EPERM;
 333                         arg = get_fs_long((unsigned long *) arg);
 334                         memcpy_fromfs(&real_tty->termios_locked,
 335                                       (struct termios *) arg,
 336                                       sizeof (struct termios));
 337                         return 0;
 338                 case TIOCPKT:
 339                         if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
 340                             tty->driver.subtype != PTY_TYPE_MASTER)
 341                                 return -ENOTTY;
 342                         retval = verify_area(VERIFY_READ, (void *) arg,
 343                                              sizeof (unsigned long));
 344                         if (retval)
 345                                 return retval;
 346                         if (get_fs_long(arg)) {
 347                                 if (!tty->packet) {
 348                                         tty->packet = 1;
 349                                         tty->link->ctrl_status = 0;
 350                                 }
 351                         } else
 352                                 tty->packet = 0;
 353                         return 0;
 354                 /* These two ioctl's always return success; even if */
 355                 /* the driver doesn't support them. */
 356                 case TCSBRK: case TCSBRKP:
 357                         retval = tty_check_change(tty);
 358                         if (retval)
 359                                 return retval;
 360                         wait_until_sent(tty, 0);
 361                         if (!tty->driver.ioctl)
 362                                 return 0;
 363                         tty->driver.ioctl(tty, file, cmd, arg);
 364                         return 0;
 365                 default:
 366                         return -ENOIOCTLCMD;
 367                 }
 368 }

/* [previous][next][first][last][top][bottom][index][help] */