stallion.c

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

C
2,551
字号
	if (portp->tx.buf == NULL)		return;	head = portp->tx.head;	tail = portp->tx.tail;	len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail)) : (tail - head);	len--;	if (len > 0) {		*head++ = ch;		if (head >= (portp->tx.buf + STL_TXBUFSIZE))			head = portp->tx.buf;	}		portp->tx.head = head;}/*****************************************************************************//* *	If there are any characters in the buffer then make sure that TX *	interrupts are on and get'em out. Normally used after the putchar *	routine has been called. */static void stl_flushchars(struct tty_struct *tty){	struct stlport	*portp;	pr_debug("stl_flushchars(tty=%p)\n", tty);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	if (portp->tx.buf == NULL)		return;	stl_startrxtx(portp, -1, 1);}/*****************************************************************************/static int stl_writeroom(struct tty_struct *tty){	struct stlport	*portp;	char		*head, *tail;	pr_debug("stl_writeroom(tty=%p)\n", tty);	if (tty == NULL)		return 0;	portp = tty->driver_data;	if (portp == NULL)		return 0;	if (portp->tx.buf == NULL)		return 0;	head = portp->tx.head;	tail = portp->tx.tail;	return (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1);}/*****************************************************************************//* *	Return number of chars in the TX buffer. Normally we would just *	calculate the number of chars in the buffer and return that, but if *	the buffer is empty and TX interrupts are still on then we return *	that the buffer still has 1 char in it. This way whoever called us *	will not think that ALL chars have drained - since the UART still *	must have some chars in it (we are busy after all). */static int stl_charsinbuffer(struct tty_struct *tty){	struct stlport	*portp;	unsigned int	size;	char		*head, *tail;	pr_debug("stl_charsinbuffer(tty=%p)\n", tty);	if (tty == NULL)		return 0;	portp = tty->driver_data;	if (portp == NULL)		return 0;	if (portp->tx.buf == NULL)		return 0;	head = portp->tx.head;	tail = portp->tx.tail;	size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));	if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate))		size = 1;	return size;}/*****************************************************************************//* *	Generate the serial struct info. */static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp){	struct serial_struct	sio;	struct stlbrd		*brdp;	pr_debug("stl_getserial(portp=%p,sp=%p)\n", portp, sp);	memset(&sio, 0, sizeof(struct serial_struct));	sio.line = portp->portnr;	sio.port = portp->ioaddr;	sio.flags = portp->flags;	sio.baud_base = portp->baud_base;	sio.close_delay = portp->close_delay;	sio.closing_wait = portp->closing_wait;	sio.custom_divisor = portp->custom_divisor;	sio.hub6 = 0;	if (portp->uartp == &stl_cd1400uart) {		sio.type = PORT_CIRRUS;		sio.xmit_fifo_size = CD1400_TXFIFOSIZE;	} else {		sio.type = PORT_UNKNOWN;		sio.xmit_fifo_size = SC26198_TXFIFOSIZE;	}	brdp = stl_brds[portp->brdnr];	if (brdp != NULL)		sio.irq = brdp->irq;	return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ? -EFAULT : 0;}/*****************************************************************************//* *	Set port according to the serial struct info. *	At this point we do not do any auto-configure stuff, so we will *	just quietly ignore any requests to change irq, etc. */static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp){	struct serial_struct	sio;	pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);	if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))		return -EFAULT;	if (!capable(CAP_SYS_ADMIN)) {		if ((sio.baud_base != portp->baud_base) ||		    (sio.close_delay != portp->close_delay) ||		    ((sio.flags & ~ASYNC_USR_MASK) !=		    (portp->flags & ~ASYNC_USR_MASK)))			return -EPERM;	} 	portp->flags = (portp->flags & ~ASYNC_USR_MASK) |		(sio.flags & ASYNC_USR_MASK);	portp->baud_base = sio.baud_base;	portp->close_delay = sio.close_delay;	portp->closing_wait = sio.closing_wait;	portp->custom_divisor = sio.custom_divisor;	stl_setport(portp, portp->tty->termios);	return 0;}/*****************************************************************************/static int stl_tiocmget(struct tty_struct *tty, struct file *file){	struct stlport	*portp;	if (tty == NULL)		return -ENODEV;	portp = tty->driver_data;	if (portp == NULL)		return -ENODEV;	if (tty->flags & (1 << TTY_IO_ERROR))		return -EIO;	return stl_getsignals(portp);}static int stl_tiocmset(struct tty_struct *tty, struct file *file,			unsigned int set, unsigned int clear){	struct stlport	*portp;	int rts = -1, dtr = -1;	if (tty == NULL)		return -ENODEV;	portp = tty->driver_data;	if (portp == NULL)		return -ENODEV;	if (tty->flags & (1 << TTY_IO_ERROR))		return -EIO;	if (set & TIOCM_RTS)		rts = 1;	if (set & TIOCM_DTR)		dtr = 1;	if (clear & TIOCM_RTS)		rts = 0;	if (clear & TIOCM_DTR)		dtr = 0;	stl_setsignals(portp, dtr, rts);	return 0;}static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){	struct stlport	*portp;	unsigned int	ival;	int		rc;	void __user *argp = (void __user *)arg;	pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,			arg);	if (tty == NULL)		return -ENODEV;	portp = tty->driver_data;	if (portp == NULL)		return -ENODEV;	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 	    (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS))		if (tty->flags & (1 << TTY_IO_ERROR))			return -EIO;	rc = 0;	switch (cmd) {	case TIOCGSOFTCAR:		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),			(unsigned __user *) argp);		break;	case TIOCSSOFTCAR:		if (get_user(ival, (unsigned int __user *) arg))			return -EFAULT;		tty->termios->c_cflag =				(tty->termios->c_cflag & ~CLOCAL) |				(ival ? CLOCAL : 0);		break;	case TIOCGSERIAL:		rc = stl_getserial(portp, argp);		break;	case TIOCSSERIAL:		rc = stl_setserial(portp, argp);		break;	case COM_GETPORTSTATS:		rc = stl_getportstats(portp, argp);		break;	case COM_CLRPORTSTATS:		rc = stl_clrportstats(portp, argp);		break;	case TIOCSERCONFIG:	case TIOCSERGWILD:	case TIOCSERSWILD:	case TIOCSERGETLSR:	case TIOCSERGSTRUCT:	case TIOCSERGETMULTI:	case TIOCSERSETMULTI:	default:		rc = -ENOIOCTLCMD;		break;	}	return rc;}/*****************************************************************************//* *	Start the transmitter again. Just turn TX interrupts back on. */static void stl_start(struct tty_struct *tty){	struct stlport	*portp;	pr_debug("stl_start(tty=%p)\n", tty);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	stl_startrxtx(portp, -1, 1);}/*****************************************************************************/static void stl_settermios(struct tty_struct *tty, struct ktermios *old){	struct stlport	*portp;	struct ktermios	*tiosp;	pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	tiosp = tty->termios;	if ((tiosp->c_cflag == old->c_cflag) &&	    (tiosp->c_iflag == old->c_iflag))		return;	stl_setport(portp, tiosp);	stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0),		-1);	if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) {		tty->hw_stopped = 0;		stl_start(tty);	}	if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))		wake_up_interruptible(&portp->open_wait);}/*****************************************************************************//* *	Attempt to flow control who ever is sending us data. Based on termios *	settings use software or/and hardware flow control. */static void stl_throttle(struct tty_struct *tty){	struct stlport	*portp;	pr_debug("stl_throttle(tty=%p)\n", tty);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	stl_flowctrl(portp, 0);}/*****************************************************************************//* *	Unflow control the device sending us data... */static void stl_unthrottle(struct tty_struct *tty){	struct stlport	*portp;	pr_debug("stl_unthrottle(tty=%p)\n", tty);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	stl_flowctrl(portp, 1);}/*****************************************************************************//* *	Stop the transmitter. Basically to do this we will just turn TX *	interrupts off. */static void stl_stop(struct tty_struct *tty){	struct stlport	*portp;	pr_debug("stl_stop(tty=%p)\n", tty);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	stl_startrxtx(portp, -1, 0);}/*****************************************************************************//* *	Hangup this port. This is pretty much like closing the port, only *	a little more brutal. No waiting for data to drain. Shutdown the *	port and maybe drop signals. */static void stl_hangup(struct tty_struct *tty){	struct stlport	*portp;	pr_debug("stl_hangup(tty=%p)\n", tty);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	portp->flags &= ~ASYNC_INITIALIZED;	stl_disableintrs(portp);	if (tty->termios->c_cflag & HUPCL)		stl_setsignals(portp, 0, 0);	stl_enablerxtx(portp, 0, 0);	stl_flushbuffer(tty);	portp->istate = 0;	set_bit(TTY_IO_ERROR, &tty->flags);	if (portp->tx.buf != NULL) {		kfree(portp->tx.buf);		portp->tx.buf = NULL;		portp->tx.head = NULL;		portp->tx.tail = NULL;	}	portp->tty = NULL;	portp->flags &= ~ASYNC_NORMAL_ACTIVE;	portp->refcount = 0;	wake_up_interruptible(&portp->open_wait);}/*****************************************************************************/static void stl_breakctl(struct tty_struct *tty, int state){	struct stlport	*portp;	pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	stl_sendbreak(portp, ((state == -1) ? 1 : 2));}/*****************************************************************************/static void stl_sendxchar(struct tty_struct *tty, char ch){	struct stlport	*portp;	pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);	if (tty == NULL)		return;	portp = tty->driver_data;	if (portp == NULL)		return;	if (ch == STOP_CHAR(tty))		stl_sendflow(portp, 0);	else if (ch == START_CHAR(tty))		stl_sendflow(portp, 1);	else		stl_putchar(tty, ch);}/*****************************************************************************/#define	MAXLINE		80/* *	Format info for a specified port. The line is deliberately limited *	to 80 characters. (If it is too long it will be truncated, if too *	short then padded with spaces). */static int stl_portinfo(struct stlport *portp, int portnr, char *pos){	char	*sp;	int	sigs, cnt;	sp = pos;	sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d",		portnr, (portp->hwid == 1) ? "SC26198" : "CD1400",		(int) portp->stats.txtotal, (int) portp->stats.rxtotal);	if (portp->stats.rxframing)		sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing);	if (portp->stats.rxparity)		sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity);	if (portp->stats.rxbreaks)		sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks);	if (portp->stats.rxoverrun)		sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun);	sigs = stl_getsignals(portp);	cnt = sprintf(sp, "%s%s%s%s%s ",		(sigs & TIOCM_RTS) ? "|RTS" : "",		(sigs & TIOCM_CTS) ? "|CTS" : "",		(sigs & TIOCM_DTR) ? "|DTR" : "",		(sigs & TIOCM_CD) ? "|DCD" : "",		(sigs & TIOCM_DSR) ? "|DSR" : "");	*sp = ' ';	sp += cnt;	for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++)		*sp++ = ' ';	if (cnt >= MAXLINE)		pos[(MAXLINE - 2)] = '+';

⌨️ 快捷键说明

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