tty_io.c
来自「linux 内核源代码」· C语言 代码 · 共 2,498 行 · 第 1/5 页
C
2,498 行
/* * linux/drivers/char/tty_io.c * * Copyright (C) 1991, 1992 Linus Torvalds *//* * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles * or rs-channels. It also implements echoing, cooked mode etc. * * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the * tty_struct and tty_queue structures. Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time. Both are now * dynamically allocated only when the tty is open. * * Also restructured routines so that there is more of a separation * between the high-level tty routines (tty_io.c and tty_ioctl.c) and * the low-level tty routines (serial.c, pty.c, console.c). This * makes for cleaner and more compact code. -TYT, 9/17/92 * * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines * which can be dynamically activated and de-activated by the line * discipline handling modules (like SLIP). * * NOTE: pay no attention to the line discipline code (yet); its * interface is still subject to change in this version... * -- TYT, 1/31/92 * * Added functionality to the OPOST tty handling. No delays, but all * other bits should be there. * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. * -- ctm@ardi.com, 9Sep95 * * New TIOCLINUX variants added. * -- mj@k332.feld.cvut.cz, 19-Nov-95 * * Restrict vt switching via ioctl() * -- grif@cs.ucr.edu, 5-Dec-95 * * Move console and virtual terminal code to more appropriate files, * implement CONFIG_VT and generalize console device interface. * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97 * * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes <whawes@star.net>, June 97 * * Added devfs support. * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998 * * Added support for a Unix98-style ptmx device. * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998 * * Reduced memory usage for older ARM systems * -- Russell King <rmk@arm.linux.org.uk> * * Move do_SAK() into process context. Less stack use in devfs functions. * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01 */#include <linux/types.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/fcntl.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/devpts_fs.h>#include <linux/file.h>#include <linux/console.h>#include <linux/timer.h>#include <linux/ctype.h>#include <linux/kd.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/module.h>#include <linux/smp_lock.h>#include <linux/device.h>#include <linux/idr.h>#include <linux/wait.h>#include <linux/bitops.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/kbd_kern.h>#include <linux/vt_kern.h>#include <linux/selection.h>#include <linux/kmod.h>#include <linux/nsproxy.h>#undef TTY_DEBUG_HANGUP#define TTY_PARANOIA_CHECK 1#define CHECK_TTY_COUNT 1struct ktermios tty_std_termios = { /* for the benefit of tty drivers */ .c_iflag = ICRNL | IXON, .c_oflag = OPOST | ONLCR, .c_cflag = B38400 | CS8 | CREAD | HUPCL, .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN, .c_cc = INIT_C_CC, .c_ispeed = 38400, .c_ospeed = 38400};EXPORT_SYMBOL(tty_std_termios);/* This list gets poked at by procfs and various bits of boot up code. This could do with some rationalisation such as pulling the tty proc function into this file */ LIST_HEAD(tty_drivers); /* linked list of tty drivers *//* Mutex to protect creating and releasing a tty. This is shared with vt.c for deeply disgusting hack reasons */DEFINE_MUTEX(tty_mutex);EXPORT_SYMBOL(tty_mutex);#ifdef CONFIG_UNIX98_PTYSextern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */extern int pty_limit; /* Config limit on Unix98 ptys */static DEFINE_IDR(allocated_ptys);static DECLARE_MUTEX(allocated_ptys_lock);static int ptmx_open(struct inode *, struct file *);#endifstatic void initialize_tty_struct(struct tty_struct *tty);static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *);static unsigned int tty_poll(struct file *, poll_table *);static int tty_open(struct inode *, struct file *);static int tty_release(struct inode *, struct file *);int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);#ifdef CONFIG_COMPATstatic long tty_compat_ioctl(struct file * file, unsigned int cmd, unsigned long arg);#else#define tty_compat_ioctl NULL#endifstatic int tty_fasync(int fd, struct file * filp, int on);static void release_tty(struct tty_struct *tty, int idx);static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);/** * alloc_tty_struct - allocate a tty object * * Return a new empty tty structure. The data fields have not * been initialized in any way but has been zeroed * * Locking: none */static struct tty_struct *alloc_tty_struct(void){ return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);}static void tty_buffer_free_all(struct tty_struct *);/** * free_tty_struct - free a disused tty * @tty: tty struct to free * * Free the write buffers, tty queue and tty memory itself. * * Locking: none. Must be called after tty is definitely unused */static inline void free_tty_struct(struct tty_struct *tty){ kfree(tty->write_buf); tty_buffer_free_all(tty); kfree(tty);}#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)/** * tty_name - return tty naming * @tty: tty structure * @buf: buffer for output * * Convert a tty structure into a name. The name reflects the kernel * naming policy and if udev is in use may not reflect user space * * Locking: none */char *tty_name(struct tty_struct *tty, char *buf){ if (!tty) /* Hmm. NULL pointer. That's fun. */ strcpy(buf, "NULL tty"); else strcpy(buf, tty->name); return buf;}EXPORT_SYMBOL(tty_name);int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, const char *routine){#ifdef TTY_PARANOIA_CHECK if (!tty) { printk(KERN_WARNING "null TTY for (%d:%d) in %s\n", imajor(inode), iminor(inode), routine); return 1; } if (tty->magic != TTY_MAGIC) { printk(KERN_WARNING "bad magic number for tty struct (%d:%d) in %s\n", imajor(inode), iminor(inode), routine); return 1; }#endif return 0;}static int check_tty_count(struct tty_struct *tty, const char *routine){#ifdef CHECK_TTY_COUNT struct list_head *p; int count = 0; file_list_lock(); list_for_each(p, &tty->tty_files) { count++; } file_list_unlock(); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) count++; if (tty->count != count) { printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " "!= #fd's(%d) in %s\n", tty->name, tty->count, count, routine); return count; }#endif return 0;}/* * Tty buffer allocation management *//** * tty_buffer_free_all - free buffers used by a tty * @tty: tty to free from * * Remove all the buffers pending on a tty whether queued with data * or in the free ring. Must be called when the tty is no longer in use * * Locking: none */static void tty_buffer_free_all(struct tty_struct *tty){ struct tty_buffer *thead; while((thead = tty->buf.head) != NULL) { tty->buf.head = thead->next; kfree(thead); } while((thead = tty->buf.free) != NULL) { tty->buf.free = thead->next; kfree(thead); } tty->buf.tail = NULL; tty->buf.memory_used = 0;}/** * tty_buffer_init - prepare a tty buffer structure * @tty: tty to initialise * * Set up the initial state of the buffer management for a tty device. * Must be called before the other tty buffer functions are used. * * Locking: none */static void tty_buffer_init(struct tty_struct *tty){ spin_lock_init(&tty->buf.lock); tty->buf.head = NULL; tty->buf.tail = NULL; tty->buf.free = NULL; tty->buf.memory_used = 0;}/** * tty_buffer_alloc - allocate a tty buffer * @tty: tty device * @size: desired size (characters) * * Allocate a new tty buffer to hold the desired number of characters. * Return NULL if out of memory or the allocation would exceed the * per device queue * * Locking: Caller must hold tty->buf.lock */static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size){ struct tty_buffer *p; if (tty->buf.memory_used + size > 65536) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if(p == NULL) return NULL; p->used = 0; p->size = size; p->next = NULL; p->commit = 0; p->read = 0; p->char_buf_ptr = (char *)(p->data); p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; tty->buf.memory_used += size; return p;}/** * tty_buffer_free - free a tty buffer * @tty: tty owning the buffer * @b: the buffer to free * * Free a tty buffer, or add it to the free list according to our * internal strategy * * Locking: Caller must hold tty->buf.lock */static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b){ /* Dumb strategy for now - should keep some stats */ tty->buf.memory_used -= b->size; WARN_ON(tty->buf.memory_used < 0); if(b->size >= 512) kfree(b); else { b->next = tty->buf.free; tty->buf.free = b; }}/** * __tty_buffer_flush - flush full tty buffers * @tty: tty to flush * * flush all the buffers containing receive data. Caller must * hold the buffer lock and must have ensured no parallel flush to * ldisc is running. * * Locking: Caller must hold tty->buf.lock */static void __tty_buffer_flush(struct tty_struct *tty){ struct tty_buffer *thead; while((thead = tty->buf.head) != NULL) { tty->buf.head = thead->next; tty_buffer_free(tty, thead); } tty->buf.tail = NULL;}/** * tty_buffer_flush - flush full tty buffers * @tty: tty to flush * * flush all the buffers containing receive data. If the buffer is * being processed by flush_to_ldisc then we defer the processing * to that function * * Locking: none */static void tty_buffer_flush(struct tty_struct *tty){ unsigned long flags; spin_lock_irqsave(&tty->buf.lock, flags); /* If the data is being pushed to the tty layer then we can't process it here. Instead set a flag and the flush_to_ldisc path will process the flush request before it exits */ if (test_bit(TTY_FLUSHING, &tty->flags)) { set_bit(TTY_FLUSHPENDING, &tty->flags); spin_unlock_irqrestore(&tty->buf.lock, flags); wait_event(tty->read_wait, test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); return; } else __tty_buffer_flush(tty); spin_unlock_irqrestore(&tty->buf.lock, flags);}/** * tty_buffer_find - find a free tty buffer * @tty: tty owning the buffer * @size: characters wanted * * Locate an existing suitable tty buffer or if we are lacking one then * allocate a new one. We round our buffers off in 256 character chunks * to get better allocation behaviour. * * Locking: Caller must hold tty->buf.lock */static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size){ struct tty_buffer **tbh = &tty->buf.free; while((*tbh) != NULL) { struct tty_buffer *t = *tbh; if(t->size >= size) { *tbh = t->next; t->next = NULL; t->used = 0; t->commit = 0; t->read = 0; tty->buf.memory_used += t->size; return t; } tbh = &((*tbh)->next); } /* Round the buffer size out */ size = (size + 0xFF) & ~ 0xFF; return tty_buffer_alloc(tty, size); /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */}/** * tty_buffer_request_room - grow tty buffer if needed * @tty: tty structure * @size: size desired * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. * * Locking: Takes tty->buf.lock */int tty_buffer_request_room(struct tty_struct *tty, size_t size){ struct tty_buffer *b, *n; int left; unsigned long flags; spin_lock_irqsave(&tty->buf.lock, flags); /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ if ((b = tty->buf.tail) != NULL) left = b->size - b->used; else left = 0; if (left < size) { /* This is the slow path - looking for new buffers to use */ if ((n = tty_buffer_find(tty, size)) != NULL) { if (b != NULL) { b->next = n; b->commit = b->used; } else tty->buf.head = n; tty->buf.tail = n; } else size = left; } spin_unlock_irqrestore(&tty->buf.lock, flags); return size;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?