📄 tty_io.c
字号:
return tiocsetd(tty, (int *) arg);#ifdef CONFIG_VT case TIOCLINUX: return tioclinux(tty, arg);#endif case TIOCTTYGSTRUCT: return tiocttygstruct(tty, (struct tty_struct *) arg); /* * Break handling */ case TIOCSBRK: /* Turn break on, unconditionally */ tty->driver.break_ctl(tty, -1); return 0; case TIOCCBRK: /* Turn break off, unconditionally */ tty->driver.break_ctl(tty, 0); return 0; case TCSBRK: /* SVID version: non-zero arg --> no break */ /* * XXX is the above comment correct, or the * code below correct? Is this ioctl used at * all by anyone? */ if (!arg) return send_break(tty, HZ/4); return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ return send_break(tty, arg ? arg*(HZ/10) : HZ/4); } if (tty->driver.ioctl) { int retval = (tty->driver.ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } if (tty->ldisc.ioctl) { int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } return -EINVAL;}/* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this * tty when the user hits the "Secure Attention Key". Required for * super-paranoid applications --- see the Orange Book for more details. * * This code could be nicer; ideally it should send a HUP, wait a few * seconds, then send a INT, and then a KILL signal. But you then * have to coordinate with the init process, since all processes associated * with the current tty must be dead before the new getty is allowed * to spawn. * * Now, if it would be correct ;-/ The current code has a nasty hole - * it doesn't catch files in flight. We may send the descriptor to ourselves * via AF_UNIX socket, close it and later fetch from socket. FIXME. */void do_SAK( struct tty_struct *tty){#ifdef TTY_SOFT_SAK tty_hangup(tty);#else struct task_struct *p; int session; int i; struct file *filp; if (!tty) return; session = tty->session; if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); read_lock(&tasklist_lock); for_each_task(p) { if ((p->tty == tty) || ((session > 0) && (p->session == session))) { send_sig(SIGKILL, p, 1); continue; } task_lock(p); if (p->files) { read_lock(&p->files->file_lock); /* FIXME: p->files could change */ for (i=0; i < p->files->max_fds; i++) { filp = fcheck_files(p->files, i); if (filp && (filp->f_op == &tty_fops) && (filp->private_data == tty)) { send_sig(SIGKILL, p, 1); break; } } read_unlock(&p->files->file_lock); } task_unlock(p); } read_unlock(&tasklist_lock);#endif}/* * This routine is called out of the software interrupt to flush data * from the flip buffer to the line discipline. */static void flush_to_ldisc(void *private_){ struct tty_struct *tty = (struct tty_struct *) private_; unsigned char *cp; char *fp; int count; unsigned long flags; if (test_bit(TTY_DONT_FLIP, &tty->flags)) { queue_task(&tty->flip.tqueue, &tq_timer); return; } if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; save_flags(flags); cli(); tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { cp = tty->flip.char_buf; fp = tty->flip.flag_buf; tty->flip.buf_num = 1; save_flags(flags); cli(); tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } count = tty->flip.count; tty->flip.count = 0; restore_flags(flags); tty->ldisc.receive_buf(tty, cp, fp, count);}/* * Routine which returns the baud rate of the tty * * Note that the baud_table needs to be kept in sync with the * include/asm/termbits.h file. */static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,#ifdef __sparc__ 76800, 153600, 307200, 614400, 921600#else 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000#endif};static int n_baud_table = sizeof(baud_table)/sizeof(int);int tty_get_baud_rate(struct tty_struct *tty){ unsigned int cflag, i; cflag = tty->termios->c_cflag; i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i+15 >= n_baud_table) tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } if (i==15 && tty->alt_speed) { if (!tty->warned) { printk("Use of setserial/setrocket to set SPD_* flags is deprecated\n"); tty->warned = 1; } return(tty->alt_speed); } return baud_table[i];}void tty_flip_buffer_push(struct tty_struct *tty){ if (tty->low_latency) flush_to_ldisc((void *) tty); else queue_task(&tty->flip.tqueue, &tq_timer);}/* * This subroutine initializes a tty structure. */static void initialize_tty_struct(struct tty_struct *tty){ memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; tty->ldisc = ldiscs[N_TTY]; tty->pgrp = -1; tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; tty->flip.tqueue.routine = flush_to_ldisc; tty->flip.tqueue.data = tty; init_MUTEX(&tty->flip.pty_sem); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); tty->tq_hangup.routine = do_tty_hangup; tty->tq_hangup.data = tty; sema_init(&tty->atomic_read, 1); sema_init(&tty->atomic_write, 1); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files);}/* * The default put_char routine if the driver did not define one. */void tty_default_put_char(struct tty_struct *tty, unsigned char ch){ tty->driver.write(tty, 0, &ch, 1);}/* * Register a tty device described by <driver>, with minor number <minor>. */void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned int minor){#ifdef CONFIG_DEVFS_FS umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR; struct tty_struct tty; char buf[32]; tty.driver = *driver; tty.device = MKDEV (driver->major, minor); switch (tty.device) { case TTY_DEV: case PTMX_DEV: mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; break; default: if (driver->major == PTY_MASTER_MAJOR) flags |= DEVFS_FL_AUTO_OWNER; break; } if ( (minor < driver->minor_start) || (minor >= driver->minor_start + driver->num) ) { printk(KERN_ERR "Attempt to register invalid minor number " "with devfs (%d:%d).\n", (int)driver->major,(int)minor); return; }# ifdef CONFIG_UNIX98_PTYS if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) && (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) flags |= DEVFS_FL_CURRENT_OWNER;# endif devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT, driver->major, minor, mode, &tty_fops, NULL);#endif /* CONFIG_DEVFS_FS */}void tty_unregister_devfs (struct tty_driver *driver, unsigned minor){#ifdef CONFIG_DEVFS_FS void * handle; struct tty_struct tty; char buf[32]; tty.driver = *driver; tty.device = MKDEV(driver->major, minor); handle = devfs_find_handle (NULL, tty_name (&tty, buf), driver->major, minor, DEVFS_SPECIAL_CHR, 0); devfs_unregister (handle);#endif /* CONFIG_DEVFS_FS */}EXPORT_SYMBOL(tty_register_devfs);EXPORT_SYMBOL(tty_unregister_devfs);/* * Called by a tty driver to register itself. */int tty_register_driver(struct tty_driver *driver){ int error; int i; if (driver->flags & TTY_DRIVER_INSTALLED) return 0; error = devfs_register_chrdev(driver->major, driver->name, &tty_fops); if (error < 0) return error; else if(driver->major == 0) driver->major = error; if (!driver->put_char) driver->put_char = tty_default_put_char; driver->prev = 0; driver->next = tty_drivers; if (tty_drivers) tty_drivers->prev = driver; tty_drivers = driver; if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { for(i = 0; i < driver->num; i++) tty_register_devfs(driver, 0, driver->minor_start + i); } proc_tty_register_driver(driver); return error;}/* * Called by a tty driver to unregister itself. */int tty_unregister_driver(struct tty_driver *driver){ int retval; struct tty_driver *p; int i, found = 0; struct termios *tp; const char *othername = NULL; if (*driver->refcount) return -EBUSY; for (p = tty_drivers; p; p = p->next) { if (p == driver) found++; else if (p->major == driver->major) othername = p->name; } if (!found) return -ENOENT; if (othername == NULL) { retval = devfs_unregister_chrdev(driver->major, driver->name); if (retval) return retval; } else devfs_register_chrdev(driver->major, othername, &tty_fops); if (driver->prev) driver->prev->next = driver->next; else tty_drivers = driver->next; if (driver->next) driver->next->prev = driver->prev; /* * Free the termios and termios_locked structures because * we don't want to get memory leaks when modular tty * drivers are removed from the kernel. */ for (i = 0; i < driver->num; i++) { tp = driver->termios[i]; if (tp) { driver->termios[i] = NULL; kfree(tp); } tp = driver->termios_locked[i]; if (tp) { driver->termios_locked[i] = NULL; kfree(tp); } tty_unregister_devfs(driver, driver->minor_start + i); } proc_tty_unregister_driver(driver); return 0;}/* * Initialize the console device. This is called *early*, so * we can't necessarily depend on lots of kernel help here. * Just do some early initializations, and do the complex setup * later. */void __init console_init(void){ /* Setup the default TTY line discipline. */ memset(ldiscs, 0, sizeof(ldiscs)); (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); /* * Set up the standard termios. Individual tty drivers may * deviate from this; this is used as a template. */ memset(&tty_std_termios, 0, sizeof(struct termios)); memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); tty_std_termios.c_iflag = ICRNL | IXON; tty_std_termios.c_oflag = OPOST | ONLCR; tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; /* * set up the console device so that later boot sequences can * inform about problems etc.. */#ifdef CONFIG_VT con_init();#endif#ifdef CONFIG_SERIAL_CONSOLE#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init();#elif defined(CONFIG_SERIAL) serial_console_init();#endif /* CONFIG_8xx */#ifdef CONFIG_SGI_SERIAL sgi_serial_console_init();#endif#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) vme_scc_console_init();#endif#if defined(CONFIG_SERIAL167) serial167_console_init();#endif#if defined(CONFIG_SH_SCI) sci_console_init();#endif#endif#ifdef CONFIG_3215 con3215_init();#endif#ifdef CONFIG_HWC hwc_console_init();#endif#ifdef CONFIG_SERIAL_21285_CONSOLE rs285_console_init();#endif#ifdef CONFIG_SERIAL_SA1100_CONSOLE sa1100_rs_console_init();#endif#ifdef CONFIG_SERIAL_AMBA_CONSOLE ambauart_console_init();#endif}static struct tty_driver dev_tty_driver, dev_syscons_driver;#ifdef CONFIG_UNIX98_PTYSstatic struct tty_driver dev_ptmx_driver;#endif#ifdef CONFIG_VTstatic struct tty_driver dev_console_driver;#endif/* * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */void __init tty_init(void){ if (sizeof(struct tty_struct) > PAGE_SIZE) panic("size of tty structure > PAGE_SIZE!"); /* * dev_tty_driver and dev_console_driver are actually magic * devices which get redirected at open time. Nevertheless, * we register them so that register_chrdev is called * appropriately. */ memset(&dev_tty_driver, 0, sizeof(struct tty_driver)); dev_tty_driver.magic = TTY_DRIVER_MAGIC; dev_tty_driver.driver_name = "/dev/tty"; dev_tty_driver.name = dev_tty_driver.driver_name + 5; dev_tty_driver.name_base = 0; dev_tty_driver.major = TTYAUX_MAJOR; dev_tty_driver.minor_start = 0; dev_tty_driver.num = 1; dev_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM; dev_tty_driver.subtype = SYSTEM_TYPE_TTY; if (tty_register_driver(&dev_tty_driver)) panic("Couldn't register /dev/tty driver\n"); dev_syscons_driver = dev_tty_driver; dev_syscons_driver.driver_name = "/dev/console"; dev_syscons_driver.name = dev_syscons_driver.driver_name + 5; dev_syscons_driver.major = TTYAUX_MAJOR; dev_syscons_driver.minor_start = 1; dev_syscons_driver.type = TTY_DRIVER_TYPE_SYSTEM; dev_syscons_driver.subtype = SYSTEM_TYPE_SYSCONS; if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); /* console calls tty_register_driver() before kmalloc() works. * Thus, we can't devfs_register() then. Do so now, instead. */#ifdef CONFIG_VT con_init_devfs();#endif#ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; dev_ptmx_driver.driver_name = "/dev/ptmx"; dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5; dev_ptmx_driver.major= MAJOR(PTMX_DEV); dev_ptmx_driver.minor_start = MINOR(PTMX_DEV); dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM; dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX; if (tty_register_driver(&dev_ptmx_driver)) panic("Couldn't register /dev/ptmx driver\n");#endif #ifdef CONFIG_VT dev_console_driver = dev_tty_driver; dev_console_driver.driver_name = "/dev/vc/0"; dev_console_driver.name = dev_console_driver.driver_name + 5; dev_console_driver.major = TTY_MAJOR; dev_console_driver.type = TTY_DRIVER_TYPE_SYSTEM; dev_console_driver.subtype = SYSTEM_TYPE_CONSOLE; if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/tty0 driver\n"); kbd_init();#endif#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ espserial_init();#endif#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) vme_scc_init();#endif#ifdef CONFIG_COMPUTONE ip2_init();#endif#ifdef CONFIG_MAC_SERIAL macserial_init();#endif#ifdef CONFIG_ROCKETPORT rp_init();#endif#ifdef CONFIG_SERIAL167 serial167_init();#endif#ifdef CONFIG_CYCLADES cy_init();#endif#ifdef CONFIG_STALLION stl_init();#endif#ifdef CONFIG_ISTALLION stli_init();#endif#ifdef CONFIG_DIGI pcxe_init();#endif#ifdef CONFIG_DIGIEPCA pc_init();#endif#ifdef CONFIG_SPECIALIX specialix_init();#endif#ifdef CONFIG_RIO rio_init();#endif#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) rs_8xx_init();#endif /* CONFIG_8xx */ pty_init();#ifdef CONFIG_MOXA_SMARTIO mxser_init();#endif #ifdef CONFIG_MOXA_INTELLIO moxa_init();#endif #ifdef CONFIG_VT vcs_init();#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -