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                 tmp_termios = *tty->termios;
 102                 memcpy_fromfs(&tmp_termio, (struct termio *) arg,
 103                               sizeof (struct termio));
 104 
 105 #define SET_LOW_BITS(x,y)       ((x) = (0xffff0000 & (x)) | (y))
 106                 SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
 107                 SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
 108                 SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
 109                 SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
 110                 memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
 111 #undef SET_LOW_BITS
 112         } else
 113                 memcpy_fromfs(&tmp_termios, (struct termios *) arg,
 114                               sizeof (struct termios));
 115 
 116         if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
 117                 tty->ldisc.flush_buffer(tty);
 118 
 119         if (opt & TERMIOS_WAIT)
 120                 wait_until_sent(tty, 0);
 121 
 122         cli();
 123         *tty->termios = tmp_termios;
 124         unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
 125         canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
 126         if (canon_change) {
 127                 memset(&tty->read_flags, 0, sizeof tty->read_flags);
 128                 tty->canon_head = tty->read_tail;
 129                 tty->canon_data = 0;
 130                 tty->erasing = 0;
 131         }
 132         sti();
 133         if (canon_change && !L_ICANON(tty) && tty->read_cnt)
 134                 /* Get characters left over from canonical mode. */
 135                 wake_up_interruptible(&tty->read_wait);
 136 
 137         /* see if packet mode change of state */
 138 
 139         if (tty->link && tty->link->packet) {
 140                 int old_flow = ((old_termios.c_iflag & IXON) &&
 141                                 (old_termios.c_cc[VSTOP] == '\023') &&
 142                                 (old_termios.c_cc[VSTART] == '\021'));
 143                 int new_flow = (I_IXON(tty) &&
 144                                 STOP_CHAR(tty) == '\023' &&
 145                                 START_CHAR(tty) == '\021');
 146                 if (old_flow != new_flow) {
 147                         tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
 148                         if (new_flow)
 149                                 tty->ctrl_status |= TIOCPKT_DOSTOP;
 150                         else
 151                                 tty->ctrl_status |= TIOCPKT_NOSTOP;
 152                         wake_up_interruptible(&tty->link->read_wait);
 153                 }
 154         }
 155 
 156         if (tty->driver.set_termios)
 157                 (*tty->driver.set_termios)(tty, &old_termios);
 158 
 159         if (tty->ldisc.set_termios)
 160                 (*tty->ldisc.set_termios)(tty, &old_termios);
 161                 
 162         return 0;
 163 }
 164 
 165 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167         int i;
 168         struct termio tmp_termio;
 169 
 170         i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
 171         if (i)
 172                 return i;
 173         tmp_termio.c_iflag = tty->termios->c_iflag;
 174         tmp_termio.c_oflag = tty->termios->c_oflag;
 175         tmp_termio.c_cflag = tty->termios->c_cflag;
 176         tmp_termio.c_lflag = tty->termios->c_lflag;
 177         tmp_termio.c_line = tty->termios->c_line;
 178         for(i=0 ; i < NCC ; i++)
 179                 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
 180         memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
 181         return 0;
 182 }
 183 
 184 static unsigned long inq_canon(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186         int nr, head, tail;
 187 
 188         if (!tty->canon_data || !tty->read_buf)
 189                 return 0;
 190         head = tty->canon_head;
 191         tail = tty->read_tail;
 192         nr = (head - tail) & (N_TTY_BUF_SIZE-1);
 193         /* Skip EOF-chars.. */
 194         while (head != tail) {
 195                 if (test_bit(tail, &tty->read_flags) &&
 196                     tty->read_buf[tail] == __DISABLED_CHAR)
 197                         nr--;
 198                 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
 199         }
 200         return nr;
 201 }
 202 
 203 int n_tty_ioctl(struct tty_struct * tty, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 204                        unsigned int cmd, unsigned long arg)
 205 {
 206         struct tty_struct * real_tty;
 207         int retval;
 208         int opt = 0;
 209 
 210         if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 211             tty->driver.subtype == PTY_TYPE_MASTER)
 212                 real_tty = tty->link;
 213         else
 214                 real_tty = tty;
 215 
 216         switch (cmd) {
 217                 case TCGETS:
 218                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 219                                              sizeof (struct termios));
 220                         if (retval)
 221                                 return retval;
 222                         memcpy_tofs((struct termios *) arg,
 223                                     real_tty->termios,
 224                                     sizeof (struct termios));
 225                         return 0;
 226                 case TCSETSF:
 227                         opt |= TERMIOS_FLUSH;
 228                 case TCSETSW:
 229                         opt |= TERMIOS_WAIT;
 230                 case TCSETS:
 231                         return set_termios(real_tty, arg, opt);
 232                 case TCGETA:
 233                         return get_termio(real_tty,(struct termio *) arg);
 234                 case TCSETAF:
 235                         opt |= TERMIOS_FLUSH;
 236                 case TCSETAW:
 237                         opt |= TERMIOS_WAIT;
 238                 case TCSETA:
 239                         return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
 240                 case TCXONC:
 241                         retval = tty_check_change(tty);
 242                         if (retval)
 243                                 return retval;
 244                         switch (arg) {
 245                         case TCOOFF:
 246                                 stop_tty(tty);
 247                                 break;
 248                         case TCOON:
 249                                 start_tty(tty);
 250                                 break;
 251                         case TCIOFF:
 252                                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
 253                                         tty->driver.write(tty, 0,
 254                                                           &STOP_CHAR(tty), 1);
 255                                 break;
 256                         case TCION:
 257                                 if (START_CHAR(tty) != __DISABLED_CHAR)
 258                                         tty->driver.write(tty, 0,
 259                                                           &START_CHAR(tty), 1);
 260                                 break;
 261                         default:
 262                                 return -EINVAL;
 263                         }
 264                         return 0;
 265                 case TCFLSH:
 266                         retval = tty_check_change(tty);
 267                         if (retval)
 268                                 return retval;
 269                         switch (arg) {
 270                         case TCIFLUSH:
 271                                 if (tty->ldisc.flush_buffer)
 272                                         tty->ldisc.flush_buffer(tty);
 273                                 break;
 274                         case TCIOFLUSH:
 275                                 if (tty->ldisc.flush_buffer)
 276                                         tty->ldisc.flush_buffer(tty);
 277                                 /* fall through */
 278                         case TCOFLUSH:
 279                                 if (tty->driver.flush_buffer)
 280                                         tty->driver.flush_buffer(tty);
 281                                 break;
 282                         default:
 283                                 return -EINVAL;
 284                         }
 285                         return 0;
 286                 case TIOCOUTQ:
 287                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 288                                              sizeof (unsigned long));
 289                         if (retval)
 290                                 return retval;
 291                         if (tty->driver.chars_in_buffer)
 292                                 put_fs_long(tty->driver.chars_in_buffer(tty),
 293                                             (unsigned long *) arg);
 294                         else
 295                                 put_fs_long(0, (unsigned long *) arg);
 296                         return 0;
 297                 case TIOCINQ:
 298                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 299                                              sizeof (unsigned long));
 300                         if (retval)
 301                                 return retval;
 302                         if (L_ICANON(tty))
 303                                 put_fs_long(inq_canon(tty),
 304                                         (unsigned long *) arg);
 305                         else
 306                                 put_fs_long(tty->read_cnt,
 307                                             (unsigned long *) arg);
 308                         return 0;
 309                 case TIOCGLCKTRMIOS:
 310                         arg = get_fs_long((unsigned long *) arg);
 311                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 312                                              sizeof (struct termios));
 313                         if (retval)
 314                                 return retval;
 315                         memcpy_tofs((struct termios *) arg,
 316                                     &real_tty->termios_locked,
 317                                     sizeof (struct termios));
 318                         return 0;
 319                 case TIOCSLCKTRMIOS:
 320                         if (!suser())
 321                                 return -EPERM;
 322                         arg = get_fs_long((unsigned long *) arg);
 323                         memcpy_fromfs(&real_tty->termios_locked,
 324                                       (struct termios *) arg,
 325                                       sizeof (struct termios));
 326                         return 0;
 327                 case TIOCPKT:
 328                         if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
 329                             tty->driver.subtype != PTY_TYPE_MASTER)
 330                                 return -ENOTTY;
 331                         retval = verify_area(VERIFY_READ, (void *) arg,
 332                                              sizeof (unsigned long));
 333                         if (retval)
 334                                 return retval;
 335                         if (get_fs_long(arg)) {
 336                                 if (!tty->packet) {
 337                                         tty->packet = 1;
 338                                         tty->link->ctrl_status = 0;
 339                                 }
 340                         } else
 341                                 tty->packet = 0;
 342                         return 0;
 343                 /* These two ioctl's always return success; even if */
 344                 /* the driver doesn't support them. */
 345                 case TCSBRK: case TCSBRKP:
 346                         retval = tty_check_change(tty);
 347                         if (retval)
 348                                 return retval;
 349                         wait_until_sent(tty, 0);
 350                         if (!tty->driver.ioctl)
 351                                 return 0;
 352                         tty->driver.ioctl(tty, file, cmd, arg);
 353                         return 0;
 354                 default:
 355                         return -ENOIOCTLCMD;
 356                 }
 357 }

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