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 + -
显示快捷键?