Browse Source

Merge branch 'master' of https://github.com/RT-Thread/rt-thread

Bernard Xiong 11 years ago
parent
commit
7f45ac18bc
43 changed files with 3511 additions and 299 deletions
  1. 28 28
      bsp/ls1bdev/applications/startup.c
  2. 24 18
      bsp/ls1bdev/drivers/board.c
  3. 7 4
      bsp/ls1bdev/drivers/uart.c
  4. 3 0
      bsp/mb9bf618s/applications/startup.c
  5. 12 4
      components/dfs/src/dfs_file.c
  6. 16 8
      components/dfs/src/dfs_posix.c
  7. 0 3
      components/drivers/i2c/i2c-bit-ops.c
  8. 2 9
      components/drivers/i2c/i2c_dev.c
  9. 22 2
      components/drivers/spi/SConscript
  10. 15 0
      components/drivers/spi/device_driver_list.txt
  11. 876 0
      components/drivers/spi/enc28j60.c
  12. 329 0
      components/drivers/spi/enc28j60.h
  13. 3 32
      components/drivers/spi/spi_dev.c
  14. 437 0
      components/drivers/spi/spi_flash_at45dbxx.c
  15. 17 0
      components/drivers/spi/spi_flash_at45dbxx.h
  16. 346 0
      components/drivers/spi/spi_flash_sst25vfxx.c
  17. 32 0
      components/drivers/spi/spi_flash_sst25vfxx.h
  18. 371 0
      components/drivers/spi/spi_flash_w25qxx.c
  19. 34 0
      components/drivers/spi/spi_flash_w25qxx.h
  20. 590 0
      components/drivers/spi/spi_wifi_rw009.c
  21. 123 0
      components/drivers/spi/spi_wifi_rw009.h
  22. 1 1
      components/external/libpng/pngconf.h
  23. 1 1
      components/finsh/shell.c
  24. 18 4
      components/libc/armlibc/mem_std.c
  25. 11 11
      components/libc/armlibc/stubs.c
  26. 10 0
      components/libc/minilibc/string.c
  27. 2 0
      components/libc/minilibc/string.h
  28. 1 1
      components/libc/minilibc/sys/types.h
  29. 8 0
      components/libc/newlib/syscalls.c
  30. 1 1
      examples/network/tcpclient.c
  31. 1 1
      examples/network/tcpserver.c
  32. 4 4
      libcpu/arm/cortex-m0/context_gcc.S
  33. 4 4
      libcpu/arm/cortex-m0/context_iar.S
  34. 4 4
      libcpu/arm/cortex-m0/context_rvds.S
  35. 4 4
      libcpu/arm/cortex-m3/context_gcc.S
  36. 4 4
      libcpu/arm/cortex-m3/context_iar.S
  37. 4 4
      libcpu/arm/cortex-m3/context_rvds.S
  38. 4 4
      libcpu/arm/cortex-m4/context_gcc.S
  39. 4 4
      libcpu/arm/cortex-m4/context_iar.S
  40. 4 4
      libcpu/arm/cortex-m4/context_rvds.S
  41. 84 87
      libcpu/mips/loongson_1b/interrupt.c
  42. 49 48
      src/mempool.c
  43. 1 0
      tools/keil.py

+ 28 - 28
bsp/ls1bdev/applications/startup.c

@@ -38,49 +38,49 @@ extern void irq_exception(void);
  */
 void rtthread_startup(void)
 {
-	/* disable interrupt first */
-	rt_hw_interrupt_disable();
+    /* disable interrupt first */
+    rt_hw_interrupt_disable();
 
-	/* init cache */
-	rt_hw_cache_init();
-	/* init hardware interrupt */
-	rt_hw_interrupt_init();
+    /* init cache */
+    rt_hw_cache_init();
+    /* init hardware interrupt */
+    rt_hw_interrupt_init();
 
-	/* copy vector */
-	memcpy((void *)A_K0BASE, tlb_refill_exception, 0x20);
-	memcpy((void *)(A_K0BASE + 0x180), general_exception, 0x20);
-	memcpy((void *)(A_K0BASE + 0x200), irq_exception, 0x20);
+    /* copy vector */
+    rt_memcpy((void *)A_K0BASE, tlb_refill_exception, 0x20);
+    rt_memcpy((void *)(A_K0BASE + 0x180), general_exception, 0x20);
+    rt_memcpy((void *)(A_K0BASE + 0x200), irq_exception, 0x20);
 
-	/* init board */
-	rt_hw_board_init();
+    /* init board */
+    rt_hw_board_init();
 
-	/* show version */
-	rt_show_version();
+    /* show version */
+    rt_show_version();
 
 #ifdef RT_USING_HEAP
-	rt_system_heap_init((void*)&__bss_end, (void*)RT_HW_HEAP_END);
+    rt_system_heap_init((void*)&__bss_end, (void*)RT_HW_HEAP_END);
 #endif
 
-	/* init scheduler system */
-	rt_system_scheduler_init();
-
-	/* init application */
-	rt_application_init();
+    /* init scheduler system */
+    rt_system_scheduler_init();
 
     /* initialize timer */
     rt_system_timer_init();
 
-	/* initialize timer thread */
-	rt_system_timer_thread_init();
+    /* initialize timer thread */
+    rt_system_timer_thread_init();
+
+    /* init idle thread */
+    rt_thread_idle_init();
 
-	/* init idle thread */
-	rt_thread_idle_init();
+    /* init application */
+    rt_application_init();
 
-	/* start scheduler */
-	rt_system_scheduler_start();
+    /* start scheduler */
+    rt_system_scheduler_start();
 
-	/* never reach here */
-	return ;
+    /* never reach here */
+    return;
 }
 
 /*@}*/

+ 24 - 18
bsp/ls1bdev/drivers/board.c

@@ -71,6 +71,23 @@ void rt_hw_board_init(void)
 	rt_kprintf("current sr: 0x%08x\n", read_c0_status());
 }
 
+#define __raw_out_put(unr) \
+	while (*ptr) \
+	{ \
+		if (*ptr == '\n') \
+		{ \
+			/* FIFO status, contain valid data */ \
+			while (!(UART_LSR(UART##unr##_BASE) & (UARTLSR_TE | UARTLSR_TFE))); \
+			/* write data */ \
+			UART_DAT(UART##unr##_BASE) = '\r'; \
+		} \
+		/* FIFO status, contain valid data */ \
+		while (!(UART_LSR(UART##unr##_BASE) & (UARTLSR_TE | UARTLSR_TFE))); \
+		/* write data */ \
+		UART_DAT(UART##unr##_BASE) = *ptr; \
+		ptr ++; \
+	}
+
 /* UART line status register value */
 #define UARTLSR_ERROR	(1 << 7)
 #define UARTLSR_TE		(1 << 6)
@@ -82,24 +99,13 @@ void rt_hw_board_init(void)
 #define UARTLSR_DR		(1 << 0)
 void rt_hw_console_output(const char *ptr)
 {
-	/* stream mode */
-	while (*ptr)
-	{
-		if (*ptr == '\n')
-		{
-			/* FIFO status, contain valid data */
-			while (!(UART_LSR(UART0_BASE) & (UARTLSR_TE | UARTLSR_TFE)));
-			/* write data */
-			UART_DAT(UART0_BASE) = '\r';
-		}
-
-		/* FIFO status, contain valid data */
-		while (!(UART_LSR(UART0_BASE) & (UARTLSR_TE | UARTLSR_TFE)));
-		/* write data */
-		UART_DAT(UART0_BASE) = *ptr;
-
-		ptr ++;
-	}
+#if defined(RT_USING_UART0)
+    __raw_out_put(0);
+#elif defined(RT_USING_UART1)
+    __raw_out_put(1);
+#elif defined(RT_USING_UART3)
+    __raw_out_put(3);
+#endif
 }
 
 /*@}*/

+ 7 - 4
bsp/ls1bdev/drivers/uart.c

@@ -249,13 +249,16 @@ void rt_hw_uart_init(void)
 	uart->parent.type = RT_Device_Class_Char;
 	rt_memset(uart->rx_buffer, 0, sizeof(uart->rx_buffer));
 	uart->read_index = uart->save_index = 0;
-	
+
 #if defined(RT_USING_UART0)
 	uart->hw_base = UART0_BASE;
 	uart->irq = LS1B_UART0_IRQ;
 #elif defined(RT_USING_UART1)
 	uart->hw_base = UART1_BASE;
 	uart->irq = LS1B_UART1_IRQ;
+#elif defined(RT_USING_UART3)
+	uart->hw_base = UART3_BASE;
+	uart->irq = LS1B_UART3_IRQ;
 #endif
 
 	/* device interface */
@@ -267,9 +270,9 @@ void rt_hw_uart_init(void)
 	uart->parent.control    = RT_NULL;
 	uart->parent.user_data  = RT_NULL;
 
-	rt_device_register(&uart->parent, "uart0", 
-						RT_DEVICE_FLAG_RDWR | 
-						RT_DEVICE_FLAG_STREAM | 
+	rt_device_register(&uart->parent, "uart0",
+						RT_DEVICE_FLAG_RDWR |
+						RT_DEVICE_FLAG_STREAM |
 						RT_DEVICE_FLAG_INT_RX);
 }
 #endif /* end of UART */

+ 3 - 0
bsp/mb9bf618s/applications/startup.c

@@ -43,6 +43,9 @@ void rtthread_startup(void)
 
     /* show version */
     rt_show_version();
+	
+    /* init timer system */
+    rt_system_timer_init();
 
 #ifdef RT_USING_HEAP
 #ifdef __CC_ARM

+ 12 - 4
components/dfs/src/dfs_file.c

@@ -555,7 +555,7 @@ void ls(const char *pathname)
     if (pathname == RT_NULL) 
         rt_free(path);
 }
-FINSH_FUNCTION_EXPORT(ls, list directory contents)
+FINSH_FUNCTION_EXPORT(ls, list directory contents);
 
 void rm(const char *filename)
 {
@@ -564,7 +564,7 @@ void rm(const char *filename)
         rt_kprintf("Delete %s failed\n", filename);
     }
 }
-FINSH_FUNCTION_EXPORT(rm, remove files or directories)
+FINSH_FUNCTION_EXPORT(rm, remove files or directories);
 
 void cat(const char* filename)
 {
@@ -590,7 +590,7 @@ void cat(const char* filename)
 
     dfs_file_close(&fd);
 }
-FINSH_FUNCTION_EXPORT(cat, print file)
+FINSH_FUNCTION_EXPORT(cat, print file);
 
 #define BUF_SZ  4096
 static void copyfile(const char *src, const char *dst)
@@ -629,7 +629,15 @@ static void copyfile(const char *src, const char *dst)
         read_bytes = dfs_file_read(&src_fd, block_ptr, BUF_SZ);
         if (read_bytes > 0)
         {
-            dfs_file_write(&fd, block_ptr, read_bytes);
+			int length;
+			
+            length = dfs_file_write(&fd, block_ptr, read_bytes);
+			if (length != read_bytes)
+			{
+				/* write failed. */
+				rt_kprintf("Write file data failed, errno=%d\n", length);
+				break;
+			}
         }
     } while (read_bytes > 0);
 

+ 16 - 8
components/dfs/src/dfs_posix.c

@@ -33,11 +33,11 @@
 
 /**
  * this function is a POSIX compliant version, which will open a file and
- * return a file descriptor.
+ * return a file descriptor according specified flags.
  *
  * @param file the path name of file.
  * @param flags the file open flags.
- * @param mode
+ * @param mode ignored parameter
  *
  * @return the non-negative integer on successful open, others for failed.
  */
@@ -120,7 +120,8 @@ RTM_EXPORT(close);
  * @param buf the buffer to save the read data.
  * @param len the maximal length of data buffer
  *
- * @return the actual read data buffer length
+ * @return the actual read data buffer length. If the returned value is 0, it
+ * may be reach the end of file, please check errno.
  */
 int read(int fd, void *buf, size_t len)
 {
@@ -200,7 +201,7 @@ RTM_EXPORT(write);
  * @param offset the offset to be seeked.
  * @param whence the directory of seek.
  *
- * @return the current file position, or -1 on failed.
+ * @return the current read/write position in the file, or -1 on failed.
  */
 off_t lseek(int fd, off_t offset, int whence)
 {
@@ -336,6 +337,8 @@ RTM_EXPORT(stat);
  *
  * @param fildes the file description
  * @param buf the data buffer to save stat description.
+ *
+ * @return 0 on successful, -1 on failed.
  */
 int fstat(int fildes, struct stat *buf)
 {
@@ -470,7 +473,7 @@ RTM_EXPORT(rmdir);
  *
  * @param name the path name to be open.
  *
- * @return the DIR pointer of directory, NULL on open failed.
+ * @return the DIR pointer of directory, NULL on open directory failed.
  */
 DIR *opendir(const char *name)
 {
@@ -537,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,

+ 0 - 3
components/drivers/i2c/i2c-bit-ops.c

@@ -451,9 +451,6 @@ static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
 rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
                             const char               *bus_name)
 {
-    struct rt_i2c_bit_ops *bit_ops = bus->priv;
-    RT_ASSERT(bit_ops != RT_NULL);
-
     bus->ops = &i2c_bit_bus_ops;
 
     return rt_i2c_bus_device_register(bus, bus_name);

+ 2 - 9
components/drivers/i2c/i2c_dev.c

@@ -20,18 +20,11 @@
  * Change Logs:
  * Date           Author        Notes
  * 2012-04-25     weety         first version
+ * 2014-08-03     bernard       fix some compiling warning
  */
 
 #include <rtdevice.h>
 
-static rt_err_t i2c_bus_device_init(rt_device_t dev)
-{
-    struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
-    RT_ASSERT(bus != RT_NULL);
-
-    return RT_EOK;
-}
-
 static rt_size_t i2c_bus_device_read(rt_device_t dev,
                                      rt_off_t    pos,
                                      void       *buffer,
@@ -122,7 +115,7 @@ rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
     /* set device type */
     device->type    = RT_Device_Class_I2CBUS;
     /* initialize device interface */
-    device->init    = i2c_bus_device_init;
+    device->init    = RT_NULL;
     device->open    = RT_NULL;
     device->close   = RT_NULL;
     device->read    = i2c_bus_device_read;

+ 22 - 2
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')

+ 15 - 0
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/

+ 876 - 0
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

+ 329 - 0
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

+ 3 - 32
components/drivers/spi/spi_dev.c

@@ -25,16 +25,6 @@
 #include <drivers/spi.h>
 
 /* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */
-static rt_err_t _spi_bus_device_init(rt_device_t dev)
-{
-    struct rt_spi_bus *bus;
-
-    bus = (struct rt_spi_bus *)dev;
-    RT_ASSERT(bus != RT_NULL);
-
-    return RT_EOK;
-}
-
 static rt_size_t _spi_bus_device_read(rt_device_t dev,
                                       rt_off_t    pos,
                                       void       *buffer,
@@ -67,11 +57,7 @@ static rt_err_t _spi_bus_device_control(rt_device_t dev,
                                         rt_uint8_t  cmd,
                                         void       *args)
 {
-    struct rt_spi_bus *bus;
-
-    bus = (struct rt_spi_bus *)dev;
-    RT_ASSERT(bus != RT_NULL);
-
+    /* TODO: add control command handle */
     switch (cmd)
     {
     case 0: /* set device */
@@ -93,7 +79,7 @@ rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
     /* set device type */
     device->type    = RT_Device_Class_SPIBUS;
     /* initialize device interface */
-    device->init    = _spi_bus_device_init;
+    device->init    = RT_NULL;
     device->open    = RT_NULL;
     device->close   = RT_NULL;
     device->read    = _spi_bus_device_read;
@@ -105,16 +91,6 @@ rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
 }
 
 /* SPI Dev device interface, compatible with RT-Thread 0.3.x/1.0.x */
-static rt_err_t _spidev_device_init(rt_device_t dev)
-{
-    struct rt_spi_device *device;
-
-    device = (struct rt_spi_device *)dev;
-    RT_ASSERT(device != RT_NULL);
-
-    return RT_EOK;
-}
-
 static rt_size_t _spidev_device_read(rt_device_t dev,
                                      rt_off_t    pos,
                                      void       *buffer,
@@ -147,11 +123,6 @@ static rt_err_t _spidev_device_control(rt_device_t dev,
                                        rt_uint8_t  cmd,
                                        void       *args)
 {
-    struct rt_spi_device *device;
-
-    device = (struct rt_spi_device *)dev;
-    RT_ASSERT(device != RT_NULL);
-
     switch (cmd)
     {
     case 0: /* set device */
@@ -172,7 +143,7 @@ rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name)
 
     /* set device type */
     device->type    = RT_Device_Class_SPIDevice;
-    device->init    = _spidev_device_init;
+    device->init    = RT_NULL;
     device->open    = RT_NULL;
     device->close   = RT_NULL;
     device->read    = _spidev_device_read;

+ 437 - 0
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;
+}

+ 17 - 0
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

+ 346 - 0
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;
+}

+ 32 - 0
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

+ 371 - 0
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;
+}

+ 34 - 0
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

+ 590 - 0
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();
+}

+ 123 - 0
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

+ 1 - 1
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

+ 1 - 1
components/finsh/shell.c

@@ -118,7 +118,7 @@ void finsh_set_device(const char* device_name)
         {
             /* close old finsh device */
             rt_device_close(shell->device);
-            rt_device_set_rx_indicate(dev, RT_NULL);
+            rt_device_set_rx_indicate(shell->device, RT_NULL);
         }
 
         shell->device = dev;

+ 18 - 4
components/libc/armlibc/mem_std.c

@@ -1,7 +1,16 @@
 /*
- * File:    mem_std.c
- * Brief:   Replace memory management functions of arm standard c library
+ * File     : mem_std.c
+ * Brief    : implement standard memory routins.
  *
+ * This file is part of Device File System in RT-Thread RTOS
+ * COPYRIGHT (C) 2014, 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:
+ * 2014-08-03     bernard      Add file header.
  */
 
 #include "rtthread.h"
@@ -9,16 +18,21 @@
 /* avoid the heap and heap-using library functions supplied by arm */
 #pragma import(__use_no_heap)
 
-void * malloc(int n)
+void *malloc(int n)
 {
     return rt_malloc(n);
 }
 
-void * realloc(void *rmem, rt_size_t newsize)
+void *realloc(void *rmem, rt_size_t newsize)
 {
     return rt_realloc(rmem, newsize);
 }
 
+void *calloc(rt_size_t nelem, rt_size_t elsize)
+{
+	return rt_calloc(nelem, elsize);
+}
+
 void free(void *rmem)
 {
     rt_free(rmem);

+ 11 - 11
components/libc/armlibc/stubs.c

@@ -13,6 +13,8 @@
  * Date           Author       Notes
  * 2012-11-23     Yihui        The first version
  * 2013-11-24     aozima       fixed _sys_read()/_sys_write() issues.
+ * 2014-08-03     bernard      If using msh, use system() implementation 
+ *                             in msh.
  */
 
 #include <string.h>
@@ -194,9 +196,13 @@ char *_sys_command_string(char *cmd, int len)
     return cmd;
 }
 
+/* This function writes a character to the console. */
 void _ttywrch(int ch)
 {
-   /* TODO */
+    char c;
+
+    c = (char)ch;
+    rt_kprintf(&c);
 }
 
 void _sys_exit(int return_code)
@@ -231,18 +237,12 @@ int remove(const char *filename)
 #endif
 }
 
-/* rename() is defined in dfs_posix.c instead */
-#if 0
-int rename(const char *old, const char *new)
-{
-    return -1;
-}
-#endif
-
+#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) && defined(RT_USING_MODULE) && defined(RT_USING_DFS)
+/* use system implementation in the msh */
+#else
 int system(const char *string)
 {
     RT_ASSERT(0);
     for(;;);
 }
-
-
+#endif

+ 10 - 0
components/libc/minilibc/string.c

@@ -621,4 +621,14 @@ char *strchr(const char *s1, int i)
 	return (char *) s;
 }
 
+long strtol(const char *str, char **endptr, int base)
+{
+    return simple_strtol(str, endptr, base);
+}
+
+long long strtoll(const char *str, char **endptr, int base)
+{
+    return simple_strtoll(str, endptr, base);
+}
+
 #endif

+ 2 - 0
components/libc/minilibc/string.h

@@ -66,6 +66,8 @@ char*strtok_r(char*s, const char*delim, char**ptrptr);
 size_t strcspn(const char *s, const char *reject);
 size_t strspn (const char *s, const char *accept);
 
+long strtol(const char *str, char **endptr, int base);
+long long strtoll(const char *str, char **endptr, int base);
 #endif
 
 #endif

+ 1 - 1
components/libc/minilibc/sys/types.h

@@ -4,7 +4,7 @@
 #include <rtthread.h>
 
 typedef long    	off_t;
-typedef rt_size_t 	size_t;
+typedef __SIZE_TYPE__ 	size_t;
 typedef signed long ssize_t;		/* Used for a count of bytes or an error indication. */
 
 typedef rt_uint8_t 	u_char;

+ 8 - 0
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

+ 1 - 1
examples/network/tcpclient.c

@@ -81,7 +81,7 @@ void tcpclient(const char* url, int port)
         else
         {
             /* 在控制终端显示收到的数据 */
-            rt_kprintf("\nRecieved data = %s " , recv_data);
+            rt_kprintf("\nReceived data = %s " , recv_data);
         }
 
         /* 发送数据到sock连接 */

+ 1 - 1
examples/network/tcpserver.c

@@ -101,7 +101,7 @@ void tcpserv(void* parameter)
            else
            {
                /* 在控制终端显示收到的数据 */
-               rt_kprintf("RECIEVED DATA = %s \n" , recv_data);
+               rt_kprintf("RECEIVED DATA = %s \n" , recv_data);
            }
        }
    }

+ 4 - 4
libcpu/arm/cortex-m0/context_gcc.S

@@ -79,8 +79,8 @@ _reswitch:
     STR     R1, [R0]
     BX      LR
 
-/* R0 --> swith from thread stack
- * R1 --> swith to thread stack
+/* R0 --> switch from thread stack
+ * R1 --> switch to thread stack
  * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
  */
     .global PendSV_Handler
@@ -103,7 +103,7 @@ PendSV_Handler:
     LDR     R0, =rt_interrupt_from_thread
     LDR     R1, [R0]
     CMP     R1, #0x00
-    BEQ     swtich_to_thread    /* skip register save at the first time */
+    BEQ     switch_to_thread    /* skip register save at the first time */
 
 	MRS     R1, PSP                 /* get from thread stack pointer */
 
@@ -118,7 +118,7 @@ PendSV_Handler:
     MOV     R6, R10
     MOV     R7, R11
     STMIA   R1!, {R4 - R7}          /* push thread {R8 - R11} high register to thread stack */
-swtich_to_thread:
+switch_to_thread:
     LDR     R1, =rt_interrupt_to_thread
     LDR     R1, [R1]
     LDR     R1, [R1]                /* load thread stack pointer */

+ 4 - 4
libcpu/arm/cortex-m0/context_iar.S

@@ -81,8 +81,8 @@ _reswitch
     STR     r1, [r0]
     BX      LR
 
-; r0 --> swith from thread stack
-; r1 --> swith to thread stack
+; r0 --> switch from thread stack
+; r1 --> switch to thread stack
 ; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
     EXPORT PendSV_Handler
 PendSV_Handler:
@@ -104,7 +104,7 @@ PendSV_Handler:
     LDR     r0, =rt_interrupt_from_thread
     LDR     r1, [r0]
     CMP     r1, #0x00
-    BEQ     swtich_to_thread        ; skip register save at the first time
+    BEQ     switch_to_thread        ; skip register save at the first time
 
     MRS     r1, psp                 ; get from thread stack pointer
 
@@ -120,7 +120,7 @@ PendSV_Handler:
     MOV     r7, r11
     STMIA   r1!, {r4 - r7}          ; push thread {r8 - r11} high register to thread stack
 
-swtich_to_thread
+switch_to_thread
     LDR     r1, =rt_interrupt_to_thread
     LDR     r1, [r1]
     LDR     r1, [r1]                ; load thread stack pointer

+ 4 - 4
libcpu/arm/cortex-m0/context_rvds.S

@@ -85,8 +85,8 @@ _reswitch
     BX      LR
     ENDP
 
-; r0 --> swith from thread stack
-; r1 --> swith to thread stack
+; r0 --> switch from thread stack
+; r1 --> switch to thread stack
 ; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
 PendSV_Handler    PROC
     EXPORT PendSV_Handler
@@ -108,7 +108,7 @@ PendSV_Handler    PROC
     LDR     r0, =rt_interrupt_from_thread
     LDR     r1, [r0]
     CMP     r1, #0x00
-    BEQ     swtich_to_thread        ; skip register save at the first time
+    BEQ     switch_to_thread        ; skip register save at the first time
 
     MRS     r1, psp                 ; get from thread stack pointer
 
@@ -124,7 +124,7 @@ PendSV_Handler    PROC
     MOV     r7, r11
     STMIA   r1!, {r4 - r7}          ; push thread {r8 - r11} high register to thread stack
 
-swtich_to_thread
+switch_to_thread
     LDR     r1, =rt_interrupt_to_thread
     LDR     r1, [r1]
     LDR     r1, [r1]                ; load thread stack pointer

+ 4 - 4
libcpu/arm/cortex-m3/context_gcc.S

@@ -80,8 +80,8 @@ _reswitch:
     STR     R1, [R0]
     BX      LR
 
-/* R0 --> swith from thread stack
- * R1 --> swith to thread stack
+/* R0 --> switch from thread stack
+ * R1 --> switch to thread stack
  * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
  */
     .global PendSV_Handler
@@ -102,14 +102,14 @@ PendSV_Handler:
 
     LDR     R0, =rt_interrupt_from_thread
     LDR     R1, [R0]
-    CBZ     R1, swtich_to_thread    /* skip register save at the first time */
+    CBZ     R1, switch_to_thread    /* skip register save at the first time */
 
     MRS     R1, PSP                 /* get from thread stack pointer */
     STMFD   R1!, {R4 - R11}         /* push R4 - R11 register */
     LDR     R0, [R0]
     STR     R1, [R0]                /* update from thread stack pointer */
 
-swtich_to_thread:
+switch_to_thread:
     LDR     R1, =rt_interrupt_to_thread
     LDR     R1, [R1]
     LDR     R1, [R1]                /* load thread stack pointer */

+ 4 - 4
libcpu/arm/cortex-m3/context_iar.S

@@ -81,8 +81,8 @@ _reswitch
     STR     r1, [r0]
     BX      LR
 
-; r0 --> swith from thread stack
-; r1 --> swith to thread stack
+; r0 --> switch from thread stack
+; r1 --> switch to thread stack
 ; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
     EXPORT PendSV_Handler
 PendSV_Handler:
@@ -102,14 +102,14 @@ PendSV_Handler:
 
     LDR     r0, =rt_interrupt_from_thread
     LDR     r1, [r0]
-    CBZ     r1, swtich_to_thread    ; skip register save at the first time
+    CBZ     r1, switch_to_thread    ; skip register save at the first time
 
     MRS     r1, psp                 ; get from thread stack pointer
     STMFD   r1!, {r4 - r11}         ; push r4 - r11 register
     LDR     r0, [r0]
     STR     r1, [r0]                ; update from thread stack pointer
 
-swtich_to_thread
+switch_to_thread
     LDR     r1, =rt_interrupt_to_thread
     LDR     r1, [r1]
     LDR     r1, [r1]                ; load thread stack pointer

+ 4 - 4
libcpu/arm/cortex-m3/context_rvds.S

@@ -84,8 +84,8 @@ _reswitch
     BX      LR
     ENDP
 
-; r0 --> swith from thread stack
-; r1 --> swith to thread stack
+; r0 --> switch from thread stack
+; r1 --> switch to thread stack
 ; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
 PendSV_Handler   PROC
     EXPORT PendSV_Handler
@@ -105,14 +105,14 @@ PendSV_Handler   PROC
 
     LDR     r0, =rt_interrupt_from_thread
     LDR     r1, [r0]
-    CBZ     r1, swtich_to_thread    ; skip register save at the first time
+    CBZ     r1, switch_to_thread    ; skip register save at the first time
 
     MRS     r1, psp                 ; get from thread stack pointer
     STMFD   r1!, {r4 - r11}         ; push r4 - r11 register
     LDR     r0, [r0]
     STR     r1, [r0]                ; update from thread stack pointer
 
-swtich_to_thread
+switch_to_thread
     LDR     r1, =rt_interrupt_to_thread
     LDR     r1, [r1]
     LDR     r1, [r1]                ; load thread stack pointer

+ 4 - 4
libcpu/arm/cortex-m4/context_gcc.S

@@ -82,8 +82,8 @@ _reswitch:
     STR r1, [r0]
     BX  LR
 
-/* r0 --> swith from thread stack
- * r1 --> swith to thread stack
+/* r0 --> switch from thread stack
+ * r1 --> switch to thread stack
  * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
  */
 .global PendSV_Handler
@@ -104,7 +104,7 @@ PendSV_Handler:
 
     LDR r0, =rt_interrupt_from_thread
     LDR r1, [r0]
-    CBZ r1, swtich_to_thread    /* skip register save at the first time */
+    CBZ r1, switch_to_thread    /* skip register save at the first time */
 
     MRS r1, psp                 /* get from thread stack pointer */
     
@@ -127,7 +127,7 @@ PendSV_Handler:
     LDR r0, [r0]
     STR r1, [r0]                /* update from thread stack pointer */
 
-swtich_to_thread:
+switch_to_thread:
     LDR r1, =rt_interrupt_to_thread
     LDR r1, [r1]
     LDR r1, [r1]                /* load thread stack pointer */

+ 4 - 4
libcpu/arm/cortex-m4/context_iar.S

@@ -82,8 +82,8 @@ _reswitch
     STR     r1, [r0]
     BX      LR
 
-; r0 --> swith from thread stack
-; r1 --> swith to thread stack
+; r0 --> switch from thread stack
+; r1 --> switch to thread stack
 ; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
     EXPORT PendSV_Handler
 PendSV_Handler:
@@ -103,7 +103,7 @@ PendSV_Handler:
 
     LDR     r0, =rt_interrupt_from_thread
     LDR     r1, [r0]
-    CBZ     r1, swtich_to_thread    ; skip register save at the first time
+    CBZ     r1, switch_to_thread    ; skip register save at the first time
 
     MRS     r1, psp                 ; get from thread stack pointer
 
@@ -130,7 +130,7 @@ push_flag
     LDR     r0, [r0]
     STR     r1, [r0]                ; update from thread stack pointer
 
-swtich_to_thread
+switch_to_thread
     LDR     r1, =rt_interrupt_to_thread
     LDR     r1, [r1]
     LDR     r1, [r1]                ; load thread stack pointer

+ 4 - 4
libcpu/arm/cortex-m4/context_rvds.S

@@ -85,8 +85,8 @@ _reswitch
     BX      LR
     ENDP
 
-; r0 --> swith from thread stack
-; r1 --> swith to thread stack
+; r0 --> switch from thread stack
+; r1 --> switch to thread stack
 ; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
 PendSV_Handler   PROC
     EXPORT PendSV_Handler
@@ -106,7 +106,7 @@ PendSV_Handler   PROC
 
     LDR     r0, =rt_interrupt_from_thread
     LDR     r1, [r0]
-    CBZ     r1, swtich_to_thread    ; skip register save at the first time
+    CBZ     r1, switch_to_thread    ; skip register save at the first time
 
     MRS     r1, psp                 ; get from thread stack pointer
 
@@ -129,7 +129,7 @@ PendSV_Handler   PROC
     LDR     r0, [r0]
     STR     r1, [r0]                ; update from thread stack pointer
 
-swtich_to_thread
+switch_to_thread
     LDR     r1, =rt_interrupt_to_thread
     LDR     r1, [r1]
     LDR     r1, [r1]                ; load thread stack pointer

+ 84 - 87
libcpu/mips/loongson_1b/interrupt.c

@@ -30,7 +30,7 @@ void rt_interrupt_dispatch(void *ptreg);
 void rt_hw_timer_handler();
 
 static struct ls1b_intc_regs volatile *ls1b_hw0_icregs
-	= (struct ls1b_intc_regs volatile *)(LS1B_INTREG_BASE);
+= (struct ls1b_intc_regs volatile *)(LS1B_INTREG_BASE);
 
 /**
  * @addtogroup Loongson LS1B
@@ -40,7 +40,7 @@ static struct ls1b_intc_regs volatile *ls1b_hw0_icregs
 
 static void rt_hw_interrupt_handler(int vector, void *param)
 {
-	rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
+    rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
 }
 
 /**
@@ -48,26 +48,26 @@ static void rt_hw_interrupt_handler(int vector, void *param)
  */
 void rt_hw_interrupt_init(void)
 {
-	rt_int32_t idx;
+    rt_int32_t idx;
 
-	/* pci active low */ 
-	ls1b_hw0_icregs->int_pol = -1; 	   //must be done here 20110802 lgnq
-	/* make all interrupts level triggered */ 	
-	(ls1b_hw0_icregs+0)->int_edge = 0x0000e000;
-	/* mask all interrupts */
-	(ls1b_hw0_icregs+0)->int_clr = 0xffffffff;
+    /* pci active low */
+    ls1b_hw0_icregs->int_pol = -1;	   //must be done here 20110802 lgnq
+    /* make all interrupts level triggered */
+    (ls1b_hw0_icregs+0)->int_edge = 0x0000e000;
+    /* mask all interrupts */
+    (ls1b_hw0_icregs+0)->int_clr = 0xffffffff;
 
     rt_memset(irq_handle_table, 0x00, sizeof(irq_handle_table));
-	for (idx = 0; idx < MAX_INTR; idx ++)
-	{
-		irq_handle_table[idx].handler = rt_hw_interrupt_handler;
-	}
-
-	/* init interrupt nest, and context in thread sp */
-	rt_interrupt_nest = 0;
-	rt_interrupt_from_thread = 0;
-	rt_interrupt_to_thread = 0;
-	rt_thread_switch_interrupt_flag = 0;
+    for (idx = 0; idx < MAX_INTR; idx ++)
+    {
+        irq_handle_table[idx].handler = rt_hw_interrupt_handler;
+    }
+
+    /* init interrupt nest, and context in thread sp */
+    rt_interrupt_nest = 0;
+    rt_interrupt_from_thread = 0;
+    rt_interrupt_to_thread = 0;
+    rt_thread_switch_interrupt_flag = 0;
 }
 
 /**
@@ -76,8 +76,8 @@ void rt_hw_interrupt_init(void)
  */
 void rt_hw_interrupt_mask(int vector)
 {
-	/* mask interrupt */
-	(ls1b_hw0_icregs+(vector>>5))->int_en &= ~(1 << (vector&0x1f));
+    /* mask interrupt */
+    (ls1b_hw0_icregs+(vector>>5))->int_en &= ~(1 << (vector&0x1f));
 }
 
 /**
@@ -86,7 +86,7 @@ void rt_hw_interrupt_mask(int vector)
  */
 void rt_hw_interrupt_umask(int vector)
 {
-	(ls1b_hw0_icregs+(vector>>5))->int_en |= (1 << (vector&0x1f));
+    (ls1b_hw0_icregs+(vector>>5))->int_en |= (1 << (vector&0x1f));
 }
 
 /**
@@ -96,22 +96,19 @@ void rt_hw_interrupt_umask(int vector)
  * @param old_handler the old interrupt service routine
  */
 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
-        void *param, char *name)
+                                         void *param, char *name)
 {
     rt_isr_handler_t old_handler = RT_NULL;
 
-	if (vector >= 0 && vector < MAX_INTR)
-	{
+    if (vector >= 0 && vector < MAX_INTR)
+    {
         old_handler = irq_handle_table[vector].handler;
 
-        if (handler != RT_NULL)
-        {
 #ifdef RT_USING_INTERRUPT_INFO
-		    rt_strncpy(irq_handle_table[vector].name, name, RT_NAME_MAX);
+        rt_strncpy(irq_handle_table[vector].name, name, RT_NAME_MAX);
 #endif /* RT_USING_INTERRUPT_INFO */
-		    irq_handle_table[vector].handler = handler;
-            irq_handle_table[vector].param = param;
-        }
+        irq_handle_table[vector].handler = handler;
+        irq_handle_table[vector].param = param;
     }
 
     return old_handler;
@@ -121,71 +118,71 @@ void rt_interrupt_dispatch(void *ptreg)
 {
     int irq;
     void *param;
-	rt_isr_handler_t irq_func;
-	static rt_uint32_t status = 0;
-	rt_uint32_t c0_status;
-	rt_uint32_t c0_cause;
-	volatile rt_uint32_t cause_im;
-	volatile rt_uint32_t status_im;
-	rt_uint32_t pending_im;
-
-	/* check os timer */
-	c0_status = read_c0_status();
-	c0_cause = read_c0_cause();
-
-	cause_im = c0_cause & ST0_IM;
-	status_im = c0_status & ST0_IM;
-	pending_im = cause_im & status_im;
-
-	if (pending_im & CAUSEF_IP7)
-	{
-		rt_hw_timer_handler();
-	}
-
-	if (pending_im & CAUSEF_IP2)
-	{
-		/* the hardware interrupt */
-		status = ls1b_hw0_icregs->int_isr;
-		if (!status) 
-			return;
-
-		for (irq = MAX_INTR; irq > 0; --irq)
-		{
-			if ((status & (1 << irq)))
-			{
-				status &= ~(1 << irq);
+    rt_isr_handler_t irq_func;
+    static rt_uint32_t status = 0;
+    rt_uint32_t c0_status;
+    rt_uint32_t c0_cause;
+    volatile rt_uint32_t cause_im;
+    volatile rt_uint32_t status_im;
+    rt_uint32_t pending_im;
+
+    /* check os timer */
+    c0_status = read_c0_status();
+    c0_cause = read_c0_cause();
+
+    cause_im = c0_cause & ST0_IM;
+    status_im = c0_status & ST0_IM;
+    pending_im = cause_im & status_im;
+
+    if (pending_im & CAUSEF_IP7)
+    {
+        rt_hw_timer_handler();
+    }
+
+    if (pending_im & CAUSEF_IP2)
+    {
+        /* the hardware interrupt */
+        status = ls1b_hw0_icregs->int_isr;
+        if (!status)
+            return;
+
+        for (irq = MAX_INTR; irq > 0; --irq)
+        {
+            if ((status & (1 << irq)))
+            {
+                status &= ~(1 << irq);
 
                 irq_func = irq_handle_table[irq].handler;
                 param = irq_handle_table[irq].param;
 
-				/* do interrupt */
-                (*irq_func)(irq, param);
+                /* do interrupt */
+                irq_func(irq, param);
 
 #ifdef RT_USING_INTERRUPT_INFO
                 irq_handle_table[irq].counter++;
 #endif /* RT_USING_INTERRUPT_INFO */
 
-				/* ack interrupt */
-				ls1b_hw0_icregs->int_clr |= (1 << irq);
-			}
-		}
-	}
-	else if (pending_im & CAUSEF_IP3)
-	{		
-		rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
-	}
-	else if (pending_im & CAUSEF_IP4)
-	{		
-		rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
-	}
-	else if (pending_im & CAUSEF_IP5)
-	{		
-		rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
-	}
-	else if (pending_im & CAUSEF_IP6)
-	{		
-		rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
-	}
+                /* ack interrupt */
+                ls1b_hw0_icregs->int_clr |= (1 << irq);
+            }
+        }
+    }
+    else if (pending_im & CAUSEF_IP3)
+    {
+        rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
+    }
+    else if (pending_im & CAUSEF_IP4)
+    {
+        rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
+    }
+    else if (pending_im & CAUSEF_IP5)
+    {
+        rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
+    }
+    else if (pending_im & CAUSEF_IP6)
+    {
+        rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
+    }
 }
 
 /*@}*/

+ 49 - 48
src/mempool.c

@@ -323,23 +323,15 @@ void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
     rt_uint8_t *block_ptr;
     register rt_base_t level;
     struct rt_thread *thread;
+    rt_uint32_t before_sleep = 0;
+
+    /* get current thread */
+    thread = rt_thread_self();
 
     /* disable interrupt */
     level = rt_hw_interrupt_disable();
 
-    if (mp->block_free_count)
-    {
-        /* memory block is available. decrease the free block counter */
-        mp->block_free_count --;
-
-        /* get block from block list */
-        block_ptr      = mp->block_list;
-        mp->block_list = *(rt_uint8_t **)block_ptr;
-
-        /* point to memory pool */
-        *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
-    }
-    else
+    while (mp->block_free_count == 0)
     {
         /* memory block is unavailable. */
         if (time == 0)
@@ -347,54 +339,63 @@ void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
             /* enable interrupt */
             rt_hw_interrupt_enable(level);
 
+            rt_set_errno(-RT_ETIMEOUT);
+
             return RT_NULL;
         }
-        else
-        {
-            RT_DEBUG_NOT_IN_INTERRUPT;
 
-            /* get current thread */
-            thread = rt_thread_self();
+        RT_DEBUG_NOT_IN_INTERRUPT;
 
-            thread->error = RT_EOK;
+        thread->error = RT_EOK;
 
-            /* need suspend thread */
-            rt_thread_suspend(thread);
-            rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
-            mp->suspend_thread_count ++;
+        /* need suspend thread */
+        rt_thread_suspend(thread);
+        rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
+        mp->suspend_thread_count++;
 
-            if (time > 0)
-            {
-                /* init thread timer and start it */
-                rt_timer_control(&(thread->thread_timer),
-                                 RT_TIMER_CTRL_SET_TIME,
-                                 &time);
-                rt_timer_start(&(thread->thread_timer));
-            }
+        if (time > 0)
+        {
+            /* get the start tick of timer */
+            before_sleep = rt_tick_get();
+
+            /* init thread timer and start it */
+            rt_timer_control(&(thread->thread_timer),
+                             RT_TIMER_CTRL_SET_TIME,
+                             &time);
+            rt_timer_start(&(thread->thread_timer));
+        }
 
-            /* enable interrupt */
-            rt_hw_interrupt_enable(level);
+        /* enable interrupt */
+        rt_hw_interrupt_enable(level);
+
+        /* do a schedule */
+        rt_schedule();
 
-            /* do a schedule */
-            rt_schedule();
+        if (thread->error != RT_EOK)
+            return RT_NULL;
 
-            if (thread->error != RT_EOK)
-                return RT_NULL;
+        if (time > 0)
+        {
+            time -= rt_tick_get() - before_sleep;
+            if (time < 0)
+                time = 0;
+        }
+        /* disable interrupt */
+        level = rt_hw_interrupt_disable();
+    }
 
-            /* disable interrupt */
-            level = rt_hw_interrupt_disable();
+    /* memory block is available. decrease the free block counter */
+    mp->block_free_count--;
 
-            /* decrease free block */
-            mp->block_free_count --;
+    /* get block from block list */
+    block_ptr = mp->block_list;
+    RT_ASSERT(block_ptr != RT_NULL);
 
-            /* get block from block list */
-            block_ptr      = mp->block_list;
-            mp->block_list = *(rt_uint8_t **)block_ptr;
+    /* Setup the next free node. */
+    mp->block_list = *(rt_uint8_t **)block_ptr;
 
-            /* point to memory pool */
-            *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
-        }
-    }
+    /* point to memory pool */
+    *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
 
     /* enable interrupt */
     rt_hw_interrupt_enable(level);

+ 1 - 0
tools/keil.py

@@ -107,6 +107,7 @@ def MDK4Project(target, script):
     groups = tree.find('Targets/Target/Groups')
     if groups is None:
         groups = SubElement(tree.find('Targets/Target'), 'Groups')
+    groups.clear() # clean old groups
     for group in script:
         group_xml = MDK4AddGroup(ProjectFiles, groups, group['name'], group['src'], project_path)