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

📄 smc.c

📁 aesop s3c2440a BSP for windowsce 6.0
💻 C
📖 第 1 页 / 共 4 页
字号:
    if (wInts & (RCV_INT | RX_OVRN_INT)) {
        dwRet = INTR_TYPE_RX;
    }
    
    WriteWord( BANKSEL_REG, wBankSave );

    return dwRet;
}

//
// This routine is used by the OAL to configure the debug Ethernet driver. Currently
// the following options are defined:
//     OPT_BROADCAST_FILTERING  -- If set, filter out all broadcast packets except ARP packets
// 
DWORD
SMCSetOptions(DWORD dwOptions)
{
    DWORD dwOldOptions = dwConfigOptions;
    dwConfigOptions = dwOptions;
    return dwOldOptions;
}

static BOOL
SMCReleaseMemory (UINT16 wCmd)
{
    DWORD dwStartTime;
    
    // issuem the release command
    WriteWord (MMU_CMD_REG, wCmd);

    // Wait until release finishes executing
    dwStartTime = OEMEthGetSecs();
    while (ReadWord (MMU_CMD_REG) & MMU_CMD_BUSY) {
        if ((OEMEthGetSecs() - dwStartTime) > 2) {
            EdbgOutputDebugString ("!GetFrame: Timed out releasing memory (wCmd = %u)\n", wCmd);
            return FALSE;
        }
    }
    return TRUE;
}

static UINT16
SMCRetrieveFrame (BYTE *pbData, UINT16 *pwLength)
{
    UINT16 i, wStatusWord;
    UINT16 *pwData = (UINT16 *)pbData;
    UINT16 wLen;
    
    // Setup pointer address register to point to first byte of Frame
    WriteWord( PTR_REG, 0xE000 );

    // read status and filter frames if error detected
    if (!((wStatusWord = ReadWord (DATA_REG)) & FRAME_FILTER)) 
    {

        // The top bits of the byte count are reserved, so mask those (pg 26 of SMC91C94 spec).
        // The byte count includes the status word, byte count and control byte so subtract 6
        wLen = (0x07FF & ReadWord( DATA_REG )) - 6;
        EDBG_DEBUGLED(LED_PKTLEN,*pwLength);

        if (*pwLength < wLen) {
            EdbgOutputDebugString("SMC9000: received packet larger (%u) than buffer (%u)\n",wLen, *pwLength);
            return 0x0800;  // frame too long
        }

        // For broadcast frames, filter out all except for ARPs
        i=0;
        if ((dwConfigOptions & OPT_BROADCAST_FILTERING) && (wStatusWord & BROADCAST_FILTER_BIT)) {
            for (; i< sizeof(EthernetFrameHeader); i++)
                *pwData++ = ReadWord( DATA_REG );
            if (ntohs(((EthernetFrameHeader UNALIGNED *)pbData)->wFrameType) != 0x0806) {
                return BROADCAST_FILTER_BIT;    // broadcast, not ARPs
            }
        }

        wStatusWord = 0;
        *pwLength = wLen;   // set return length
        
        // Read all but the last word, which will contain the control word
        wLen >>= 1;    // in words
        EDBG_DEBUGLED(LED_COPY,0);
        for( ; i < wLen; i++ )
            *pwData++ = ReadWord( DATA_REG );
        EDBG_DEBUGLED(LED_COPY,wLen);
            
        // Now check to see if there were an odd number of bytes sent.  If so, I have to extract the
        //  last one (pg 27 of the SCM91C94 spec).
        wLen = ReadWord( DATA_REG );
        if (wLen & 0x2000) {
            *pwData = (BYTE)wLen;
            (*pwLength)++;
        }
    }
    return wStatusWord;
}


#if 1


unsigned char *NetRxPackets[3000];
UINT16
SMCGetFrame( BYTE *pbData, UINT16 *pwLength )
{
        int     packet_number;
        WORD    status;
        WORD    packet_length;
        int     is_error = 0;
        BYTE saved_pnr;
        WORD saved_ptr;

        SMC_SELECT_BANK(2);
        /* save PTR and PTR registers */
        saved_pnr = SMC_inb( PN_REG );
        saved_ptr = SMC_inw( PTR_REG );

        packet_number = SMC_inw( RXFIFO_REG );

        if ( packet_number & RXFIFO_REMPTY ) {

                return 0;
        }

//        EdbgOutputDebugString("%s:smc_rcv\n", SMC_DEV_NAME);
        /*  start reading from the start of the packet */
        SMC_outw( PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG );

        /* First two words are status and packet_length */
        status          = SMC_inw( DATA_REG );
        packet_length   = SMC_inw( DATA_REG );

        packet_length &= 0x07ff;  /* mask off top bits */

        if ( !(status & RS_ERRORS ) ){
                /* Adjust for having already read the first two words */
                packet_length -= 4; /*4; */


                /* set odd length for bug in LAN91C111, */
                /* which never sets RS_ODDFRAME */
                /* TODO ? */


//                EdbgOutputDebugString(" Reading %d words and %d byte(s) \n", (packet_length >> 1 ), packet_length & 1 );
                SMC_insw(DATA_REG , pbData, packet_length >> 1);


//#if     SMC_DEBUG > 2
//                EdbgOutputDebugString("Receiving Packet\n");
//                DumpEtherFrame(pbData, packet_length);
//#endif
        } else {
                /* error ... */
                /* TODO ? */
                is_error = 1;
        }

        while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
                udelay(1); /* Wait until not busy */

        /*  error or good, tell the card to get rid of this packet */
        SMC_outw( MC_RELEASE, MMU_CMD_REG );

        while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
                udelay(1); /* Wait until not busy */

        /* restore saved registers */
        SMC_outb( saved_pnr, PN_REG );
        SMC_outw( saved_ptr, PTR_REG );

        if (!is_error) {
                /* Pass the packet up to the protocol layers. */
                *pwLength = packet_length;
                return 1;
        } else {
                return 0;
        }

}

#endif

// This routine should be called with a pointer to the ethernet frame data.  It is the caller's
//  responsibility to fill in all information including the destination and source addresses and
//  the frame type.  The length parameter gives the number of bytes in the ethernet frame.
// The routine will not return until the frame has been transmitted or an error has occured.  If
//  the frame transmits successfully, 0 is returned.  If an error occured, a message is sent to
//  the serial port and the routine returns non-zero.
 #define MEMORY_WAIT_TIME 16
static int poll4int (BYTE mask, int timeout)
{
        unsigned int tmo = OEMEthGetSecs() + (unsigned int)timeout;
        int is_timeout = 0;
        WORD old_bank = SMC_inw (BSR_REG);

//        EdbgOutputDebugString ("Polling...\n");
        SMC_SELECT_BANK (2);
        while ((SMC_inw (SMC91111_INT_REG) & mask) == 0) {
                if (OEMEthGetSecs() >= tmo) {
                        is_timeout = 1;
                        break;
                }
        }

        /* restore old bank selection */
        SMC_SELECT_BANK (old_bank);

        if (is_timeout)
                return 1;
        else
                return 0;
}
UINT16 SMCSendFrame( BYTE *pbData, DWORD dwLength ) 
{
        BYTE packet_no;
        BYTE *buf;
        int length;
        int numPages;
        int trycnt = 0;
        int time_out;
        BYTE status;
        BYTE saved_pnr;
        WORD saved_ptr;

        /* save PTR and PNR registers before manipulation */
        SMC_SELECT_BANK (2);
        saved_pnr = SMC_inb( PN_REG );
        saved_ptr = SMC_inw( PTR_REG );

//        EdbgOutputDebugString ("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);

        length = ETH_ZLEN < dwLength ? dwLength : ETH_ZLEN;

        /* allocate memory
         ** The MMU wants the number of pages to be the number of 256 bytes
         ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
         **
         ** The 91C111 ignores the size bits, but the code is left intact
         ** for backwards and future compatibility.
         **
         ** Pkt size for allocating is data length +6 (for additional status
         ** words, length and ctl!)
         **
         ** If odd size then last byte is included in this header.
         */
        numPages = ((length & 0xfffe) + 6);
        numPages >>= 8;         /* Divide by 256 */

        if (numPages > 7) {
                EdbgOutputDebugString ("%s: Far too big packet error. \n", SMC_DEV_NAME);
                return 0;
        }

        /* now, try to allocate the memory */
        SMC_SELECT_BANK (2);
        SMC_outw (MC_ALLOC | numPages, MMU_CMD_REG);

        /* FIXME: the ALLOC_INT bit never gets set *
         * so the following will always give a     *
         * memory allocation error.                *
         * same code works in armboot though       *
         * -ro
         */

again:
        trycnt++;
        time_out = MEMORY_WAIT_TIME;
        do {
                status = SMC_inb (SMC91111_INT_REG);
                if (status & IM_ALLOC_INT) {
                        /* acknowledge the interrupt */
                        SMC_outb (IM_ALLOC_INT, SMC91111_INT_REG);
                        break;
                }
        } while (--time_out);

        if (!time_out) {
                EdbgOutputDebugString ("%s: memory allocation, try %d failed ...\n",
                         SMC_DEV_NAME, trycnt);
                if (trycnt < SMC_ALLOC_MAX_TRY)
                        goto again;
                else
		{

        /* Reset the MMU */
        SMC_SELECT_BANK (2);
        smc_wait_mmu_release_complete ();
        SMC_outw (MC_RESET, MMU_CMD_REG);
        while (SMC_inw (MMU_CMD_REG) & MC_BUSY)
                udelay (1);     /* Wait until not busy */
			
                        return 0;
		}
        }

//        EdbgOutputDebugString ("%s: memory allocation, try %d succeeded ...\n", SMC_DEV_NAME, trycnt);

        /* I can send the packet now.. */


        buf = (BYTE *) pbData;

        /* If I get here, I _know_ there is a packet slot waiting for me */
        packet_no = SMC_inb (AR_REG);
        if (packet_no & AR_FAILED) {
                /* or isn't there?  BAD CHIP! */
                EdbgOutputDebugString ("%s: Memory allocation failed. \n", SMC_DEV_NAME);
                return 0;
        }

        /* we have a packet address, so tell the card to use it */
        SMC_outb (packet_no, PN_REG);

        /* do not write new ptr value if Write data fifo not empty */
        while ( saved_ptr & PTR_NOTEMPTY )
                EdbgOutputDebugString ("Write data fifo not empty!\n");

        /* point to the beginning of the packet */
        SMC_outw (PTR_AUTOINC, PTR_REG);

//        EdbgOutputDebugString ("%s: Trying to xmit packet of length %x\n", SMC_DEV_NAME, length);

//#if SMC_DEBUG > 2
//        EdbgOutputDebugString ("Transmitting Packet\n");
//	DumpEtherFrame(pbData, (WORD)dwLength);
//#endif

        /* send the packet length ( +6 for status, length and ctl byte )
           and the status word ( set to zeros ) */

        SMC_outw (0, DATA_REG);
        /* send the packet length ( +6 for status words, length, and ctl */
        SMC_outw ((length + 6), DATA_REG);

        /* send the actual data
           . I _think_ it's faster to send the longs first, and then
           . mop up by sending the last word.  It depends heavily
           . on alignment, at least on the 486.  Maybe it would be
           . a good idea to check which is optimal?  But that could take
           . almost as much time as is saved?
         */

        SMC_outsw (DATA_REG, buf, (length) >> 1);

        /* Send the last byte, if there is one.   */
        if ((length & 1) == 0) {
                SMC_outw (0, DATA_REG);
        } else {
                SMC_outw (buf[length - 1] | 0x2000, DATA_REG);
        }

        /* and let the chipset deal with it */
        SMC_outw (MC_ENQUEUE, MMU_CMD_REG);

        /* poll for TX INT */
        /* if (poll4int (IM_TX_INT, SMC_TX_TIMEOUT)) { */
        /* poll for TX_EMPTY INT - autorelease enabled */
        if (poll4int(IM_TX_EMPTY_INT, SMC_TX_TIMEOUT)) {
                /* sending failed */
                EdbgOutputDebugString ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);

                /* release packet */
                /* no need to release, MMU does that now */
                /* SMC_outw (MC_FREEPKT, MMU_CMD_REG); */

                /* wait for MMU getting ready (low) */
                while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
                        udelay (10);
                }

                EdbgOutputDebugString ("MMU ready\n");


                return 0;
        } else {
                /* ack. int */
                SMC_outb (IM_TX_EMPTY_INT, SMC91111_INT_REG);
                /* SMC_outb (IM_TX_INT, SMC91111_INT_REG); */
  //              EdbgOutputDebugString ("%s: Sent packet of length %d \n", SMC_DEV_NAME, length);

⌨️ 快捷键说明

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