root/kernel/chr_drv/tty_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. change_speed
  2. flush
  3. flush_input
  4. wait_until_sent
  5. send_break
  6. do_get_ps_info
  7. get_termios
  8. set_termios
  9. get_termio
  10. set_termio
  11. set_window_size
  12. get_window_size
  13. tty_ioctl

   1 /*
   2  *  linux/kernel/chr_drv/tty_ioctl.c
   3  *
   4  *  (C) 1991  Linus Torvalds
   5  */
   6 
   7 #include <errno.h>
   8 #include <termios.h>
   9 #include <sys/types.h>
  10 
  11 #include <linux/sched.h>
  12 #include <linux/kernel.h>
  13 #include <linux/tty.h>
  14 
  15 #include <asm/io.h>
  16 #include <asm/segment.h>
  17 #include <asm/system.h>
  18 
  19 extern int session_of_pgrp(int pgrp);
  20 extern int do_screendump(int arg);
  21 extern int kill_pg(int pgrp, int sig, int priv);
  22 extern int vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg);
  23 
  24 static unsigned short quotient[] = {
  25         0, 2304, 1536, 1047, 857,
  26         768, 576, 384, 192, 96,
  27         64, 48, 24, 12, 6, 3
  28 };
  29 
  30 static void change_speed(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32         unsigned short port,quot;
  33 
  34         if (!(port = tty->read_q->data))
  35                 return;
  36         quot = quotient[tty->termios.c_cflag & CBAUD];
  37         cli();
  38         outb_p(0x80,port+3);            /* set DLAB */
  39         outb_p(quot & 0xff,port);       /* LS of divisor */
  40         outb_p(quot >> 8,port+1);       /* MS of divisor */
  41         outb(0x03,port+3);              /* reset DLAB */
  42         sti();
  43 }
  44 
  45 static void flush(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
  46 {
  47         if (queue) {
  48                 cli();
  49                 queue->head = queue->tail;
  50                 sti();
  51                 wake_up(&queue->proc_list);
  52         }
  53 }
  54 
  55 void flush_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         flush(tty->read_q);
  58         flush(tty->secondary);
  59         tty->secondary->data = 0;
  60         wake_up(&tty->read_q->proc_list);
  61 }
  62 
  63 static void wait_until_sent(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65         while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
  66                 TTY_WRITE_FLUSH(tty);
  67                 current->counter = 0;
  68                 cli();
  69                 if (EMPTY(tty->write_q))
  70                         break;
  71                 else
  72                         interruptible_sleep_on(&tty->write_q->proc_list);
  73                 sti();
  74         }
  75         sti();
  76 }
  77 
  78 static void send_break(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80         unsigned short port;
  81 
  82         if (!(port = tty->read_q->data))
  83                 return;
  84         port += 3;
  85         current->state = TASK_INTERRUPTIBLE;
  86         current->timeout = jiffies + 25;
  87         outb_p(inb_p(port) | 0x40,port);
  88         schedule();
  89         outb_p(inb_p(port) & 0xbf,port);
  90 }
  91 
  92 static int do_get_ps_info(int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94         struct tstruct {
  95                 int flag;
  96                 int present[NR_TASKS];
  97                 struct task_struct tasks[NR_TASKS];
  98         };
  99         struct tstruct *ts = (struct tstruct *)arg;
 100         struct task_struct **p;
 101         char *c, *d;
 102         int i, n = 0;
 103         
 104         verify_area((void *)arg, sizeof(struct tstruct));
 105                 
 106         for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
 107                 if (*p)
 108                 {
 109                         c = (char *)(*p);
 110                         d = (char *)(ts->tasks+n);
 111                         for (i=0 ; i<sizeof(struct task_struct) ; i++)
 112                                 put_fs_byte(*c++, d++);
 113                         put_fs_long(1, (unsigned long *)(ts->present+n));
 114                 }
 115                 else    
 116                         put_fs_long(0, (unsigned long *)(ts->present+n));
 117         return(0);                      
 118 }
 119 
 120 static int get_termios(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         int i;
 123 
 124         verify_area(termios, sizeof (*termios));
 125         for (i=0 ; i< (sizeof (*termios)) ; i++)
 126                 put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
 127         return 0;
 128 }
 129 
 130 static int set_termios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 131                         int channel)
 132 {
 133         int i;
 134 
 135         /* If we try to set the state of terminal and we're not in the
 136            foreground, send a SIGTTOU.  If the signal is blocked or
 137            ignored, go ahead and perform the operation.  POSIX 7.2) */
 138         if ((current->tty == channel) &&
 139              (tty->pgrp != current->pgrp)) {
 140                 if (is_orphaned_pgrp(current->pgrp))
 141                         return -EIO;
 142                 if (!is_ignored(SIGTTOU))
 143                         return tty_signal(SIGTTOU, tty);
 144         }
 145         for (i=0 ; i< (sizeof (*termios)) ; i++)
 146                 ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
 147         change_speed(tty);
 148         return 0;
 149 }
 150 
 151 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153         int i;
 154         struct termio tmp_termio;
 155 
 156         verify_area(termio, sizeof (*termio));
 157         tmp_termio.c_iflag = tty->termios.c_iflag;
 158         tmp_termio.c_oflag = tty->termios.c_oflag;
 159         tmp_termio.c_cflag = tty->termios.c_cflag;
 160         tmp_termio.c_lflag = tty->termios.c_lflag;
 161         tmp_termio.c_line = tty->termios.c_line;
 162         for(i=0 ; i < NCC ; i++)
 163                 tmp_termio.c_cc[i] = tty->termios.c_cc[i];
 164         for (i=0 ; i< (sizeof (*termio)) ; i++)
 165                 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
 166         return 0;
 167 }
 168 
 169 /*
 170  * This only works as the 386 is low-byte-first
 171  */
 172 static int set_termio(struct tty_struct * tty, struct termio * termio,
     /* [previous][next][first][last][top][bottom][index][help] */
 173                         int channel)
 174 {
 175         int i;
 176         struct termio tmp_termio;
 177 
 178         if ((current->tty == channel) &&
 179             (tty->pgrp > 0) &&
 180             (tty->pgrp != current->pgrp)) {
 181                 if (is_orphaned_pgrp(current->pgrp))
 182                         return -EIO;
 183                 if (!is_ignored(SIGTTOU))
 184                         return tty_signal(SIGTTOU, tty);
 185         }
 186         for (i=0 ; i< (sizeof (*termio)) ; i++)
 187                 ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
 188         *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
 189         *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
 190         *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
 191         *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
 192         tty->termios.c_line = tmp_termio.c_line;
 193         for(i=0 ; i < NCC ; i++)
 194                 tty->termios.c_cc[i] = tmp_termio.c_cc[i];
 195         change_speed(tty);
 196         return 0;
 197 }
 198 
 199 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201         int i,changed;
 202         char c, * tmp;
 203 
 204         if (!ws)
 205                 return -EINVAL;
 206         tmp = (char *) &tty->winsize;
 207         changed = 0;
 208         for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
 209                 c = get_fs_byte(i + (char *) ws);
 210                 if (c == *tmp)
 211                         continue;
 212                 changed = 1;
 213                 *tmp = c;
 214         }
 215         if (changed)
 216                 kill_pg(tty->pgrp, SIGWINCH, 1);
 217         return 0;
 218 }
 219 
 220 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222         int i;
 223         char * tmp;
 224 
 225         if (!ws)
 226                 return -EINVAL;
 227         verify_area(ws, sizeof (*ws));
 228         tmp = (char *) ws;
 229         for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
 230                 put_fs_byte(((char *) &tty->winsize)[i], tmp);
 231         return 0;
 232 }
 233 
 234 int tty_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 235         unsigned int cmd, unsigned int arg)
 236 {
 237         struct tty_struct * tty;
 238         struct tty_struct * other_tty;
 239         int pgrp;
 240         int dev;
 241 
 242         if (MAJOR(inode->i_rdev) == 5) {
 243                 dev = current->tty;
 244                 if (dev<0)
 245                         return -EINVAL;
 246         } else
 247                 dev = MINOR(inode->i_rdev);
 248         tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
 249 
 250         if (IS_A_PTY(dev))
 251                 other_tty = tty_table + PTY_OTHER(dev);
 252         else
 253                 other_tty = NULL;
 254                 
 255         if (!(tty->write_q && tty->read_q && tty->secondary && tty->write))
 256                 return -EINVAL;
 257         switch (cmd) {
 258                 case TCGETS:
 259                         return get_termios(tty,(struct termios *) arg);
 260                 case TCSETSF:
 261                         flush_input(tty);
 262                         if (other_tty)
 263                                 flush(other_tty->write_q);
 264                 /* fallthrough */
 265                 case TCSETSW:
 266                         wait_until_sent(tty);
 267                 /* fallthrough */
 268                 case TCSETS:
 269                         return set_termios(tty,(struct termios *) arg, dev);
 270                 case TCGETA:
 271                         return get_termio(tty,(struct termio *) arg);
 272                 case TCSETAF:
 273                         flush_input(tty);
 274                         if (other_tty)
 275                                 flush(other_tty->write_q);
 276                 /* fallthrough */
 277                 case TCSETAW:
 278                         wait_until_sent(tty); /* fallthrough */
 279                 case TCSETA:
 280                         return set_termio(tty,(struct termio *) arg, dev);
 281                 case TCSBRK:
 282                         wait_until_sent(tty);
 283                         if (!arg)
 284                                 send_break(tty);
 285                         return 0;
 286                 case TCXONC:
 287                         switch (arg) {
 288                         case TCOOFF:
 289                                 tty->stopped = 1;
 290                                 TTY_WRITE_FLUSH(tty);
 291                                 return 0;
 292                         case TCOON:
 293                                 tty->stopped = 0;
 294                                 TTY_WRITE_FLUSH(tty);
 295                                 return 0;
 296                         case TCIOFF:
 297                                 if (STOP_CHAR(tty))
 298                                         PUTCH(STOP_CHAR(tty),tty->write_q);
 299                                 return 0;
 300                         case TCION:
 301                                 if (START_CHAR(tty))
 302                                         PUTCH(START_CHAR(tty),tty->write_q);
 303                                 return 0;
 304                         }
 305                         return -EINVAL; /* not implemented */
 306                 case TCFLSH:
 307                         if (arg==0) {
 308                                 flush_input(tty);
 309                                 if (other_tty)
 310                                         flush(other_tty->write_q);
 311                         } else if (arg==1)
 312                                 flush(tty->write_q);
 313                         else if (arg==2) {
 314                                 flush_input(tty);
 315                                 flush(tty->write_q);
 316                                 if (other_tty)
 317                                         flush(other_tty->write_q);
 318                         } else
 319                                 return -EINVAL;
 320                         return 0;
 321                 case TIOCEXCL:
 322                         return -EINVAL; /* not implemented */
 323                 case TIOCNXCL:
 324                         return -EINVAL; /* not implemented */
 325                 case TIOCSCTTY:
 326                         return -EINVAL; /* set controlling term NI */
 327                 case TIOCGPGRP:
 328                         verify_area((void *) arg,4);
 329                         put_fs_long(tty->pgrp,(unsigned long *) arg);
 330                         return 0;
 331                 case TIOCSPGRP:
 332                         if ((current->tty < 0) ||
 333                             (current->tty != dev) ||
 334                             (tty->session != current->session))
 335                                 return -ENOTTY;
 336                         pgrp=get_fs_long((unsigned long *) arg);
 337                         if (pgrp < 0)
 338                                 return -EINVAL;
 339                         if (session_of_pgrp(pgrp) != current->session)
 340                                 return -EPERM;
 341                         tty->pgrp = pgrp;                       
 342                         return 0;
 343                 case TIOCOUTQ:
 344                         verify_area((void *) arg,4);
 345                         put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
 346                         return 0;
 347                 case TIOCINQ:
 348                         verify_area((void *) arg,4);
 349                         if (L_CANON(tty) && !tty->secondary->data)
 350                                 put_fs_long(0, (unsigned long *) arg);
 351                         else
 352                                 put_fs_long(CHARS(tty->secondary),
 353                                         (unsigned long *) arg);
 354                         return 0;
 355                 case TIOCSTI:
 356                         return -EINVAL; /* not implemented */
 357                 case TIOCGWINSZ:
 358                         return get_window_size(tty,(struct winsize *) arg);
 359                 case TIOCSWINSZ:
 360                         if (IS_A_PTY_MASTER(dev))
 361                                 set_window_size(other_tty,(struct winsize *) arg);
 362                         return set_window_size(tty,(struct winsize *) arg);
 363                 case TIOCMGET:
 364                         return -EINVAL; /* not implemented */
 365                 case TIOCMBIS:
 366                         return -EINVAL; /* not implemented */
 367                 case TIOCMBIC:
 368                         return -EINVAL; /* not implemented */
 369                 case TIOCMSET:
 370                         return -EINVAL; /* not implemented */
 371                 case TIOCGSOFTCAR:
 372                         return -EINVAL; /* not implemented */
 373                 case TIOCSSOFTCAR:
 374                         return -EINVAL; /* not implemented */
 375                 case TIOCLINUX:
 376                         switch (get_fs_byte((char *)arg))
 377                         {
 378                                 case 0: 
 379                                         return do_screendump(arg);
 380                                 case 1: 
 381                                         return do_get_ps_info(arg);
 382                                 default: 
 383                                         return -EINVAL;
 384                         }
 385                 case TIOCCONS:
 386                         if (!IS_A_PTY(dev))
 387                                 return -EINVAL;
 388                         if (redirect)
 389                                 return -EBUSY;
 390                         if (!suser())
 391                                 return -EPERM;
 392                         if (IS_A_PTY_MASTER(dev))
 393                                 redirect = other_tty;
 394                         else
 395                                 redirect = tty;
 396                         return 0;
 397                 default:
 398                         return vt_ioctl(tty, dev, cmd, arg);
 399         }
 400 }

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