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

📄 istallion.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
			interruptible_sleep_on(&portp->raw_wait);		}	}/* *	Write the close command into shared memory. */	EBRDENABLE(brdp);	cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;	cp->closearg = arg;	cp->close = 1;	hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);	bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +		portp->portidx;	*bits |= portp->portbit;	EBRDDISABLE(brdp);	set_bit(ST_CLOSING, &portp->state);	if (wait == 0) {		restore_flags(flags);		return(0);	}/* *	Slave is in action, so now we must wait for the open acknowledgment *	to come back. */	rc = 0;	while (test_bit(ST_CLOSING, &portp->state)) {		if (signal_pending(current)) {			rc = -ERESTARTSYS;			break;		}		interruptible_sleep_on(&portp->raw_wait);	}	restore_flags(flags);	if ((rc == 0) && (portp->rc != 0))		rc = -EIO;	return(rc);}/*****************************************************************************//* *	Send a command to the slave and wait for the response. This must *	have user context (it sleeps). This routine is generic in that it *	can send any type of command. Its purpose is to wait for that command *	to complete (as opposed to initiating the command then returning). */static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback){	unsigned long	flags;#if DEBUG	printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"		"copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,		(int) arg, size, copyback);#endif	save_flags(flags);	cli();	while (test_bit(ST_CMDING, &portp->state)) {		if (signal_pending(current)) {			restore_flags(flags);			return(-ERESTARTSYS);		}		interruptible_sleep_on(&portp->raw_wait);	}	stli_sendcmd(brdp, portp, cmd, arg, size, copyback);	while (test_bit(ST_CMDING, &portp->state)) {		if (signal_pending(current)) {			restore_flags(flags);			return(-ERESTARTSYS);		}		interruptible_sleep_on(&portp->raw_wait);	}	restore_flags(flags);	if (portp->rc != 0)		return(-EIO);	return(0);}/*****************************************************************************//* *	Send the termios settings for this port to the slave. This sleeps *	waiting for the command to complete - so must have user context. */static int stli_setport(stliport_t *portp){	stlibrd_t	*brdp;	asyport_t	aport;#if DEBUG	printk("stli_setport(portp=%x)\n", (int) portp);#endif	if (portp == (stliport_t *) NULL)		return(-ENODEV);	if (portp->tty == (struct tty_struct *) NULL)		return(-ENODEV);	if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds))		return(-ENODEV);	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return(-ENODEV);	stli_mkasyport(portp, &aport, portp->tty->termios);	return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));}/*****************************************************************************//* *	Wait for a specified delay period, this is not a busy-loop. It will *	give up the processor while waiting. Unfortunately this has some *	rather intimate knowledge of the process management stuff. */static void stli_delay(int len){#if DEBUG	printk("stli_delay(len=%d)\n", len);#endif	if (len > 0) {		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(len);		current->state = TASK_RUNNING;	}}/*****************************************************************************//* *	Possibly need to wait for carrier (DCD signal) to come high. Say *	maybe because if we are clocal then we don't need to wait... */static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp){	unsigned long	flags;	int		rc, doclocal;#if DEBUG	printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n",		(int) brdp, (int) portp, (int) filp);#endif	rc = 0;	doclocal = 0;	if (portp->flags & ASYNC_CALLOUT_ACTIVE) {		if (portp->normaltermios.c_cflag & CLOCAL)			doclocal++;	} else {		if (portp->tty->termios->c_cflag & CLOCAL)			doclocal++;	}	save_flags(flags);	cli();	portp->openwaitcnt++;	if (! tty_hung_up_p(filp))		portp->refcount--;	for (;;) {		if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) {			stli_mkasysigs(&portp->asig, 1, 1);			if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,			    &portp->asig, sizeof(asysigs_t), 0)) < 0)				break;		}		if (tty_hung_up_p(filp) ||		    ((portp->flags & ASYNC_INITIALIZED) == 0)) {			if (portp->flags & ASYNC_HUP_NOTIFY)				rc = -EBUSY;			else				rc = -ERESTARTSYS;			break;		}		if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&		    ((portp->flags & ASYNC_CLOSING) == 0) &&		    (doclocal || (portp->sigs & TIOCM_CD))) {			break;		}		if (signal_pending(current)) {			rc = -ERESTARTSYS;			break;		}		interruptible_sleep_on(&portp->open_wait);	}	if (! tty_hung_up_p(filp))		portp->refcount++;	portp->openwaitcnt--;	restore_flags(flags);	return(rc);}/*****************************************************************************//* *	Write routine. Take the data and put it in the shared memory ring *	queue. If port is not already sending chars then need to mark the *	service bits for this port. */static int stli_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){	volatile cdkasy_t	*ap;	volatile cdkhdr_t	*hdrp;	volatile unsigned char	*bits;	unsigned char		*shbuf, *chbuf;	stliport_t		*portp;	stlibrd_t		*brdp;	unsigned int		len, stlen, head, tail, size;	unsigned long		flags;#if DEBUG	printk("stli_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",		(int) tty, from_user, (int) buf, count);#endif	if ((tty == (struct tty_struct *) NULL) ||	    (stli_tmpwritebuf == (char *) NULL))		return(0);	if (tty == stli_txcooktty)		stli_flushchars(tty);	portp = tty->driver_data;	if (portp == (stliport_t *) NULL)		return(0);	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))		return(0);	brdp = stli_brds[portp->brdnr];	if (brdp == (stlibrd_t *) NULL)		return(0);	chbuf = (unsigned char *) buf;/* *	If copying direct from user space we need to be able to handle page *	faults while we are copying. To do this copy as much as we can now *	into a kernel buffer. From there we copy it into shared memory. The *	big problem is that we do not want shared memory enabled when we are *	sleeping (other boards may be serviced while asleep). Something else *	to note here is the reading of the tail twice. Since the boards *	shared memory can be on an 8-bit bus then we need to be very careful *	reading 16 bit quantities - since both the board (slave) and host *	could be writing and reading at the same time. */	if (from_user) {		save_flags(flags);		cli();		EBRDENABLE(brdp);		ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);		head = (unsigned int) ap->txq.head;		tail = (unsigned int) ap->txq.tail;		if (tail != ((unsigned int) ap->txq.tail))			tail = (unsigned int) ap->txq.tail;		len = (head >= tail) ? (portp->txsize - (head - tail) - 1) :			(tail - head - 1);		count = MIN(len, count);		EBRDDISABLE(brdp);		restore_flags(flags);		down(&stli_tmpwritesem);		copy_from_user(stli_tmpwritebuf, chbuf, count);		chbuf = &stli_tmpwritebuf[0];	}/* *	All data is now local, shove as much as possible into shared memory. */	save_flags(flags);	cli();	EBRDENABLE(brdp);	ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);	head = (unsigned int) ap->txq.head;	tail = (unsigned int) ap->txq.tail;	if (tail != ((unsigned int) ap->txq.tail))		tail = (unsigned int) ap->txq.tail;	size = portp->txsize;	if (head >= tail) {		len = size - (head - tail) - 1;		stlen = size - head;	} else {		len = tail - head - 1;		stlen = len;	}	len = MIN(len, count);	count = 0;	shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);	while (len > 0) {		stlen = MIN(len, stlen);		memcpy((shbuf + head), chbuf, stlen);		chbuf += stlen;		len -= stlen;		count += stlen;		head += stlen;		if (head >= size) {			head = 0;			stlen = tail;		}	}	ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);	ap->txq.head = head;	if (test_bit(ST_TXBUSY, &portp->state)) {		if (ap->changed.data & DT_TXEMPTY)			ap->changed.data &= ~DT_TXEMPTY;	}	hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);	bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +		portp->portidx;	*bits |= portp->portbit;	set_bit(ST_TXBUSY, &portp->state);	EBRDDISABLE(brdp);	if (from_user)		up(&stli_tmpwritesem);	restore_flags(flags);	return(count);}/*****************************************************************************//* *	Output a single character. We put it into a temporary local buffer *	(for speed) then write out that buffer when the flushchars routine *	is called. There is a safety catch here so that if some other port *	writes chars before the current buffer has been, then we write them *	first them do the new ports. */static void stli_putchar(struct tty_struct *tty, unsigned char ch){#if DEBUG	printk("stli_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);#endif	if (tty == (struct tty_struct *) NULL)		return;	if (tty != stli_txcooktty) {		if (stli_txcooktty != (struct tty_struct *) NULL)			stli_flushchars(stli_txcooktty);		stli_txcooktty = tty;	}	stli_txcookbuf[stli_txcooksize++] = ch;}/*****************************************************************************//* *	Transfer characters from the local TX cooking buffer to the board. *	We sort of ignore the tty that gets passed in here. We rely on the *	info stored with the TX cook buffer to tell us which port to flush *	the data on. In any case we clean out the TX cook buffer, for re-use *	by someone else. */static void stli_flushchars(struct tty_struct *tty){	volatile cdkhdr_t	*hdrp;	volatile unsigned char	*bits;	volatile cdkasy_t	*ap;	struct tty_struct	*cooktty;	stliport_t		*portp;	stlibrd_t		*brdp;	unsigned int		len, stlen, head, tail, size, count, cooksize;	unsigned char		*buf, *shbuf;	unsigned long		flags;#if DEBUG	printk("stli_flushchars(tty=%x)\n", (int) tty);#endif	cooksize = stli_txcooksize;	cooktty = stli_txcooktty;	stli_txcooksize = 0;	stli_txcookrealsize = 0;	stli_txcooktty = (struct tty_struct *) NULL;	if (tty == (struct tty_struct *) NULL)		return;	if (cooktty == (struct tty_struct *) NULL)		return;	if (tty != cooktty)		tty = cooktty;	if (cooksize == 0)		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;	save_flags(flags);	cli();	EBRDENABLE(brdp);	ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);	head = (unsigned int) ap->txq.head;	tail = (unsigned int) ap->txq.tail;	if (tail != ((unsigned int) ap->txq.tail))		tail = (unsigned int) ap->txq.tail;	size = portp->txsize;	if (head >= tail) {		len = size - (head - tail) - 1;		stlen = size - head;	} else {		len = tail - head - 1;		stlen = len;	}	len = MIN(len, cooksize);	count = 0;	shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);	buf = stli_txcookbuf;	while (len > 0) {		stlen = MIN(len, stlen);		memcpy((shbuf + head), buf, stlen);		buf += stlen;		len -= stlen;		count += stlen;		head += stlen;		if (head >= size) {			head = 0;			stlen = tail;		}	}	ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);	ap->txq.head = head;	if (test_bit(ST_TXBUSY, &portp->state)) {		if (ap->changed.data & DT_TXEMPTY)			ap->changed.data &= ~DT_TXEMPTY;	}	hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);	bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +		portp->portidx;	*bits |= portp->portbit;	set_bit(ST_TXBUSY, &portp->state);	EBRDDISABLE(brdp);	restore_flags(flags);}/*****************************************************************************/static int stli_writeroom(struct tty_struct *tty){	volatile cdkasyrq_t	*rp;	stliport_t		*portp;	stlibrd_t		*brdp;

⌨️ 快捷键说明

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