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; }
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; }
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; }