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

📄 smsc.c

📁 含有完整TCP/IP PPP协议的嵌入式操作系统
💻 C
字号:
#include <stdio.h>#include <sys/timer.h>#include "utils.h"#include "uart.h"#include "smscregs.h"#include "smsc.h"/*! * \brief Select specified PHY register for reading or writing. * * \param reg PHY register number. * \param we  Should be 1 for write access, 0 for read access. * * \return Contents of the PHY interface rgister. */static u_char NicPhyRegSelect(u_char reg, u_char we){    u_char rs;    u_char msk;    u_char i;    nic_bs(3);    rs = (nic_inlb(NIC_MGMT) & ~(MGMT_MCLK | MGMT_MDO)) | MGMT_MDOE;    /* Send idle pattern. */    for (i = 0; i < 33; i++) {        nic_outlb(NIC_MGMT, rs | MGMT_MDO);        nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);    }    /* Send start sequence. */    nic_outlb(NIC_MGMT, rs);    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);    nic_outlb(NIC_MGMT, rs | MGMT_MDO);    nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);    /* Write or read mode. */    if (we) {        nic_outlb(NIC_MGMT, rs);        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);        nic_outlb(NIC_MGMT, rs | MGMT_MDO);        nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);    } else {        nic_outlb(NIC_MGMT, rs | MGMT_MDO);        nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);        nic_outlb(NIC_MGMT, rs);        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);    }    /* Send PHY address. Zero is used for the internal PHY. */    for (i = 0; i < 5; i++) {        nic_outlb(NIC_MGMT, rs);        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);    }    /* Send PHY register number. */    for (msk = 0x10; msk; msk >>= 1) {        if (reg & msk) {            nic_outlb(NIC_MGMT, rs | MGMT_MDO);            nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);        } else {            nic_outlb(NIC_MGMT, rs);            nic_outlb(NIC_MGMT, rs | MGMT_MCLK);        }    }    nic_outlb(NIC_MGMT, rs);    return rs;}/*! * \brief Read contents of PHY register. * * \param reg PHY register number. * * \return Contents of the specified register. */static u_short NicPhyRead(u_char reg){    u_short rc = 0;    u_char rs;    u_char i;    /* Select register for reading. */    rs = NicPhyRegSelect(reg, 0);    /* Switch data direction. */    rs &= ~MGMT_MDOE;    nic_outlb(NIC_MGMT, rs);    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);    /* Clock data in. */    for (i = 0; i < 16; i++) {        nic_outlb(NIC_MGMT, rs);        nic_outlb(NIC_MGMT, rs | MGMT_MCLK);        rc <<= 1;        rc |= (nic_inlb(NIC_MGMT) & MGMT_MDI) != 0;    }    /* This will set the clock line to low. */    nic_outlb(NIC_MGMT, rs);    return rc;}/*! * \brief Write value to PHY register. * * \param reg PHY register number. * \param val Value to write. */static void NicPhyWrite(u_char reg, u_short val){    u_short msk;    u_char rs;    /* Select register for writing. */    rs = NicPhyRegSelect(reg, 1);    /* Switch data direction dummy. */    nic_outlb(NIC_MGMT, rs | MGMT_MDO);    nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);    nic_outlb(NIC_MGMT, rs);    nic_outlb(NIC_MGMT, rs | MGMT_MCLK);    /* Clock data out. */    for (msk = 0x8000; msk; msk >>= 1) {        if (val & msk) {            nic_outlb(NIC_MGMT, rs | MGMT_MDO);            nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);        } else {            nic_outlb(NIC_MGMT, rs);            nic_outlb(NIC_MGMT, rs | MGMT_MCLK);        }    }    /* Set clock line low and output line int z-state. */    nic_outlb(NIC_MGMT, rs & ~MGMT_MDOE);}/*! * \brief Configure the internal PHY. * * Reset the PHY and initiate auto-negotiation. */static int NicPhyConfig(void){    u_short phy_sor;    u_short phy_sr;    u_short phy_to;    u_short mode;    /*      * Reset the PHY and wait until this self clearing bit     * becomes zero. We sleep 63 ms before each poll and     * give up after 3 retries.      */    NicPhyWrite(NIC_PHYCR, PHYCR_RST);    for (phy_to = 0;; phy_to++) {        Delay(100000);        if ((NicPhyRead(NIC_PHYCR) & PHYCR_RST) == 0)            break;        if (phy_to > 3) {            return -1;        }    }    Delay(200000);    /* Store PHY status output. */    phy_sor = NicPhyRead(NIC_PHYSOR);    /* Enable PHY interrupts. */    NicPhyWrite(NIC_PHYMSK, PHYMSK_MLOSSSYN | PHYMSK_MCWRD | PHYMSK_MSSD |                PHYMSK_MESD | PHYMSK_MRPOL | PHYMSK_MJAB | PHYMSK_MSPDDT | PHYMSK_MDPLDT);    /* Set RPC register. */    mode = RPCR_ANEG | RPCR_LEDA_PAT | RPCR_LEDB_PAT;    nic_bs(0);    nic_outw(NIC_RPCR, mode);    /*     * Advertise our capabilities, initiate auto negotiation     * and wait until this has been completed.     */    NicPhyWrite(NIC_PHYANAD, PHYANAD_TX_FDX | PHYANAD_TX_HDX | PHYANAD_10FDX | PHYANAD_10_HDX | PHYANAD_CSMA);    for (phy_to = 0, phy_sr = 0;; phy_to++) {        /* Give up after long time wait. */        if (phy_to >= 32) {            return -1;        }        /* Restart auto negotiation every 4 seconds or on failures. */        if ((phy_to & 127) == 0 /* || (phy_sr & PHYSR_REM_FLT) != 0 */) {            NicPhyWrite(NIC_PHYCR, PHYCR_ANEG_EN | PHYCR_ANEG_RST);            Delay(200000);        }        /* Check if link status detected. */        phy_sr = NicPhyRead(NIC_PHYSR);        if (phy_sr & PHYSR_ANEG_ACK)            break;        Delay(300000);    }    return 0;}/*! * \brief Wait until MMU is ready. * * Poll the MMU command register until \ref MMUCR_BUSY * is cleared. * * \param tmo Timeout in milliseconds. * * \return 0 on success or -1 on timeout. */static INLINE int NicMmuWait(u_short tmo){    while (tmo--) {        if ((nic_inlb(NIC_MMUCR) & MMUCR_BUSY) == 0)            break;        Delay(2000);    }    return tmo ? 0 : -1;}/*! * \brief Reset the Ethernet controller. * * \return 0 on success, -1 otherwise. */static int NicReset(void){    /* Disable all interrupts. */    nic_outlb(NIC_MSK, 0);    /* MAC and PHY software reset. */    nic_bs(0);    nic_outw(NIC_RCR, RCR_SOFT_RST);    /* Enable Ethernet protocol handler. */    nic_bs(1);    nic_outw(NIC_CR, CR_EPH_EN);    Delay(20000);    /* Disable transmit and receive. */    nic_bs(0);    nic_outw(NIC_RCR, 0);    nic_outw(NIC_TCR, 0);    /* Enable auto release. */    nic_bs(1);    nic_outw(NIC_CTR, CTR_AUTO_RELEASE);    /* Reset MMU. */    nic_bs(2);    nic_outlb(NIC_MMUCR, MMU_RST);    if (NicMmuWait(1000))        return -1;    return 0;}int SmscDetect(void){    u_char bv;    /* High byte of base select is always 0x33. */    if((bv = nic_inhb(NIC_BSR)) != 0x33) {        return -1;    }    /* Read revision. */    nic_bs(3);    if(((bv = nic_inlb(NIC_REV)) & 0xF0) != 0x90) {        return -1;    }    return 0;}/*! * \brief Test NIC interrupt line. */static int SmscTestInterrupt(void){    u_char tmo;    /*     * Set PE5 to input. This is our interrupt signal line.     */    cbi(DDRE, 5);    if (NicReset()) {        puts("reset failed");        return -1;    }    if(bit_is_set(PINE, 5)) {        puts("IRQ stuck");        return -1;    }    /* Enable receiver. */    nic_bs(3);    nic_outlb(NIC_ERCV, 7);    nic_bs(0);    nic_outw(NIC_RCR, RCR_RXEN);    /* Enable transmitter and padding. */    nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);    /* Configure the PHY. */    if (NicPhyConfig()) {        puts("link failed");        return -1;    }    /* Allocate packet buffer space. */    nic_bs(2);    nic_outlb(NIC_MMUCR, MMU_ALO);    if (NicMmuWait(100))        return -1;    /* Enable interrupts including allocation success. */    nic_outlb(NIC_MSK, INT_ALLOC);    /* Wait for allocation success. */    tmo = 255;    while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {        if(--tmo == 0) {            puts("IRQ failed");            return -1;        }        Delay(2000);    }    if(bit_is_clear(PINE, 5)) {        puts("no IRQ");        return -1;    }    return 0;}/*! * \brief Test NIC RAM buffer. */static int SmscTestBuffer(void){    ureg_t i;    ureg_t tmo;    u_short cnt;    u_short val;    /* Disable interrupts. */    if (NicReset()) {        puts("reset failed");        return -1;    }    for(i = 0; i < 3; i++) {        /* Allocate packet buffer space. */        nic_bs(2);        nic_outlb(NIC_MMUCR, MMU_ALO);        if (NicMmuWait(100)) {            printf("Alloc failed\n");            return -1;        }        /* Wait for allocation success. */        tmo = 255;        while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {            if(--tmo == 0) {                puts("IRQ failed");                return -1;            }            Delay(2000);        }        /*         * Transfer the allocated packet number to TX packet number.         */        nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));        /*         * Reset the pointer register, no auto increment.         */        nic_outw(NIC_PTR, 0);        /*         * Data write.         */        for(cnt = 0; cnt < 1024; cnt++) {            val = ~cnt;            nic_outw(NIC_PTR, cnt * 2);            nic_outlb(NIC_DATA, (u_char)val);            nic_outw(NIC_PTR, cnt * 2 + 1);            nic_outlb(NIC_DATA, val >> 8);        }        /*         * Data read.         */        for(cnt = 0; cnt < 1024; cnt++) {            nic_outw(NIC_PTR, PTR_READ | (cnt * 2));            if((val = ~nic_inw(NIC_DATA)) != cnt) {                printf("bad val %04X at %04X\n", val, cnt);                return -1;            }        }    }    return 0;}/*! * \brief Test NIC functions. */int SmscTest(void){    if(SmscTestInterrupt()) {        puts("IRQ failed");        return -1;    }    if(SmscTestBuffer()) {        puts("Buf failed");        return -1;    }    puts("OK");    return 0;}/* * \brief Continously send baroadcasts. */void SmscSend(void){    u_char mac[] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 };    ureg_t i;    u_short sz;    u_long cnt = 0;    printf("\nInit controller...");    if (NicReset()) {        puts("reset failed");        return;    }    /* Enable receiver. */    nic_bs(3);    nic_outlb(NIC_ERCV, 7);    nic_bs(0);    //nic_outw(NIC_RCR, RCR_RXEN);    /* Enable transmitter and padding. */    nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);    /* Configure the PHY. */    if (NicPhyConfig()) {        puts("link failed");        return;    }    /* Set MAC address. */    nic_bs(1);    for (i = 0; i < 6; i++)        nic_outlb(NIC_IAR + i, mac[i]);    puts("OK");    for(cnt = 0;; cnt++) {        Delay(500000);        printf("\r%lu", cnt);        sz = 1500;        /* Allocate packet buffer space. */        nic_bs(2);        nic_outlb(NIC_MMUCR, MMU_ALO);        if (NicMmuWait(100)) {            puts("Alloc");            break;        }        /* Enable allocation interrupt. */        nic_outlb(NIC_MSK, INT_ALLOC);        /*          * Wait for allocation success. This fails quite often, possibly         * because we do not clear our receive buffer.         */        if ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {            puts(" Alloc");            Delay(500000);            if ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {                nic_outlb(NIC_MMUCR, MMU_RST);                NicMmuWait(1000);                nic_outlb(NIC_MMUCR, MMU_ALO);                if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {                    break;                }            }        }        /* Disable interrupts. */        nic_outlb(NIC_MSK, 0);        nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));        nic_outw(NIC_PTR, 0x4000);        /* Transfer control word. */        nic_outlb(NIC_DATA, 0);        nic_outlb(NIC_DATA, 0);        /* Transfer the byte count. */        nic_outw(NIC_DATA, sz);        /* Transfer the Ethernet frame. */        for (i = 0; i < 6; i++) {            nic_outlb(NIC_DATA, 0xFF);        }        for (i = 0; i < 6; i++) {            nic_outlb(NIC_DATA, mac[i]);        }                    nic_outlb(NIC_DATA, 0x08);        nic_outlb(NIC_DATA, 0x00);        /*         * Add pad bytes.         */        while (sz--) {            nic_outlb(NIC_DATA, 0x00);        }        /* Transfer the control word. */        nic_outlb(NIC_DATA, 0);        nic_outlb(NIC_DATA, 0);        /* Enqueue packet. */        if (NicMmuWait(100)) {            puts("Enqueue");            break;        }        nic_outlb(NIC_MMUCR, MMU_ENQ);        if (GetChar())            break;    }}void SmscLoop(void){    printf_P(presskey_P);    for (;;) {        nic_bs(3);        printf("\rrev=0x%02X        ", nic_inlb(NIC_REV));        if (GetChar()) {            puts("");            return;        }    }}

⌨️ 快捷键说明

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