📄 epca.c
字号:
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 + -