riointr.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 658 行 · 第 1/2 页
C
658 行
** Lock the port before we begin working on it. */ rio_spin_lock(&PortP->portSem); /* ** If we can't add anything to the transmit queue, then ** we need do none of this processing. */ if (!can_add_transmit(&PacketP, PortP)) { rio_dprintk(RIO_DEBUG_INTR, "Can't add to port, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } /* ** find corresponding tty structure. The process of mapping ** the ports puts these here. */ ttyP = PortP->gs.tty; /* If ttyP is NULL, the port is getting closed. Forget about it. */ if (!ttyP) { rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } /* ** If there is more room available we start up the transmit ** data process again. This can be direct I/O, if the cookmode ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch ** characters via the line discipline. We must always call ** the line discipline, ** so that user input characters can be echoed correctly. ** ** ++++ Update +++++ ** With the advent of double buffering, we now see if ** TxBufferOut-In is non-zero. If so, then we copy a packet ** to the output place, and set it going. If this empties ** the buffer, then we must issue a wakeup( ) on OUT. ** If it frees space in the buffer then we must issue ** a wakeup( ) on IN. ** ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we ** have to send a WFLUSH command down the PHB, to mark the ** end point of a WFLUSH. We also need to clear out any ** data from the double buffer! ( note that WflushFlag is a ** *count* of the number of WFLUSH commands outstanding! ) ** ** ++++ And there's more! ** If an RTA is powered off, then on again, and rebooted, ** whilst it has ports open, then we need to re-open the ports. ** ( reasonable enough ). We can't do this when we spot the ** re-boot, in interrupt time, because the queue is probably ** full. So, when we come in here, we need to test if any ** ports are in this condition, and re-open the port before ** we try to send any more data to it. Now, the re-booted ** RTA will be discarding packets from the PHB until it ** receives this open packet, but don't worry tooo much ** about that. The one thing that is interesting is the ** combination of this effect and the WFLUSH effect! */ /* For now don't handle RTA reboots. -- REW. Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */ if (PortP->MagicFlags) { if (PortP->MagicFlags & MAGIC_REBOOT) { /* ** well, the RTA has been rebooted, and there is room ** on its queue to add the open packet that is required. ** ** The messy part of this line is trying to decide if ** we need to call the Param function as a tty or as ** a modem. ** DONT USE CLOCAL AS A TEST FOR THIS! ** ** If we can't param the port, then move on to the ** next port. */ PortP->InUse = NOT_INUSE; rio_spin_unlock(&PortP->portSem); if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) { continue; /* with next port */ } rio_spin_lock(&PortP->portSem); PortP->MagicFlags &= ~MAGIC_REBOOT; } /* ** As mentioned above, this is a tacky hack to cope ** with WFLUSH */ if (PortP->WflushFlag) { rio_dprintk(RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n"); if (PortP->InUse) rio_dprintk(RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n"); } while (PortP->WflushFlag && can_add_transmit(&PacketP, PortP) && (PortP->InUse == NOT_INUSE)) { int p; struct PktCmd *PktCmdP; rio_dprintk(RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n"); /* ** make it look just like a WFLUSH command */ PktCmdP = (struct PktCmd *) &PacketP->data[0]; writeb(WFLUSH, &PktCmdP->Command); p = PortP->HostPort % (u16) PORTS_PER_RTA; /* ** If second block of ports for 16 port RTA, add 8 ** to index 8-15. */ if (PortP->SecondBlock) p += PORTS_PER_RTA; writeb(p, &PktCmdP->PhbNum); /* ** to make debuggery easier */ writeb('W', &PacketP->data[2]); writeb('F', &PacketP->data[3]); writeb('L', &PacketP->data[4]); writeb('U', &PacketP->data[5]); writeb('S', &PacketP->data[6]); writeb('H', &PacketP->data[7]); writeb(' ', &PacketP->data[8]); writeb('0' + PortP->WflushFlag, &PacketP->data[9]); writeb(' ', &PacketP->data[10]); writeb(' ', &PacketP->data[11]); writeb('\0', &PacketP->data[12]); /* ** its two bytes long! */ writeb(PKT_CMD_BIT | 2, &PacketP->len); /* ** queue it! */ if (!(PortP->State & RIO_DELETED)) { add_transmit(PortP); /* ** Count chars tx'd for port statistics reporting */ if (PortP->statsGather) PortP->txchars += 2; } if (--(PortP->WflushFlag) == 0) { PortP->MagicFlags &= ~MAGIC_FLUSH; } rio_dprintk(RIO_DEBUG_INTR, "Wflush count now stands at %d\n", PortP->WflushFlag); } if (PortP->MagicFlags & MORE_OUTPUT_EYGOR) { if (PortP->MagicFlags & MAGIC_FLUSH) { PortP->MagicFlags |= MORE_OUTPUT_EYGOR; } else { if (!can_add_transmit(&PacketP, PortP)) { rio_spin_unlock(&PortP->portSem); continue; } rio_spin_unlock(&PortP->portSem); RIOTxEnable((char *) PortP); rio_spin_lock(&PortP->portSem); PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR; } } } /* ** If we can't add anything to the transmit queue, then ** we need do none of the remaining processing. */ if (!can_add_transmit(&PacketP, PortP)) { rio_spin_unlock(&PortP->portSem); continue; } rio_spin_unlock(&PortP->portSem); RIOTxEnable((char *) PortP); } }}/*** Routine for handling received data for tty drivers*/static void RIOReceive(struct rio_info *p, struct Port *PortP){ struct tty_struct *TtyP; unsigned short transCount; struct PKT *PacketP; register unsigned int DataCnt; unsigned char *ptr; unsigned char *buf; int copied = 0; static int intCount, RxIntCnt; /* ** The receive data process is to remove packets from the ** PHB until there aren't any more or the current cblock ** is full. When this occurs, there will be some left over ** data in the packet, that we must do something with. ** As we haven't unhooked the packet from the read list ** yet, we can just leave the packet there, having first ** made a note of how far we got. This means that we need ** a pointer per port saying where we start taking the ** data from - this will normally be zero, but when we ** run out of space it will be set to the offset of the ** next byte to copy from the packet data area. The packet ** length field is decremented by the number of bytes that ** we succesfully removed from the packet. When this reaches ** zero, we reset the offset pointer to be zero, and free ** the packet from the front of the queue. */ intCount++; TtyP = PortP->gs.tty; if (!TtyP) { rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n"); return; } if (PortP->State & RIO_THROTTLE_RX) { rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n"); return; } if (PortP->State & RIO_DELETED) { while (can_remove_receive(&PacketP, PortP)) { remove_receive(PortP); put_free_end(PortP->HostP, PacketP); } } else { /* ** loop, just so long as: ** i ) there's some data ( i.e. can_remove_receive ) ** ii ) we haven't been blocked ** iii ) there's somewhere to put the data ** iv ) we haven't outstayed our welcome */ transCount = 1; while (can_remove_receive(&PacketP, PortP) && transCount) { RxIntCnt++; /* ** check that it is not a command! */ if (PacketP->len & PKT_CMD_BIT) { rio_dprintk(RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n"); /* rio_dprint(RIO_DEBUG_INTR, (" sysport = %d\n", p->RIOPortp->PortNum)); */ rio_dprintk(RIO_DEBUG_INTR, " dest_unit = %d\n", PacketP->dest_unit); rio_dprintk(RIO_DEBUG_INTR, " dest_port = %d\n", PacketP->dest_port); rio_dprintk(RIO_DEBUG_INTR, " src_unit = %d\n", PacketP->src_unit); rio_dprintk(RIO_DEBUG_INTR, " src_port = %d\n", PacketP->src_port); rio_dprintk(RIO_DEBUG_INTR, " len = %d\n", PacketP->len); rio_dprintk(RIO_DEBUG_INTR, " control = %d\n", PacketP->control); rio_dprintk(RIO_DEBUG_INTR, " csum = %d\n", PacketP->csum); rio_dprintk(RIO_DEBUG_INTR, " data bytes: "); for (DataCnt = 0; DataCnt < PKT_MAX_DATA_LEN; DataCnt++) rio_dprintk(RIO_DEBUG_INTR, "%d\n", PacketP->data[DataCnt]); remove_receive(PortP); put_free_end(PortP->HostP, PacketP); continue; /* with next packet */ } /* ** How many characters can we move 'upstream' ? ** ** Determine the minimum of the amount of data ** available and the amount of space in which to ** put it. ** ** 1. Get the packet length by masking 'len' ** for only the length bits. ** 2. Available space is [buffer size] - [space used] ** ** Transfer count is the minimum of packet length ** and available space. */ transCount = tty_buffer_request_room(TtyP, PacketP->len & PKT_LEN_MASK); rio_dprintk(RIO_DEBUG_REC, "port %d: Copy %d bytes\n", PortP->PortNum, transCount); /* ** To use the following 'kkprintfs' for debugging - change the '#undef' ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the ** driver). */ ptr = (unsigned char *) PacketP->data + PortP->RxDataStart; tty_prepare_flip_string(TtyP, &buf, transCount); rio_memcpy_fromio(buf, ptr, transCount); PortP->RxDataStart += transCount; PacketP->len -= transCount; copied += transCount; if (PacketP->len == 0) { /* ** If we have emptied the packet, then we can ** free it, and reset the start pointer for ** the next packet. */ remove_receive(PortP); put_free_end(PortP->HostP, PacketP); PortP->RxDataStart = 0; } } } if (copied) { rio_dprintk(RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied); tty_flip_buffer_push(TtyP); } return;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?