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

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