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

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