⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 line.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */#include "linux/sched.h"#include "linux/slab.h"#include "linux/list.h"#include "linux/kd.h"#include "linux/interrupt.h"#include "linux/devfs_fs_kernel.h"#include "asm/uaccess.h"#include "chan_kern.h"#include "irq_user.h"#include "line.h"#include "kern.h"#include "user_util.h"#include "kern_util.h"#include "os.h"#include "irq_kern.h"#define LINE_BUFSIZE 4096static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused){	struct tty_struct *tty = data;	struct line *line = tty->driver_data;	if (line)		chan_interrupt(&line->chan_list, &line->task, tty, irq);	return IRQ_HANDLED;}static void line_timer_cb(void *arg){	struct tty_struct *tty = arg;	struct line *line = tty->driver_data;	line_interrupt(line->driver->read_irq, arg, NULL);}/* Returns the free space inside the ring buffer of this line. * * Should be called while holding line->lock (this does not modify datas). */static int write_room(struct line *line){	int n;	if (line->buffer == NULL)		return LINE_BUFSIZE - 1;	/* This is for the case where the buffer is wrapped! */	n = line->head - line->tail;	if (n <= 0)		n = LINE_BUFSIZE + n; /* The other case */	return n - 1;}int line_write_room(struct tty_struct *tty){	struct line *line = tty->driver_data;	unsigned long flags;	int room;	if (tty->stopped)		return 0;	spin_lock_irqsave(&line->lock, flags);	room = write_room(line);	spin_unlock_irqrestore(&line->lock, flags);	/*XXX: Warning to remove */	if (0 == room)		printk(KERN_DEBUG "%s: %s: no room left in buffer\n",		       __FUNCTION__,tty->name);	return room;}int line_chars_in_buffer(struct tty_struct *tty){	struct line *line = tty->driver_data;	unsigned long flags;	int ret;	spin_lock_irqsave(&line->lock, flags);	/*write_room subtracts 1 for the needed NULL, so we readd it.*/	ret = LINE_BUFSIZE - (write_room(line) + 1);	spin_unlock_irqrestore(&line->lock, flags);	return ret;}/* * This copies the content of buf into the circular buffer associated with * this line. * The return value is the number of characters actually copied, i.e. the ones * for which there was space: this function is not supposed to ever flush out * the circular buffer. * * Must be called while holding line->lock! */static int buffer_data(struct line *line, const char *buf, int len){	int end, room;	if(line->buffer == NULL){		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);		if (line->buffer == NULL) {			printk("buffer_data - atomic allocation failed\n");			return(0);		}		line->head = line->buffer;		line->tail = line->buffer;	}	room = write_room(line);	len = (len > room) ? room : len;	end = line->buffer + LINE_BUFSIZE - line->tail;	if (len < end){		memcpy(line->tail, buf, len);		line->tail += len;	} else {		/* The circular buffer is wrapping */		memcpy(line->tail, buf, end);		buf += end;		memcpy(line->buffer, buf, len - end);		line->tail = line->buffer + len - end;	}	return len;}/* * Flushes the ring buffer to the output channels. That is, write_chan is * called, passing it line->head as buffer, and an appropriate count. * * On exit, returns 1 when the buffer is empty, * 0 when the buffer is not empty on exit, * and -errno when an error occurred. * * Must be called while holding line->lock!*/static int flush_buffer(struct line *line){	int n, count;	if ((line->buffer == NULL) || (line->head == line->tail))		return 1;	if (line->tail < line->head) {		/* line->buffer + LINE_BUFSIZE is the end of the buffer! */		count = line->buffer + LINE_BUFSIZE - line->head;		n = write_chan(&line->chan_list, line->head, count,			       line->driver->write_irq);		if (n < 0)			return n;		if (n == count) {			/* We have flushed from ->head to buffer end, now we			 * must flush only from the beginning to ->tail.*/			line->head = line->buffer;		} else {			line->head += n;			return 0;		}	}	count = line->tail - line->head;	n = write_chan(&line->chan_list, line->head, count, 		       line->driver->write_irq);	if(n < 0)		return n;	line->head += n;	return line->head == line->tail;}void line_flush_buffer(struct tty_struct *tty){	struct line *line = tty->driver_data;	unsigned long flags;	int err;	/*XXX: copied from line_write, verify if it is correct!*/	if(tty->stopped)		return;		//return 0;	spin_lock_irqsave(&line->lock, flags);	err = flush_buffer(line);	/*if (err == 1)		err = 0;*/	spin_unlock_irqrestore(&line->lock, flags);	//return err;}/* We map both ->flush_chars and ->put_char (which go in pair) onto ->flush_buffer * and ->write. Hope it's not that bad.*/void line_flush_chars(struct tty_struct *tty){	line_flush_buffer(tty);}void line_put_char(struct tty_struct *tty, unsigned char ch){	line_write(tty, &ch, sizeof(ch));}int line_write(struct tty_struct *tty, const unsigned char *buf, int len){	struct line *line = tty->driver_data;	unsigned long flags;	int n, err, ret = 0;	if(tty->stopped)		return 0;	spin_lock_irqsave(&line->lock, flags);	if (line->head != line->tail) {		ret = buffer_data(line, buf, len);		err = flush_buffer(line);		if (err <= 0 && (err != -EAGAIN || !ret))			ret = err;	} else {		n = write_chan(&line->chan_list, buf, len, 			       line->driver->write_irq);		if (n < 0) {			ret = n;			goto out_up;		}		len -= n;		ret += n;		if (len > 0)			ret += buffer_data(line, buf + n, len);	}out_up:	spin_unlock_irqrestore(&line->lock, flags);	return ret;}void line_set_termios(struct tty_struct *tty, struct termios * old){	/* nothing */}static struct {	int  cmd;	char *level;	char *name;} tty_ioctls[] = {	/* don't print these, they flood the log ... */	{ TCGETS,      NULL,       "TCGETS"      },        { TCSETS,      NULL,       "TCSETS"      },        { TCSETSW,     NULL,       "TCSETSW"     },        { TCFLSH,      NULL,       "TCFLSH"      },        { TCSBRK,      NULL,       "TCSBRK"      },	/* general tty stuff */        { TCSETSF,     KERN_DEBUG, "TCSETSF"     },        { TCGETA,      KERN_DEBUG, "TCGETA"      },        { TIOCMGET,    KERN_DEBUG, "TIOCMGET"    },        { TCSBRKP,     KERN_DEBUG, "TCSBRKP"     },        { TIOCMSET,    KERN_DEBUG, "TIOCMSET"    },	/* linux-specific ones */	{ TIOCLINUX,   KERN_INFO,  "TIOCLINUX"   },	{ KDGKBMODE,   KERN_INFO,  "KDGKBMODE"   },	{ KDGKBTYPE,   KERN_INFO,  "KDGKBTYPE"   },	{ KDSIGACCEPT, KERN_INFO,  "KDSIGACCEPT" },};int line_ioctl(struct tty_struct *tty, struct file * file,	       unsigned int cmd, unsigned long arg){	int ret;	int i;	ret = 0;	switch(cmd) {#ifdef TIOCGETP	case TIOCGETP:	case TIOCSETP:	case TIOCSETN:#endif#ifdef TIOCGETC	case TIOCGETC:	case TIOCSETC:#endif#ifdef TIOCGLTC	case TIOCGLTC:	case TIOCSLTC:#endif	case TCGETS:	case TCSETSF:	case TCSETSW:	case TCSETS:	case TCGETA:	case TCSETAF:	case TCSETAW:	case TCSETA:	case TCXONC:	case TCFLSH:	case TIOCOUTQ:	case TIOCINQ:	case TIOCGLCKTRMIOS:	case TIOCSLCKTRMIOS:	case TIOCPKT:	case TIOCGSOFTCAR:	case TIOCSSOFTCAR:		return -ENOIOCTLCMD;#if 0	case TCwhatever:		/* do something */		break;#endif	default:		for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++)			if (cmd == tty_ioctls[i].cmd)				break;		if (i < ARRAY_SIZE(tty_ioctls)) {			if (NULL != tty_ioctls[i].level)				printk("%s%s: %s: ioctl %s called\n",				       tty_ioctls[i].level, __FUNCTION__,				       tty->name, tty_ioctls[i].name);		} else {			printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",			       __FUNCTION__, tty->name, cmd);		}		ret = -ENOIOCTLCMD;		break;	}	return ret;}static irqreturn_t line_write_interrupt(int irq, void *data,					struct pt_regs *unused){	struct tty_struct *tty = data;	struct line *line = tty->driver_data;	int err;	/* Interrupts are enabled here because we registered the interrupt with	 * SA_INTERRUPT (see line_setup_irq).*/	spin_lock_irq(&line->lock);	err = flush_buffer(line);	if (err == 0) {		return IRQ_NONE;	} else if(err < 0) {		line->head = line->buffer;		line->tail = line->buffer;	}	spin_unlock_irq(&line->lock);	if(tty == NULL)		return IRQ_NONE;	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&	   (tty->ldisc.write_wakeup != NULL))		(tty->ldisc.write_wakeup)(tty);		/* BLOCKING mode	 * In blocking mode, everything sleeps on tty->write_wait.	 * Sleeping in the console driver would break non-blocking	 * writes.	 */	if (waitqueue_active(&tty->write_wait))		wake_up_interruptible(&tty->write_wait);	return IRQ_HANDLED;}int line_setup_irq(int fd, int input, int output, struct tty_struct *tty){	struct line *line = tty->driver_data;	struct line_driver *driver = line->driver;	int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;	if (input)		err = um_request_irq(driver->read_irq, fd, IRQ_READ,				       line_interrupt, flags, 				       driver->read_irq_name, tty);	if (err)		return err;	if (output)		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,					line_write_interrupt, flags, 					driver->write_irq_name, tty);	line->have_irq = 1;	return err;}void line_disable(struct tty_struct *tty, int current_irq){	struct line *line = tty->driver_data;	if(!line->have_irq)		return;	if(line->driver->read_irq == current_irq)		free_irq_later(line->driver->read_irq, tty);	else {		free_irq(line->driver->read_irq, tty);	}	if(line->driver->write_irq == current_irq)		free_irq_later(line->driver->write_irq, tty);	else {

⌨️ 快捷键说明

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