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

📄 epca.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
			0      1      2      3      4      5      6      7      8      9   		                tail                               head			The above diagram shows that buffer locations 2,3,4,5 and 6 have			data to be transmited, while head points at the next empty			location.  To calculate how much space is available first we have			to determine if the head pointer (tin) has wrapped.  To do this			compare the head pointer to the tail pointer,  If head is equal			or greater than tail; then it has not wrapped; and the space may			be calculated by subtracting tail from head and then subtracting			that value from the buffers size.  A one is subtracted from the			new value to indicate how much space is available between the 			head pointer and end of buffer; as well as the space between the			begining of the buffer and the tail.  If the head is not greater			or equal to the tail this indicates that the head has wrapped			around to the begining of the buffer.  To calculate the space 			available in this case simply subtract head from tail.  This new 			value minus one represents the space available betwwen the head 			and tail pointers.  In this example head (7) is greater than tail (2)			and therefore has not wrapped around.  We find the space by first			subtracting tail from head (7-2=5).  We then subtract this value			from the buffer size of ten and subtract one (10-5-1=4).  The space			remaining is 4 bytes. 			Example 2:						Consider a 10 byte buffer where head is a pointer to the next			empty location in the buffer and tail is a pointer to the next 			byte to transmit.  In this example head will wrapped around and 			therefore head < tail.  			0      1      2      3      4      5      6      7      8      9   		                head                               tail			The above diagram shows that buffer locations 7,8,9,0 and 1 have			data to be transmited, while head points at the next empty			location.  To find the space available we compare head to tail.  If			head is not equal to, or greater than tail this indicates that head			has wrapped around. In this case head (2) is not equal to, or			greater than tail (7) and therefore has already wrapped around.  To			calculate the available space between the two pointers we subtract			head from tail (7-2=5).  We then subtract one from this new value			(5-1=4).  We have 5 bytes empty remaining in the buffer.  Unlike the			previous example these five bytes are located between the head and			tail pointers. 		----------------------------------------------------------------------- */		dataLen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);		/* ----------------------------------------------------------------------			In this case bytesAvailable has been passed into pc_write and			represents the amount of data that needs to be written.  dataLen			represents the amount of space available on the card.  Whichever			value is smaller will be the amount actually written. 			bytesAvailable will then take on this newly calculated value.		---------------------------------------------------------------------- */		bytesAvailable = MIN(dataLen, bytesAvailable);		/* First we read the data in from the file system into a temp buffer */		if (bytesAvailable) 		{ /* Begin bytesAvailable */			/* Can the user buffer be accessed at the moment ? */			if (verify_area(VERIFY_READ, (char*)buf, bytesAvailable))				bytesAvailable = 0; /* Can't do; try again later */			else  /* Evidently it can, began transmission */			{ /* Begin if area verified */				/* ---------------------------------------------------------------					The below function reads data from user memory.  This routine					can not be used in an interrupt routine. (Because it may 					generate a page fault)  It can only be called while we can the					user context is accessible. 					The prototype is :					inline void copy_from_user(void * to, const void * from,					                          unsigned long count);					You must include <asm/segment.h>					I also think (Check hackers guide) that optimization must					be turned ON.  (Which sounds strange to me...)						Remember copy_from_user WILL generate a page fault if the					user memory being accessed has been swapped out.  This can					cause this routine to temporarily sleep while this page					fault is occuring.								----------------------------------------------------------------- */				copy_from_user(ch->tmp_buf, buf, bytesAvailable);			} /* End if area verified */		} /* End bytesAvailable */		/* ------------------------------------------------------------------ 			Set buf to this address for the moment.  tmp_buf was allocated in			post_fep_init.		--------------------------------------------------------------------- */		buf = ch->tmp_buf;		memoff(ch);		restore_flags(flags);	} /* End from_user */	/* All data is now local */	amountCopied = 0;	save_flags(flags);	cli();	globalwinon(ch);	head = bc->tin & (size - 1);	tail = bc->tout;	if (tail != bc->tout)		tail = bc->tout;	tail &= (size - 1);	/*	If head >= tail, head has not wrapped around. */ 	if (head >= tail) 	{ /* Begin head has not wrapped */		/* ---------------------------------------------------------------			remain (much like dataLen above) represents the total amount of			space available on the card for data.  Here dataLen represents			the space existing between the head pointer and the end of 			buffer.  This is important because a memcpy cannot be told to			automatically wrap around when it hits the buffer end.		------------------------------------------------------------------ */ 		dataLen = size - head;		remain = size - (head - tail) - 1;	} /* End head has not wrapped */	else 	{ /* Begin head has wrapped around */		remain = tail - head - 1;		dataLen = remain;	} /* End head has wrapped around */	/* -------------------------------------------------------------------			Check the space on the card.  If we have more data than 			space; reduce the amount of data to fit the space.	---------------------------------------------------------------------- */	bytesAvailable = MIN(remain, bytesAvailable);	txwinon(ch);	while (bytesAvailable > 0) 	{ /* Begin while there is data to copy onto card */		/* -----------------------------------------------------------------			If head is not wrapped, the below will make sure the first 			data copy fills to the end of card buffer.		------------------------------------------------------------------- */		dataLen = MIN(bytesAvailable, dataLen);		memcpy(ch->txptr + head, buf, dataLen);		buf += dataLen;		head += dataLen;		amountCopied += dataLen;		bytesAvailable -= dataLen;		if (head >= size) 		{			head = 0;			dataLen = tail;		}	} /* End while there is data to copy onto card */	ch->statusflags |= TXBUSY;	globalwinon(ch);	bc->tin = head;	if ((ch->statusflags & LOWWAIT) == 0) 	{		ch->statusflags |= LOWWAIT;		bc->ilow = 1;	}	memoff(ch);	restore_flags(flags);	return(amountCopied);} /* End pc_write *//* ------------------ Begin pc_put_char  ------------------------- */static void pc_put_char(struct tty_struct *tty, unsigned char c){ /* Begin pc_put_char */   	pc_write(tty, 0, &c, 1);	return;} /* End pc_put_char *//* ------------------ Begin pc_write_room  ------------------------- */static int pc_write_room(struct tty_struct *tty){ /* Begin pc_write_room */	int remain;	struct channel *ch;	unsigned long flags;	unsigned int head, tail;	volatile struct board_chan *bc;	remain = 0;	/* ---------------------------------------------------------		verifyChannel returns the channel from the tty struct		if it is valid.  This serves as a sanity check.	------------------------------------------------------------- */	if ((ch = verifyChannel(tty)) != NULL) 	{		save_flags(flags);		cli();		globalwinon(ch);		bc   = ch->brdchan;		head = bc->tin & (ch->txbufsize - 1);		tail = bc->tout;		if (tail != bc->tout)			tail = bc->tout;		/* Wrap tail if necessary */		tail &= (ch->txbufsize - 1);		if ((remain = tail - head - 1) < 0 )			remain += ch->txbufsize;		if (remain && (ch->statusflags & LOWWAIT) == 0) 		{			ch->statusflags |= LOWWAIT;			bc->ilow = 1;		}		memoff(ch);		restore_flags(flags);	}	/* Return how much room is left on card */	return remain;} /* End pc_write_room *//* ------------------ Begin pc_chars_in_buffer  ---------------------- */static int pc_chars_in_buffer(struct tty_struct *tty){ /* Begin pc_chars_in_buffer */	int chars;	unsigned int ctail, head, tail;	int remain;	unsigned long flags;	struct channel *ch;	volatile struct board_chan *bc;	/* ---------------------------------------------------------		verifyChannel returns the channel from the tty struct		if it is valid.  This serves as a sanity check.	------------------------------------------------------------- */	if ((ch = verifyChannel(tty)) == NULL)		return(0);	save_flags(flags);	cli();	globalwinon(ch);	bc = ch->brdchan;	tail = bc->tout;	head = bc->tin;	ctail = ch->mailbox->cout;	if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)		chars = 0;	else 	{ /* Begin if some space on the card has been used */		head = bc->tin & (ch->txbufsize - 1);		tail &= (ch->txbufsize - 1);		/*  --------------------------------------------------------------			The logic here is basically opposite of the above pc_write_room			here we are finding the amount of bytes in the buffer filled.			Not the amount of bytes empty.		------------------------------------------------------------------- */		if ((remain = tail - head - 1) < 0 )			remain += ch->txbufsize;		chars = (int)(ch->txbufsize - remain);		/* -------------------------------------------------------------  			Make it possible to wakeup anything waiting for output			in tty_ioctl.c, etc.			If not already set.  Setup an event to indicate when the			transmit buffer empties 		----------------------------------------------------------------- */		if (!(ch->statusflags & EMPTYWAIT))			setup_empty_event(tty,ch);	} /* End if some space on the card has been used */	memoff(ch);	restore_flags(flags);	/* Return number of characters residing on card. */	return(chars);} /* End pc_chars_in_buffer *//* ------------------ Begin pc_flush_buffer  ---------------------- */static void pc_flush_buffer(struct tty_struct *tty){ /* Begin pc_flush_buffer */	unsigned int tail;	unsigned long flags;	struct channel *ch;	volatile struct board_chan *bc;	/* ---------------------------------------------------------		verifyChannel returns the channel from the tty struct		if it is valid.  This serves as a sanity check.	------------------------------------------------------------- */	if ((ch = verifyChannel(tty)) == NULL)		return;	save_flags(flags);	cli();	globalwinon(ch);	bc   = ch->brdchan;	tail = bc->tout;	/* Have FEP move tout pointer; effectively flushing transmit buffer */	fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);	memoff(ch);	restore_flags(flags);	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);} /* End pc_flush_buffer *//* ------------------ Begin pc_flush_chars  ---------------------- */static void pc_flush_chars(struct tty_struct *tty){ /* Begin pc_flush_chars */	struct channel * ch;	/* ---------------------------------------------------------		verifyChannel returns the channel from the tty struct		if it is valid.  This serves as a sanity check.	------------------------------------------------------------- */	if ((ch = verifyChannel(tty)) != NULL) 	{		unsigned long flags;		save_flags(flags);		cli();		/* ----------------------------------------------------------------			If not already set and the transmitter is busy setup an event			to indicate when the transmit empties.		------------------------------------------------------------------- */		if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))			setup_empty_event(tty,ch);		restore_flags(flags);	}} /* End pc_flush_chars *//* ------------------ Begin block_til_ready  ---------------------- */static int block_til_ready(struct tty_struct *tty,                            struct file *filp, struct channel *ch){ /* Begin block_til_ready */	struct wait_queue wait = {current, NULL};	int	retval, do_clocal = 0;	unsigned long flags;	if (tty_hung_up_p(filp))	{		if (ch->asyncflags & ASYNC_HUP_NOTIFY)			retval = -EAGAIN;		else			retval = -ERESTARTSYS;			return(retval);	}	/* ----------------------------------------------------------------- 		If the device is in the middle of being closed, then block		until it's done, and then try again.	-------------------------------------------------------------------- */	if (ch->asyncflags & ASYNC_CLOSING) 	{		interruptible_sleep_on(&ch->close_wait);		if (ch->asyncflags & ASYNC_HUP_NOTIFY)			return -EAGAIN;		else			return -ERESTARTSYS;	}	/* ----------------------------------------------------------------- 	   If this is a callout device, then just make sure the normal	   device isn't being used.	-------------------------------------------------------------------- */

⌨️ 快捷键说明

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