tty_io.c

来自「linux 内核源代码」· C语言 代码 · 共 2,498 行 · 第 1/5 页

C
2,498
字号
EXPORT_SYMBOL_GPL(tty_buffer_request_room);/** *	tty_insert_flip_string	-	Add characters to the tty buffer *	@tty: tty structure *	@chars: characters *	@size: size * *	Queue a series of bytes to the tty buffering. All the characters *	passed are marked as without error. Returns the number added. * *	Locking: Called functions may take tty->buf.lock */int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,				size_t size){	int copied = 0;	do {		int space = tty_buffer_request_room(tty, size - copied);		struct tty_buffer *tb = tty->buf.tail;		/* If there is no space then tb may be NULL */		if(unlikely(space == 0))			break;		memcpy(tb->char_buf_ptr + tb->used, chars, space);		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);		tb->used += space;		copied += space;		chars += space;		/* There is a small chance that we need to split the data over		   several buffers. If this is the case we must loop */	} while (unlikely(size > copied));	return copied;}EXPORT_SYMBOL(tty_insert_flip_string);/** *	tty_insert_flip_string_flags	-	Add characters to the tty buffer *	@tty: tty structure *	@chars: characters *	@flags: flag bytes *	@size: size * *	Queue a series of bytes to the tty buffering. For each character *	the flags array indicates the status of the character. Returns the *	number added. * *	Locking: Called functions may take tty->buf.lock */int tty_insert_flip_string_flags(struct tty_struct *tty,		const unsigned char *chars, const char *flags, size_t size){	int copied = 0;	do {		int space = tty_buffer_request_room(tty, size - copied);		struct tty_buffer *tb = tty->buf.tail;		/* If there is no space then tb may be NULL */		if(unlikely(space == 0))			break;		memcpy(tb->char_buf_ptr + tb->used, chars, space);		memcpy(tb->flag_buf_ptr + tb->used, flags, space);		tb->used += space;		copied += space;		chars += space;		flags += space;		/* There is a small chance that we need to split the data over		   several buffers. If this is the case we must loop */	} while (unlikely(size > copied));	return copied;}EXPORT_SYMBOL(tty_insert_flip_string_flags);/** *	tty_schedule_flip	-	push characters to ldisc *	@tty: tty to push from * *	Takes any pending buffers and transfers their ownership to the *	ldisc side of the queue. It then schedules those characters for *	processing by the line discipline. * *	Locking: Takes tty->buf.lock */void tty_schedule_flip(struct tty_struct *tty){	unsigned long flags;	spin_lock_irqsave(&tty->buf.lock, flags);	if (tty->buf.tail != NULL)		tty->buf.tail->commit = tty->buf.tail->used;	spin_unlock_irqrestore(&tty->buf.lock, flags);	schedule_delayed_work(&tty->buf.work, 1);}EXPORT_SYMBOL(tty_schedule_flip);/** *	tty_prepare_flip_string		-	make room for characters *	@tty: tty *	@chars: return pointer for character write area *	@size: desired size * *	Prepare a block of space in the buffer for data. Returns the length *	available and buffer pointer to the space which is now allocated and *	accounted for as ready for normal characters. This is used for drivers *	that need their own block copy routines into the buffer. There is no *	guarantee the buffer is a DMA target! * *	Locking: May call functions taking tty->buf.lock */int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size){	int space = tty_buffer_request_room(tty, size);	if (likely(space)) {		struct tty_buffer *tb = tty->buf.tail;		*chars = tb->char_buf_ptr + tb->used;		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);		tb->used += space;	}	return space;}EXPORT_SYMBOL_GPL(tty_prepare_flip_string);/** *	tty_prepare_flip_string_flags	-	make room for characters *	@tty: tty *	@chars: return pointer for character write area *	@flags: return pointer for status flag write area *	@size: desired size * *	Prepare a block of space in the buffer for data. Returns the length *	available and buffer pointer to the space which is now allocated and *	accounted for as ready for characters. This is used for drivers *	that need their own block copy routines into the buffer. There is no *	guarantee the buffer is a DMA target! * *	Locking: May call functions taking tty->buf.lock */int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size){	int space = tty_buffer_request_room(tty, size);	if (likely(space)) {		struct tty_buffer *tb = tty->buf.tail;		*chars = tb->char_buf_ptr + tb->used;		*flags = tb->flag_buf_ptr + tb->used;		tb->used += space;	}	return space;}EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);/** *	tty_set_termios_ldisc		-	set ldisc field *	@tty: tty structure *	@num: line discipline number * *	This is probably overkill for real world processors but *	they are not on hot paths so a little discipline won't do  *	any harm. * *	Locking: takes termios_mutex */ static void tty_set_termios_ldisc(struct tty_struct *tty, int num){	mutex_lock(&tty->termios_mutex);	tty->termios->c_line = num;	mutex_unlock(&tty->termios_mutex);}/* *	This guards the refcounted line discipline lists. The lock *	must be taken with irqs off because there are hangup path *	callers who will do ldisc lookups and cannot sleep. */ static DEFINE_SPINLOCK(tty_ldisc_lock);static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);static struct tty_ldisc tty_ldiscs[NR_LDISCS];	/* line disc dispatch table *//** *	tty_register_ldisc	-	install a line discipline *	@disc: ldisc number *	@new_ldisc: pointer to the ldisc object * *	Installs a new line discipline into the kernel. The discipline *	is set up as unreferenced and then made available to the kernel *	from this point onwards. * *	Locking: *		takes tty_ldisc_lock to guard against ldisc races */int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc){	unsigned long flags;	int ret = 0;		if (disc < N_TTY || disc >= NR_LDISCS)		return -EINVAL;		spin_lock_irqsave(&tty_ldisc_lock, flags);	tty_ldiscs[disc] = *new_ldisc;	tty_ldiscs[disc].num = disc;	tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;	tty_ldiscs[disc].refcount = 0;	spin_unlock_irqrestore(&tty_ldisc_lock, flags);		return ret;}EXPORT_SYMBOL(tty_register_ldisc);/** *	tty_unregister_ldisc	-	unload a line discipline *	@disc: ldisc number *	@new_ldisc: pointer to the ldisc object * *	Remove a line discipline from the kernel providing it is not *	currently in use. * *	Locking: *		takes tty_ldisc_lock to guard against ldisc races */int tty_unregister_ldisc(int disc){	unsigned long flags;	int ret = 0;	if (disc < N_TTY || disc >= NR_LDISCS)		return -EINVAL;	spin_lock_irqsave(&tty_ldisc_lock, flags);	if (tty_ldiscs[disc].refcount)		ret = -EBUSY;	else		tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;	spin_unlock_irqrestore(&tty_ldisc_lock, flags);	return ret;}EXPORT_SYMBOL(tty_unregister_ldisc);/** *	tty_ldisc_get		-	take a reference to an ldisc *	@disc: ldisc number * *	Takes a reference to a line discipline. Deals with refcounts and *	module locking counts. Returns NULL if the discipline is not available. *	Returns a pointer to the discipline and bumps the ref count if it is *	available * *	Locking: *		takes tty_ldisc_lock to guard against ldisc races */struct tty_ldisc *tty_ldisc_get(int disc){	unsigned long flags;	struct tty_ldisc *ld;	if (disc < N_TTY || disc >= NR_LDISCS)		return NULL;		spin_lock_irqsave(&tty_ldisc_lock, flags);	ld = &tty_ldiscs[disc];	/* Check the entry is defined */	if(ld->flags & LDISC_FLAG_DEFINED)	{		/* If the module is being unloaded we can't use it */		if (!try_module_get(ld->owner))		       	ld = NULL;		else /* lock it */			ld->refcount++;	}	else		ld = NULL;	spin_unlock_irqrestore(&tty_ldisc_lock, flags);	return ld;}EXPORT_SYMBOL_GPL(tty_ldisc_get);/** *	tty_ldisc_put		-	drop ldisc reference *	@disc: ldisc number * *	Drop a reference to a line discipline. Manage refcounts and *	module usage counts * *	Locking: *		takes tty_ldisc_lock to guard against ldisc races */void tty_ldisc_put(int disc){	struct tty_ldisc *ld;	unsigned long flags;		BUG_ON(disc < N_TTY || disc >= NR_LDISCS);			spin_lock_irqsave(&tty_ldisc_lock, flags);	ld = &tty_ldiscs[disc];	BUG_ON(ld->refcount == 0);	ld->refcount--;	module_put(ld->owner);	spin_unlock_irqrestore(&tty_ldisc_lock, flags);}	EXPORT_SYMBOL_GPL(tty_ldisc_put);/** *	tty_ldisc_assign	-	set ldisc on a tty *	@tty: tty to assign *	@ld: line discipline * *	Install an instance of a line discipline into a tty structure. The *	ldisc must have a reference count above zero to ensure it remains/ *	The tty instance refcount starts at zero. * *	Locking: *		Caller must hold references */static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld){	tty->ldisc = *ld;	tty->ldisc.refcount = 0;}/** *	tty_ldisc_try		-	internal helper *	@tty: the tty * *	Make a single attempt to grab and bump the refcount on *	the tty ldisc. Return 0 on failure or 1 on success. This is *	used to implement both the waiting and non waiting versions *	of tty_ldisc_ref * *	Locking: takes tty_ldisc_lock */static int tty_ldisc_try(struct tty_struct *tty){	unsigned long flags;	struct tty_ldisc *ld;	int ret = 0;		spin_lock_irqsave(&tty_ldisc_lock, flags);	ld = &tty->ldisc;	if(test_bit(TTY_LDISC, &tty->flags))	{		ld->refcount++;		ret = 1;	}	spin_unlock_irqrestore(&tty_ldisc_lock, flags);	return ret;}/** *	tty_ldisc_ref_wait	-	wait for the tty ldisc *	@tty: tty device * *	Dereference the line discipline for the terminal and take a  *	reference to it. If the line discipline is in flux then  *	wait patiently until it changes. * *	Note: Must not be called from an IRQ/timer context. The caller *	must also be careful not to hold other locks that will deadlock *	against a discipline change, such as an existing ldisc reference *	(which we check for) * *	Locking: call functions take tty_ldisc_lock */ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty){	/* wait_event is a macro */	wait_event(tty_ldisc_wait, tty_ldisc_try(tty));	if(tty->ldisc.refcount == 0)		printk(KERN_ERR "tty_ldisc_ref_wait\n");	return &tty->ldisc;}EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);/** *	tty_ldisc_ref		-	get the tty ldisc *	@tty: tty device * *	Dereference the line discipline for the terminal and take a  *	reference to it. If the line discipline is in flux then  *	return NULL. Can be called from IRQ and timer functions. * *	Locking: called functions take tty_ldisc_lock */ struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty){	if(tty_ldisc_try(tty))		return &tty->ldisc;	return NULL;}EXPORT_SYMBOL_GPL(tty_ldisc_ref);/** *	tty_ldisc_deref		-	free a tty ldisc reference *	@ld: reference to free up * *	Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May *	be called in IRQ context. * *	Locking: takes tty_ldisc_lock */ void tty_ldisc_deref(struct tty_ldisc *ld){	unsigned long flags;	BUG_ON(ld == NULL);			spin_lock_irqsave(&tty_ldisc_lock, flags);	if(ld->refcount == 0)		printk(KERN_ERR "tty_ldisc_deref: no references.\n");	else		ld->refcount--;	if(ld->refcount == 0)		wake_up(&tty_ldisc_wait);	spin_unlock_irqrestore(&tty_ldisc_lock, flags);}EXPORT_SYMBOL_GPL(tty_ldisc_deref);/** *	tty_ldisc_enable	-	allow ldisc use *	@tty: terminal to activate ldisc on * *	Set the TTY_LDISC flag when the line discipline can be called *	again. Do necessary wakeups for existing sleepers. * *	Note: nobody should set this bit except via this function. Clearing *	directly is allowed. */static void tty_ldisc_enable(struct tty_struct *tty){	set_bit(TTY_LDISC, &tty->flags);	wake_up(&tty_ldisc_wait);}	/** *	tty_set_ldisc		-	set line discipline *	@tty: the terminal to set *	@ldisc: the line discipline * *	Set the discipline of a tty line. Must be called from a process *	context. * *	Locking: takes tty_ldisc_lock. *		 called functions take termios_mutex */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc){	int retval = 0;	struct tty_ldisc o_ldisc;	char buf[64];	int work;	unsigned long flags;	struct tty_ldisc *ld;	struct tty_struct *o_tty;	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))		return -EINVAL;restart:	ld = tty_ldisc_get(ldisc);	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */	/* Cyrus Durgin <cider@speakeasy.org> */	if (ld == NULL) {		request_module("tty-ldisc-%d", ldisc);		ld = tty_ldisc_get(ldisc);	}	if (ld == NULL)		return -EINVAL;	/*	 *	Problem: What do we do if this blocks ?	 */	tty_wait_until_sent(tty, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?