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

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