/* * linux/kernel/chr_drv/tty_ioctl.c * * (C) 1991 Linus Torvalds */ #include #include #include #include #include #include #include #include static unsigned short quotient[] = { 0, 2304, 1536, 1047, 857, 768, 576, 384, 192, 96, 64, 48, 24, 12, 6, 3 }; static void change_speed(struct tty_struct * tty) { unsigned short port,quot; if (!(port = tty->read_q.data)) return; quot = quotient[tty->termios.c_cflag & CBAUD]; cli(); outb_p(0x80,port+3); /* set DLAB */ outb_p(quot & 0xff,port); /* LS of divisor */ outb_p(quot >> 8,port+1); /* MS of divisor */ outb(0x03,port+3); /* reset DLAB */ sti(); } static void flush(struct tty_queue * queue) { cli(); queue->head = queue->tail; sti(); } static void wait_until_sent(struct tty_struct * tty) { /* do nothing - not implemented */ } static void send_break(struct tty_struct * tty) { /* do nothing - not implemented */ } static int get_termios(struct tty_struct * tty, struct termios * termios) { int i; verify_area(termios, sizeof (*termios)); for (i=0 ; i< (sizeof (*termios)) ; i++) put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios ); return 0; } static int set_termios(struct tty_struct * tty, struct termios * termios) { int i; for (i=0 ; i< (sizeof (*termios)) ; i++) ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); change_speed(tty); return 0; } static int get_termio(struct tty_struct * tty, struct termio * termio) { int i; struct termio tmp_termio; verify_area(termio, sizeof (*termio)); tmp_termio.c_iflag = tty->termios.c_iflag; tmp_termio.c_oflag = tty->termios.c_oflag; tmp_termio.c_cflag = tty->termios.c_cflag; tmp_termio.c_lflag = tty->termios.c_lflag; tmp_termio.c_line = tty->termios.c_line; for(i=0 ; i < NCC ; i++) tmp_termio.c_cc[i] = tty->termios.c_cc[i]; for (i=0 ; i< (sizeof (*termio)) ; i++) put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); return 0; } /* * This only works as the 386 is low-byt-first */ static int set_termio(struct tty_struct * tty, struct termio * termio) { int i; struct termio tmp_termio; for (i=0 ; i< (sizeof (*termio)) ; i++) ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; tty->termios.c_line = tmp_termio.c_line; for(i=0 ; i < NCC ; i++) tty->termios.c_cc[i] = tmp_termio.c_cc[i]; change_speed(tty); return 0; } int tty_ioctl(int dev, int cmd, int arg) { struct tty_struct * tty; if (MAJOR(dev) == 5) { dev=current->tty; if (dev<0) panic("tty_ioctl: dev<0"); } else dev=MINOR(dev); tty = dev + tty_table; switch (cmd) { case TCGETS: return get_termios(tty,(struct termios *) arg); case TCSETSF: flush(&tty->read_q); /* fallthrough */ case TCSETSW: wait_until_sent(tty); /* fallthrough */ case TCSETS: return set_termios(tty,(struct termios *) arg); case TCGETA: return get_termio(tty,(struct termio *) arg); case TCSETAF: flush(&tty->read_q); /* fallthrough */ case TCSETAW: wait_until_sent(tty); /* fallthrough */ case TCSETA: return set_termio(tty,(struct termio *) arg); case TCSBRK: if (!arg) { wait_until_sent(tty); send_break(tty); } return 0; case TCXONC: return -EINVAL; /* not implemented */ case TCFLSH: if (arg==0) flush(&tty->read_q); else if (arg==1) flush(&tty->write_q); else if (arg==2) { flush(&tty->read_q); flush(&tty->write_q); } else return -EINVAL; return 0; case TIOCEXCL: return -EINVAL; /* not implemented */ case TIOCNXCL: return -EINVAL; /* not implemented */ case TIOCSCTTY: return -EINVAL; /* set controlling term NI */ case TIOCGPGRP: verify_area((void *) arg,4); put_fs_long(tty->pgrp,(unsigned long *) arg); return 0; case TIOCSPGRP: tty->pgrp=get_fs_long((unsigned long *) arg); return 0; case TIOCOUTQ: verify_area((void *) arg,4); put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); return 0; case TIOCINQ: verify_area((void *) arg,4); put_fs_long(CHARS(tty->secondary), (unsigned long *) arg); return 0; case TIOCSTI: return -EINVAL; /* not implemented */ case TIOCGWINSZ: return -EINVAL; /* not implemented */ case TIOCSWINSZ: return -EINVAL; /* not implemented */ case TIOCMGET: return -EINVAL; /* not implemented */ case TIOCMBIS: return -EINVAL; /* not implemented */ case TIOCMBIC: return -EINVAL; /* not implemented */ case TIOCMSET: return -EINVAL; /* not implemented */ case TIOCGSOFTCAR: return -EINVAL; /* not implemented */ case TIOCSSOFTCAR: return -EINVAL; /* not implemented */ default: return -EINVAL; } }