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