istallion.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,375 行 · 第 1/5 页

C
2,375
字号
		return(0);	save_flags(flags);	cli();	EBRDENABLE(brdp);	rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;	head = (unsigned int) rp->head;	tail = (unsigned int) rp->tail;	if (tail != ((unsigned int) rp->tail))		tail = (unsigned int) rp->tail;	len = (head >= tail) ? (head - tail) : (portp->txsize - (tail - head));	if ((len == 0) && test_bit(ST_TXBUSY, &portp->state))		len = 1;	EBRDDISABLE(brdp);	restore_flags(flags);	return(len);}/*****************************************************************************//* *	Generate the serial struct info. */static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp){	struct serial_struct	sio;	stlibrd_t		*brdp;#ifdef DEBUG	printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);#endif	memset(&sio, 0, sizeof(struct serial_struct));	sio.type = PORT_UNKNOWN;	sio.line = portp->portnr;	sio.irq = 0;	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.xmit_fifo_size = 0;	sio.hub6 = 0;	brdp = stli_brds[portp->brdnr];	if (brdp != (stlibrd_t *) NULL)		sio.port = brdp->iobase;			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 stli_setserial(stliport_t *portp, struct serial_struct __user *sp){	struct serial_struct	sio;	int			rc;#ifdef DEBUG	printk("stli_setserial(portp=%p,sp=%p)\n", portp, sp);#endif	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;	if ((rc = stli_setport(portp)) < 0)		return(rc);	return(0);}/*****************************************************************************/static int stli_tiocmget(struct tty_struct *tty, struct file *file){	stliport_t *portp = tty->driver_data;	stlibrd_t *brdp;	int rc;	if (portp == (stliport_t *) NULL)		return(-ENODEV);	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return(0);	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return(0);	if (tty->flags & (1 << TTY_IO_ERROR))		return(-EIO);	if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,			       &portp->asig, sizeof(asysigs_t), 1)) < 0)		return(rc);	return stli_mktiocm(portp->asig.sigvalue);}static int stli_tiocmset(struct tty_struct *tty, struct file *file,			 unsigned int set, unsigned int clear){	stliport_t *portp = tty->driver_data;	stlibrd_t *brdp;	int rts = -1, dtr = -1;	if (portp == (stliport_t *) NULL)		return(-ENODEV);	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return(0);	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return(0);	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;	stli_mkasysigs(&portp->asig, dtr, rts);	return stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,			    sizeof(asysigs_t), 0);}static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){	stliport_t	*portp;	stlibrd_t	*brdp;	unsigned int	ival;	int		rc;	void __user *argp = (void __user *)arg;#ifdef DEBUG	printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",		(int) tty, (int) file, cmd, (int) arg);#endif	if (tty == (struct tty_struct *) NULL)		return(-ENODEV);	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return(-ENODEV);	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return(0);	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return(0);	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 *) arg);		break;	case TIOCSSOFTCAR:		if ((rc = get_user(ival, (unsigned __user *) arg)) == 0)			tty->termios->c_cflag =				(tty->termios->c_cflag & ~CLOCAL) |				(ival ? CLOCAL : 0);		break;	case TIOCGSERIAL:		rc = stli_getserial(portp, argp);		break;	case TIOCSSERIAL:		rc = stli_setserial(portp, argp);		break;	case STL_GETPFLAG:		rc = put_user(portp->pflag, (unsigned __user *)argp);		break;	case STL_SETPFLAG:		if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0)			stli_setport(portp);		break;	case COM_GETPORTSTATS:		rc = stli_getportstats(portp, argp);		break;	case COM_CLRPORTSTATS:		rc = stli_clrportstats(portp, argp);		break;	case TIOCSERCONFIG:	case TIOCSERGWILD:	case TIOCSERSWILD:	case TIOCSERGETLSR:	case TIOCSERGSTRUCT:	case TIOCSERGETMULTI:	case TIOCSERSETMULTI:	default:		rc = -ENOIOCTLCMD;		break;	}	return(rc);}/*****************************************************************************//* *	This routine assumes that we have user context and can sleep. *	Looks like it is true for the current ttys implementation..!! */static void stli_settermios(struct tty_struct *tty, struct termios *old){	stliport_t	*portp;	stlibrd_t	*brdp;	struct termios	*tiosp;	asyport_t	aport;#ifdef DEBUG	printk("stli_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);#endif	if (tty == (struct tty_struct *) NULL)		return;	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return;	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return;	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return;	tiosp = tty->termios;	if ((tiosp->c_cflag == old->c_cflag) &&	    (tiosp->c_iflag == old->c_iflag))		return;	stli_mkasyport(portp, &aport, tiosp);	stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);	stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);	stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,		sizeof(asysigs_t), 0);	if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0))		tty->hw_stopped = 0;	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. We won't really *	do any flow control action here. We can't directly, and even if we *	wanted to we would have to send a command to the slave. The slave *	knows how to flow control, and will do so when its buffers reach its *	internal high water marks. So what we will do is set a local state *	bit that will stop us sending any RX data up from the poll routine *	(which is the place where RX data from the slave is handled). */static void stli_throttle(struct tty_struct *tty){	stliport_t	*portp;#ifdef DEBUG	printk("stli_throttle(tty=%x)\n", (int) tty);#endif	if (tty == (struct tty_struct *) NULL)		return;	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return;	set_bit(ST_RXSTOP, &portp->state);}/*****************************************************************************//* *	Unflow control the device sending us data... That means that all *	we have to do is clear the RXSTOP state bit. The next poll call *	will then be able to pass the RX data back up. */static void stli_unthrottle(struct tty_struct *tty){	stliport_t	*portp;#ifdef DEBUG	printk("stli_unthrottle(tty=%x)\n", (int) tty);#endif	if (tty == (struct tty_struct *) NULL)		return;	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return;	clear_bit(ST_RXSTOP, &portp->state);}/*****************************************************************************//* *	Stop the transmitter. Basically to do this we will just turn TX *	interrupts off. */static void stli_stop(struct tty_struct *tty){	stlibrd_t	*brdp;	stliport_t	*portp;	asyctrl_t	actrl;#ifdef DEBUG	printk("stli_stop(tty=%x)\n", (int) tty);#endif	if (tty == (struct tty_struct *) NULL)		return;	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return;	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return;	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return;	memset(&actrl, 0, sizeof(asyctrl_t));	actrl.txctrl = CT_STOPFLOW;#if 0	stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);#endif}/*****************************************************************************//* *	Start the transmitter again. Just turn TX interrupts back on. */static void stli_start(struct tty_struct *tty){	stliport_t	*portp;	stlibrd_t	*brdp;	asyctrl_t	actrl;#ifdef DEBUG	printk("stli_start(tty=%x)\n", (int) tty);#endif	if (tty == (struct tty_struct *) NULL)		return;	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return;	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return;	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return;	memset(&actrl, 0, sizeof(asyctrl_t));	actrl.txctrl = CT_STARTFLOW;#if 0	stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);#endif}/*****************************************************************************//* *	Scheduler called hang up routine. This is called from the scheduler, *	not direct from the driver "poll" routine. We can't call it there *	since the real local hangup code will enable/disable the board and *	other things that we can't do while handling the poll. Much easier *	to deal with it some time later (don't really care when, hangups *	aren't that time critical). */static void stli_dohangup(void *arg){	stliport_t	*portp;#ifdef DEBUG	printk(KERN_DEBUG "stli_dohangup(portp=%x)\n", (int) arg);#endif	/*	 * FIXME: There's a module removal race here: tty_hangup	 * calls schedule_work which will call into this	 * driver later.	 */	portp = (stliport_t *) arg;	if (portp != (stliport_t *) NULL) {		if (portp->tty != (struct tty_struct *) NULL) {			tty_hangup(portp->tty);		}	}}/*****************************************************************************//* *	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. This is rather tricky really. We want *	to close the port as well. */static void stli_hangup(struct tty_struct *tty){	stliport_t	*portp;	stlibrd_t	*brdp;	unsigned long	flags;#ifdef DEBUG	printk(KERN_DEBUG "stli_hangup(tty=%x)\n", (int) tty);#endif	if (tty == (struct tty_struct *) NULL)		return;	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return;	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return;	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return;	portp->flags &= ~ASYNC_INITIALIZED;	save_flags(flags);	cli();	if (! test_bit(ST_CLOSING, &portp->state))		stli_rawclose(brdp, portp, 0, 0);	if (tty->termios->c_cflag & HUPCL) {		stli_mkasysigs(&portp->asig, 0, 0);		if (test_bit(ST_CMDING, &portp->state)) {			set_bit(ST_DOSIGS, &portp->state);			set_bit(ST_DOFLUSHTX, &portp->state);			set_bit(ST_DOFLUSHRX, &portp->state);		} else {			stli_sendcmd(brdp, portp, A_SETSIGNALSF,				&portp->asig, sizeof(asysigs_t), 0);		}	}	restore_flag

⌨️ 快捷键说明

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