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

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