Ethernet driver for MPS2

Refactor SMSC9220 Ethernet controller driver

Change-Id: I75c3c42d5675441de1292100a54c50d990070c6f
Signed-off-by: Gabor Kertesz <gabor.kertesz@arm.com>
pull/4414/head
gabker01 2017-05-18 10:40:29 +02:00 committed by Marc Moreno Berengue
parent fdec3f51eb
commit e4501f320b
3 changed files with 885 additions and 24 deletions

View File

@ -0,0 +1,694 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Code implementation file for the LAN Ethernet interface.
*
* This file is the based on mps2_ethernet_api and Selftest's ETH_MPS2.
* MPS2 Selftest:https://silver.arm.com/browse/VEI10 ->
* \ISCM-1-0\AN491\software\Selftest\v2m_mps2\
*/
#include <stdio.h>
#include "mbed_retarget.h"
#include "mbed_wait_api.h"
#include "SMM_MPS2.h"
#include "smsc9220_eth.h"
#define REG_WRITE_TIME_OUT 50
#define RESET_TIME_OUT 10
#define PHY_RESET_TIME_OUT_MS 100
/* Forward declarations */
static unsigned int smsc9220_mac_regread(unsigned char regoffset, unsigned int *data);
static unsigned int smsc9220_mac_regwrite(unsigned char regoffset, unsigned int data);
static unsigned int smsc9220_phy_regread(unsigned char regoffset, unsigned int *data);
static unsigned int smsc9220_phy_regwrite(unsigned char regoffset, unsigned int data);
static unsigned int smsc9220_read_id(void);
static unsigned int smsc9220_soft_reset(void);
static void smsc9220_set_txfifo(unsigned int val);
static unsigned int smsc9220_wait_eeprom(void);
static void smsc9220_init_irqs(void);
static unsigned int smsc9220_check_phy(void);
static unsigned int smsc9220_reset_phy(void);
static void smsc9220_advertise_cap(void);
static void smsc9220_enable_xmit(void);
static void smsc9220_enable_mac_xmit(void);
static void smsc9220_enable_mac_recv(void);
/* SMSC9220 low-level operations */
/**
* \brief Read MAC register.
*
* \param[in] regoffset Register offset
* \param[out] data Register value is read
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_mac_regread(unsigned char regoffset, unsigned int *data)
{
unsigned int val = 0;
unsigned int maccmd = 0;
int time_out = REG_WRITE_TIME_OUT;
val = SMSC9220->MAC_CSR_CMD;
if(!(val & ((unsigned int)1 << 31))) { /* Make sure there's no pending operation */
maccmd |= regoffset;
maccmd |= ((unsigned int)1 << 30); /* Indicates read */
maccmd |= ((unsigned int)1 << 31); /* Start bit */
SMSC9220->MAC_CSR_CMD = maccmd; /* Start operation */
do {
val = SMSC9220->BYTE_TEST; /* A no-op read. */
wait_ms(1);
time_out--;
} while(time_out && (SMSC9220->MAC_CSR_CMD & ((unsigned int)1 << 31)));
if(!time_out) {
return 1;
}
else {
*data = SMSC9220->MAC_CSR_DATA;
}
} else {
*data = 0;
}
return 0;
}
/**
* \brief Write MAC register.
*
* \param[in] regoffset Register offset
* \param[in] data Register value to write
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_mac_regwrite(unsigned char regoffset, unsigned int data)
{
unsigned int read = 0;
unsigned int maccmd = 0;
int time_out = REG_WRITE_TIME_OUT;
read = SMSC9220->MAC_CSR_CMD;
if(!(read & ((unsigned int)1 << 31))) { /* Make sure there's no pending operation */
SMSC9220->MAC_CSR_DATA = data; /* Store data. */
maccmd |= regoffset;
maccmd &= ~((unsigned int)1 << 30); /* Clear indicates write */
maccmd |= ((unsigned int)1 << 31); /* Indicate start of operation */
SMSC9220->MAC_CSR_CMD = maccmd;
do {
read = SMSC9220->BYTE_TEST; /* A no-op read. */
wait_ms(1);
time_out--;
} while(time_out && (SMSC9220->MAC_CSR_CMD & ((unsigned int)1 << 31)));
if(!time_out) {
return 1;
}
} else {
printf("Error: SMSC9220 MAC CSR is busy. No data written.\n");
}
return 0;
}
/**
* \brief Read PHY register.
*
* \param[in] regoffset Register offset
* \param[out] data Register value is read
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_phy_regread(unsigned char regoffset, unsigned int *data)
{
unsigned int val = 0;
unsigned int phycmd = 0;
int time_out = REG_WRITE_TIME_OUT;
if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC, &val)) {
return 1;
}
if(!(val & 1)) { /* Not busy */
phycmd = 0;
phycmd |= (1 << 11); /* 1 to [15:11] */
phycmd |= ((regoffset & 0x1F) << 6); /* Put regoffset to [10:6] */
phycmd &= ~(1 << 1); /* Clear [1] indicates read. */
phycmd |= (1 << 0); /* Set [0] indicates operation start */
if (smsc9220_mac_regwrite(SMSC9220_MAC_MII_ACC, phycmd)) {
return 1;
}
val = 0;
do {
wait_ms(1);
time_out--;
if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC,&val)) {
return 1;
}
} while(time_out && (val & ((unsigned int)1 << 0)));
if (!time_out) {
return 1;
} else if (smsc9220_mac_regread(SMSC9220_MAC_MII_DATA, data)) {
return 1;
}
} else {
*data = 0;
return 1;
}
return 0;
}
/**
* \brief Write PHY register.
*
* \param[in] regoffset Register offset
* \param[in] data Register value to write
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_phy_regwrite(unsigned char regoffset, unsigned int data)
{
unsigned int val = 0;
unsigned int phycmd = 0;
int time_out = REG_WRITE_TIME_OUT;
if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC, &val)) {
return 1;
}
if(!(val & 1)) { /* Not busy */
/* Load the data */
if (smsc9220_mac_regwrite(SMSC9220_MAC_MII_DATA, (data & 0xFFFF))) {
return 1;
}
phycmd = 0;
phycmd |= (1 << 11); /* 1 to [15:11] */
phycmd |= ((regoffset & 0x1F) << 6); /* Put regoffset to [10:6] */
phycmd |= (1 << 1); /* Set [1] indicates write. */
phycmd |= (1 << 0); /* Set [0] indicates operation start */
/* Start operation */
if (smsc9220_mac_regwrite(SMSC9220_MAC_MII_ACC, phycmd)) {
return 1;
}
phycmd = 0;
do {
wait_ms(1);
time_out--;
if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC, &phycmd)){
return 1;
}
} while(time_out && (phycmd & (1 << 0)));
if (!time_out) {
return 1;
}
} else {
printf("Error: SMSC9220 MAC MII is busy. No data written.\n");
}
return 0;
}
/**
* \brief Read SMSC9220 ID.
*
* \return ID number
*/
inline static unsigned int smsc9220_read_id(void)
{
return SMSC9220->ID_REV;
}
/**
* \brief Initiates a soft reset, returns failure or success.
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_soft_reset(void)
{
int time_out = RESET_TIME_OUT;
/* Soft reset */
SMSC9220->HW_CFG |= 1;
do {
wait_ms(1);
time_out--;
} while(time_out && (SMSC9220->HW_CFG & 1));
if (!time_out) {
return 1;
}
return 0;
}
/**
* \brief Set maximum transition unit by Tx fifo size.
* Note: The MTU will be smaller by 512 bytes,
* because the status uses this fixed space.
*
* \param[in] val Size of the fifo in kbytes, 2-14
*/
static void smsc9220_set_txfifo(unsigned int val)
{
/* 2kb minimum, 14kb maximum */
if(val >= 2 && val <= 14) {
SMSC9220->HW_CFG = val << 16;
}
}
/**
* \brief Wait for EEPROM to be ready to use.
*
* \return 0 if ready, 1 in case of timeout
*/
static unsigned int smsc9220_wait_eeprom(void)
{
int time_out = REG_WRITE_TIME_OUT;
do {
wait_ms(1);
time_out--;
} while(time_out && (SMSC9220->E2P_CMD & ((unsigned int) 1 << 31)));
if (!time_out) {
return 1;
}
return 0;
}
/**
* \brief Initialise irqs
*/
static void smsc9220_init_irqs(void)
{
SMSC9220->INT_EN = 0x0;
SMSC9220->INT_STS = 0xFFFFFFFF; /* clear all interrupts */
SMSC9220->IRQ_CFG = 0x22000100; /* irq deassertion at 220 usecs and master IRQ enable. */
}
/**
* \brief Check PHY ID registers.
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_check_phy(void)
{
unsigned int phyid1, phyid2;
if (smsc9220_phy_regread(SMSC9220_PHY_ID1,&phyid1)) {
return 1;
}
if (smsc9220_phy_regread(SMSC9220_PHY_ID2,&phyid2)) {
return 1;
}
return ((phyid1 == 0xFFFF && phyid2 == 0xFFFF) ||
(phyid1 == 0x0 && phyid2 == 0x0));
}
/**
* \brief Reset PHY
*
* \return 0 in case of success, 1 otherwise
*/
static unsigned int smsc9220_reset_phy(void)
{
unsigned int read;
if(smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &read)) {
return 1;
}
read |= (1 << 15);
if(smsc9220_phy_regwrite(SMSC9220_PHY_BCONTROL, read)) {
return 1;
}
return 0;
}
/**
* \brief Advertise all speeds and pause capabilities
*
* \return 0 in case of success, 1 otherwise
*/
static void smsc9220_advertise_cap(void)
{
unsigned int aneg_adv = 0;
smsc9220_phy_regread(SMSC9220_PHY_ANEG_ADV, &aneg_adv);
aneg_adv |= 0xDE0;
smsc9220_phy_regwrite(SMSC9220_PHY_ANEG_ADV, aneg_adv);
smsc9220_phy_regread(SMSC9220_PHY_ANEG_ADV, &aneg_adv);
}
/**
* \brief Enable trasmission
*/
inline static void smsc9220_enable_xmit(void)
{
SMSC9220->TX_CFG = 0x2;
}
static void smsc9220_enable_mac_xmit(void)
{
unsigned int mac_cr = 0;
smsc9220_mac_regread(SMSC9220_MAC_CR, &mac_cr);
mac_cr |= (1 << 3); /* xmit enable */
mac_cr |= (1 << 28); /* Heartbeat disable */
smsc9220_mac_regwrite(SMSC9220_MAC_CR, mac_cr);
}
/**
* \brief Enable receive
*/
static void smsc9220_enable_mac_recv(void)
{
unsigned int mac_cr = 0;
smsc9220_mac_regread(SMSC9220_MAC_CR, &mac_cr);
mac_cr |= (1 << 2); /* Recv enable */
smsc9220_mac_regwrite(SMSC9220_MAC_CR, mac_cr);
}
/**
* \brief Check device ID.
*
* \return 0 in case of success, 1 otherwise
*/
static int smsc9220_check_id(void)
{
unsigned int id = smsc9220_read_id();
/* If bottom and top halves of the word are the same */
if(((id >> 16) & 0xFFFF) == (id & 0xFFFF)) {
return 1;
}
switch(((id >> 16) & 0xFFFF)) {
case 0x9220:
break;
default:
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------
Public API
*----------------------------------------------------------------------------*/
int smsc9220_init(void)
{
unsigned int phyreset = 0;
if(smsc9220_check_id()) {
return 1;
}
if(smsc9220_soft_reset()) {
return 1;
}
smsc9220_set_txfifo(5);
/* Sets automatic flow control thresholds, and backpressure */
/* threshold to defaults specified. */
SMSC9220->AFC_CFG = 0x006E3740;
if(smsc9220_wait_eeprom()) {
return 1;
}
/* Configure GPIOs as LED outputs. */
SMSC9220->GPIO_CFG = 0x70070000;
smsc9220_init_irqs();
/* Configure MAC addresses here if needed. */
if(smsc9220_check_phy()) {
return 1;
}
if(smsc9220_reset_phy()) {
return 1;
}
wait_ms(PHY_RESET_TIME_OUT_MS);
/* Checking whether phy reset completed successfully.*/
if (smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &phyreset)) {
return 1;
}
if(phyreset & (1 << 15)) {
return 1;
}
smsc9220_advertise_cap();
smsc9220_establish_link(); /* bit [12] of BCONTROL seems self-clearing. */
/* Although it's not so in the manual. */
/* Interrupt threshold */
SMSC9220->FIFO_INT = 0xFF000000;
smsc9220_enable_mac_xmit();
smsc9220_enable_xmit();
SMSC9220->RX_CFG = 0;
smsc9220_enable_mac_recv();
/* Rx status FIFO level irq threshold */
SMSC9220->FIFO_INT &= ~(0xFF); /* Clear 2 bottom nibbles */
/* This sleep is compulsory otherwise txmit/receive will fail. */
wait_ms(2000);
return 0;
}
void smsc9220_enable_interrupt(enum smsc9220_interrupt_source source)
{
SMSC9220->INT_EN |= (1 << source);
}
void smsc9220_disable_interrupt(enum smsc9220_interrupt_source source)
{
SMSC9220->INT_EN &= ~(1 << source);
}
void smsc9220_clear_interrupt(enum smsc9220_interrupt_source source)
{
SMSC9220->INT_STS |= (1 << source);
}
int smsc9220_get_interrupt(enum smsc9220_interrupt_source source)
{
return (SMSC9220->INT_STS & (1 << source));
}
void smsc9220_establish_link(void)
{
unsigned int bcr = 0;
unsigned int hw_cfg = 0;
smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &bcr);
bcr |= (1 << 12) | (1 << 9);
smsc9220_phy_regwrite(SMSC9220_PHY_BCONTROL, bcr);
smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &bcr);
hw_cfg = SMSC9220->HW_CFG;
hw_cfg &= 0xF0000;
hw_cfg |= (1 << 20);
SMSC9220->HW_CFG = hw_cfg;
}
int smsc9220_read_mac_address(char *mac)
{
unsigned int mac_low = 0;
unsigned int mac_high = 0;
if( !mac ) {
return 1;
}
/* Read current mac address. */
if (smsc9220_mac_regread(SMSC9220_MAC_ADDRH, &mac_high)) {
return 1;
}
if (smsc9220_mac_regread(SMSC9220_MAC_ADDRL, &mac_low)) {
return 1;
}
mac[0] = mac_low & 0xFF;
mac[1] = (mac_low >> 8) & 0xFF;
mac[2] = (mac_low >> 16) & 0xFF;
mac[3] = (mac_low >> 24) & 0xFF;
mac[4] = mac_high & 0xFF;
mac[5] = (mac_high >> 8) & 0xFF;
return 0;
}
unsigned int smsc9220_get_tx_data_fifo_size(void)
{
const unsigned int tx_status_fifo_size = 512; /* fixed allocation in bytes */
unsigned int tx_fifo_size = SMSC9220->HW_CFG;
tx_fifo_size = (( tx_fifo_size >> 16 ) & 0x0F) * 1024; /* size is set in kbytes */
return (tx_fifo_size - tx_status_fifo_size);
}
int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet,
const char *data, unsigned int current_size)
{
static unsigned int ongoing_packet_length = 0; /* size in bytes of the packet is sending */
static unsigned int ongoing_packet_length_sent = 0; /* size in bytes of the packet has been sent */
int is_first_segment = 0; /* signing this is the first segment of the packet to be sent */
int is_last_segment = 0; /* signing this is the last segment of the packet to be sent */
unsigned int txcmd_a, txcmd_b = 0;
unsigned int dwords_to_write = 0;
unsigned int *pktptr = 0;
unsigned int xmit_inf = 0;
unsigned int tx_buffer_free_space = 0;
volatile unsigned int xmit_stat = 0;
if (!data) {
return -1; /* Invalid input parameter */
}
if (is_new_packet) {
is_first_segment = 1;
ongoing_packet_length = total_packet_length;
ongoing_packet_length_sent = 0;
} else if (ongoing_packet_length != total_packet_length ||
ongoing_packet_length_sent >= total_packet_length) {
return -1; /* Invalid input parameter */
}
/* Would next chunk fit into buffer? */
xmit_inf = SMSC9220->TX_FIFO_INF;
tx_buffer_free_space = xmit_inf & 0xFFFF;
if (current_size > tx_buffer_free_space) {
return -1; /* Not enough space in FIFO */
}
if ((ongoing_packet_length_sent + current_size) == total_packet_length) {
is_last_segment = 1;
}
pktptr = (unsigned int *) data;
txcmd_a = 0;
txcmd_b = 0;
txcmd_a |= (is_last_segment << 12) | (is_first_segment << 13); /* Last and first segments */
txcmd_a |= current_size & 0x7FF; /* [10:0] contains length */
txcmd_b |= ((current_size & 0xFFFF) << 16); /* [31:16] contains length */
txcmd_b |= current_size & 0x7FF; /* [10:0] also contains length */
SMSC9220->TX_DATA_PORT = txcmd_a;
SMSC9220->TX_DATA_PORT = txcmd_b;
dwords_to_write = (current_size + 3) >> 2;
/* PIO Copy to FIFO. Could replace this with DMA. */
while(dwords_to_write > 0) {
SMSC9220->TX_DATA_PORT = *pktptr;
pktptr++;
dwords_to_write--;
}
if (is_last_segment) {
/* pop status port */
/* for error check it should be checked "at a later time" according to data sheet */
xmit_stat = SMSC9220->TX_STAT_PORT;
}
ongoing_packet_length_sent += current_size;
return 0;
}
unsigned int smsc9220_get_rxfifo_data_used_space(void)
{
unsigned int rxfifo_inf = SMSC9220->RX_FIFO_INF;
return rxfifo_inf & 0xFFFF;
}
unsigned int smsc9220_receive_by_chunks(char *data, unsigned int dlen)
{
static unsigned int current_packet_size_words = 0;
unsigned int rxfifo_inf = 0;
unsigned int rxfifo_stat = 0;
unsigned int dlen_word = 0;
unsigned int read_length_word = 0;
unsigned int i = 0;
if (!data) {
return 0; /* Invalid input parameter */
}
if (current_packet_size_words == 0) {
/* First the packet status word should be read, */
/* which tells the size of the data, */
/* after the data can be read in synchron. */
rxfifo_inf = SMSC9220->RX_FIFO_INF;
if(rxfifo_inf & 0xFFFF) { /* If there's data */
rxfifo_stat = SMSC9220->RX_STAT_PORT;
if(rxfifo_stat != 0) { /* Fetch status of this packet */
if(rxfifo_stat & (1 << 15)) {
current_packet_size_words = 0; /* error */
}
else {
/* Ethernet controller is padding to 32bit aligned data */
current_packet_size_words = (((rxfifo_stat >> 16) & 0x3FFF) + 3) >> 2;
}
}
}
}
dlen_word = dlen / 4;
read_length_word = (dlen_word < current_packet_size_words) ? dlen_word : current_packet_size_words;
for (i = 0; i < read_length_word; i++) {
((unsigned int*)data)[i] = SMSC9220->RX_DATA_PORT;
current_packet_size_words--;
}
return (current_packet_size_words * 4);
}
unsigned int smsc9220_peek_next_packet_size(void)
{
unsigned int packet_size = 0;
unsigned int rx_stat_peek = 0;
if(smsc9220_get_rxfifo_data_used_space()) {
rx_stat_peek = SMSC9220->RX_STAT_PEEK;
packet_size = ((rx_stat_peek >> 16) & 0x3FFF);
}
return (((packet_size + 3) >> 2) << 2);
}

View File

@ -0,0 +1,170 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* This file is the re-implementation of mps2_ethernet_api and Selftest's ETH_MPS2.
* MPS2 Selftest:https://silver.arm.com/browse/VEI10 ->
* \ISCM-1-0\AN491\software\Selftest\v2m_mps2\
*/
#ifndef _SMSC9220_ETH_H_
#define _SMSC9220_ETH_H_
enum smsc9220_interrupt_source {
enum_smsc9220_interrupt_gpio0 = 0,
enum_smsc9220_interrupt_gpio1 = 1,
enum_smsc9220_interrupt_gpio2 = 2,
enum_smsc9220_interrupt_rxstatus_fifo_level = 3,
enum_smsc9220_interrupt_rxstatus_fifo_full = 4,
/* 5 Reserved according to Datasheet */
enum_smsc9220_interrupt_rx_dropped_frame = 6,
enum_smsc9220_interrupt_txstatus_fifo_level = 7,
enum_smsc9220_interrupt_txstatus_fifo_full = 8,
enum_smsc9220_interrupt_txdata_fifo_available = 9,
enum_smsc9220_interrupt_txdata_fifo_overrun = 10,
/* 11, 12 Reserved according to Datasheet */
enum_smsc9220_interrupt_transmit_error = 13,
enum_smsc9220_interrupt_receive_error = 14,
enum_smsc9220_interrupt_receive_watchdog_timeout = 15,
enum_smsc9220_interrupt_txstatus_overflow = 16,
enum_smsc9220_interrupt_power_management = 17,
enum_smsc9220_interrupt_phy = 18,
enum_smsc9220_interrupt_gp_timer = 19,
enum_smsc9220_interrupt_rx_dma = 20,
enum_smsc9220_interrupt_tx_ioc = 21,
/* 22 Reserved according to Datasheet*/
enum_smsc9220_interrupt_rx_dropped_frame_half = 23,
enum_smsc9220_interrupt_rx_stopped = 24,
enum_smsc9220_interrupt_tx_stopped = 25,
/* 26 - 30 Reserved according to Datasheet*/
enum_smsc9220_interrupt_sw = 31
};
/* Function declarations */
/**
* \brief Initialize SMS9220 Ethernet controller
*
* \return 0 if init is successful, 1 otherwise
*/
int smsc9220_init(void);
/**
* \brief Enable the given interrupt source.
*
* \param[in] source Enum of the interrupt source.
*/
void smsc9220_enable_interrupt(enum smsc9220_interrupt_source source);
/**
* \brief Disable the given interrupt source.
*
* \param[in] source Enum of the interrupt source.
*/
void smsc9220_disable_interrupt(enum smsc9220_interrupt_source source);
/**
* \brief Clear the given interrupt source.
*
* \param[in] source Enum of the interrupt source.
*/
void smsc9220_clear_interrupt(enum smsc9220_interrupt_source source);
/**
* \brief Get the status of the given interrupt source.
*
* \param[in] source Enum of the interrupt source.
*
* \return non-zero if the given interrupt source is triggered, zero otherwise
*/
int smsc9220_get_interrupt(enum smsc9220_interrupt_source source);
/**
* \brief Establish link
*/
void smsc9220_establish_link(void);
/**
* \brief Read MAC address from EEPROM.
*
* \param[in,out] mac array will include the read MAC address in
* 6 bytes hexadecimal format.
* It should be allocated by the caller to 6 bytes.
*
* \return 0 if read is successful, 1 otherwise
*/
int smsc9220_read_mac_address(char *mac);
/**
* \brief Get the data size of the Tx buffer, aka Maximum Transition Unit
*
* \return Fifo data size in bytes
*/
unsigned int smsc9220_get_tx_data_fifo_size(void);
/**
* \brief Send Ethernet packet from buffer chain.
* The full packet length should be known in the beginning
* of a new packet.
*
* \param[in] total_packet_length Length of the packet. Should be equal to
* the sum of passed buffers within a packet.
* \param[in] is_new_packet Should be set to non-zero if the passed buffer
* should be sent as the start of a new packet.
* If the current buffer should be sent as a full packet,
* it should be set to non-zero respectively.
* \param[in] data Pointer to the data should be sent.
* \param[in] current_size Size of the data in bytes.
*
* \return 0 if the send process is successful, standard C error code otherwise
*/
int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet,
const char *data, unsigned int current_size);
/**
* \brief Receive Ethernet packet from Rx FIFO to the passed buffer.
* Stops reading at packet border.
* If the passed buffer is larger than the current packet,
* the whole packet will be read into the buffer.
* If the current packet is larger than the passed buffer,
* the buffer will be filled with data and the next call
* will continue the read from that point.
*
* \param[in,out] data Pointer where the data will be read to.
* The caller is responsible to allocate it.
* \param[in] dlen Length of the allocated data in bytes.
*
* \return Remaining bytes left in the fifo of the current packet.
*/
unsigned int smsc9220_receive_by_chunks(char *data, unsigned int dlen);
/**
* \brief Get the used space of Rx fifo in bytes.
*
* \return Data received and waiting for read in bytes
*/
unsigned int smsc9220_get_rxfifo_data_used_space(void);
/**
* \brief Get the size of next unread packet in Rx buffer, using the peak
* register, which is not destructive so can be read asynchronously.
* Warning: In case of heavy receiving load, it's possible this register
* is not perfectly in sync.
*
* \return Size in bytes of the next packet can be read from Rx fifo, according
* to the peek register.
*/
unsigned int smsc9220_peek_next_packet_size(void);
#endif

View File

@ -21,60 +21,57 @@
#include "mbed_toolchain.h"
#include "mbed_error.h"
#include "mbed_wait_api.h"
#define TX_PKT_SIZE 256
#define RX_PKT_SIZE 300
// Types
#undef FALSE
#undef TRUE
#define FALSE 0
#define TRUE 1
#include "smsc9220_eth.h"
/*----------------------------------------------------------------------------
Ethernet Device initialize
*----------------------------------------------------------------------------*/
int ethernet_init()
{
return 0;
return smsc9220_init();
}
/*----------------------------------------------------------------------------
Ethernet Device Uninitialize
*----------------------------------------------------------------------------*/
void ethernet_free() {
void ethernet_free()
{
/* Uninitialize function is not implemented in Ethernet driver. */
}
int ethernet_write(const char *data, int size)
{
/* smsc9220 cannot provide the functionality of writing into the tx buffer */
/* by chunks, without knowing the full size of the packet in the beginning */
return 0;
}
int ethernet_send()
{
/* smsc9220 cannot provide the functionality of writing into the tx buffer */
/* by chunks, without knowing the full size of the packet in the beginning */
return 0;
}
int ethernet_receive()
{
return 0;
return smsc9220_peek_next_packet_size();
}
// Read from an recevied ethernet packet.
// After receive returnd a number bigger than 0 it is
// possible to read bytes from this packet.
// Read will write up to size bytes into data.
// It is possible to use read multible times.
// Each time read will start reading after the last read byte before.
/* Read from an recevied ethernet packet.*/
/* After receive returnd a number bigger than 0 it is*/
/* possible to read bytes from this packet.*/
/* Read will write up to size bytes into data.*/
/* It is possible to use read multible times.*/
/* Each time read will start reading after the last read byte before. */
int ethernet_read(char *data, int dlen)
{
return 0;
return smsc9220_receive_by_chunks(data, dlen);
}
void ethernet_address(char *mac) {
mbed_mac_address(mac);
void ethernet_address(char *mac)
{
smsc9220_read_mac_address(mac);
}
int ethernet_link(void)
@ -84,5 +81,5 @@ int ethernet_link(void)
void ethernet_set_link(int speed, int duplex)
{
smsc9220_establish_link();
}