/* * Function: serpkt_int_rx_processing * Purpose: Deferred Rx processing for interrupt handler * * Params: (via args) * Input: devid device ID of the driver * * Returns: Nothing */ void serpkt_int_rx_processing(void *args) { const DeviceID devid = (DeviceID) args; RingBuffer *ring = SerCtrl(devid)->rx_ring; volatile int *rx_flow = &(SerCtrl(devid)->rx_tx_state->rx_pkt_flow); volatile unsigned int *status = angel_DeviceStatus + devid; struct data_packet *rxp = SerEngine(devid)->rx_packet; unsigned int s; ASSERT(devid < DI_NUM_DEVICES, ("devid")); LogInfo(LOG_RX, ("Entry: count = %d\n", ringBufCount(ring))); /* * We need to disable IRQ & FIQ whenever we modify critical data * shared with the interrupt handler */ s = Angel_DisableInterruptsFromSVC(); /* * If there are characters in the rx ring buffer, process them * through the rx engine and take appropriate action. */ while (ringBufNotEmpty(ring)) { re_status rx_eng_status; unsigned char new_ch; unsigned char overrun; /* if we've been stopped, get out*/ if (*rx_flow == 0) { LogWarning(LOG_RX, ("Packet processing postponed; rx_flow == 0, ring->count = %d\n", ringBufCount(ring))); break; } overrun = ringBufIsOvr(ring); if (overrun) { LogWarning(LOG_RX, ("Character Overflow detected, ring->count = %d\n", ringBufCount(ring))); ringBufResetOvr(ring); } new_ch = ringBufGetChar(ring); Angel_RestoreInterruptsFromSVC(s); #if DEBUG == 1 /* don't want 'count' maintained in release versions */ { static int count = 0; LogInfo(LOG_WIRE, ("<%02X ", new_ch)); if (++count > 16) { LogInfo(LOG_WIRE, ("\n")); count = 0; } } #endif rx_eng_status = Angel_RxEngine(new_ch, overrun, rxp, SerEngine(devid)->re_state); switch (rx_eng_status) { case RS_WAIT_PKT: case RS_IN_PKT: /* we've done all we need within the engine */ break; case RS_BAD_PKT: /* tell the channels layer about a bad packet */ spk_rx_numbadpackets++; if (rxp->type < DC_NUM_CHANNELS) { LogWarning(LOG_SERPKT, ( "Bad packet: Chan %d; delivering...\n", rxp->type)); angel_DD_GotPacket(devid, rxp->data, rxp->len, DS_BAD_PACKET, rxp->type); } else { LogWarning(LOG_SERPKT, ( "Bad packet: can't deliver...\n")); /* * we assume that if type is bad, no storage has been * allocated in the engine, so just do this to be safe: */ if (rxp->data != NULL) { LogInfo(LOG_SERPKT, ("Bad packet's data non-null, freeing...")); Angel_BufferRelease(rxp->data); } spk_rx_numdrops++; } /* I think now bad packets shouldn't count towards incrementing the * flow; when the flow is set negative, we are really saying "let this * many _good_ packets through. * * if (*rx_flow < 0) * (*rx_flow)++; */ rxp->data = NULL; rxp->type = DC_NUM_CHANNELS; break; case RS_NO_BUF: LogWarning(LOG_SERPKT, ( "No buffer available: can't deliver...\n")); spk_rx_numdrops++; /* * See msg above. * if (*rx_flow < 0) * (*rx_flow)++; */ /* * We've done all we can do within the engine. Don't * try to deliver this; it can cause havoc with task * priorities and anyway there's little point... ric */ rxp->data = NULL; rxp->type = DC_NUM_CHANNELS; /* invalid */ break; case RS_GOOD_PKT: spk_rx_numbytes += rxp->len; spk_rx_numpackets ++; if (*rx_flow < 0) (*rx_flow)++; LogInfo(LOG_SERPKT, ( "Delivering good packet:\n")); angel_DD_GotPacket(devid, rxp->data, rxp->len, DS_DONE, rxp->type); rxp->data = NULL; rxp->type = DC_NUM_CHANNELS; /* invalid */ break; } s = Angel_DisableInterruptsFromSVC(); /* for next test */ } /* * need to clear the flag to say we have been here */ *status &= ~SER_RX_QUEUED; /* * call rx control to reenable interrupts in case they were disabled */ SerCtrl(devid)->control_rx(devid); /* * remember to reenable interrupts before we leave */ Angel_RestoreInterruptsFromSVC(s); LogInfo(LOG_RX, ("Exit: count = %d\n", ringBufCount(ring))); }
static int SerparRead(DriverCall *dc, bool block) { static unsigned char readbuf[MAXREADSIZE]; static int rbindex = 0; int nread; int read_errno; int c = 0; re_status restatus; int ret_code = -1; /* assume bad packet or error */ /* * we must not overflow buffer, and must start after * the existing data */ #ifdef COMPILING_ON_WINDOWS { BOOL dummy = FALSE; nread = BytesInRXBufferSerial(); if (nread > MAXREADSIZE - rbindex) nread = MAXREADSIZE - rbindex; read_errno = ReadSerial(readbuf+rbindex, nread, &dummy); if (pfnProgressCallback != NULL && read_errno == COM_OK) { progressInfo.nRead += nread; (*pfnProgressCallback)(&progressInfo); } } #else nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block); read_errno = errno; #endif if ((nread > 0) || (rbindex > 0)) { #ifdef DO_TRACE printf("[%d@%d] ", nread, rbindex); #endif if (nread > 0) rbindex = rbindex + nread; do { restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate); #ifdef DO_TRACE printf("<%02X ",readbuf[c]); #endif c++; } while (c < rbindex && ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT))); #ifdef DO_TRACE printf("\n"); #endif switch(restatus) { case RS_GOOD_PKT: ret_code = 1; /* fall through to: */ case RS_BAD_PKT: /* * We now need to shuffle any left over data down to the * beginning of our private buffer ready to be used *for the next packet */ #ifdef DO_TRACE printf("SerparRead() processed %d, moving down %d\n", c, rbindex - c); #endif if (c != rbindex) memmove((char *) readbuf, (char *) (readbuf + c), rbindex - c); rbindex -= c; break; case RS_IN_PKT: case RS_WAIT_PKT: rbindex = 0; /* will have processed all we had */ ret_code = 0; break; default: #ifdef DEBUG printf("Bad re_status in SerparRead()\n"); #endif break; } } else if (nread == 0) /* nothing to read */ ret_code = 0; else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */ ret_code = 0; #ifdef DEBUG if ((nread < 0) && (read_errno != ERRNO_FOR_BLOCKED_IO)) perror("read() error in SerparRead()"); #endif return ret_code; }