summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/dfs/src/dfs_posix.c11
-rw-r--r--components/drivers/spi/SConscript24
-rw-r--r--components/drivers/spi/device_driver_list.txt15
-rw-r--r--components/drivers/spi/enc28j60.c876
-rw-r--r--components/drivers/spi/enc28j60.h329
-rw-r--r--components/drivers/spi/spi_flash_at45dbxx.c437
-rw-r--r--components/drivers/spi/spi_flash_at45dbxx.h17
-rw-r--r--components/drivers/spi/spi_flash_sst25vfxx.c346
-rw-r--r--components/drivers/spi/spi_flash_sst25vfxx.h32
-rw-r--r--components/drivers/spi/spi_flash_w25qxx.c371
-rw-r--r--components/drivers/spi/spi_flash_w25qxx.h34
-rw-r--r--components/drivers/spi/spi_wifi_rw009.c590
-rw-r--r--components/drivers/spi/spi_wifi_rw009.h123
-rw-r--r--components/external/libpng/pngconf.h2
-rw-r--r--components/libc/newlib/syscalls.c8
15 files changed, 3209 insertions, 6 deletions
diff --git a/components/dfs/src/dfs_posix.c b/components/dfs/src/dfs_posix.c
index f516eccd93..c1a6a5beb6 100644
--- a/components/dfs/src/dfs_posix.c
+++ b/components/dfs/src/dfs_posix.c
@@ -540,12 +540,17 @@ struct dirent *readdir(DIR *d)
if (fd == RT_NULL)
{
rt_set_errno(-DFS_STATUS_EBADF);
-
return RT_NULL;
}
- if (!d->num ||
- (d->cur += ((struct dirent *)(d->buf + d->cur))->d_reclen) >= d->num)
+ if (d->num)
+ {
+ struct dirent* dirent_ptr;
+ dirent_ptr = (struct dirent*)&d->buf[d->cur];
+ d->cur += dirent_ptr->d_reclen;
+ }
+
+ if (!d->num || d->cur >= d->num)
{
/* get a new entry */
result = dfs_file_getdents(fd,
diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript
index f114ef7a41..f9fc82a777 100644
--- a/components/drivers/spi/SConscript
+++ b/components/drivers/spi/SConscript
@@ -1,8 +1,28 @@
from building import *
-cwd = GetCurrentDir()
-src = Glob('*.c')
+cwd = GetCurrentDir()
+src = ['spi_core.c', 'spi_dev.c']
CPPPATH = [cwd + '/../include']
+
+src_device = []
+
+if GetDepend('RT_USING_SPI_WIFI'):
+ src_device += ['spi_wifi_rw009.c']
+
+if GetDepend('RT_USING_W25QXX'):
+ src_device += ['spi_flash_w25qxx.c']
+
+if GetDepend('RT_USING_ENC28J60'):
+ src_device += ['enc28j60.c']
+
+if GetDepend('RT_USING_AT45DBXX'):
+ src_device += ['spi_flash_at45dbxx.c']
+
+if GetDepend('RT_USING_SST25VFXX'):
+ src_device += ['spi_flash_sst25vfxx.c']
+
+src += src_device
+
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/spi/device_driver_list.txt b/components/drivers/spi/device_driver_list.txt
new file mode 100644
index 0000000000..2c9d6a16b8
--- /dev/null
+++ b/components/drivers/spi/device_driver_list.txt
@@ -0,0 +1,15 @@
+spi_wifi_rw009.c/spi_wifi_rw009.h
+RW009
+http://www.rt-thread.com/
+
+enc28j60.c/enc28j60.h
+http://www.microchip.com/
+
+spi_flash_at45dbxx.c/spi_flash_at45dbxx.h
+http://www.atmel.com/
+
+spi_flash_sst25vfxx.c/spi_flash_sst25vfxx.h
+http://www.microchip.com/
+
+spi_flash_w25qxx.c/spi_flash_w25qxx.h
+http://www.winbond.com/
diff --git a/components/drivers/spi/enc28j60.c b/components/drivers/spi/enc28j60.c
new file mode 100644
index 0000000000..68f1181dcc
--- /dev/null
+++ b/components/drivers/spi/enc28j60.c
@@ -0,0 +1,876 @@
+#include "enc28j60.h"
+
+#define NET_TRACE
+#define ETH_RX_DUMP
+#define ETH_TX_DUMP
+
+#ifdef NET_TRACE
+#define NET_DEBUG rt_kprintf
+#else
+#define NET_DEBUG(...)
+#endif /* #ifdef NET_TRACE */
+
+struct enc28j60_tx_list_typedef
+{
+ struct enc28j60_tx_list_typedef * prev;
+ struct enc28j60_tx_list_typedef * next;
+ rt_uint32_t addr; /* pkt addr in buffer */
+ rt_uint32_t len; /* pkt len */
+ volatile rt_bool_t free; /* 0:busy, 1:free */
+};
+static struct enc28j60_tx_list_typedef enc28j60_tx_list[2];
+static volatile struct enc28j60_tx_list_typedef * tx_current;
+static volatile struct enc28j60_tx_list_typedef * tx_ack;
+static struct rt_event tx_event;
+
+/* private enc28j60 define */
+/* enc28j60 spi interface function */
+static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address);
+static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data);
+
+static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address);
+static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data);
+
+static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk);
+static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address);
+static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device);
+static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level);
+
+static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address);
+static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data);
+static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device);
+
+#define enc28j60_lock(dev) rt_mutex_take(&((struct net_device*)dev)->lock, RT_WAITING_FOREVER);
+#define enc28j60_unlock(dev) rt_mutex_release(&((struct net_device*)dev)->lock);
+
+static struct net_device enc28j60_dev;
+static uint8_t Enc28j60Bank;
+//struct rt_spi_device * spi_device;
+static uint16_t NextPacketPtr;
+
+static void _delay_us(uint32_t us)
+{
+ volatile uint32_t len;
+ for (; us > 0; us --)
+ for (len = 0; len < 20; len++ );
+}
+
+/* enc28j60 spi interface function */
+static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address)
+{
+ uint8_t send_buffer[2];
+ uint8_t recv_buffer[1];
+ uint32_t send_size = 1;
+
+ send_buffer[0] = op | (address & ADDR_MASK);
+ send_buffer[1] = 0xFF;
+
+ /* do dummy read if needed (for mac and mii, see datasheet page 29). */
+ if(address & 0x80)
+ {
+ send_size = 2;
+ }
+
+ rt_spi_send_then_recv(spi_device, send_buffer, send_size, recv_buffer, 1);
+ return (recv_buffer[0]);
+}
+
+static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data)
+{
+ uint32_t level;
+ uint8_t buffer[2];
+
+ level = rt_hw_interrupt_disable();
+
+ buffer[0] = op | (address & ADDR_MASK);
+ buffer[1] = data;
+ rt_spi_send(spi_device, buffer, 2);
+
+ rt_hw_interrupt_enable(level);
+}
+
+/* enc28j60 function */
+static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk)
+{
+ /* setup clkout: 2 is 12.5MHz: */
+ spi_write(spi_device, ECOCON, clk & 0x7);
+}
+
+static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address)
+{
+ /* set the bank (if needed) .*/
+ if((address & BANK_MASK) != Enc28j60Bank)
+ {
+ /* set the bank. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
+ Enc28j60Bank = (address & BANK_MASK);
+ }
+}
+
+static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address)
+{
+ /* set the bank. */
+ enc28j60_set_bank(spi_device, address);
+ /* do the read. */
+ return spi_read_op(spi_device, ENC28J60_READ_CTRL_REG, address);
+}
+
+static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data)
+{
+ /* set the bank. */
+ enc28j60_set_bank(spi_device, address);
+ /* do the write. */
+ spi_write_op(spi_device, ENC28J60_WRITE_CTRL_REG, address, data);
+}
+
+static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address)
+{
+ uint16_t value;
+
+ /* Set the right address and start the register read operation. */
+ spi_write(spi_device, MIREGADR, address);
+ spi_write(spi_device, MICMD, MICMD_MIIRD);
+
+ _delay_us(15);
+
+ /* wait until the PHY read completes. */
+ while(spi_read(spi_device, MISTAT) & MISTAT_BUSY);
+
+ /* reset reading bit */
+ spi_write(spi_device, MICMD, 0x00);
+
+ value = spi_read(spi_device, MIRDL) | spi_read(spi_device, MIRDH)<<8;
+
+ return (value);
+}
+
+static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data)
+{
+ /* set the PHY register address. */
+ spi_write(spi_device, MIREGADR, address);
+
+ /* write the PHY data. */
+ spi_write(spi_device, MIWRL, data);
+ spi_write(spi_device, MIWRH, data>>8);
+
+ /* wait until the PHY write completes. */
+ while(spi_read(spi_device, MISTAT) & MISTAT_BUSY)
+ {
+ _delay_us(15);
+ }
+}
+
+static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device)
+{
+ uint32_t level;
+
+ /* switch to bank 0 */
+ enc28j60_set_bank(spi_device, EIE);
+
+ /* get last interrupt level */
+ level = spi_read(spi_device, EIE);
+ /* disable interrutps */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, level);
+
+ return level;
+}
+
+static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level)
+{
+ /* switch to bank 0 */
+ enc28j60_set_bank(spi_device, EIE);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, level);
+}
+
+/*
+ * Access the PHY to determine link status
+ */
+static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device)
+{
+ uint16_t reg;
+ int duplex;
+
+ reg = enc28j60_phy_read(spi_device, PHSTAT2);
+ duplex = reg & PHSTAT2_DPXSTAT;
+
+ if (reg & PHSTAT2_LSTAT)
+ {
+ /* on */
+ return RT_TRUE;
+ }
+ else
+ {
+ /* off */
+ return RT_FALSE;
+ }
+}
+
+
+/************************* RT-Thread Device Interface *************************/
+void enc28j60_isr(void)
+{
+ eth_device_ready(&enc28j60_dev.parent);
+ NET_DEBUG("enc28j60_isr\r\n");
+}
+
+static void _tx_chain_init(void)
+{
+ enc28j60_tx_list[0].next = &enc28j60_tx_list[1];
+ enc28j60_tx_list[1].next = &enc28j60_tx_list[0];
+
+ enc28j60_tx_list[0].prev = &enc28j60_tx_list[1];
+ enc28j60_tx_list[1].prev = &enc28j60_tx_list[0];
+
+ enc28j60_tx_list[0].addr = TXSTART_INIT;
+ enc28j60_tx_list[1].addr = TXSTART_INIT + MAX_TX_PACKAGE_SIZE;
+
+ enc28j60_tx_list[0].free = RT_TRUE;
+ enc28j60_tx_list[1].free = RT_TRUE;
+
+ tx_current = &enc28j60_tx_list[0];
+ tx_ack = tx_current;
+}
+
+/* initialize the interface */
+static rt_err_t enc28j60_init(rt_device_t dev)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ struct rt_spi_device * spi_device = enc28j60->spi_device;
+
+ enc28j60_lock(dev);
+
+ _tx_chain_init();
+
+ // perform system reset
+ spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+ rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */
+
+ NextPacketPtr = RXSTART_INIT;
+
+ // Rx start
+ spi_write(spi_device, ERXSTL, RXSTART_INIT&0xFF);
+ spi_write(spi_device, ERXSTH, RXSTART_INIT>>8);
+ // set receive pointer address
+ spi_write(spi_device, ERXRDPTL, RXSTOP_INIT&0xFF);
+ spi_write(spi_device, ERXRDPTH, RXSTOP_INIT>>8);
+ // RX end
+ spi_write(spi_device, ERXNDL, RXSTOP_INIT&0xFF);
+ spi_write(spi_device, ERXNDH, RXSTOP_INIT>>8);
+
+ // TX start
+ spi_write(spi_device, ETXSTL, TXSTART_INIT&0xFF);
+ spi_write(spi_device, ETXSTH, TXSTART_INIT>>8);
+ // set transmission pointer address
+ spi_write(spi_device, EWRPTL, TXSTART_INIT&0xFF);
+ spi_write(spi_device, EWRPTH, TXSTART_INIT>>8);
+ // TX end
+ spi_write(spi_device, ETXNDL, TXSTOP_INIT&0xFF);
+ spi_write(spi_device, ETXNDH, TXSTOP_INIT>>8);
+
+ // do bank 1 stuff, packet filter:
+ // For broadcast packets we allow only ARP packtets
+ // All other packets should be unicast only for our mac (MAADR)
+ //
+ // The pattern to match on is therefore
+ // Type ETH.DST
+ // ARP BROADCAST
+ // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
+ // in binary these poitions are:11 0000 0011 1111
+ // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
+ spi_write(spi_device, ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_BCEN);
+
+ // do bank 2 stuff
+ // enable MAC receive
+ spi_write(spi_device, MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
+ // enable automatic padding to 60bytes and CRC operations
+ // spi_write_op(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
+ // bring MAC out of reset
+
+ // set inter-frame gap (back-to-back)
+ // spi_write(MABBIPG, 0x12);
+ spi_write(spi_device, MABBIPG, 0x15);
+
+ spi_write(spi_device, MACON4, MACON4_DEFER);
+ spi_write(spi_device, MACLCON2, 63);
+
+ // set inter-frame gap (non-back-to-back)
+ spi_write(spi_device, MAIPGL, 0x12);
+ spi_write(spi_device, MAIPGH, 0x0C);
+
+ // Set the maximum packet size which the controller will accept
+ // Do not send packets longer than MAX_FRAMELEN:
+ spi_write(spi_device, MAMXFLL, MAX_FRAMELEN&0xFF);
+ spi_write(spi_device, MAMXFLH, MAX_FRAMELEN>>8);
+
+ // do bank 3 stuff
+ // write MAC address
+ // NOTE: MAC address in ENC28J60 is byte-backward
+ spi_write(spi_device, MAADR0, enc28j60->dev_addr[5]);
+ spi_write(spi_device, MAADR1, enc28j60->dev_addr[4]);
+ spi_write(spi_device, MAADR2, enc28j60->dev_addr[3]);
+ spi_write(spi_device, MAADR3, enc28j60->dev_addr[2]);
+ spi_write(spi_device, MAADR4, enc28j60->dev_addr[1]);
+ spi_write(spi_device, MAADR5, enc28j60->dev_addr[0]);
+
+ /* output off */
+ spi_write(spi_device, ECOCON, 0x00);
+
+ // enc28j60_phy_write(PHCON1, 0x00);
+ enc28j60_phy_write(spi_device, PHCON1, PHCON1_PDPXMD); // full duplex
+ // no loopback of transmitted frames
+ enc28j60_phy_write(spi_device, PHCON2, PHCON2_HDLDIS);
+
+ enc28j60_set_bank(spi_device, ECON2);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_AUTOINC);
+
+ // switch to bank 0
+ enc28j60_set_bank(spi_device, ECON1);
+ // enable all interrutps
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, 0xFF);
+ // enable packet reception
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+ /* clock out */
+ enc28j60_clkout(spi_device, 2);
+
+ enc28j60_phy_write(spi_device, PHLCON, 0xD76); //0x476
+ rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */
+
+ enc28j60_unlock(dev);
+ return RT_EOK;
+}
+
+/* control the interface */
+static rt_err_t enc28j60_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ switch(cmd)
+ {
+ case NIOCTL_GADDR:
+ /* get mac address */
+ if(args) rt_memcpy(args, enc28j60->dev_addr, 6);
+ else return -RT_ERROR;
+ break;
+
+ default :
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/* Open the ethernet interface */
+static rt_err_t enc28j60_open(rt_device_t dev, uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+/* Close the interface */
+static rt_err_t enc28j60_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+/* Read */
+static rt_size_t enc28j60_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return RT_EOK;
+}
+
+/* Write */
+static rt_size_t enc28j60_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+/* ethernet device interface */
+/* Transmit packet. */
+static rt_err_t enc28j60_tx( rt_device_t dev, struct pbuf* p)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ struct rt_spi_device * spi_device = enc28j60->spi_device;
+ struct pbuf* q;
+ rt_uint32_t level;
+#ifdef ETH_TX_DUMP
+ rt_size_t dump_count = 0;
+ rt_uint8_t * dump_ptr;
+ rt_size_t dump_i;
+#endif
+
+ if(tx_current->free == RT_FALSE)
+ {
+ NET_DEBUG("[Tx] no empty buffer!\r\n");
+ while(tx_current->free == RT_FALSE)
+ {
+ rt_err_t result;
+ rt_uint32_t recved;
+
+ /* there is no block yet, wait a flag */
+ result = rt_event_recv(&tx_event, 0x01,
+ RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved);
+
+ RT_ASSERT(result == RT_EOK);
+ }
+ NET_DEBUG("[Tx] wait empty buffer done!\r\n");
+ }
+
+ enc28j60_lock(dev);
+
+ /* disable enc28j60 interrupt */
+ level = enc28j60_interrupt_disable(spi_device);
+
+ // Set the write pointer to start of transmit buffer area
+// spi_write(EWRPTL, TXSTART_INIT&0xFF);
+// spi_write(EWRPTH, TXSTART_INIT>>8);
+ spi_write(spi_device, EWRPTL, (tx_current->addr)&0xFF);
+ spi_write(spi_device, EWRPTH, (tx_current->addr)>>8);
+ // Set the TXND pointer to correspond to the packet size given
+ tx_current->len = p->tot_len;
+// spi_write(ETXNDL, (TXSTART_INIT+ p->tot_len + 1)&0xFF);
+// spi_write(ETXNDH, (TXSTART_INIT+ p->tot_len + 1)>>8);
+
+ // write per-packet control byte (0x00 means use macon3 settings)
+ spi_write_op(spi_device, ENC28J60_WRITE_BUF_MEM, 0, 0x00);
+
+#ifdef ETH_TX_DUMP
+ NET_DEBUG("tx_dump, size:%d\r\n", p->tot_len);
+#endif
+ for (q = p; q != NULL; q = q->next)
+ {
+ uint8_t cmd = ENC28J60_WRITE_BUF_MEM;
+ rt_spi_send_then_send(enc28j60->spi_device, &cmd, 1, q->payload, q->len);
+#ifdef ETH_RX_DUMP
+ dump_ptr = q->payload;
+ for(dump_i=0; dump_i<q->len; dump_i++)
+ {
+ NET_DEBUG("%02x ", *dump_ptr);
+ if( ((dump_count+1)%8) == 0 )
+ {
+ NET_DEBUG(" ");
+ }
+ if( ((dump_count+1)%16) == 0 )
+ {
+ NET_DEBUG("\r\n");
+ }
+ dump_count++;
+ dump_ptr++;
+ }
+#endif
+ }
+#ifdef ETH_RX_DUMP
+ NET_DEBUG("\r\n");
+#endif
+
+ // send the contents of the transmit buffer onto the network
+ if(tx_current == tx_ack)
+ {
+ NET_DEBUG("[Tx] stop, restart!\r\n");
+ // TX start
+ spi_write(spi_device, ETXSTL, (tx_current->addr)&0xFF);
+ spi_write(spi_device, ETXSTH, (tx_current->addr)>>8);
+ // TX end
+ spi_write(spi_device, ETXNDL, (tx_current->addr + tx_current->len)&0xFF);
+ spi_write(spi_device, ETXNDH, (tx_current->addr + tx_current->len)>>8);
+
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+ }
+ else
+ {
+ NET_DEBUG("[Tx] busy, add to chain!\r\n");
+ }
+
+ tx_current->free = RT_FALSE;
+ tx_current = tx_current->next;
+
+ /* Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. */
+ if( (spi_read(spi_device, EIR) & EIR_TXERIF) )
+ {
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
+ }
+
+ /* enable enc28j60 interrupt */
+ enc28j60_interrupt_enable(spi_device, level);
+
+ enc28j60_unlock(dev);
+
+ return RT_EOK;
+}
+
+/* recv packet. */
+static struct pbuf *enc28j60_rx(rt_device_t dev)
+{
+ struct net_device * enc28j60 = (struct net_device *)dev;
+ struct rt_spi_device * spi_device = enc28j60->spi_device;
+ struct pbuf* p = RT_NULL;
+
+ uint8_t eir, eir_clr;
+ uint32_t pk_counter;
+ rt_uint32_t level;
+ rt_uint32_t len;
+ rt_uint16_t rxstat;
+
+ enc28j60_lock(dev);
+
+ /* disable enc28j60 interrupt */
+ level = enc28j60_interrupt_disable(spi_device);
+
+ /* get EIR */
+ eir = spi_read(spi_device, EIR);
+
+ while(eir & ~EIR_PKTIF)
+ {
+ eir_clr = 0;
+
+ /* clear PKTIF */
+ if (eir & EIR_PKTIF)
+ {
+ NET_DEBUG("EIR_PKTIF\r\n");
+
+ /* switch to bank 0. */
+ enc28j60_set_bank(spi_device, EIE);
+ /* disable rx interrutps. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, EIE_PKTIE);
+ eir_clr |= EIR_PKTIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_PKTIF);
+ }
+
+ /* clear DMAIF */
+ if (eir & EIR_DMAIF)
+ {
+ NET_DEBUG("EIR_DMAIF\r\n");
+ eir_clr |= EIR_DMAIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_DMAIF);
+ }
+
+ /* LINK changed handler */
+ if ( eir & EIR_LINKIF)
+ {
+ rt_bool_t link_status;
+
+ NET_DEBUG("EIR_LINKIF\r\n");
+ link_status = enc28j60_check_link_status(spi_device);
+
+ /* read PHIR to clear the flag */
+ enc28j60_phy_read(spi_device, PHIR);
+ eir_clr |= EIR_LINKIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_LINKIF);
+
+ eth_device_linkchange(&(enc28j60->parent), link_status);
+ }
+
+ if (eir & EIR_TXIF)
+ {
+ /* A frame has been transmitted. */
+ enc28j60_set_bank(spi_device, EIR);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXIF);
+
+ tx_ack->free = RT_TRUE;
+ tx_ack = tx_ack->next;
+ if(tx_ack->free == RT_FALSE)
+ {
+ NET_DEBUG("[tx isr] Tx chain not empty, continue send the next pkt!\r\n");
+ // TX start
+ spi_write(spi_device, ETXSTL, (tx_ack->addr)&0xFF);
+ spi_write(spi_device, ETXSTH, (tx_ack->addr)>>8);
+ // TX end
+ spi_write(spi_device, ETXNDL, (tx_ack->addr + tx_ack->len)&0xFF);
+ spi_write(spi_device, ETXNDH, (tx_ack->addr + tx_ack->len)>>8);
+
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+ }
+ else
+ {
+ NET_DEBUG("[tx isr] Tx chain empty, stop!\r\n");
+ }
+
+ /* set event */
+ rt_event_send(&tx_event, 0x01);
+ }
+
+ /* wake up handler */
+ if ( eir & EIR_WOLIF)
+ {
+ NET_DEBUG("EIR_WOLIF\r\n");
+ eir_clr |= EIR_WOLIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_WOLIF);
+ }
+
+ /* TX Error handler */
+ if ((eir & EIR_TXERIF) != 0)
+ {
+ NET_DEBUG("EIR_TXERIF re-start tx chain!\r\n");
+ enc28j60_set_bank(spi_device, ECON1);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
+ eir_clr |= EIR_TXERIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
+
+ /* re-init tx chain */
+ _tx_chain_init();
+ }
+
+ /* RX Error handler */
+ if ((eir & EIR_RXERIF) != 0)
+ {
+ NET_DEBUG("EIR_RXERIF re-start rx!\r\n");
+
+ NextPacketPtr = RXSTART_INIT;
+ enc28j60_set_bank(spi_device, ECON1);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXRST);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXRST);
+ /* switch to bank 0. */
+ enc28j60_set_bank(spi_device, ECON1);
+ /* enable packet reception. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+ eir_clr |= EIR_RXERIF;
+// enc28j60_set_bank(spi_device, EIR);
+// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_RXERIF);
+ }
+
+ enc28j60_set_bank(spi_device, EIR);
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, eir_clr);
+
+ eir = spi_read(spi_device, EIR);
+ }
+
+ /* read pkt */
+ pk_counter = spi_read(spi_device, EPKTCNT);
+ if(pk_counter)
+ {
+ /* Set the read pointer to the start of the received packet. */
+ spi_write(spi_device, ERDPTL, (NextPacketPtr));
+ spi_write(spi_device, ERDPTH, (NextPacketPtr)>>8);
+
+ /* read the next packet pointer. */
+ NextPacketPtr = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);
+ NextPacketPtr |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8;
+
+ /* read the packet length (see datasheet page 43). */
+ len = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0); //0x54
+ len |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8; //5554
+
+ len-=4; //remove the CRC count
+
+ // read the receive status (see datasheet page 43)
+ rxstat = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);
+ rxstat |= ((rt_uint16_t)spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0))<<8;
+
+ // check CRC and symbol errors (see datasheet page 44, table 7-3):
+ // The ERXFCON.CRCEN is set by default. Normally we should not
+ // need to check this.
+ if ((rxstat & 0x80)==0)
+ {
+ // invalid
+ len=0;
+ }
+ else
+ {
+ /* allocation pbuf */
+ p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
+ if (p != RT_NULL)
+ {
+ struct pbuf* q;
+#ifdef ETH_RX_DUMP
+ rt_size_t dump_count = 0;
+ rt_uint8_t * dump_ptr;
+ rt_size_t dump_i;
+ NET_DEBUG("rx_dump, size:%d\r\n", len);
+#endif
+ for (q = p; q != RT_NULL; q= q->next)
+ {
+ uint8_t cmd = ENC28J60_READ_BUF_MEM;
+ rt_spi_send_then_recv(spi_device, &cmd, 1, q->payload, q->len);
+#ifdef ETH_RX_DUMP
+ dump_ptr = q->payload;
+ for(dump_i=0; dump_i<q->len; dump_i++)
+ {
+ NET_DEBUG("%02x ", *dump_ptr);
+ if( ((dump_count+1)%8) == 0 )
+ {
+ NET_DEBUG(" ");
+ }
+ if( ((dump_count+1)%16) == 0 )
+ {
+ NET_DEBUG("\r\n");
+ }
+ dump_count++;
+ dump_ptr++;
+ }
+#endif
+ }
+#ifdef ETH_RX_DUMP
+ NET_DEBUG("\r\n");
+#endif
+ }
+ }
+
+ /* Move the RX read pointer to the start of the next received packet. */
+ /* This frees the memory we just read out. */
+ spi_write(spi_device, ERXRDPTL, (NextPacketPtr));
+ spi_write(spi_device, ERXRDPTH, (NextPacketPtr)>>8);
+
+ /* decrement the packet counter indicate we are done with this packet. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
+ }
+ else
+ {
+ /* switch to bank 0. */
+ enc28j60_set_bank(spi_device, ECON1);
+ /* enable packet reception. */
+ spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+ level |= EIE_PKTIE;
+ }
+
+ /* enable enc28j60 interrupt */
+ enc28j60_interrupt_enable(spi_device, level);
+
+ enc28j60_unlock(dev);
+
+ return p;
+}
+
+rt_err_t enc28j60_attach(const char * spi_device_name)
+{
+ struct rt_spi_device * spi_device;
+
+ spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(spi_device == RT_NULL)
+ {
+ NET_DEBUG("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+ cfg.max_hz = 20 * 1000 * 1000; /* SPI Interface with Clock Speeds Up to 20 MHz */
+ rt_spi_configure(spi_device, &cfg);
+ } /* config spi */
+
+ memset(&enc28j60_dev, 0, sizeof(enc28j60_dev));
+
+ rt_event_init(&tx_event, "eth_tx", RT_IPC_FLAG_FIFO);
+ enc28j60_dev.spi_device = spi_device;
+
+ /* detect device */
+ {
+ uint16_t value;
+
+ /* perform system reset. */
+ spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+ rt_thread_delay(1); /* delay 20ms */
+
+ enc28j60_dev.emac_rev = spi_read(spi_device, EREVID);
+ value = enc28j60_phy_read(spi_device, PHHID2);
+ enc28j60_dev.phy_rev = value&0x0F;
+ enc28j60_dev.phy_pn = (value>>4)&0x3F;
+ enc28j60_dev.phy_id = (enc28j60_phy_read(spi_device, PHHID1) | ((value>>10)<<16))<<3;
+
+ if(enc28j60_dev.phy_id != 0x00280418)
+ {
+ NET_DEBUG("ENC28J60 PHY ID not correct!\r\n");
+ NET_DEBUG("emac_rev:%d\r\n", enc28j60_dev.emac_rev);
+ NET_DEBUG("phy_rev:%02X\r\n", enc28j60_dev.phy_rev);
+ NET_DEBUG("phy_pn:%02X\r\n", enc28j60_dev.phy_pn);
+ NET_DEBUG("phy_id:%08X\r\n", enc28j60_dev.phy_id);
+ return RT_EIO;
+ }
+ }
+
+ /* OUI 00-04-A3 (hex): Microchip Technology, Inc. */
+ enc28j60_dev.dev_addr[0] = 0x00;
+ enc28j60_dev.dev_addr[1] = 0x04;
+ enc28j60_dev.dev_addr[2] = 0xA3;
+ /* set MAC address, only for test */
+ enc28j60_dev.dev_addr[3] = 0x12;
+ enc28j60_dev.dev_addr[4] = 0x34;
+ enc28j60_dev.dev_addr[5] = 0x56;
+
+ /* init rt-thread device struct */
+ enc28j60_dev.parent.parent.type = RT_Device_Class_NetIf;
+ enc28j60_dev.parent.parent.init = enc28j60_init;
+ enc28j60_dev.parent.parent.open = enc28j60_open;
+ enc28j60_dev.parent.parent.close = enc28j60_close;
+ enc28j60_dev.parent.parent.read = enc28j60_read;
+ enc28j60_dev.parent.parent.write = enc28j60_write;
+ enc28j60_dev.parent.parent.control = enc28j60_control;
+
+ /* init rt-thread ethernet device struct */
+ enc28j60_dev.parent.eth_rx = enc28j60_rx;
+ enc28j60_dev.parent.eth_tx = enc28j60_tx;
+
+ rt_mutex_init(&enc28j60_dev.lock, "enc28j60", RT_IPC_FLAG_FIFO);
+
+ eth_device_init(&(enc28j60_dev.parent), "e0");
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+/*
+ * Debug routine to dump useful register contents
+ */
+static void enc28j60(void)
+{
+ struct rt_spi_device * spi_device = enc28j60_dev.spi_device;
+ enc28j60_lock(&enc28j60_dev);
+
+ rt_kprintf("-- enc28j60 registers:\n");
+ rt_kprintf("HwRevID: 0x%02X\n", spi_read(spi_device, EREVID));
+
+ rt_kprintf("Cntrl: ECON1 ECON2 ESTAT EIR EIE\n");
+ rt_kprintf(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ spi_read(spi_device, ECON1),
+ spi_read(spi_device, ECON2),
+ spi_read(spi_device, ESTAT),
+ spi_read(spi_device, EIR),
+ spi_read(spi_device, EIE));
+
+ rt_kprintf("MAC : MACON1 MACON3 MACON4\n");
+ rt_kprintf(" 0x%02X 0x%02X 0x%02X\n",
+ spi_read(spi_device, MACON1),
+ spi_read(spi_device, MACON3),
+ spi_read(spi_device, MACON4));
+
+ rt_kprintf("Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n");
+ rt_kprintf(" 0x%04X 0x%04X 0x%04X 0x%04X ",
+ (spi_read(spi_device, ERXSTH) << 8) | spi_read(spi_device, ERXSTL),
+ (spi_read(spi_device, ERXNDH) << 8) | spi_read(spi_device, ERXNDL),
+ (spi_read(spi_device, ERXWRPTH) << 8) | spi_read(spi_device, ERXWRPTL),
+ (spi_read(spi_device, ERXRDPTH) << 8) | spi_read(spi_device, ERXRDPTL));
+
+ rt_kprintf("0x%02X 0x%02X 0x%04X\n",
+ spi_read(spi_device, ERXFCON),
+ spi_read(spi_device, EPKTCNT),
+ (spi_read(spi_device, MAMXFLH) << 8) | spi_read(spi_device, MAMXFLL));
+
+ rt_kprintf("Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\n");
+ rt_kprintf(" 0x%04X 0x%04X 0x%02X 0x%02X 0x%02X\n",
+ (spi_read(spi_device, ETXSTH) << 8) | spi_read(spi_device, ETXSTL),
+ (spi_read(spi_device, ETXNDH) << 8) | spi_read(spi_device, ETXNDL),
+ spi_read(spi_device, MACLCON1),
+ spi_read(spi_device, MACLCON2),
+ spi_read(spi_device, MAPHSUP));
+
+ rt_kprintf("PHY : PHCON1 PHSTAT1\r\n");
+ rt_kprintf(" 0x%04X 0x%04X\r\n",
+ enc28j60_phy_read(spi_device, PHCON1),
+ enc28j60_phy_read(spi_device, PHSTAT1));
+
+ enc28j60_unlock(&enc28j60_dev);
+}
+FINSH_FUNCTION_EXPORT(enc28j60, dump enc28j60 registers);
+#endif
diff --git a/components/drivers/spi/enc28j60.h b/components/drivers/spi/enc28j60.h
new file mode 100644
index 0000000000..8c647d5fc2
--- /dev/null
+++ b/components/drivers/spi/enc28j60.h
@@ -0,0 +1,329 @@
+#ifndef EN28J60_H_INCLUDED
+#define EN28J60_H_INCLUDED
+
+#include <stdint.h>
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+#include <netif/ethernetif.h>
+
+// ENC28J60 Control Registers
+// Control register definitions are a combination of address,
+// bank number, and Ethernet/MAC/PHY indicator bits.
+// - Register address (bits 0-4)
+// - Bank number (bits 5-6)
+// - MAC/PHY indicator (bit 7)
+#define ADDR_MASK 0x1F
+#define BANK_MASK 0x60
+#define SPRD_MASK 0x80
+// All-bank registers
+#define EIE 0x1B
+#define EIR 0x1C
+#define ESTAT 0x1D
+#define ECON2 0x1E
+#define ECON1 0x1F
+// Bank 0 registers
+#define ERDPTL (0x00|0x00)
+#define ERDPTH (0x01|0x00)
+#define EWRPTL (0x02|0x00)
+#define EWRPTH (0x03|0x00)
+#define ETXSTL (0x04|0x00)
+#define ETXSTH (0x05|0x00)
+#define ETXNDL (0x06|0x00)
+#define ETXNDH (0x07|0x00)
+#define ERXSTL (0x08|0x00)
+#define ERXSTH (0x09|0x00)
+#define ERXNDL (0x0A|0x00)
+#define ERXNDH (0x0B|0x00)
+#define ERXRDPTL (0x0C|0x00)
+#define ERXRDPTH (0x0D|0x00)
+#define ERXWRPTL (0x0E|0x00)
+#define ERXWRPTH (0x0F|0x00)
+#define EDMASTL (0x10|0x00)
+#define EDMASTH (0x11|0x00)
+#define EDMANDL (0x12|0x00)
+#define EDMANDH (0x13|0x00)
+#define EDMADSTL (0x14|0x00)
+#define EDMADSTH (0x15|0x00)
+#define EDMACSL (0x16|0x00)
+#define EDMACSH (0x17|0x00)
+// Bank 1 registers
+#define EHT0 (0x00|0x20)
+#define EHT1 (0x01|0x20)
+#define EHT2 (0x02|0x20)
+#define EHT3 (0x03|0x20)
+#define EHT4 (0x04|0x20)
+#define EHT5 (0x05|0x20)
+#define EHT6 (0x06|0x20)
+#define EHT7 (0x07|0x20)
+#define EPMM0 (0x08|0x20)
+#define EPMM1 (0x09|0x20)
+#define EPMM2 (0x0A|0x20)
+#define EPMM3 (0x0B|0x20)
+#define EPMM4 (0x0C|0x20)
+#define EPMM5 (0x0D|0x20)
+#define EPMM6 (0x0E|0x20)
+#define EPMM7 (0x0F|0x20)
+#define EPMCSL (0x10|0x20)
+#define EPMCSH (0x11|0x20)
+#define EPMOL (0x14|0x20)
+#define EPMOH (0x15|0x20)
+#define EWOLIE (0x16|0x20)
+#define EWOLIR (0x17|0x20)
+#define ERXFCON (0x18|0x20)
+#define EPKTCNT (0x19|0x20)
+// Bank 2 registers
+#define MACON1 (0x00|0x40|0x80)
+#define MACON2 (0x01|0x40|0x80)
+#define MACON3 (0x02|0x40|0x80)
+#define MACON4 (0x03|0x40|0x80)
+#define MABBIPG (0x04|0x40|0x80)
+#define MAIPGL (0x06|0x40|0x80)
+#define MAIPGH (0x07|0x40|0x80)
+#define MACLCON1 (0x08|0x40|0x80)
+#define MACLCON2 (0x09|0x40|0x80)
+#define MAMXFLL (0x0A|0x40|0x80)
+#define MAMXFLH (0x0B|0x40|0x80)
+#define MAPHSUP (0x0D|0x40|0x80)
+#define MICON (0x11|0x40|0x80)
+#define MICMD (0x12|0x40|0x80)
+#define MIREGADR (0x14|0x40|0x80)
+#define MIWRL (0x16|0x40|0x80)
+#define MIWRH (0x17|0x40|0x80)
+#define MIRDL (0x18|0x40|0x80)
+#define MIRDH (0x19|0x40|0x80)
+// Bank 3 registers
+#define MAADR1 (0x00|0x60|0x80)
+#define MAADR0 (0x01|0x60|0x80)
+#define MAADR3 (0x02|0x60|0x80)
+#define MAADR2 (0x03|0x60|0x80)
+#define MAADR5 (0x04|0x60|0x80)
+#define MAADR4 (0x05|0x60|0x80)
+#define EBSTSD (0x06|0x60)
+#define EBSTCON (0x07|0x60)
+#define EBSTCSL (0x08|0x60)
+#define EBSTCSH (0x09|0x60)
+#define MISTAT (0x0A|0x60|0x80)
+#define EREVID (0x12|0x60)
+#define ECOCON (0x15|0x60)
+#define EFLOCON (0x17|0x60)
+#define EPAUSL (0x18|0x60)
+#define EPAUSH (0x19|0x60)
+// PHY registers
+#define PHCON1 0x00
+#define PHSTAT1 0x01
+#define PHHID1 0x02
+#define PHHID2 0x03
+#define PHCON2 0x10
+#define PHSTAT2 0x11
+#define PHIE 0x12
+#define PHIR 0x13
+#define PHLCON 0x14
+
+// ENC28J60 ERXFCON Register Bit Definitions
+#define ERXFCON_UCEN 0x80
+#define ERXFCON_ANDOR 0x40
+#define ERXFCON_CRCEN 0x20
+#define ERXFCON_PMEN 0x10
+#define ERXFCON_MPEN 0x08
+#define ERXFCON_HTEN 0x04
+#define ERXFCON_MCEN 0x02
+#define ERXFCON_BCEN 0x01
+// ENC28J60 EIE Register Bit Definitions
+#define EIE_INTIE 0x80
+#define EIE_PKTIE 0x40
+#define EIE_DMAIE 0x20
+#define EIE_LINKIE 0x10
+#define EIE_TXIE 0x08
+#define EIE_WOLIE 0x04
+#define EIE_TXERIE 0x02
+#define EIE_RXERIE 0x01
+// ENC28J60 EIR Register Bit Definitions
+#define EIR_PKTIF 0x40
+#define EIR_DMAIF 0x20
+#define EIR_LINKIF 0x10
+#define EIR_TXIF 0x08
+#define EIR_WOLIF 0x04
+#define EIR_TXERIF 0x02
+#define EIR_RXERIF 0x01
+// ENC28J60 ESTAT Register Bit Definitions
+#define ESTAT_INT 0x80
+#define ESTAT_LATECOL 0x10
+#define ESTAT_RXBUSY 0x04
+#define ESTAT_TXABRT 0x02
+#define ESTAT_CLKRDY 0x01
+// ENC28J60 ECON2 Register Bit Definitions
+#define ECON2_AUTOINC 0x80
+#define ECON2_PKTDEC 0x40
+#define ECON2_PWRSV 0x20
+#define ECON2_VRPS 0x08
+// ENC28J60 ECON1 Register Bit Definitions
+#define ECON1_TXRST 0x80
+#define ECON1_RXRST 0x40
+#define ECON1_DMAST 0x20
+#define ECON1_CSUMEN 0x10
+#define ECON1_TXRTS 0x08
+#define ECON1_RXEN 0x04
+#define ECON1_BSEL1 0x02
+#define ECON1_BSEL0 0x01
+// ENC28J60 MACON1 Register Bit Definitions
+#define MACON1_LOOPBK 0x10
+#define MACON1_TXPAUS 0x08
+#define MACON1_RXPAUS 0x04
+#define MACON1_PASSALL 0x02
+#define MACON1_MARXEN 0x01
+// ENC28J60 MACON2 Register Bit Definitions
+#define MACON2_MARST 0x80
+#define MACON2_RNDRST 0x40
+#define MACON2_MARXRST 0x08
+#define MACON2_RFUNRST 0x04
+#define MACON2_MATXRST 0x02
+#define MACON2_TFUNRST 0x01
+// ENC28J60 MACON3 Register Bit Definitions
+#define MACON3_PADCFG2 0x80
+#define MACON3_PADCFG1 0x40
+#define MACON3_PADCFG0 0x20
+#define MACON3_TXCRCEN 0x10
+#define MACON3_PHDRLEN 0x08
+#define MACON3_HFRMLEN 0x04
+#define MACON3_FRMLNEN 0x02
+#define MACON3_FULDPX 0x01
+// ENC28J60 MACON4 Register Bit Definitions
+#define MACON4_DEFER (1<<6)
+#define MACON4_BPEN (1<<5)
+#define MACON4_NOBKOFF (1<<4)
+// ENC28J60 MICMD Register Bit Definitions
+#define MICMD_MIISCAN 0x02
+#define MICMD_MIIRD 0x01
+// ENC28J60 MISTAT Register Bit Definitions
+#define MISTAT_NVALID 0x04
+#define MISTAT_SCAN 0x02
+#define MISTAT_BUSY 0x01
+// ENC28J60 PHY PHCON1 Register Bit Definitions
+#define PHCON1_PRST 0x8000
+#define PHCON1_PLOOPBK 0x4000
+#define PHCON1_PPWRSV 0x0800
+#define PHCON1_PDPXMD 0x0100
+// ENC28J60 PHY PHSTAT1 Register Bit Definitions
+#define PHSTAT1_PFDPX 0x1000
+#define PHSTAT1_PHDPX 0x0800
+#define PHSTAT1_LLSTAT 0x0004
+#define PHSTAT1_JBSTAT 0x0002
+/* ENC28J60 PHY PHSTAT2 Register Bit Definitions */
+#define PHSTAT2_TXSTAT (1 << 13)
+#define PHSTAT2_RXSTAT (1 << 12)
+#define PHSTAT2_COLSTAT (1 << 11)
+#define PHSTAT2_LSTAT (1 << 10)
+#define PHSTAT2_DPXSTAT (1 << 9)
+#define PHSTAT2_PLRITY (1 << 5)
+// ENC28J60 PHY PHCON2 Register Bit Definitions
+#define PHCON2_FRCLINK 0x4000
+#define PHCON2_TXDIS 0x2000
+#define PHCON2_JABBER 0x0400
+#define PHCON2_HDLDIS 0x0100
+
+// ENC28J60 Packet Control Byte Bit Definitions
+#define PKTCTRL_PHUGEEN 0x08
+#define PKTCTRL_PPADEN 0x04
+#define PKTCTRL_PCRCEN 0x02
+#define PKTCTRL_POVERRIDE 0x01
+
+/* ENC28J60 Transmit Status Vector */
+#define TSV_TXBYTECNT 0
+#define TSV_TXCOLLISIONCNT 16
+#define TSV_TXCRCERROR 20
+#define TSV_TXLENCHKERROR 21
+#define TSV_TXLENOUTOFRANGE 22
+#define TSV_TXDONE 23
+#define TSV_TXMULTICAST 24
+#define TSV_TXBROADCAST 25
+#define TSV_TXPACKETDEFER 26
+#define TSV_TXEXDEFER 27
+#define TSV_TXEXCOLLISION 28
+#define TSV_TXLATECOLLISION 29
+#define TSV_TXGIANT 30
+#define TSV_TXUNDERRUN 31
+#define TSV_TOTBYTETXONWIRE 32
+#define TSV_TXCONTROLFRAME 48
+#define TSV_TXPAUSEFRAME 49
+#define TSV_BACKPRESSUREAPP 50
+#define TSV_TXVLANTAGFRAME 51
+
+#define TSV_SIZE 7
+#define TSV_BYTEOF(x) ((x) / 8)
+#define TSV_BITMASK(x) (1 << ((x) % 8))
+#define TSV_GETBIT(x, y) (((x)[TSV_BYTEOF(y)] & TSV_BITMASK(y)) ? 1 : 0)
+
+/* ENC28J60 Receive Status Vector */
+#define RSV_RXLONGEVDROPEV 16
+#define RSV_CARRIEREV 18
+#define RSV_CRCERROR 20
+#define RSV_LENCHECKERR 21
+#define RSV_LENOUTOFRANGE 22
+#define RSV_RXOK 23
+#define RSV_RXMULTICAST 24
+#define RSV_RXBROADCAST 25
+#define RSV_DRIBBLENIBBLE 26
+#define RSV_RXCONTROLFRAME 27
+#define RSV_RXPAUSEFRAME 28
+#define RSV_RXUNKNOWNOPCODE 29
+#define RSV_RXTYPEVLAN 30
+
+#define RSV_SIZE 6
+#define RSV_BITMASK(x) (1 << ((x) - 16))
+#define RSV_GETBIT(x, y) (((x) & RSV_BITMASK(y)) ? 1 : 0)
+
+// SPI operation codes
+#define ENC28J60_READ_CTRL_REG 0x00
+#define ENC28J60_READ_BUF_MEM 0x3A
+#define ENC28J60_WRITE_CTRL_REG 0x40
+#define ENC28J60_WRITE_BUF_MEM 0x7A
+#define ENC28J60_BIT_FIELD_SET 0x80
+#define ENC28J60_BIT_FIELD_CLR 0xA0
+#define ENC28J60_SOFT_RESET 0xFF
+
+// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
+// buffer boundaries applied to internal 8K ram
+// the entire available packet buffer space is allocated
+//
+
+#define MAX_TX_PACKAGE_SIZE (1536)
+
+// start with recbuf at 0/
+#define RXSTART_INIT 0x0
+// receive buffer end
+#define RXSTOP_INIT (0x1FFF - MAX_TX_PACKAGE_SIZE*2) - 1
+// start TX buffer at 0x1FFF-0x0600, pace for one full ethernet frame (~1500 bytes)
+
+#define TXSTART_INIT (0x1FFF - MAX_TX_PACKAGE_SIZE*2)
+// stp TX buffer at end of mem
+#define TXSTOP_INIT 0x1FFF
+
+// max frame length which the conroller will accept:
+#define MAX_FRAMELEN 1518
+
+#define MAX_ADDR_LEN 6
+
+struct net_device
+{
+ /* inherit from ethernet device */
+ struct eth_device parent;
+
+ /* interface address info. */
+ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
+
+ rt_uint8_t emac_rev;
+ rt_uint8_t phy_rev;
+ rt_uint8_t phy_pn;
+ rt_uint32_t phy_id;
+
+ /* spi device */
+ struct rt_spi_device * spi_device;
+ struct rt_mutex lock;
+};
+
+/* export function */
+extern rt_err_t enc28j60_attach(const char * spi_device_name);
+extern void enc28j60_isr(void);
+
+#endif // EN28J60_H_INCLUDED
diff --git a/components/drivers/spi/spi_flash_at45dbxx.c b/components/drivers/spi/spi_flash_at45dbxx.c
new file mode 100644
index 0000000000..be474f7c65
--- /dev/null
+++ b/components/drivers/spi/spi_flash_at45dbxx.c
@@ -0,0 +1,437 @@
+/*
+ * File : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ */
+
+#include <stdint.h>
+#include "spi_flash_at45dbxx.h"
+
+#define FLASH_DEBUG
+#define DMA_BUFFER_SIZE 512
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /**< #ifdef FLASH_DEBUG */
+
+/* JEDEC Manufacturer��s ID */
+#define MF_ID (0x1F) /* atmel */
+#define DENSITY_CODE_011D (0x02) /* AT45DB011D Density Code : 00010 = 1-Mbit */
+#define DENSITY_CODE_021D (0x03) /* AT45DB021D Density Code : 00011 = 2-Mbit */
+#define DENSITY_CODE_041D (0x04) /* AT45DB041D Density Code : 00100 = 4-Mbit */
+#define DENSITY_CODE_081D (0x05) /* AT45DB081D Density Code : 00101 = 8-Mbit */
+#define DENSITY_CODE_161D (0x06) /* AT45DB161D Density Code : 00110 = 16-Mbit */
+#define DENSITY_CODE_321D (0x07) /* AT45DB321D Density Code : 00111 = 32-Mbit */
+#define DENSITY_CODE_642D (0x08) /* AT45DB642D Density Code : 01000 = 64-Mbit */
+
+struct JEDEC_ID
+{
+ uint8_t manufacturer_id; /* Manufacturer ID */
+ uint8_t density_code:5; /* Density Code */
+ uint8_t family_code:3; /* Family Code */
+ uint8_t version_code:5; /* Product Version Code */
+ uint8_t mlc_code:3; /* MLC Code */
+ uint8_t byte_count; /* Byte Count */
+};
+
+#define AT45DB_BUFFER_1_WRITE 0x84
+#define AT45DB_BUFFER_2_WRITE 0x87
+#define AT45DB_BUFFER_1_READ 0xD4
+#define AT45DB_BUFFER_2_READ 0xD6
+#define AT45DB_B1_TO_MM_PAGE_PROG_WITH_ERASE 0x83
+#define AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86
+#define AT45DB_MM_PAGE_TO_B1_XFER 0x53
+#define AT45DB_MM_PAGE_TO_B2_XFER 0x55
+#define AT45DB_PAGE_ERASE 0x81
+#define AT45DB_SECTOR_ERASE 0x7C
+#define AT45DB_READ_STATE_REGISTER 0xD7
+#define AT45DB_MM_PAGE_READ 0xD2
+#define AT45DB_MM_PAGE_PROG_THRU_BUFFER1 0x82
+#define AT45DB_CMD_JEDEC_ID 0x9F
+
+static struct spi_flash_at45dbxx spi_flash_at45dbxx;
+
+/*****************************************************************************/
+/*Status Register Format: */
+/* ------------------------------------------------------------------------- */
+/* | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | */
+/* |--------|--------|--------|--------|--------|--------|--------|--------| */
+/* |RDY/BUSY| COMP | device density | X | X | */
+/* ------------------------------------------------------------------------- */
+/* 0:busy | | AT45DB041:0111 | protect|page size */
+/* 1:ready | | AT45DB161:1011 | */
+/* --------------------------------------------------------------------------*/
+/*****************************************************************************/
+static uint8_t AT45DB_StatusRegisterRead(void)
+{
+ return rt_spi_sendrecv8(spi_flash_at45dbxx.rt_spi_device, AT45DB_READ_STATE_REGISTER);
+}
+
+static void wait_busy(void)
+{
+ uint16_t i = 0;
+ while (i++ < 10000)
+ {
+ if (AT45DB_StatusRegisterRead() & 0x80)
+ {
+ return;
+ }
+ }
+ FLASH_TRACE("\r\nSPI_FLASH timeout!!!\r\n");
+}
+
+/* RT-Thread Device Driver Interface */
+static rt_err_t AT45DB_flash_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+
+ return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = 512;
+ geometry->sector_count = 4096;
+ geometry->block_size = 4096; /* block erase: 4k */
+ }
+
+ return RT_EOK;
+}
+
+static rt_size_t AT45DB_flash_read_page_256(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ uint32_t index, nr;
+ uint8_t * read_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[8];
+ uint32_t i;
+
+ for(i=0; i<sizeof(send_buffer); i++)
+ {
+ send_buffer[i] = 0;
+ }
+
+ send_buffer[0] = AT45DB_MM_PAGE_READ;
+ send_buffer[1] = (uint8_t)(page >> 7);
+ send_buffer[2] = (uint8_t)(page << 1);
+
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 256);
+ read_buffer += 256;
+ page++;
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_read_page_512(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ uint32_t index, nr;
+ uint8_t * read_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[8];
+ uint32_t i;
+
+ for(i=0; i<sizeof(send_buffer); i++)
+ {
+ send_buffer[i] = 0;
+ }
+
+ send_buffer[0] = AT45DB_MM_PAGE_READ;
+ send_buffer[1] = (uint8_t)(page >> 6);
+ send_buffer[2] = (uint8_t)(page << 2);
+
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 512);
+ read_buffer += 512;
+ page++;
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_read_page_1024(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ uint32_t index, nr;
+ uint8_t * read_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[8];
+ uint32_t i;
+
+ for(i=0; i<sizeof(send_buffer); i++)
+ {
+ send_buffer[i] = 0;
+ }
+
+ send_buffer[0] = AT45DB_MM_PAGE_READ;
+ send_buffer[1] = (uint8_t)(page >> 5);
+ send_buffer[2] = (uint8_t)(page << 3);
+
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 1024);
+ read_buffer += 1024;
+ page++;
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_256(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_uint32_t index, nr;
+ const uint8_t * write_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+ send_buffer[1] = (uint8_t) (page >> 7);
+ send_buffer[2] = (uint8_t) (page << 1);
+ send_buffer[3] = 0;
+
+ rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 256);
+
+ write_buffer += 256;
+ page++;
+
+ wait_busy();
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_512(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_uint32_t index, nr;
+ const uint8_t * write_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+ send_buffer[1] = (uint8_t) (page >> 6);
+ send_buffer[2] = (uint8_t) (page << 2);
+ send_buffer[3] = 0;
+
+ rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 512);
+
+ write_buffer += 512;
+ page++;
+
+ wait_busy();
+ }
+
+ return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_1024(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_uint32_t index, nr;
+ const uint8_t * write_buffer = buffer;
+
+ nr = size;
+
+ for (index = 0; index < nr; index++)
+ {
+ uint32_t page = pos;
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+ send_buffer[1] = (uint8_t) (page >> 5);
+ send_buffer[2] = (uint8_t) (page << 3);
+ send_buffer[3] = 0;
+
+ rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 1024);
+
+ write_buffer += 1024;
+ page++;
+
+ wait_busy();
+ }
+
+ return size;
+}
+
+rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+ struct rt_spi_device * rt_spi_device;
+ struct JEDEC_ID * JEDEC_ID;
+
+ rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(rt_spi_device == RT_NULL)
+ {
+ FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+ spi_flash_at45dbxx.rt_spi_device = rt_spi_device;
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 and 3 */
+ cfg.max_hz = 66000000; /* Atmel RapidS Serial Interface: 66MHz Maximum Clock Frequency */
+ rt_spi_configure(spi_flash_at45dbxx.rt_spi_device, &cfg);
+ }
+
+ /* read JEDEC ID */
+ {
+ uint8_t cmd;
+ uint8_t id_recv[6];
+ JEDEC_ID = (struct JEDEC_ID *)id_recv;
+
+ cmd = AT45DB_CMD_JEDEC_ID;
+ rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, &cmd, 1, id_recv, 6);
+
+ /**< 1FH = Atmel */
+ /**< 001 = Atmel DataFlash */
+ if(JEDEC_ID->manufacturer_id != 0x1F || JEDEC_ID->family_code != 0x01)
+ {
+ FLASH_TRACE("Manufacturer��s ID or Memory Type error!\r\n");
+ FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+ return -RT_ENOSYS;
+ }
+
+ if(JEDEC_ID->density_code == DENSITY_CODE_011D)
+ {
+ /**< AT45DB011D Density Code : 00010 = 1-Mbit */
+ FLASH_TRACE("AT45DB011D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512; /* 1-Mbit / 8 / 256 = 512 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_021D)
+ {
+ /**< AT45DB021D Density Code : 00011 = 2-Mbit */
+ FLASH_TRACE("AT45DB021D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512*2; /* 2-Mbit / 8 / 256 = 1024 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_041D)
+ {
+ /**< AT45DB041D Density Code : 00100 = 4-Mbit */
+ FLASH_TRACE("AT45DB041D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512*4; /* 4-Mbit / 8 / 256 = 2048 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_081D)
+ {
+ /**< AT45DB081D Density Code : 00101 = 8-Mbit */
+ FLASH_TRACE("AT45DB081D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 512*8; /* 8-Mbit / 8 / 256 = 4096 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_161D)
+ {
+ /**< AT45DB161D Density Code : 00110 = 16-Mbit */
+ FLASH_TRACE("AT45DB161D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 256*16; /* 16-Mbit / 8 / 512 = 4096 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*4; /* Block Erase (4-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_321D)
+ {
+ /**< AT45DB321D Density Code : 00111 = 32-Mbit */
+ FLASH_TRACE("AT45DB321D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */
+ spi_flash_at45dbxx.geometry.sector_count = 256*32; /* 32-Mbit / 8 / 512 = 8192 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*4; /* Block Erase (4-Kbytes) */
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_642D)
+ {
+ /**< AT45DB642D Density Code : 01000 = 64-Mbit */
+ FLASH_TRACE("AT45DB642D detection\r\n");
+ spi_flash_at45dbxx.geometry.bytes_per_sector = 1024; /* Page Erase (1 Kbyte) */
+ spi_flash_at45dbxx.geometry.sector_count = 128*64; /* 64-Mbit / 8 / 1024 = 8192 */
+ spi_flash_at45dbxx.geometry.block_size = 1024*8; /* Block Erase (8 Kbytes) */
+ }
+ else
+ {
+ FLASH_TRACE("Memory Capacity error!\r\n");
+ return -RT_ENOSYS;
+ }
+ }
+
+ /* register device */
+ spi_flash_at45dbxx.flash_device.type = RT_Device_Class_Block;
+ spi_flash_at45dbxx.flash_device.init = AT45DB_flash_init;
+ spi_flash_at45dbxx.flash_device.open = AT45DB_flash_open;
+ spi_flash_at45dbxx.flash_device.close = AT45DB_flash_close;
+ spi_flash_at45dbxx.flash_device.control = AT45DB_flash_control;
+
+ if(JEDEC_ID->density_code == DENSITY_CODE_642D)
+ {
+ spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_1024;
+ spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_1024;
+ }
+ else if(JEDEC_ID->density_code == DENSITY_CODE_161D
+ || JEDEC_ID->density_code == DENSITY_CODE_321D )
+ {
+ spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_512;
+ spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_512;
+ }
+ else
+ {
+ spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_256;
+ spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_256;
+ }
+
+ /* no private */
+ spi_flash_at45dbxx.flash_device.user_data = RT_NULL;
+
+ rt_device_register(&spi_flash_at45dbxx.flash_device, flash_device_name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/spi/spi_flash_at45dbxx.h b/components/drivers/spi/spi_flash_at45dbxx.h
new file mode 100644
index 0000000000..9b72cf0a0f
--- /dev/null
+++ b/components/drivers/spi/spi_flash_at45dbxx.h
@@ -0,0 +1,17 @@
+#ifndef SPI_FLASH_AT45DBXX_H_INCLUDED
+#define SPI_FLASH_AT45DBXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_at45dbxx
+{
+ struct rt_device flash_device;
+ struct rt_device_blk_geometry geometry;
+ struct rt_spi_device * rt_spi_device;
+};
+
+extern rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name);
+
+
+#endif // SPI_FLASH_AT45DBXX_H_INCLUDED
diff --git a/components/drivers/spi/spi_flash_sst25vfxx.c b/components/drivers/spi/spi_flash_sst25vfxx.c
new file mode 100644
index 0000000000..f0e28b5584
--- /dev/null
+++ b/components/drivers/spi/spi_flash_sst25vfxx.c
@@ -0,0 +1,346 @@
+/*
+ * File : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ */
+
+#include <stdint.h>
+#include "spi_flash_sst25vfxx.h"
+
+#define FLASH_DEBUG
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /* #ifdef FLASH_DEBUG */
+
+/* JEDEC Manufacturer��s ID */
+#define MF_ID (0xBF)
+/* JEDEC Device ID : Memory Type */
+#define MT_ID (0x25)
+/* JEDEC Device ID: Memory Capacity */
+#define MC_ID_SST25VF020B (0x8C) /* 2Mbit */
+#define MC_ID_SST25VF040B (0x8D) /* 4Mbit */
+#define MC_ID_SST25VF080B (0x8E) /* 8Mbit */
+#define MC_ID_SST25VF016B (0x41) /* 16Mbit */
+#define MC_ID_SST25VF032B (0x4A) /* 32Mbit */
+#define MC_ID_SST25VF064C (0x4B) /* 64Mbit */
+
+/* command list */
+#define CMD_RDSR (0x05)
+#define CMD_WRSR (0x01)
+#define CMD_EWSR (0x50)
+#define CMD_WRDI (0x04)
+#define CMD_WREN (0x06)
+#define CMD_READ (0x03)
+#define CMD_FAST_READ (0x0B)
+#define CMD_BP (0x02)
+#define CMD_AAIP (0xAD)
+#define CMD_ERASE_4K (0x20)
+#define CMD_ERASE_32K (0x52)
+#define CMD_ERASE_64K (0xD8)
+#define CMD_ERASE_full (0xC7)
+#define CMD_JEDEC_ID (0x9F)
+#define CMD_EBSY (0x70)
+#define CMD_DBSY (0x80)
+
+#define DUMMY (0xFF)
+
+static struct spi_flash_sst25vfxx spi_flash_sst25vfxx;
+
+static uint8_t sst25vfxx_read_status(struct spi_flash_sst25vfxx * spi_flash)
+{
+ return rt_spi_sendrecv8(spi_flash->rt_spi_device, CMD_RDSR);
+}
+
+static void sst25vfxx_wait_busy(struct spi_flash_sst25vfxx * spi_flash)
+{
+ while( sst25vfxx_read_status(spi_flash) & (0x01));
+}
+
+/** \brief write N page on [page]
+ *
+ * \param page uint32_t unit : byte (4096 * N,1 page = 4096byte)
+ * \param buffer const uint8_t*
+ * \param size uint32_t unit : byte ( 4096*N )
+ * \return uint32_t
+ *
+ */
+static uint32_t sst25vfxx_page_write(struct spi_flash_sst25vfxx * spi_flash, uint32_t page, const uint8_t * buffer, uint32_t size)
+{
+ uint32_t index;
+ uint32_t need_wirte = size;
+ uint8_t send_buffer[6];
+
+ page &= ~0xFFF; // page size = 4096byte
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_ERASE_4K;
+ send_buffer[1] = (page >> 16);
+ send_buffer[2] = (page >> 8);
+ send_buffer[3] = (page);
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 4);
+
+ sst25vfxx_wait_busy(spi_flash); // wait erase done.
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_AAIP;
+ send_buffer[1] = (uint8_t)(page >> 16);
+ send_buffer[2] = (uint8_t)(page >> 8);
+ send_buffer[3] = (uint8_t)(page);
+ send_buffer[4] = *buffer++;
+ send_buffer[5] = *buffer++;
+ need_wirte -= 2;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 6);
+
+ sst25vfxx_wait_busy(spi_flash);
+
+ for(index=0; index < need_wirte/2; index++)
+ {
+ send_buffer[0] = CMD_AAIP;
+ send_buffer[1] = *buffer++;
+ send_buffer[2] = *buffer++;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 3);
+ sst25vfxx_wait_busy(spi_flash);
+ }
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ return size;
+}
+
+/* RT-Thread device interface */
+static rt_err_t sst25vfxx_flash_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ rt_err_t result;
+ uint8_t send_buffer[2];
+ struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+ /* lock spi flash */
+ result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+ if(result != RT_EOK)
+ {
+ return result;
+ }
+
+ send_buffer[0] = CMD_DBSY;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_EWSR;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_WRSR;
+ send_buffer[1] = 0;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 2);
+
+ /* release lock */
+ rt_mutex_release(&(spi_flash->lock));
+
+ return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ struct spi_flash_sst25vfxx * spi_flash;
+
+ spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+ RT_ASSERT(dev != RT_NULL);
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = spi_flash->geometry.bytes_per_sector;
+ geometry->sector_count = spi_flash->geometry.sector_count;
+ geometry->block_size = spi_flash->geometry.block_size;
+ }
+
+ return RT_EOK;
+}
+
+static rt_size_t sst25vfxx_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_err_t result;
+ uint8_t send_buffer[4];
+ struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+ uint32_t offset = pos * spi_flash->geometry.bytes_per_sector;
+
+ /* lock spi flash */
+ result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+ if(result != RT_EOK)
+ {
+ return 0;
+ }
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_READ;
+ send_buffer[1] = (uint8_t)(offset>>16);
+ send_buffer[2] = (uint8_t)(offset>>8);
+ send_buffer[3] = (uint8_t)(offset);
+ rt_spi_send_then_recv(spi_flash->rt_spi_device, send_buffer, 4, buffer, size * spi_flash->geometry.bytes_per_sector);
+
+ /* release lock */
+ rt_mutex_release(&(spi_flash->lock));
+
+ return size;
+}
+
+static rt_size_t sst25vfxx_flash_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ uint32_t i;
+ rt_err_t result;
+ const uint8_t * write_buffer = buffer;
+ struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+ /* lock spi flash */
+ result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+ if(result != RT_EOK)
+ {
+ return 0;
+ }
+
+ for(i=0; i<size; i++)
+ {
+ sst25vfxx_page_write(spi_flash,
+ (pos + i) * spi_flash->geometry.bytes_per_sector,
+ write_buffer,
+ spi_flash->geometry.bytes_per_sector);
+ write_buffer += spi_flash->geometry.bytes_per_sector;
+ }
+
+ /* release lock */
+ rt_mutex_release(&(spi_flash->lock));
+
+ return size;
+}
+
+rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+ struct rt_spi_device * rt_spi_device;
+ struct spi_flash_sst25vfxx * spi_flash = &spi_flash_sst25vfxx;
+
+ rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(rt_spi_device == RT_NULL)
+ {
+ FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+ spi_flash->rt_spi_device = rt_spi_device;
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+ cfg.max_hz = 50000000; /* 50M */
+ rt_spi_configure(spi_flash->rt_spi_device, &cfg);
+ }
+
+ /* init flash */
+ {
+ rt_uint8_t cmd;
+ rt_uint8_t id_recv[3];
+
+ cmd = CMD_WRDI;
+ rt_spi_send(spi_flash->rt_spi_device, &cmd, 1);
+
+ /* read flash id */
+ cmd = CMD_JEDEC_ID;
+ rt_spi_send_then_recv(spi_flash->rt_spi_device, &cmd, 1, id_recv, 3);
+
+ if(id_recv[0] != MF_ID || id_recv[1] != MT_ID)
+ {
+ FLASH_TRACE("Manufacturer��s ID or Memory Type error!\r\n");
+ FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+ return -RT_ENOSYS;
+ }
+
+ spi_flash->geometry.bytes_per_sector = 4096;
+ spi_flash->geometry.block_size = 4096; /* block erase: 4k */
+
+ if(id_recv[2] == MC_ID_SST25VF020B)
+ {
+ FLASH_TRACE("SST25VF020B detection\r\n");
+ spi_flash->geometry.sector_count = 64;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF040B)
+ {
+ FLASH_TRACE("SST25VF040B detection\r\n");
+ spi_flash->geometry.sector_count = 128;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF080B)
+ {
+ FLASH_TRACE("SST25VF080B detection\r\n");
+ spi_flash->geometry.sector_count = 256;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF016B)
+ {
+ FLASH_TRACE("SST25VF016B detection\r\n");
+ spi_flash->geometry.sector_count = 512;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF032B)
+ {
+ FLASH_TRACE("SST25VF032B detection\r\n");
+ spi_flash->geometry.sector_count = 1024;
+ }
+ else if(id_recv[2] == MC_ID_SST25VF064C)
+ {
+ FLASH_TRACE("SST25VF064C detection\r\n");
+ spi_flash->geometry.sector_count = 2048;
+ }
+ else
+ {
+ FLASH_TRACE("Memory Capacity error!\r\n");
+ return -RT_ENOSYS;
+ }
+ }
+
+ /* initialize mutex lock */
+ rt_mutex_init(&spi_flash->lock, flash_device_name, RT_IPC_FLAG_PRIO);
+
+ /* register device */
+ spi_flash->flash_device.type = RT_Device_Class_Block;
+ spi_flash->flash_device.init = sst25vfxx_flash_init;
+ spi_flash->flash_device.open = sst25vfxx_flash_open;
+ spi_flash->flash_device.close = sst25vfxx_flash_close;
+ spi_flash->flash_device.read = sst25vfxx_flash_read;
+ spi_flash->flash_device.write = sst25vfxx_flash_write;
+ spi_flash->flash_device.control = sst25vfxx_flash_control;
+ /* no private */
+ spi_flash->flash_device.user_data = RT_NULL;
+
+ rt_device_register(&spi_flash->flash_device, flash_device_name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/spi/spi_flash_sst25vfxx.h b/components/drivers/spi/spi_flash_sst25vfxx.h
new file mode 100644
index 0000000000..b4575c2b68
--- /dev/null
+++ b/components/drivers/spi/spi_flash_sst25vfxx.h
@@ -0,0 +1,32 @@
+/*
+ * File : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ */
+
+#ifndef SPI_FLASH_SST25VFXX_H_INCLUDED
+#define SPI_FLASH_SST25VFXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_sst25vfxx
+{
+ struct rt_device flash_device;
+ struct rt_device_blk_geometry geometry;
+ struct rt_spi_device * rt_spi_device;
+ struct rt_mutex lock;
+};
+
+extern rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name);
+
+
+#endif // SPI_FLASH_SST25VFXX_H_INCLUDED
diff --git a/components/drivers/spi/spi_flash_w25qxx.c b/components/drivers/spi/spi_flash_w25qxx.c
new file mode 100644
index 0000000000..bdcdbd83c1
--- /dev/null
+++ b/components/drivers/spi/spi_flash_w25qxx.c
@@ -0,0 +1,371 @@
+/*
+ * File : spi_flash_w25qxx.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ * 2012-05-06 aozima can page write.
+ * 2012-08-23 aozima add flash lock.
+ * 2012-08-24 aozima fixed write status register BUG.
+ */
+
+#include <stdint.h>
+#include "spi_flash_w25qxx.h"
+
+#define FLASH_DEBUG
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /* #ifdef FLASH_DEBUG */
+
+#define PAGE_SIZE 4096
+
+/* JEDEC Manufacturer��s ID */
+#define MF_ID (0xEF)
+/* JEDEC Device ID: Memory type and Capacity */
+#define MTC_W25Q16_BV_CL_CV (0x4015) /* W25Q16BV W25Q16CL W25Q16CV */
+#define MTC_W25Q16_DW (0x6015) /* W25Q16DW */
+#define MTC_W25Q32_BV (0x4016) /* W25Q32BV */
+#define MTC_W25Q32_DW (0x6016) /* W25Q32DW */
+#define MTC_W25Q64_BV_CV (0x4017) /* W25Q64BV W25Q64CV */
+#define MTC_W25Q64_DW (0x4017) /* W25Q64DW */
+#define MTC_W25Q128_BV (0x4018) /* W25Q128BV */
+#define MTC_W25Q256_FV (TBD) /* W25Q256FV */
+
+/* command list */
+#define CMD_WRSR (0x01) /* Write Status Register */
+#define CMD_PP (0x02) /* Page Program */
+#define CMD_READ (0x03) /* Read Data */
+#define CMD_WRDI (0x04) /* Write Disable */
+#define CMD_RDSR1 (0x05) /* Read Status Register-1 */
+#define CMD_WREN (0x06) /* Write Enable */
+#define CMD_FAST_READ (0x0B) /* Fast Read */
+#define CMD_ERASE_4K (0x20) /* Sector Erase:4K */
+#define CMD_RDSR2 (0x35) /* Read Status Register-2 */
+#define CMD_ERASE_32K (0x52) /* 32KB Block Erase */
+#define CMD_JEDEC_ID (0x9F) /* Read JEDEC ID */
+#define CMD_ERASE_full (0xC7) /* Chip Erase */
+#define CMD_ERASE_64K (0xD8) /* 64KB Block Erase */
+
+#define DUMMY (0xFF)
+
+static struct spi_flash_device spi_flash_device;
+
+static void flash_lock(struct spi_flash_device * flash_device)
+{
+ rt_mutex_take(&flash_device->lock, RT_WAITING_FOREVER);
+}
+
+static void flash_unlock(struct spi_flash_device * flash_device)
+{
+ rt_mutex_release(&flash_device->lock);
+}
+
+static uint8_t w25qxx_read_status(void)
+{
+ return rt_spi_sendrecv8(spi_flash_device.rt_spi_device, CMD_RDSR1);
+}
+
+static void w25qxx_wait_busy(void)
+{
+ while( w25qxx_read_status() & (0x01));
+}
+
+/** \brief read [size] byte from [offset] to [buffer]
+ *
+ * \param offset uint32_t unit : byte
+ * \param buffer uint8_t*
+ * \param size uint32_t unit : byte
+ * \return uint32_t byte for read
+ *
+ */
+static uint32_t w25qxx_read(uint32_t offset, uint8_t * buffer, uint32_t size)
+{
+ uint8_t send_buffer[4];
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_READ;
+ send_buffer[1] = (uint8_t)(offset>>16);
+ send_buffer[2] = (uint8_t)(offset>>8);
+ send_buffer[3] = (uint8_t)(offset);
+
+ rt_spi_send_then_recv(spi_flash_device.rt_spi_device,
+ send_buffer, 4,
+ buffer, size);
+
+ return size;
+}
+
+/** \brief write N page on [page]
+ *
+ * \param page_addr uint32_t unit : byte (4096 * N,1 page = 4096byte)
+ * \param buffer const uint8_t*
+ * \return uint32_t
+ *
+ */
+uint32_t w25qxx_page_write(uint32_t page_addr, const uint8_t* buffer)
+{
+ uint32_t index;
+ uint8_t send_buffer[4];
+
+ RT_ASSERT((page_addr&0xFF) == 0); /* page addr must align to 256byte. */
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_ERASE_4K;
+ send_buffer[1] = (page_addr >> 16);
+ send_buffer[2] = (page_addr >> 8);
+ send_buffer[3] = (page_addr);
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 4);
+
+ w25qxx_wait_busy(); // wait erase done.
+
+ for(index=0; index < (PAGE_SIZE / 256); index++)
+ {
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_PP;
+ send_buffer[1] = (uint8_t)(page_addr >> 16);
+ send_buffer[2] = (uint8_t)(page_addr >> 8);
+ send_buffer[3] = (uint8_t)(page_addr);
+
+ rt_spi_send_then_send(spi_flash_device.rt_spi_device,
+ send_buffer,
+ 4,
+ buffer,
+ 256);
+
+ buffer += 256;
+ page_addr += 256;
+ w25qxx_wait_busy();
+ }
+
+ send_buffer[0] = CMD_WRDI;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ return PAGE_SIZE;
+}
+
+/* RT-Thread device interface */
+static rt_err_t w25qxx_flash_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ uint8_t send_buffer[3];
+
+ flash_lock((struct spi_flash_device *)dev);
+
+ send_buffer[0] = CMD_WREN;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+ send_buffer[0] = CMD_WRSR;
+ send_buffer[1] = 0;
+ send_buffer[2] = 0;
+ rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 3);
+
+ w25qxx_wait_busy();
+
+ flash_unlock((struct spi_flash_device *)dev);
+
+ return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ RT_ASSERT(dev != RT_NULL);
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector;
+ geometry->sector_count = spi_flash_device.geometry.sector_count;
+ geometry->block_size = spi_flash_device.geometry.block_size;
+ }
+
+ return RT_EOK;
+}
+
+static rt_size_t w25qxx_flash_read(rt_device_t dev,
+ rt_off_t pos,
+ void* buffer,
+ rt_size_t size)
+{
+ flash_lock((struct spi_flash_device *)dev);
+
+ w25qxx_read(pos*spi_flash_device.geometry.bytes_per_sector,
+ buffer,
+ size*spi_flash_device.geometry.bytes_per_sector);
+
+ flash_unlock((struct spi_flash_device *)dev);
+
+ return size;
+}
+
+static rt_size_t w25qxx_flash_write(rt_device_t dev,
+ rt_off_t pos,
+ const void* buffer,
+ rt_size_t size)
+{
+ rt_size_t i = 0;
+ rt_size_t block = size;
+ const uint8_t * ptr = buffer;
+
+ flash_lock((struct spi_flash_device *)dev);
+
+ while(block--)
+ {
+ w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector,
+ ptr);
+ ptr += PAGE_SIZE;
+ i++;
+ }
+
+ flash_unlock((struct spi_flash_device *)dev);
+
+ return size;
+}
+
+rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+ struct rt_spi_device * rt_spi_device;
+
+ /* initialize mutex */
+ if (rt_mutex_init(&spi_flash_device.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK)
+ {
+ rt_kprintf("init sd lock mutex failed\n");
+ return -RT_ENOSYS;
+ }
+
+ rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+ if(rt_spi_device == RT_NULL)
+ {
+ FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+ spi_flash_device.rt_spi_device = rt_spi_device;
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+ cfg.max_hz = 50 * 1000 * 1000; /* 50M */
+ rt_spi_configure(spi_flash_device.rt_spi_device, &cfg);
+ }
+
+ /* init flash */
+ {
+ rt_uint8_t cmd;
+ rt_uint8_t id_recv[3];
+ uint16_t memory_type_capacity;
+
+ flash_lock(&spi_flash_device);
+
+ cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
+ rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
+
+ cmd = CMD_WRDI;
+ rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
+
+ /* read flash id */
+ cmd = CMD_JEDEC_ID;
+ rt_spi_send_then_recv(spi_flash_device.rt_spi_device, &cmd, 1, id_recv, 3);
+
+ flash_unlock(&spi_flash_device);
+
+ if(id_recv[0] != MF_ID)
+ {
+ FLASH_TRACE("Manufacturers ID error!\r\n");
+ FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+ return -RT_ENOSYS;
+ }
+
+ spi_flash_device.geometry.bytes_per_sector = 4096;
+ spi_flash_device.geometry.block_size = 4096; /* block erase: 4k */
+
+ /* get memory type and capacity */
+ memory_type_capacity = id_recv[1];
+ memory_type_capacity = (memory_type_capacity << 8) | id_recv[2];
+
+ if(memory_type_capacity == MTC_W25Q128_BV)
+ {
+ FLASH_TRACE("W25Q128BV detection\r\n");
+ spi_flash_device.geometry.sector_count = 4096;
+ }
+ else if(memory_type_capacity == MTC_W25Q64_BV_CV)
+ {
+ FLASH_TRACE("W25Q64BV or W25Q64CV detection\r\n");
+ spi_flash_device.geometry.sector_count = 2048;
+ }
+ else if(memory_type_capacity == MTC_W25Q64_DW)
+ {
+ FLASH_TRACE("W25Q64DW detection\r\n");
+ spi_flash_device.geometry.sector_count = 2048;
+ }
+ else if(memory_type_capacity == MTC_W25Q32_BV)
+ {
+ FLASH_TRACE("W25Q32BV detection\r\n");
+ spi_flash_device.geometry.sector_count = 1024;
+ }
+ else if(memory_type_capacity == MTC_W25Q32_DW)
+ {
+ FLASH_TRACE("W25Q32DW detection\r\n");
+ spi_flash_device.geometry.sector_count = 1024;
+ }
+ else if(memory_type_capacity == MTC_W25Q16_BV_CL_CV)
+ {
+ FLASH_TRACE("W25Q16BV or W25Q16CL or W25Q16CV detection\r\n");
+ spi_flash_device.geometry.sector_count = 512;
+ }
+ else if(memory_type_capacity == MTC_W25Q16_DW)
+ {
+ FLASH_TRACE("W25Q16DW detection\r\n");
+ spi_flash_device.geometry.sector_count = 512;
+ }
+ else
+ {
+ FLASH_TRACE("Memory Capacity error!\r\n");
+ return -RT_ENOSYS;
+ }
+ }
+
+ /* register device */
+ spi_flash_device.flash_device.type = RT_Device_Class_Block;
+ spi_flash_device.flash_device.init = w25qxx_flash_init;
+ spi_flash_device.flash_device.open = w25qxx_flash_open;
+ spi_flash_device.flash_device.close = w25qxx_flash_close;
+ spi_flash_device.flash_device.read = w25qxx_flash_read;
+ spi_flash_device.flash_device.write = w25qxx_flash_write;
+ spi_flash_device.flash_device.control = w25qxx_flash_control;
+ /* no private */
+ spi_flash_device.flash_device.user_data = RT_NULL;
+
+ rt_device_register(&spi_flash_device.flash_device, flash_device_name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+ return RT_EOK;
+}
diff --git a/components/drivers/spi/spi_flash_w25qxx.h b/components/drivers/spi/spi_flash_w25qxx.h
new file mode 100644
index 0000000000..ebab35da33
--- /dev/null
+++ b/components/drivers/spi/spi_flash_w25qxx.h
@@ -0,0 +1,34 @@
+/*
+ * File : spi_flash_w25qxx.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-16 aozima the first version
+ * 2012-08-23 aozima add flash lock.
+ */
+
+#ifndef SPI_FLASH_W25QXX_H_INCLUDED
+#define SPI_FLASH_W25QXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_device
+{
+ struct rt_device flash_device;
+ struct rt_device_blk_geometry geometry;
+ struct rt_spi_device * rt_spi_device;
+ struct rt_mutex lock;
+};
+
+extern rt_err_t w25qxx_init(const char * flash_device_name,
+ const char * spi_device_name);
+
+
+#endif // SPI_FLASH_W25QXX_H_INCLUDED
diff --git a/components/drivers/spi/spi_wifi_rw009.c b/components/drivers/spi/spi_wifi_rw009.c
new file mode 100644
index 0000000000..f45d493717
--- /dev/null
+++ b/components/drivers/spi/spi_wifi_rw009.c
@@ -0,0 +1,590 @@
+/*
+ * File : spi_wifi_rw009.c
+ * This file is part of RT-Thread RTOS
+ * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2014-07-31 aozima the first version
+ */
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+#include <netif/ethernetif.h>
+#include <netif/etharp.h>
+#include <lwip/icmp.h>
+#include "lwipopts.h"
+
+#include "spi_wifi_rw009.h"
+
+#define SSID_NAME "AP_SSID"
+#define SSID_PASSWORD "AP_passwd"
+
+//#define WIFI_DEBUG_ON
+// #define ETH_RX_DUMP
+// #define ETH_TX_DUMP
+
+#ifdef WIFI_DEBUG_ON
+#define WIFI_DEBUG rt_kprintf("[WIFI] ");rt_kprintf
+#else
+#define WIFI_DEBUG(...)
+#endif /* #ifdef WIFI_DEBUG_ON */
+
+#define MAX_BUFFER_SIZE (sizeof(struct response) + MAX_DATA_LEN)
+#define MAX_ADDR_LEN 6
+struct spi_wifi_eth
+{
+ /* inherit from ethernet device */
+ struct eth_device parent;
+
+ struct rt_spi_device *rt_spi_device;
+
+ /* interface address info. */
+ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
+ rt_uint8_t active;
+
+ struct rt_mempool spi_tx_mp;
+ struct rt_mempool spi_rx_mp;
+
+ struct rt_mailbox spi_tx_mb;
+ struct rt_mailbox eth_rx_mb;
+
+ int spi_tx_mb_pool[SPI_TX_POOL_SIZE];
+ int eth_rx_mb_pool[SPI_TX_POOL_SIZE];
+
+ int spi_wifi_cmd_mb_pool[3];
+ struct rt_mailbox spi_wifi_cmd_mb;
+
+ ALIGN(4)
+ rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
+ ALIGN(4)
+ rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
+
+ ALIGN(4)
+ uint8_t spi_hw_rx_buffer[MAX_BUFFER_SIZE];
+};
+static struct spi_wifi_eth spi_wifi_device;
+static struct rt_event spi_wifi_data_event;
+
+static void resp_handler(struct spi_wifi_eth *wifi_device, struct spi_wifi_resp *resp)
+{
+ struct spi_wifi_resp *resp_return;
+
+ switch (resp->cmd)
+ {
+ case SPI_WIFI_CMD_INIT:
+ WIFI_DEBUG("resp_handler SPI_WIFI_CMD_INIT\n");
+ resp_return = (struct spi_wifi_resp *)rt_malloc(sizeof(struct spi_wifi_resp)); //TODO:
+ memcpy(resp_return, resp, 10);
+ rt_mb_send(&wifi_device->spi_wifi_cmd_mb, (rt_uint32_t)resp_return);
+ break;
+
+ case SPI_WIFI_CMD_SCAN:
+ WIFI_DEBUG("resp_handler SPI_WIFI_CMD_SCAN\n");
+ break;
+
+ case SPI_WIFI_CMD_JOIN:
+ WIFI_DEBUG("resp_handler SPI_WIFI_CMD_JOIN\n");
+ wifi_device->active = 1;
+ eth_device_linkchange(&wifi_device->parent, RT_TRUE);
+ break;
+
+ default:
+ WIFI_DEBUG("resp_handler %d\n", resp->cmd);
+ break;
+ }
+
+}
+
+static rt_err_t spi_wifi_transfer(struct spi_wifi_eth *dev)
+{
+ struct pbuf *p = RT_NULL;
+ struct cmd_request cmd;
+ struct response resp;
+
+ rt_err_t result;
+ const struct spi_data_packet *data_packet = RT_NULL;
+
+ struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+ struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
+
+ spi_wifi_int_cmd(0);
+ while (spi_wifi_is_busy());
+ WIFI_DEBUG("sequence start!\n");
+
+ memset(&cmd, 0, sizeof(struct cmd_request));
+ cmd.magic1 = CMD_MAGIC1;
+ cmd.magic2 = CMD_MAGIC2;
+
+ cmd.flag |= CMD_FLAG_MRDY;
+
+ result = rt_mb_recv(&wifi_device->spi_tx_mb,
+ (rt_uint32_t *)&data_packet,
+ 0);
+ if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
+ {
+ cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
+ //WIFI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len);
+ }
+
+ rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
+ while (spi_wifi_is_busy());
+
+ {
+ struct rt_spi_message message;
+ uint32_t max_data_len = 0;
+
+ /* setup message */
+ message.send_buf = RT_NULL;
+ message.recv_buf = &resp;
+ message.length = sizeof(resp);
+ message.cs_take = 1;
+ message.cs_release = 0;
+
+ rt_spi_take_bus(rt_spi_device);
+
+ /* transfer message */
+ rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+ if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
+ {
+ WIFI_DEBUG("bad resp magic, abort!\n");
+ goto _bad_resp_magic;
+ }
+
+ if (resp.flag & RESP_FLAG_SRDY)
+ {
+ WIFI_DEBUG("RESP_FLAG_SRDY\n");
+ max_data_len = cmd.M2S_len;
+ }
+
+ if (resp.S2M_len)
+ {
+ WIFI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len);
+ if (resp.S2M_len > sizeof(struct spi_data_packet))
+ {
+ WIFI_DEBUG("resp.S2M_len > sizeof(struct spi_data_packet), drop!\n");
+ resp.S2M_len = 0;//drop
+ }
+
+ if (resp.S2M_len > max_data_len)
+ max_data_len = resp.S2M_len;
+ }
+
+ if (max_data_len == 0)
+ {
+ WIFI_DEBUG("no rx or tx data!\n");
+ }
+
+ //WIFI_DEBUG("max_data_len = %d\n", max_data_len);
+
+_bad_resp_magic:
+ /* setup message */
+ message.send_buf = data_packet;//&tx_buffer;
+ message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer;
+ message.length = max_data_len;
+ message.cs_take = 0;
+ message.cs_release = 1;
+
+ /* transfer message */
+ rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+ rt_spi_release_bus(rt_spi_device);
+
+ if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY))
+ {
+ rt_mp_free((void *)data_packet);
+ }
+
+ if ((resp.S2M_len) && (resp.S2M_len <= MAX_DATA_LEN))
+ {
+ data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
+ if (data_packet->data_type == data_type_eth_data)
+ {
+
+ if (wifi_device->active)
+ {
+ p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
+ pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
+
+ rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
+ eth_device_ready((struct eth_device *)dev);
+ }
+ else
+ {
+ WIFI_DEBUG("!active, RX drop.\n");
+ }
+ }
+ else if (data_packet->data_type == data_type_resp)
+ {
+ WIFI_DEBUG("data_type_resp\n");
+ resp_handler(dev, (struct spi_wifi_resp *)data_packet->buffer);
+ }
+ else
+ {
+ WIFI_DEBUG("data_type: %d, %dbyte\n",
+ data_packet->data_type,
+ data_packet->data_len);
+ }
+ }
+ }
+ spi_wifi_int_cmd(1);
+
+ WIFI_DEBUG("sequence finish!\n\n");
+
+ if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
+static void packet_dump(const char *msg, const struct pbuf *p)
+{
+ rt_uint32_t i;
+ rt_uint8_t *ptr = p->payload;
+
+ rt_kprintf("%s %d byte\n", msg, p->tot_len);
+
+ for (i = 0; i < p->tot_len; i++)
+ {
+ if ((i % 8) == 0)
+ {
+ rt_kprintf(" ");
+ }
+ if ((i % 16) == 0)
+ {
+ rt_kprintf("\r\n");
+ }
+ rt_kprintf("%02x ", *ptr);
+ ptr++;
+ }
+ rt_kprintf("\n\n");
+}
+#endif /* dump */
+
+/* initialize the interface */
+static rt_err_t spi_wifi_eth_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t spi_wifi_eth_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+static rt_err_t spi_wifi_eth_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_size_t spi_wifi_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+static rt_size_t spi_wifi_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+
+static rt_err_t spi_wifi_eth_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+ struct spi_data_packet *data_packet;
+ struct spi_wifi_cmd *wifi_cmd;
+ struct spi_wifi_resp *resp;
+
+ switch (cmd)
+ {
+ case NIOCTL_GADDR:
+ memcpy(args, wifi_device->dev_addr, 6);
+ break;
+
+ case SPI_WIFI_CMD_INIT:
+ /* get mac address */
+ if (args)
+ {
+ rt_err_t result;
+
+ data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+ // TODO: check result.
+
+ wifi_cmd = (struct spi_wifi_cmd *)data_packet->buffer;
+ wifi_cmd->cmd = SPI_WIFI_CMD_INIT;
+
+ data_packet->data_type = data_type_cmd;
+ data_packet->data_len = member_offset(struct spi_wifi_cmd, buffer) + 0;
+
+ rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+ rt_event_send(&spi_wifi_data_event, 1);
+
+ result = rt_mb_recv(&wifi_device->spi_wifi_cmd_mb,
+ (rt_uint32_t *)&resp,
+ RT_WAITING_FOREVER);
+
+ if ((result == RT_EOK) && (resp != RT_NULL))
+ {
+ WIFI_DEBUG("resp cmd: %d\n", resp->cmd);
+
+ rt_memcpy(args, resp->buffer, 6);
+ }
+ }
+ else return -RT_ERROR;
+ break;
+
+
+ case SPI_WIFI_CMD_SCAN:
+
+ case SPI_WIFI_CMD_JOIN:
+ if (args)
+ {
+ struct cmd_join *cmd_join;
+
+ data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+
+ wifi_cmd = (struct spi_wifi_cmd *)data_packet->buffer;
+ wifi_cmd->cmd = SPI_WIFI_CMD_JOIN;
+ cmd_join = (struct cmd_join *)wifi_cmd->buffer;
+
+#define WPA_SECURITY 0x00200000
+#define WPA2_SECURITY 0x00400000
+
+#define TKIP_ENABLED 0x0002
+#define AES_ENABLED 0x0004
+
+
+ strncpy(cmd_join->ssid, SSID_NAME, SSID_NAME_LENGTH_MAX);
+ strncpy(cmd_join->passwd, SSID_PASSWORD, PASSWORD_LENGTH_MAX);
+ cmd_join->security = WPA2_SECURITY | TKIP_ENABLED | AES_ENABLED;
+ // cmd_join->security = WPA_SECURITY | TKIP_ENABLED;
+ data_packet->data_type = data_type_cmd;
+ data_packet->data_len = sizeof(struct cmd_join) + member_offset(struct spi_wifi_cmd, buffer);
+
+ rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+ rt_event_send(&spi_wifi_data_event, 1);
+ }
+ else return -RT_ERROR;
+ break;
+
+ default :
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/* transmit packet. */
+rt_err_t spi_wifi_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ rt_err_t result = RT_EOK;
+ struct spi_data_packet *data_packet;
+ struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+
+ if (!wifi_device->active)
+ {
+ WIFI_DEBUG("!active, TX drop!\n");
+ return RT_EOK;
+ }
+
+ /* get free tx buffer */
+ data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+ if (data_packet != RT_NULL)
+ {
+ data_packet->data_type = data_type_eth_data;
+ data_packet->data_len = p->tot_len;
+
+ pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
+
+ rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+ eth_device_ready((struct eth_device *)dev);
+ }
+ else
+ return -RT_ERROR;
+
+#ifdef ETH_TX_DUMP
+ packet_dump("TX dump", p);
+#endif /* ETH_TX_DUMP */
+
+ /* Return SUCCESS */
+ return result;
+}
+
+/* reception packet. */
+struct pbuf *spi_wifi_eth_rx(rt_device_t dev)
+{
+ struct pbuf *p = RT_NULL;
+ struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+
+ if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK)
+ {
+ return RT_NULL;
+ }
+
+
+
+ return p;
+}
+
+static void spi_wifi_data_thread_entry(void *parameter)
+{
+ rt_uint32_t e;
+ rt_err_t result;
+
+ while (1)
+ {
+ /* receive first event */
+ if (rt_event_recv(&spi_wifi_data_event,
+ 1,
+ RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+ RT_WAITING_FOREVER,
+ &e) != RT_EOK)
+ {
+ continue;
+ }
+
+ result = spi_wifi_transfer(&spi_wifi_device);
+
+ if (result == RT_EOK)
+ {
+ rt_event_send(&spi_wifi_data_event, 1);
+ }
+ }
+}
+
+rt_err_t rt_hw_wifi_init(const char *spi_device_name)
+{
+ memset(&spi_wifi_device, 0, sizeof(struct spi_wifi_eth));
+
+ spi_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+
+ if (spi_wifi_device.rt_spi_device == RT_NULL)
+ {
+ WIFI_DEBUG("spi device %s not found!\r\n", spi_device_name);
+ return -RT_ENOSYS;
+ }
+
+ /* config spi */
+ {
+ struct rt_spi_configuration cfg;
+ cfg.data_width = 8;
+ cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+ cfg.max_hz = 1000000; /* 50M */
+ rt_spi_configure(spi_wifi_device.rt_spi_device, &cfg);
+ }
+
+ spi_wifi_device.parent.parent.init = spi_wifi_eth_init;
+ spi_wifi_device.parent.parent.open = spi_wifi_eth_open;
+ spi_wifi_device.parent.parent.close = spi_wifi_eth_close;
+ spi_wifi_device.parent.parent.read = spi_wifi_eth_read;
+ spi_wifi_device.parent.parent.write = spi_wifi_eth_write;
+ spi_wifi_device.parent.parent.control = spi_wifi_eth_control;
+ spi_wifi_device.parent.parent.user_data = RT_NULL;
+
+ spi_wifi_device.parent.eth_rx = spi_wifi_eth_rx;
+ spi_wifi_device.parent.eth_tx = spi_wifi_eth_tx;
+
+ rt_mp_init(&spi_wifi_device.spi_tx_mp,
+ "spi_tx",
+ &spi_wifi_device.spi_tx_mempool[0],
+ sizeof(spi_wifi_device.spi_tx_mempool),
+ sizeof(struct spi_data_packet));
+
+ rt_mp_init(&spi_wifi_device.spi_rx_mp,
+ "spi_rx",
+ &spi_wifi_device.spi_rx_mempool[0],
+ sizeof(spi_wifi_device.spi_rx_mempool),
+ sizeof(struct spi_data_packet));
+
+ rt_mb_init(&spi_wifi_device.spi_tx_mb,
+ "spi_tx",
+ &spi_wifi_device.spi_tx_mb_pool[0],
+ SPI_TX_POOL_SIZE,
+ RT_IPC_FLAG_PRIO);
+
+ rt_mb_init(&spi_wifi_device.eth_rx_mb,
+ "eth_rx",
+ &spi_wifi_device.eth_rx_mb_pool[0],
+ SPI_TX_POOL_SIZE,
+ RT_IPC_FLAG_PRIO);
+
+ rt_mb_init(&spi_wifi_device.spi_wifi_cmd_mb,
+ "wifi_cmd",
+ &spi_wifi_device.spi_wifi_cmd_mb_pool[0],
+ sizeof(spi_wifi_device.spi_wifi_cmd_mb_pool) / 4,
+ RT_IPC_FLAG_PRIO);
+ rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
+
+ spi_wifi_hw_init();
+
+ {
+ rt_thread_t tid;
+
+
+ tid = rt_thread_create("wifi",
+ spi_wifi_data_thread_entry,
+ RT_NULL,
+ 2048,
+ RT_THREAD_PRIORITY_MAX - 2,
+ 20);
+
+ if (tid != RT_NULL)
+ rt_thread_startup(tid);
+ }
+
+ /* init: get mac address */
+ {
+ WIFI_DEBUG("wifi_control SPI_WIFI_CMD_INIT\n");
+ spi_wifi_eth_control((rt_device_t)&spi_wifi_device,
+ SPI_WIFI_CMD_INIT,
+ (void *)&spi_wifi_device.dev_addr[0]);
+
+ }
+ /* register eth device */
+ eth_device_init(&(spi_wifi_device.parent), "w0");
+ eth_device_linkchange(&spi_wifi_device.parent, RT_FALSE);
+
+ {
+ WIFI_DEBUG("wifi_control SPI_WIFI_CMD_JOIN\n");
+ spi_wifi_eth_control((rt_device_t)&spi_wifi_device,
+ SPI_WIFI_CMD_JOIN,
+ (void *)&spi_wifi_device.dev_addr[0]);
+
+ WIFI_DEBUG("wifi_control exit\n");
+ }
+
+ return RT_EOK;
+}
+
+void spi_wifi_isr(int vector)
+{
+ /* enter interrupt */
+ rt_interrupt_enter();
+
+ WIFI_DEBUG("spi_wifi_isr\n");
+ rt_event_send(&spi_wifi_data_event, 1);
+
+ /* leave interrupt */
+ rt_interrupt_leave();
+}
diff --git a/components/drivers/spi/spi_wifi_rw009.h b/components/drivers/spi/spi_wifi_rw009.h
new file mode 100644
index 0000000000..b609e7cb13
--- /dev/null
+++ b/components/drivers/spi/spi_wifi_rw009.h
@@ -0,0 +1,123 @@
+/*
+ * File : spi_wifi_rw009.h
+ * This file is part of RT-Thread RTOS
+ * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2014-07-31 aozima the first version
+ */
+
+#ifndef SPI_WIFI_H_INCLUDED
+#define SPI_WIFI_H_INCLUDED
+
+#include <stdint.h>
+
+// little-endian
+struct cmd_request
+{
+ uint32_t flag;
+ uint32_t M2S_len; // master to slave data len.
+ uint32_t magic1;
+ uint32_t magic2;
+};
+
+#define CMD_MAGIC1 (0x67452301)
+#define CMD_MAGIC2 (0xEFCDAB89)
+
+#define CMD_FLAG_MRDY (0x01)
+
+// little-endian
+struct response
+{
+ uint32_t flag;
+ uint32_t S2M_len; // slave to master data len.
+ uint32_t magic1;
+ uint32_t magic2;
+};
+
+#define RESP_FLAG_SRDY (0x01)
+#define RESP_MAGIC1 (0x98BADCFE)
+#define RESP_MAGIC2 (0x10325476)
+
+/* spi slave configure. */
+#define MAX_DATA_LEN 1520
+#define SPI_TX_POOL_SIZE 2
+
+// align check
+#if (MAX_DATA_LEN & 0x03) != 0
+#error MAX_DATA_LEN must ALIGN to 4byte!
+#endif
+
+typedef enum
+{
+ data_type_eth_data = 0,
+ data_type_cmd,
+ data_type_resp,
+}
+app_data_type_typedef;
+
+struct spi_data_packet
+{
+ uint32_t data_len;
+ uint32_t data_type;
+ char buffer[MAX_DATA_LEN];
+};
+
+struct spi_wifi_cmd
+{
+ uint32_t cmd;
+ char buffer[128];
+};
+
+struct spi_wifi_resp
+{
+ uint32_t cmd;
+ char buffer[128];
+};
+
+#define SPI_WIFI_CMD_INIT 128 //wait
+#define SPI_WIFI_CMD_SCAN 129 //no wait
+#define SPI_WIFI_CMD_JOIN 130 //no wait
+
+/* porting */
+extern void spi_wifi_hw_init(void);
+extern void spi_wifi_int_cmd(rt_bool_t cmd);
+extern rt_bool_t spi_wifi_is_busy(void);
+
+/* tools */
+#define node_entry(node, type, member) \
+ ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
+#define member_offset(type, member) \
+ ((unsigned long)(&((type *)0)->member))
+
+#define SSID_NAME_LENGTH_MAX (32)
+#define PASSWORD_LENGTH_MAX (32)
+
+struct cmd_join
+{
+ char ssid[SSID_NAME_LENGTH_MAX];
+ char passwd[PASSWORD_LENGTH_MAX];
+
+ uint8_t bssid[8]; // 6byte + 2byte PAD.
+
+ uint32_t channel;
+ uint32_t security;
+};
+
+
+#endif // SPI_WIFI_H_INCLUDED
diff --git a/components/external/libpng/pngconf.h b/components/external/libpng/pngconf.h
index bb0a189f9d..cca0657e4c 100644
--- a/components/external/libpng/pngconf.h
+++ b/components/external/libpng/pngconf.h
@@ -24,10 +24,10 @@
#define PNG_MAX_MALLOC_64K
#define PNG_NO_STDIO
#define PNG_NO_ERROR_NUMBERS
+#define PNG_NO_WRITE_SUPPORTED
#define PNG_ABORT() do { rt_kprintf("libpng abort.\n"); } while (0)
#ifndef RT_USING_NEWLIB
-#define PNG_NO_WRITE_SUPPORTED
#define PNG_NO_SETJMP_SUPPORTED
#define malloc rtgui_malloc
#define free rtgui_free
diff --git a/components/libc/newlib/syscalls.c b/components/libc/newlib/syscalls.c
index 5b829f4753..388d240c94 100644
--- a/components/libc/newlib/syscalls.c
+++ b/components/libc/newlib/syscalls.c
@@ -3,6 +3,14 @@
#include <sys/time.h>
#include <rtthread.h>
+#ifdef RT_USING_DFS
+#include <dfs_posix.h>
+#endif
+
+#ifdef RT_USING_PTHREADS
+#include <pthread.h>
+#endif
+
/* Reentrant versions of system calls. */
int