Exemplo n.º 1
0
/*
 *  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)));
}
Exemplo n.º 2
0
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;
}