Пример #1
0
static int nd_send(netdev2_t *netdev, const struct iovec *data, unsigned count)
{
    enc28j60_t *dev = (enc28j60_t *)netdev;
    uint8_t ctrl = 0;
    int c = 0;

    mutex_lock(&dev->devlock);

#ifdef MODULE_NETSTATS_L2
    netdev->stats.tx_bytes += count;
#endif

    /* set write pointer */
    cmd_w_addr(dev, ADDR_WRITE_PTR, BUF_TX_START);
    /* write control byte and the actual data into the buffer */
    cmd_wbm(dev, &ctrl, 1);
    for (int i = 0; i < count; i++) {
        c += data[i].iov_len;
        cmd_wbm(dev, (uint8_t *)data[i].iov_base, data[i].iov_len);
    }
    /* set TX end pointer */
    cmd_w_addr(dev, ADDR_TX_END, cmd_r_addr(dev, ADDR_WRITE_PTR) - 1);
    /* trigger the send process */
    cmd_bfs(dev, REG_ECON1, -1, ECON1_TXRTS);

    mutex_unlock(&dev->devlock);
    return c;
}
Пример #2
0
static int nd_recv(netdev2_t *netdev, char *buf, int max_len, void *info)
{
    enc28j60_t *dev = (enc28j60_t *)netdev;
    uint8_t head[6];
    size_t size;
    uint16_t next;

    (void)info;
    mutex_lock(&dev->devlock);

    /* set read pointer to RX read address */
    cmd_w_addr(dev, ADDR_READ_PTR, cmd_r_addr(dev, ADDR_RX_READ));
    /* read packet header */
    cmd_rbm(dev, head, 6);
    /* TODO: care for endianess */
    next = (uint16_t)((head[1] << 8) | head[0]);
    size = (size_t)((head[3] << 8) | head[2]) - 4;  /* discard CRC */

    if (buf != NULL) {
        /* read packet content into the supplied buffer */
        if (size <= max_len) {
            cmd_rbm(dev, (uint8_t *)buf, size);
        } else {
            DEBUG("[enc28j60] recv: unable to get packet - buffer too small\n");
            size = 0;
        }
        /* release memory */
        cmd_w_addr(dev, ADDR_RX_READ, next);
        cmd_bfs(dev, REG_ECON2, -1, ECON2_PKTDEC);
    }

    mutex_unlock(&dev->devlock);
    return (int)size;
}
Пример #3
0
static int nd_init(netdev2_t *netdev)
{
    enc28j60_t *dev = (enc28j60_t *)netdev;
    int res;
    uint8_t tmp;

    /* get exclusive access of the device */
    mutex_lock(&dev->devlock);

    /* setup the low-level interfaces */
    gpio_init(dev->reset_pin, GPIO_OUT);
    gpio_clear(dev->reset_pin);     /* this puts the device into reset state */
    gpio_init(dev->cs_pin, GPIO_OUT);
    gpio_set(dev->cs_pin);
    gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, on_int, (void *)dev);
    res = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED);
    if (res < 0) {
        DEBUG("[enc28j60] init: error initializing SPI bus [%i]\n", res);
        return -1;
    }

    /* wait at least 1ms and then release device from reset state */
    xtimer_usleep(DELAY_RESET);
    gpio_set(dev->reset_pin);

    /* wait for oscillator to be stable before proceeding */
    res = 0;
    do {
        tmp = cmd_rcr(dev, REG_ESTAT, -1);
        if (res++ >= STARTUP_TIMEOUT) {
            DEBUG("[enc28j60] init: error waiting for stable clock, SPI ok?\n");
            return -1;
        }
    } while (!(tmp & ESTAT_CLKRDY));

    /* disable clock output to save a little power */
    cmd_wcr(dev, REG_B3_ECOCON, 3, 0x00);

    /* BUFFER configuration */
    /* configure the RX buffer */
    cmd_w_addr(dev, ADDR_RX_START, BUF_RX_START);
    cmd_w_addr(dev, ADDR_RX_END, BUF_RX_END);
    cmd_w_addr(dev, ADDR_RX_READ, BUF_RX_START);
    /* configure the TX buffer */
    cmd_w_addr(dev, ADDR_TX_START, BUF_TX_START);
    cmd_w_addr(dev, ADDR_TX_END, BUF_TX_END);

    /* FILTER configuration */
    /* setup receive filters - we accept everything per default */
    cmd_wcr(dev, REG_B1_ERXFCON, 1, 0);

    /* MAC configuration */
    /* enable RX through filter and enable sending of RX and TX pause frames */
    tmp = (MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
    cmd_wcr(dev, REG_B2_MACON1, 2, tmp);
    /* enable full duplex mode, padding to min 60 byte + CRC for all frames and
     * CRC creation for all packets before transmission */
    tmp = (MACON3_FULDPX | MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
    cmd_wcr(dev, REG_B2_MACON3, 2, tmp);
    /* defer TX infinitely if medium is busy for IEEE 802.3 compliance */
    tmp = (MACON4_DEFER);
    cmd_wcr(dev, REG_B2_MACON4, 2, tmp);
    /* set back-to-back inter-packet gap -> 0x15 for full duplex */
    cmd_wcr(dev, REG_B2_MABBIPG, 2, MABBIPG_FD);
    /* set non-back-to-back inter packet gap -> 0x12 is default */
    cmd_wcr(dev, REG_B2_MAIPGL, 2, MAIPGL_FD);
    /* set default MAC address */
#if CPUID_LEN
    uint8_t macbuf[CPUID_LEN];
    cpuid_get(&macbuf);     /* we get the full ID but use only parts of it */
    macbuf[0] |= 0x02;      /* locally administered address */
    macbuf[0] &= ~0x01;     /* unicast address */
#else
    uint8_t macbuf[] = ENC28J60_FALLBACK_MAC;
#endif
    mac_set(dev, macbuf);

    /* PHY configuration */
    cmd_w_phy(dev, REG_PHY_PHCON1, PHCON1_PDPXMD);
    cmd_w_phy(dev, REG_PHY_PHIE, PHIE_PLNKIE | PHIE_PGEIE);

    /* Finishing touches */
    /* enable hardware flow control */
    cmd_wcr(dev, REG_B3_EFLOCON, 3, EFLOCON_FULDPXS | EFLOCON_FCEN1);
    /* enable auto-inc of read and write pointers for the RBM/WBM commands */
    cmd_bfs(dev, REG_ECON2, -1, ECON2_AUTOINC);
    /* enable receive, link and tx interrupts */
    cmd_bfc(dev, REG_EIR, -1, (EIR_LINKIF | EIR_PKTIF | EIR_RXERIF | EIR_TXIF |
                               EIR_TXERIF));
    cmd_bfs(dev, REG_EIE, -1, (EIE_INTIE | EIE_LINKIE | EIE_PKTIE | EIE_RXERIE |
                               EIE_TXIE | EIE_TXERIE));
    /* allow receiving bytes from now on */
    cmd_bfs(dev, REG_ECON1, -1, ECON1_RXEN);

#ifdef MODULE_NETSTATS_L2
    memset(&netdev->stats, 0, sizeof(netstats_t));
#endif
    mutex_unlock(&dev->devlock);
    return 0;
}