diff options
Diffstat (limited to 'components')
47 files changed, 4328 insertions, 616 deletions
diff --git a/components/dfs/include/dfs_fs.h b/components/dfs/include/dfs_fs.h index 3fa999c344..498aa5db54 100644 --- a/components/dfs/include/dfs_fs.h +++ b/components/dfs/include/dfs_fs.h @@ -94,6 +94,8 @@ struct dfs_mount_tbl int dfs_register(const struct dfs_filesystem_operation *ops); struct dfs_filesystem *dfs_filesystem_lookup(const char *path); +const char* dfs_filesystem_get_mounted_path(struct rt_device* device); + rt_err_t dfs_filesystem_get_partition(struct dfs_partition *part, rt_uint8_t *buf, rt_uint32_t pindex); diff --git a/components/dfs/src/dfs_file.c b/components/dfs/src/dfs_file.c index 32198371d7..f5619e2354 100644 --- a/components/dfs/src/dfs_file.c +++ b/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); diff --git a/components/dfs/src/dfs_fs.c b/components/dfs/src/dfs_fs.c index a41f36cf09..bdd9560d56 100644 --- a/components/dfs/src/dfs_fs.c +++ b/components/dfs/src/dfs_fs.c @@ -116,6 +116,37 @@ struct dfs_filesystem *dfs_filesystem_lookup(const char *path) } /** + * this function will return the mounted path for specified device. + * + * @param device the device object which is mounted. + * + * @return the mounted path or RT_NULL if none device mounted. + */ +const char* dfs_filesystem_get_mounted_path(struct rt_device* device) +{ + const char* path = RT_NULL; + struct dfs_filesystem *iter; + + dfs_lock(); + for (iter = &filesystem_table[0]; + iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++) + { + /* fint the mounted device */ + if (iter->ops == RT_NULL) continue; + else if (iter->dev_id == device) + { + path = iter->path; + break; + } + } + + /* release filesystem_table lock */ + dfs_unlock(); + + return path; +} + +/** * this function will fetch the partition table on specified buffer. * * @param part the returned partition structure. diff --git a/components/dfs/src/dfs_posix.c b/components/dfs/src/dfs_posix.c index 96139837e9..c1a6a5beb6 100644 --- a/components/dfs/src/dfs_posix.c +++ b/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, diff --git a/components/drivers/i2c/i2c-bit-ops.c b/components/drivers/i2c/i2c-bit-ops.c index 0d82d55fd4..d4a26ea72a 100644 --- a/components/drivers/i2c/i2c-bit-ops.c +++ b/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); diff --git a/components/drivers/i2c/i2c_dev.c b/components/drivers/i2c/i2c_dev.c index cce53d5c92..4b811c62ea 100644 --- a/components/drivers/i2c/i2c_dev.c +++ b/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; diff --git a/components/drivers/include/drivers/serial.h b/components/drivers/include/drivers/serial.h index 41132ed916..bf2a25ae1e 100644 --- a/components/drivers/include/drivers/serial.h +++ b/components/drivers/include/drivers/serial.h @@ -30,9 +30,15 @@ #include <rtthread.h> +#define BAUD_RATE_2400 2400 #define BAUD_RATE_4800 4800 #define BAUD_RATE_9600 9600 +#define BAUD_RATE_38400 38400 +#define BAUD_RATE_57600 57600 #define BAUD_RATE_115200 115200 +#define BAUD_RATE_230400 230400 +#define BAUD_RATE_460800 460800 +#define BAUD_RATE_921600 921600 #define DATA_BITS_5 5 #define DATA_BITS_6 6 @@ -64,6 +70,15 @@ #define RT_DEVICE_CTRL_CLR_INT 0x11 /* disable receive irq */ #define RT_DEVICE_CTRL_GET_INT 0x12 +#define RT_SERIAL_EVENT_RX_IND 0x01 /* Rx indication */ +#define RT_SERIAL_EVENT_TX_DONE 0x02 /* Tx complete */ +#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* Rx DMA transfer done */ +#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* Tx DMA transfer done */ +#define RT_SERIAL_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ + +#define RT_SERIAL_DMA_RX 0x01 +#define RT_SERIAL_DMA_TX 0x02 + #define RT_SERIAL_RX_INT 0x01 #define RT_SERIAL_TX_INT 0x02 @@ -83,24 +98,51 @@ PARITY_NONE, /* No parity */ \ BIT_ORDER_LSB, /* LSB first sent */ \ NRZ_NORMAL, /* Normal mode */ \ + RT_SERIAL_RB_BUFSZ, /* Buffer size */ \ 0 \ } -struct serial_ringbuffer -{ - rt_uint8_t buffer[RT_SERIAL_RB_BUFSZ]; - rt_uint16_t put_index, get_index; -}; - struct serial_configure { rt_uint32_t baud_rate; + rt_uint32_t data_bits :4; rt_uint32_t stop_bits :2; rt_uint32_t parity :2; rt_uint32_t bit_order :1; rt_uint32_t invert :1; - rt_uint32_t reserved :20; + rt_uint32_t bufsz :16; + rt_uint32_t reserved :4; +}; + +/* + * Serial FIFO mode + */ +struct rt_serial_rx_fifo +{ + /* software fifo */ + rt_uint8_t *buffer; + + rt_uint16_t put_index, get_index; +}; + +struct rt_serial_tx_fifo +{ + struct rt_completion completion; +}; + +/* + * Serial DMA mode + */ +struct rt_serial_rx_dma +{ + rt_bool_t activated; +}; + +struct rt_serial_tx_dma +{ + rt_bool_t activated; + struct rt_data_queue data_queue; }; struct rt_serial_device @@ -110,14 +152,8 @@ struct rt_serial_device const struct rt_uart_ops *ops; struct serial_configure config; - /* rx structure */ - struct serial_ringbuffer *int_rx; - /* tx structure */ - struct serial_ringbuffer *int_tx; - - struct rt_data_queue tx_dq; /* tx dataqueue */ - - volatile rt_bool_t dma_flag; /* dma transfer flag */ + void *serial_rx; + void *serial_tx; }; typedef struct rt_serial_device rt_serial_t; @@ -132,14 +168,15 @@ struct rt_uart_ops int (*putc)(struct rt_serial_device *serial, char c); int (*getc)(struct rt_serial_device *serial); - rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const char *buf, rt_size_t size); + rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction); }; -void rt_hw_serial_isr(struct rt_serial_device *serial); -void rt_hw_serial_dma_tx_isr(struct rt_serial_device *serial); +void rt_hw_serial_isr(struct rt_serial_device *serial, int event); + rt_err_t rt_hw_serial_register(struct rt_serial_device *serial, const char *name, rt_uint32_t flag, void *data); #endif + diff --git a/components/drivers/include/drivers/usb_common.h b/components/drivers/include/drivers/usb_common.h index cd6f0432f3..1e9cf3dc9f 100644 --- a/components/drivers/include/drivers/usb_common.h +++ b/components/drivers/include/drivers/usb_common.h @@ -373,7 +373,7 @@ struct uhid_descriptor }; typedef struct uhid_descriptor* uhid_desc_t; -struct ureqest +struct urequest { rt_uint8_t request_type; rt_uint8_t request; @@ -381,7 +381,7 @@ struct ureqest rt_uint16_t index; rt_uint16_t length; }; -typedef struct ureqest* ureq_t; +typedef struct urequest* ureq_t; #ifndef MIN #define MIN(a, b) (a < b ? a : b) diff --git a/components/drivers/include/drivers/usb_device.h b/components/drivers/include/drivers/usb_device.h index 722251c82a..b104da6ab9 100644 --- a/components/drivers/include/drivers/usb_device.h +++ b/components/drivers/include/drivers/usb_device.h @@ -76,7 +76,7 @@ typedef enum /* request to read full count */ UIO_REQUEST_READ_FULL, /* request to read any count */ - UIO_REQUEST_READ_BEST, + UIO_REQUEST_READ_MOST, /* request to write full count */ UIO_REQUEST_WRITE, }UIO_REQUEST_TYPE; @@ -239,7 +239,7 @@ struct udev_msg union { struct ep_msg ep_msg; - struct ureqest setup; + struct urequest setup; } content; }; typedef struct udev_msg* udev_msg_t; @@ -292,7 +292,7 @@ rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep); rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep); rt_err_t rt_usbd_ep0_set_stall(udevice_t device); rt_err_t rt_usbd_ep0_clear_stall(udevice_t device); -rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup); +rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup); rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd); rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size); rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address); diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index dac85eb716..dc9761032e 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -20,6 +20,7 @@ * Change Logs: * Date Author Notes * 2012-01-08 bernard first version. + * 2014-07-12 bernard Add workqueue implementation. */ #ifndef __RT_DEVICE_H__ @@ -143,6 +144,21 @@ struct rt_data_queue void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event); }; +/* workqueue implementation */ +struct rt_workqueue +{ + rt_list_t work_list; + rt_thread_t work_thread; +}; + +struct rt_work +{ + rt_list_t list; + + void (*work_func)(struct rt_work* work, void* work_data); + void *work_data; +}; + /** * Completion */ @@ -274,6 +290,24 @@ rt_err_t rt_data_queue_peak(struct rt_data_queue *queue, rt_size_t *size); void rt_data_queue_reset(struct rt_data_queue *queue); +#ifdef RT_USING_HEAP +/** + * WorkQueue for DeviceDriver + */ +struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority); +rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue); +rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work); +rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work); + +rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_work* work, void* work_data), + void* work_data) +{ + rt_list_init(&(work->list)); + work->work_func = work_func; + work->work_data = work_data; +} +#endif + #ifdef RT_USING_RTC #include "drivers/rtc.h" #ifdef RT_USING_ALARM diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index 622d2cd68c..776316baf5 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -25,104 +25,197 @@ * 2012-11-23 bernard fix compiler warning. * 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define * the size of ring buffer. + * 2014-07-10 bernard rewrite serial framework */ #include <rthw.h> #include <rtthread.h> #include <rtdevice.h> -rt_inline void serial_ringbuffer_init(struct serial_ringbuffer *rbuffer) +/* + * Serial poll routines + */ +rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) { - rt_memset(rbuffer->buffer, 0, sizeof(rbuffer->buffer)); - rbuffer->put_index = 0; - rbuffer->get_index = 0; + int ch; + int size; + + RT_ASSERT(serial != RT_NULL); + size = length; + + while (length) + { + ch = serial->ops->getc(serial); + *data = ch; + data ++; length --; + + if (ch == '\n') break; + } + + return size - length; } -rt_inline void serial_ringbuffer_putc(struct serial_ringbuffer *rbuffer, - char ch) +rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) { - rt_base_t level; + int size; + RT_ASSERT(serial != RT_NULL); - /* disable interrupt */ - level = rt_hw_interrupt_disable(); + size = length; + while (length) + { + /* + * to be polite with serial console add a line feed + * to the carriage return character + */ + if (*data == '\n' && (serial->parent.flag & RT_DEVICE_FLAG_STREAM)) + { + serial->ops->putc(serial, '\r'); + } + + serial->ops->putc(serial, *data); + + ++ data; + -- length; + } - rbuffer->buffer[rbuffer->put_index] = ch; - rbuffer->put_index = (rbuffer->put_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); + return size - length; +} - /* if the next position is read index, discard this 'read char' */ - if (rbuffer->put_index == rbuffer->get_index) - { - rbuffer->get_index = (rbuffer->get_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - } +/* + * Serial interrupt routines + */ +rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) +{ + int size; + struct rt_serial_rx_fifo* rx_fifo; + + RT_ASSERT(serial != RT_NULL); + size = length; + + rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + /* read from software FIFO */ + while (length) + { + int ch; + rt_base_t level; - /* enable interrupt */ - rt_hw_interrupt_enable(level); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + if (rx_fifo->get_index != rx_fifo->put_index) + { + ch = rx_fifo->buffer[rx_fifo->get_index]; + rx_fifo->get_index += 1; + if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; + } + else + { + /* no data, enable interrupt and break out */ + rt_hw_interrupt_enable(level); + break; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + *data = ch & 0xff; + data ++; length --; + } + + return size - length; } -rt_inline int serial_ringbuffer_putchar(struct serial_ringbuffer *rbuffer, - char ch) +rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) { - rt_base_t level; - rt_uint16_t next_index; + int size; + struct rt_serial_tx_fifo *tx; + + RT_ASSERT(serial != RT_NULL); - /* disable interrupt */ - level = rt_hw_interrupt_disable(); + size = length; + tx = (struct rt_serial_tx_fifo*) serial->serial_tx; + RT_ASSERT(tx != RT_NULL); - next_index = (rbuffer->put_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - if (next_index != rbuffer->get_index) - { - rbuffer->buffer[rbuffer->put_index] = ch; - rbuffer->put_index = next_index; - } - else - { - /* enable interrupt */ - rt_hw_interrupt_enable(level); + while (length) + { + if (serial->ops->putc(serial, *(char*)data) == -1) + { + rt_completion_wait(&(tx->completion), RT_WAITING_FOREVER); + continue; + } - return -1; - } + data ++; length --; + } - /* enable interrupt */ - rt_hw_interrupt_enable(level); - - return 1; + return size - length; } -rt_inline int serial_ringbuffer_getc(struct serial_ringbuffer *rbuffer) +/* + * Serial DMA routines + */ +rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) { - int ch; - rt_base_t level; + rt_base_t level; + int result = RT_EOK; + struct rt_serial_rx_dma *rx_dma; - ch = -1; - /* disable interrupt */ - level = rt_hw_interrupt_disable(); - if (rbuffer->get_index != rbuffer->put_index) - { - ch = rbuffer->buffer[rbuffer->get_index]; - rbuffer->get_index = (rbuffer->get_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - } - /* enable interrupt */ - rt_hw_interrupt_enable(level); + RT_ASSERT((serial != RT_NULL) && (data != RT_NULL)); + rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx; + RT_ASSERT(rx_dma != RT_NULL); + + level = rt_hw_interrupt_disable(); + if (rx_dma->activated != RT_TRUE) + { + rx_dma->activated = RT_TRUE; + serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX); + } + else result = -RT_EBUSY; + rt_hw_interrupt_enable(level); - return ch; + if (result == RT_EOK) return length; + + rt_set_errno(result); + return 0; } -rt_inline rt_uint32_t serial_ringbuffer_size(struct serial_ringbuffer *rbuffer) +rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) { - rt_uint32_t size; - rt_base_t level; + rt_base_t level; + rt_err_t result; + struct rt_serial_tx_dma *tx_dma; + + tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx); + + result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + level = rt_hw_interrupt_disable(); + if (tx_dma->activated != RT_TRUE) + { + tx_dma->activated = RT_TRUE; + rt_hw_interrupt_enable(level); - level = rt_hw_interrupt_disable(); - size = (rbuffer->put_index - rbuffer->get_index) & (RT_SERIAL_RB_BUFSZ - 1); - rt_hw_interrupt_enable(level); + /* make a DMA transfer */ + serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX); + } + else + { + rt_hw_interrupt_enable(level); + } - return size; + return length; + } + else + { + rt_set_errno(result); + return 0; + } } /* RT-Thread Device Interface */ - /* - * This function initializes serial + * This function initializes serial device. */ static rt_err_t rt_serial_init(struct rt_device *dev) { @@ -132,61 +225,107 @@ static rt_err_t rt_serial_init(struct rt_device *dev) RT_ASSERT(dev != RT_NULL); serial = (struct rt_serial_device *)dev; - if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) - { - /* apply configuration */ - if (serial->ops->configure) - result = serial->ops->configure(serial, &serial->config); - - if (result != RT_EOK) - return result; - - if (dev->flag & RT_DEVICE_FLAG_INT_RX) - serial_ringbuffer_init(serial->int_rx); - - if (dev->flag & RT_DEVICE_FLAG_INT_TX) - { - /* not supported yet */ - /* - serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_NULL); - serial_ringbuffer_init(serial->int_tx); - serial->int_sending_flag = RT_FALSE; - */ - } + /* initialize rx/tx */ + serial->serial_rx = RT_NULL; + serial->serial_tx = RT_NULL; - if (dev->flag & RT_DEVICE_FLAG_DMA_TX) - { - serial->dma_flag = RT_FALSE; - - /* init data queue */ - rt_data_queue_init(&(serial->tx_dq), RT_SERIAL_TX_DATAQUEUE_SIZE, - RT_SERIAL_TX_DATAQUEUE_LWM, RT_NULL); - } + /* apply configuration */ + if (serial->ops->configure) + result = serial->ops->configure(serial, &serial->config); - /* set activated */ - dev->flag |= RT_DEVICE_FLAG_ACTIVATED; - } - - return result; + return result; } static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) { struct rt_serial_device *serial; - rt_uint32_t int_flags = 0; RT_ASSERT(dev != RT_NULL); serial = (struct rt_serial_device *)dev; - if (dev->flag & RT_DEVICE_FLAG_INT_RX) - int_flags = RT_SERIAL_RX_INT; - if (dev->flag & RT_DEVICE_FLAG_INT_TX) - int_flags |= RT_SERIAL_TX_INT; + /* check device flag with the open flag */ + if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX)) + return -RT_EIO; + if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX)) + return -RT_EIO; + if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX)) + return -RT_EIO; + if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX)) + return -RT_EIO; - if (int_flags) - { - serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)int_flags); - } + /* get open flags */ + dev->open_flag = oflag & 0xff; + + /* initialize the Rx/Tx structure according to open flag */ + if (serial->serial_rx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_DMA_RX) + { + struct rt_serial_rx_dma* rx_dma; + + rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma)); + RT_ASSERT(rx_dma != RT_NULL); + rx_dma->activated = RT_FALSE; + + serial->serial_rx = rx_dma; + dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; + } + else if (oflag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_serial_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + + serial->config.bufsz); + RT_ASSERT(rx_fifo != RT_NULL); + rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); + rt_memset(rx_fifo->buffer, 0, RT_SERIAL_RB_BUFSZ); + rx_fifo->put_index = 0; + rx_fifo->get_index = 0; + + serial->serial_rx = rx_fifo; + dev->open_flag |= RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } + else + { + serial->serial_rx = RT_NULL; + } + } + + if (serial->serial_tx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_DMA_TX) + { + struct rt_serial_tx_dma* tx_dma; + + tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma)); + RT_ASSERT(tx_dma != RT_NULL); + + rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); + serial->serial_tx = tx_dma; + + dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; + } + else if (oflag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_serial_tx_fifo *tx_fifo; + + tx_fifo = (struct rt_serial_tx_fifo*) rt_malloc(sizeof(struct rt_serial_tx_fifo)); + RT_ASSERT(tx_fifo != RT_NULL); + + rt_completion_init(&(tx_fifo->completion)); + serial->serial_tx = tx_fifo; + + dev->open_flag |= RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX); + } + else + { + serial->serial_tx = RT_NULL; + } + } return RT_EOK; } @@ -194,20 +333,62 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) static rt_err_t rt_serial_close(struct rt_device *dev) { struct rt_serial_device *serial; - rt_uint32_t int_flags = 0; RT_ASSERT(dev != RT_NULL); serial = (struct rt_serial_device *)dev; - if (dev->flag & RT_DEVICE_FLAG_INT_RX) - int_flags = RT_SERIAL_RX_INT; - if (dev->flag & RT_DEVICE_FLAG_INT_TX) - int_flags |= RT_SERIAL_TX_INT; + /* this device has more reference count */ + if (dev->ref_count > 1) return RT_EOK; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_serial_rx_fifo* rx_fifo; - if (int_flags) - { - serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)int_flags); - } + rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + rt_free(rx_fifo); + serial->serial_rx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX) + { + struct rt_serial_rx_dma* rx_dma; + + rx_dma = (struct rt_serial_rx_dma*)serial->serial_tx; + RT_ASSERT(rx_dma != RT_NULL); + + rt_free(rx_dma); + serial->serial_rx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX; + } + + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_serial_tx_fifo* tx_fifo; + + tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_rx; + RT_ASSERT(tx_fifo != RT_NULL); + + rt_free(tx_fifo); + serial->serial_tx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) + { + struct rt_serial_tx_dma* tx_dma; + + tx_dma = (struct rt_serial_tx_dma*)serial->serial_tx; + RT_ASSERT(tx_dma != RT_NULL); + + rt_free(tx_dma); + serial->serial_tx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX; + } return RT_EOK; } @@ -217,53 +398,23 @@ static rt_size_t rt_serial_read(struct rt_device *dev, void *buffer, rt_size_t size) { - rt_uint8_t *ptr; - rt_uint32_t read_nbytes; struct rt_serial_device *serial; RT_ASSERT(dev != RT_NULL); - - if (size == 0) - return 0; + if (size == 0) return 0; serial = (struct rt_serial_device *)dev; - ptr = (rt_uint8_t *)buffer; + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + return _serial_int_rx(serial, buffer, size); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX) + { + return _serial_dma_rx(serial, buffer, size); + } - if (dev->flag & RT_DEVICE_FLAG_INT_RX) - { - /* interrupt mode Rx */ - while (size) - { - int ch; - - ch = serial_ringbuffer_getc(serial->int_rx); - if (ch == -1) - break; - - *ptr = ch & 0xff; - ptr ++; - size --; - } - } - else - { - /* polling mode */ - while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size) - { - *ptr = serial->ops->getc(serial); - ptr ++; - } - } - - read_nbytes = (rt_uint32_t)ptr - (rt_uint32_t)buffer; - /* set error code */ - if (read_nbytes == 0) - { - rt_set_errno(-RT_EEMPTY); - } - - return read_nbytes; + return _serial_poll_rx(serial, buffer, size); } static rt_size_t rt_serial_write(struct rt_device *dev, @@ -271,90 +422,23 @@ static rt_size_t rt_serial_write(struct rt_device *dev, const void *buffer, rt_size_t size) { - rt_uint8_t *ptr; - rt_size_t write_nbytes = 0; struct rt_serial_device *serial; RT_ASSERT(dev != RT_NULL); - - if (size == 0) - return 0; + if (size == 0) return 0; serial = (struct rt_serial_device *)dev; - ptr = (rt_uint8_t*)buffer; - - if (dev->flag & RT_DEVICE_FLAG_INT_TX) - { - /* warning: data will be discarded if buffer is full */ - while (size) - { - if (serial_ringbuffer_putchar(serial->int_tx, *ptr) != -1) - { - ptr ++; - size --; - } - else - break; - } - } - else if (dev->flag & RT_DEVICE_FLAG_DMA_TX) - { - rt_base_t level; - rt_err_t result; - - RT_ASSERT(0 == (dev->flag & RT_DEVICE_FLAG_STREAM)); - - result = rt_data_queue_push(&(serial->tx_dq), buffer, size, 20); - if (result == RT_EOK) - { - level = rt_hw_interrupt_disable(); - if (serial->dma_flag == RT_FALSE) - { - serial->dma_flag = RT_TRUE; - rt_hw_interrupt_enable(level); - serial->ops->dma_transmit(serial, buffer, size); - } - else - rt_hw_interrupt_enable(level); - - return size; - } - else - { - rt_set_errno(result); - - return 0; - } - } - else - { - /* polling mode */ - while (size) - { - /* - * to be polite with serial console add a line feed - * to the carriage return character - */ - if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM)) - { - serial->ops->putc(serial, '\r'); - } + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + _serial_int_tx(serial, buffer, size); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) + { + _serial_dma_tx(serial, buffer, size); + } - serial->ops->putc(serial, *ptr); - - ++ ptr; - -- size; - } - } - - write_nbytes = (rt_uint32_t)ptr - (rt_uint32_t)buffer; - if (write_nbytes == 0) - { - rt_set_errno(-RT_EFULL); - } - - return write_nbytes; + return _serial_poll_tx(serial, buffer, size); } static rt_err_t rt_serial_control(struct rt_device *dev, @@ -422,56 +506,108 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial, } /* ISR for serial interrupt */ -void rt_hw_serial_isr(struct rt_serial_device *serial) +void rt_hw_serial_isr(struct rt_serial_device *serial, int event) { - int ch = -1; + switch (event & 0xff) + { + case RT_SERIAL_EVENT_RX_IND: + { + int ch = -1; + rt_base_t level; + struct rt_serial_rx_fifo* rx_fifo; - /* interrupt mode receive */ - RT_ASSERT(serial->parent.flag & RT_DEVICE_FLAG_INT_RX); + rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + /* interrupt mode receive */ + RT_ASSERT(serial->parent.open_flag & RT_DEVICE_FLAG_INT_RX); + + while (1) + { + ch = serial->ops->getc(serial); + if (ch == -1) break; - while (1) - { - ch = serial->ops->getc(serial); - if (ch == -1) - break; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + rx_fifo->buffer[rx_fifo->put_index] = ch; + rx_fifo->put_index += 1; + if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0; + + /* if the next position is read index, discard this 'read char' */ + if (rx_fifo->put_index == rx_fifo->get_index) + { + rx_fifo->get_index += 1; + if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } + + /* invoke callback */ + if (serial->parent.rx_indicate != RT_NULL) + { + rt_size_t rx_length; + + /* get rx length */ + level = rt_hw_interrupt_disable(); + rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index): + (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index)); + rt_hw_interrupt_enable(level); - serial_ringbuffer_putc(serial->int_rx, ch); - } + serial->parent.rx_indicate(&serial->parent, rx_length); + } + break; + } + case RT_SERIAL_EVENT_TX_DONE: + { + struct rt_serial_tx_fifo* tx_fifo; - /* invoke callback */ - if (serial->parent.rx_indicate != RT_NULL) - { - rt_size_t rx_length; + tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx; + rt_completion_done(&(tx_fifo->completion)); + break; + } + case RT_SERIAL_EVENT_TX_DMADONE: + { + const void *data_ptr; + rt_size_t data_size; + const void *last_data_ptr; + struct rt_serial_tx_dma* tx_dma; - /* get rx length */ - rx_length = serial_ringbuffer_size(serial->int_rx); - serial->parent.rx_indicate(&serial->parent, rx_length); - } -} - -/* - * ISR for DMA mode Tx - */ -void rt_hw_serial_dma_tx_isr(struct rt_serial_device *serial) -{ - const void *data_ptr; - rt_size_t data_size; - const void *last_data_ptr; - - rt_data_queue_pop(&(serial->tx_dq), &last_data_ptr, &data_size, 0); - if (RT_EOK == rt_data_queue_peak(&(serial->tx_dq), &data_ptr, &data_size)) - { - /* transmit next data node */ - serial->ops->dma_transmit(serial, data_ptr, data_size); - } - else - { - serial->dma_flag = RT_FALSE; - } + tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx; + + rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0); + if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK) + { + /* transmit next data node */ + tx_dma->activated = RT_TRUE; + serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX); + } + else + { + tx_dma->activated = RT_FALSE; + } + + /* invoke callback */ + if (serial->parent.tx_complete != RT_NULL) + { + serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr); + } + break; + } + case RT_SERIAL_EVENT_RX_DMADONE: + { + int length; + struct rt_serial_rx_dma* rx_dma; - /* invoke callback */ - if (serial->parent.tx_complete != RT_NULL) - { - serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr); - } + rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx; + /* get DMA rx length */ + length = (event & (~0xff)) >> 8; + serial->parent.rx_indicate(&(serial->parent), length); + rx_dma->activated = RT_FALSE; + break; + } + } } diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index f114ef7a41..f9fc82a777 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -1,8 +1,28 @@ from building import * -cwd = GetCurrentDir() -src = Glob('*.c') +cwd = GetCurrentDir() +src = ['spi_core.c', 'spi_dev.c'] CPPPATH = [cwd + '/../include'] + +src_device = [] + +if GetDepend('RT_USING_SPI_WIFI'): + src_device += ['spi_wifi_rw009.c'] + +if GetDepend('RT_USING_W25QXX'): + src_device += ['spi_flash_w25qxx.c'] + +if GetDepend('RT_USING_ENC28J60'): + src_device += ['enc28j60.c'] + +if GetDepend('RT_USING_AT45DBXX'): + src_device += ['spi_flash_at45dbxx.c'] + +if GetDepend('RT_USING_SST25VFXX'): + src_device += ['spi_flash_sst25vfxx.c'] + +src += src_device + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/spi/device_driver_list.txt b/components/drivers/spi/device_driver_list.txt new file mode 100644 index 0000000000..2c9d6a16b8 --- /dev/null +++ b/components/drivers/spi/device_driver_list.txt @@ -0,0 +1,15 @@ +spi_wifi_rw009.c/spi_wifi_rw009.h +RW009 +http://www.rt-thread.com/ + +enc28j60.c/enc28j60.h +http://www.microchip.com/ + +spi_flash_at45dbxx.c/spi_flash_at45dbxx.h +http://www.atmel.com/ + +spi_flash_sst25vfxx.c/spi_flash_sst25vfxx.h +http://www.microchip.com/ + +spi_flash_w25qxx.c/spi_flash_w25qxx.h +http://www.winbond.com/ diff --git a/components/drivers/spi/enc28j60.c b/components/drivers/spi/enc28j60.c new file mode 100644 index 0000000000..68f1181dcc --- /dev/null +++ b/components/drivers/spi/enc28j60.c @@ -0,0 +1,876 @@ +#include "enc28j60.h" + +#define NET_TRACE +#define ETH_RX_DUMP +#define ETH_TX_DUMP + +#ifdef NET_TRACE +#define NET_DEBUG rt_kprintf +#else +#define NET_DEBUG(...) +#endif /* #ifdef NET_TRACE */ + +struct enc28j60_tx_list_typedef +{ + struct enc28j60_tx_list_typedef * prev; + struct enc28j60_tx_list_typedef * next; + rt_uint32_t addr; /* pkt addr in buffer */ + rt_uint32_t len; /* pkt len */ + volatile rt_bool_t free; /* 0:busy, 1:free */ +}; +static struct enc28j60_tx_list_typedef enc28j60_tx_list[2]; +static volatile struct enc28j60_tx_list_typedef * tx_current; +static volatile struct enc28j60_tx_list_typedef * tx_ack; +static struct rt_event tx_event; + +/* private enc28j60 define */ +/* enc28j60 spi interface function */ +static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address); +static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data); + +static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address); +static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data); + +static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk); +static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address); +static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device); +static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level); + +static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address); +static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data); +static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device); + +#define enc28j60_lock(dev) rt_mutex_take(&((struct net_device*)dev)->lock, RT_WAITING_FOREVER); +#define enc28j60_unlock(dev) rt_mutex_release(&((struct net_device*)dev)->lock); + +static struct net_device enc28j60_dev; +static uint8_t Enc28j60Bank; +//struct rt_spi_device * spi_device; +static uint16_t NextPacketPtr; + +static void _delay_us(uint32_t us) +{ + volatile uint32_t len; + for (; us > 0; us --) + for (len = 0; len < 20; len++ ); +} + +/* enc28j60 spi interface function */ +static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address) +{ + uint8_t send_buffer[2]; + uint8_t recv_buffer[1]; + uint32_t send_size = 1; + + send_buffer[0] = op | (address & ADDR_MASK); + send_buffer[1] = 0xFF; + + /* do dummy read if needed (for mac and mii, see datasheet page 29). */ + if(address & 0x80) + { + send_size = 2; + } + + rt_spi_send_then_recv(spi_device, send_buffer, send_size, recv_buffer, 1); + return (recv_buffer[0]); +} + +static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data) +{ + uint32_t level; + uint8_t buffer[2]; + + level = rt_hw_interrupt_disable(); + + buffer[0] = op | (address & ADDR_MASK); + buffer[1] = data; + rt_spi_send(spi_device, buffer, 2); + + rt_hw_interrupt_enable(level); +} + +/* enc28j60 function */ +static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk) +{ + /* setup clkout: 2 is 12.5MHz: */ + spi_write(spi_device, ECOCON, clk & 0x7); +} + +static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address) +{ + /* set the bank (if needed) .*/ + if((address & BANK_MASK) != Enc28j60Bank) + { + /* set the bank. */ + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); + Enc28j60Bank = (address & BANK_MASK); + } +} + +static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address) +{ + /* set the bank. */ + enc28j60_set_bank(spi_device, address); + /* do the read. */ + return spi_read_op(spi_device, ENC28J60_READ_CTRL_REG, address); +} + +static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data) +{ + /* set the bank. */ + enc28j60_set_bank(spi_device, address); + /* do the write. */ + spi_write_op(spi_device, ENC28J60_WRITE_CTRL_REG, address, data); +} + +static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address) +{ + uint16_t value; + + /* Set the right address and start the register read operation. */ + spi_write(spi_device, MIREGADR, address); + spi_write(spi_device, MICMD, MICMD_MIIRD); + + _delay_us(15); + + /* wait until the PHY read completes. */ + while(spi_read(spi_device, MISTAT) & MISTAT_BUSY); + + /* reset reading bit */ + spi_write(spi_device, MICMD, 0x00); + + value = spi_read(spi_device, MIRDL) | spi_read(spi_device, MIRDH)<<8; + + return (value); +} + +static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data) +{ + /* set the PHY register address. */ + spi_write(spi_device, MIREGADR, address); + + /* write the PHY data. */ + spi_write(spi_device, MIWRL, data); + spi_write(spi_device, MIWRH, data>>8); + + /* wait until the PHY write completes. */ + while(spi_read(spi_device, MISTAT) & MISTAT_BUSY) + { + _delay_us(15); + } +} + +static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device) +{ + uint32_t level; + + /* switch to bank 0 */ + enc28j60_set_bank(spi_device, EIE); + + /* get last interrupt level */ + level = spi_read(spi_device, EIE); + /* disable interrutps */ + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, level); + + return level; +} + +static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level) +{ + /* switch to bank 0 */ + enc28j60_set_bank(spi_device, EIE); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, level); +} + +/* + * Access the PHY to determine link status + */ +static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device) +{ + uint16_t reg; + int duplex; + + reg = enc28j60_phy_read(spi_device, PHSTAT2); + duplex = reg & PHSTAT2_DPXSTAT; + + if (reg & PHSTAT2_LSTAT) + { + /* on */ + return RT_TRUE; + } + else + { + /* off */ + return RT_FALSE; + } +} + + +/************************* RT-Thread Device Interface *************************/ +void enc28j60_isr(void) +{ + eth_device_ready(&enc28j60_dev.parent); + NET_DEBUG("enc28j60_isr\r\n"); +} + +static void _tx_chain_init(void) +{ + enc28j60_tx_list[0].next = &enc28j60_tx_list[1]; + enc28j60_tx_list[1].next = &enc28j60_tx_list[0]; + + enc28j60_tx_list[0].prev = &enc28j60_tx_list[1]; + enc28j60_tx_list[1].prev = &enc28j60_tx_list[0]; + + enc28j60_tx_list[0].addr = TXSTART_INIT; + enc28j60_tx_list[1].addr = TXSTART_INIT + MAX_TX_PACKAGE_SIZE; + + enc28j60_tx_list[0].free = RT_TRUE; + enc28j60_tx_list[1].free = RT_TRUE; + + tx_current = &enc28j60_tx_list[0]; + tx_ack = tx_current; +} + +/* initialize the interface */ +static rt_err_t enc28j60_init(rt_device_t dev) +{ + struct net_device * enc28j60 = (struct net_device *)dev; + struct rt_spi_device * spi_device = enc28j60->spi_device; + + enc28j60_lock(dev); + + _tx_chain_init(); + + // perform system reset + spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); + rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */ + + NextPacketPtr = RXSTART_INIT; + + // Rx start + spi_write(spi_device, ERXSTL, RXSTART_INIT&0xFF); + spi_write(spi_device, ERXSTH, RXSTART_INIT>>8); + // set receive pointer address + spi_write(spi_device, ERXRDPTL, RXSTOP_INIT&0xFF); + spi_write(spi_device, ERXRDPTH, RXSTOP_INIT>>8); + // RX end + spi_write(spi_device, ERXNDL, RXSTOP_INIT&0xFF); + spi_write(spi_device, ERXNDH, RXSTOP_INIT>>8); + + // TX start + spi_write(spi_device, ETXSTL, TXSTART_INIT&0xFF); + spi_write(spi_device, ETXSTH, TXSTART_INIT>>8); + // set transmission pointer address + spi_write(spi_device, EWRPTL, TXSTART_INIT&0xFF); + spi_write(spi_device, EWRPTH, TXSTART_INIT>>8); + // TX end + spi_write(spi_device, ETXNDL, TXSTOP_INIT&0xFF); + spi_write(spi_device, ETXNDH, TXSTOP_INIT>>8); + + // do bank 1 stuff, packet filter: + // For broadcast packets we allow only ARP packtets + // All other packets should be unicast only for our mac (MAADR) + // + // The pattern to match on is therefore + // Type ETH.DST + // ARP BROADCAST + // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 + // in binary these poitions are:11 0000 0011 1111 + // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 + spi_write(spi_device, ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_BCEN); + + // do bank 2 stuff + // enable MAC receive + spi_write(spi_device, MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); + // enable automatic padding to 60bytes and CRC operations + // spi_write_op(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX); + // bring MAC out of reset + + // set inter-frame gap (back-to-back) + // spi_write(MABBIPG, 0x12); + spi_write(spi_device, MABBIPG, 0x15); + + spi_write(spi_device, MACON4, MACON4_DEFER); + spi_write(spi_device, MACLCON2, 63); + + // set inter-frame gap (non-back-to-back) + spi_write(spi_device, MAIPGL, 0x12); + spi_write(spi_device, MAIPGH, 0x0C); + + // Set the maximum packet size which the controller will accept + // Do not send packets longer than MAX_FRAMELEN: + spi_write(spi_device, MAMXFLL, MAX_FRAMELEN&0xFF); + spi_write(spi_device, MAMXFLH, MAX_FRAMELEN>>8); + + // do bank 3 stuff + // write MAC address + // NOTE: MAC address in ENC28J60 is byte-backward + spi_write(spi_device, MAADR0, enc28j60->dev_addr[5]); + spi_write(spi_device, MAADR1, enc28j60->dev_addr[4]); + spi_write(spi_device, MAADR2, enc28j60->dev_addr[3]); + spi_write(spi_device, MAADR3, enc28j60->dev_addr[2]); + spi_write(spi_device, MAADR4, enc28j60->dev_addr[1]); + spi_write(spi_device, MAADR5, enc28j60->dev_addr[0]); + + /* output off */ + spi_write(spi_device, ECOCON, 0x00); + + // enc28j60_phy_write(PHCON1, 0x00); + enc28j60_phy_write(spi_device, PHCON1, PHCON1_PDPXMD); // full duplex + // no loopback of transmitted frames + enc28j60_phy_write(spi_device, PHCON2, PHCON2_HDLDIS); + + enc28j60_set_bank(spi_device, ECON2); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_AUTOINC); + + // switch to bank 0 + enc28j60_set_bank(spi_device, ECON1); + // enable all interrutps + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, 0xFF); + // enable packet reception + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + + /* clock out */ + enc28j60_clkout(spi_device, 2); + + enc28j60_phy_write(spi_device, PHLCON, 0xD76); //0x476 + rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */ + + enc28j60_unlock(dev); + return RT_EOK; +} + +/* control the interface */ +static rt_err_t enc28j60_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + struct net_device * enc28j60 = (struct net_device *)dev; + switch(cmd) + { + case NIOCTL_GADDR: + /* get mac address */ + if(args) rt_memcpy(args, enc28j60->dev_addr, 6); + else return -RT_ERROR; + break; + + default : + break; + } + + return RT_EOK; +} + +/* Open the ethernet interface */ +static rt_err_t enc28j60_open(rt_device_t dev, uint16_t oflag) +{ + return RT_EOK; +} + +/* Close the interface */ +static rt_err_t enc28j60_close(rt_device_t dev) +{ + return RT_EOK; +} + +/* Read */ +static rt_size_t enc28j60_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return RT_EOK; +} + +/* Write */ +static rt_size_t enc28j60_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +/* ethernet device interface */ +/* Transmit packet. */ +static rt_err_t enc28j60_tx( rt_device_t dev, struct pbuf* p) +{ + struct net_device * enc28j60 = (struct net_device *)dev; + struct rt_spi_device * spi_device = enc28j60->spi_device; + struct pbuf* q; + rt_uint32_t level; +#ifdef ETH_TX_DUMP + rt_size_t dump_count = 0; + rt_uint8_t * dump_ptr; + rt_size_t dump_i; +#endif + + if(tx_current->free == RT_FALSE) + { + NET_DEBUG("[Tx] no empty buffer!\r\n"); + while(tx_current->free == RT_FALSE) + { + rt_err_t result; + rt_uint32_t recved; + + /* there is no block yet, wait a flag */ + result = rt_event_recv(&tx_event, 0x01, + RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved); + + RT_ASSERT(result == RT_EOK); + } + NET_DEBUG("[Tx] wait empty buffer done!\r\n"); + } + + enc28j60_lock(dev); + + /* disable enc28j60 interrupt */ + level = enc28j60_interrupt_disable(spi_device); + + // Set the write pointer to start of transmit buffer area +// spi_write(EWRPTL, TXSTART_INIT&0xFF); +// spi_write(EWRPTH, TXSTART_INIT>>8); + spi_write(spi_device, EWRPTL, (tx_current->addr)&0xFF); + spi_write(spi_device, EWRPTH, (tx_current->addr)>>8); + // Set the TXND pointer to correspond to the packet size given + tx_current->len = p->tot_len; +// spi_write(ETXNDL, (TXSTART_INIT+ p->tot_len + 1)&0xFF); +// spi_write(ETXNDH, (TXSTART_INIT+ p->tot_len + 1)>>8); + + // write per-packet control byte (0x00 means use macon3 settings) + spi_write_op(spi_device, ENC28J60_WRITE_BUF_MEM, 0, 0x00); + +#ifdef ETH_TX_DUMP + NET_DEBUG("tx_dump, size:%d\r\n", p->tot_len); +#endif + for (q = p; q != NULL; q = q->next) + { + uint8_t cmd = ENC28J60_WRITE_BUF_MEM; + rt_spi_send_then_send(enc28j60->spi_device, &cmd, 1, q->payload, q->len); +#ifdef ETH_RX_DUMP + dump_ptr = q->payload; + for(dump_i=0; dump_i<q->len; dump_i++) + { + NET_DEBUG("%02x ", *dump_ptr); + if( ((dump_count+1)%8) == 0 ) + { + NET_DEBUG(" "); + } + if( ((dump_count+1)%16) == 0 ) + { + NET_DEBUG("\r\n"); + } + dump_count++; + dump_ptr++; + } +#endif + } +#ifdef ETH_RX_DUMP + NET_DEBUG("\r\n"); +#endif + + // send the contents of the transmit buffer onto the network + if(tx_current == tx_ack) + { + NET_DEBUG("[Tx] stop, restart!\r\n"); + // TX start + spi_write(spi_device, ETXSTL, (tx_current->addr)&0xFF); + spi_write(spi_device, ETXSTH, (tx_current->addr)>>8); + // TX end + spi_write(spi_device, ETXNDL, (tx_current->addr + tx_current->len)&0xFF); + spi_write(spi_device, ETXNDH, (tx_current->addr + tx_current->len)>>8); + + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + } + else + { + NET_DEBUG("[Tx] busy, add to chain!\r\n"); + } + + tx_current->free = RT_FALSE; + tx_current = tx_current->next; + + /* Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. */ + if( (spi_read(spi_device, EIR) & EIR_TXERIF) ) + { + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); + } + + /* enable enc28j60 interrupt */ + enc28j60_interrupt_enable(spi_device, level); + + enc28j60_unlock(dev); + + return RT_EOK; +} + +/* recv packet. */ +static struct pbuf *enc28j60_rx(rt_device_t dev) +{ + struct net_device * enc28j60 = (struct net_device *)dev; + struct rt_spi_device * spi_device = enc28j60->spi_device; + struct pbuf* p = RT_NULL; + + uint8_t eir, eir_clr; + uint32_t pk_counter; + rt_uint32_t level; + rt_uint32_t len; + rt_uint16_t rxstat; + + enc28j60_lock(dev); + + /* disable enc28j60 interrupt */ + level = enc28j60_interrupt_disable(spi_device); + + /* get EIR */ + eir = spi_read(spi_device, EIR); + + while(eir & ~EIR_PKTIF) + { + eir_clr = 0; + + /* clear PKTIF */ + if (eir & EIR_PKTIF) + { + NET_DEBUG("EIR_PKTIF\r\n"); + + /* switch to bank 0. */ + enc28j60_set_bank(spi_device, EIE); + /* disable rx interrutps. */ + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, EIE_PKTIE); + eir_clr |= EIR_PKTIF; +// enc28j60_set_bank(spi_device, EIR); +// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_PKTIF); + } + + /* clear DMAIF */ + if (eir & EIR_DMAIF) + { + NET_DEBUG("EIR_DMAIF\r\n"); + eir_clr |= EIR_DMAIF; +// enc28j60_set_bank(spi_device, EIR); +// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_DMAIF); + } + + /* LINK changed handler */ + if ( eir & EIR_LINKIF) + { + rt_bool_t link_status; + + NET_DEBUG("EIR_LINKIF\r\n"); + link_status = enc28j60_check_link_status(spi_device); + + /* read PHIR to clear the flag */ + enc28j60_phy_read(spi_device, PHIR); + eir_clr |= EIR_LINKIF; +// enc28j60_set_bank(spi_device, EIR); +// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_LINKIF); + + eth_device_linkchange(&(enc28j60->parent), link_status); + } + + if (eir & EIR_TXIF) + { + /* A frame has been transmitted. */ + enc28j60_set_bank(spi_device, EIR); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXIF); + + tx_ack->free = RT_TRUE; + tx_ack = tx_ack->next; + if(tx_ack->free == RT_FALSE) + { + NET_DEBUG("[tx isr] Tx chain not empty, continue send the next pkt!\r\n"); + // TX start + spi_write(spi_device, ETXSTL, (tx_ack->addr)&0xFF); + spi_write(spi_device, ETXSTH, (tx_ack->addr)>>8); + // TX end + spi_write(spi_device, ETXNDL, (tx_ack->addr + tx_ack->len)&0xFF); + spi_write(spi_device, ETXNDH, (tx_ack->addr + tx_ack->len)>>8); + + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + } + else + { + NET_DEBUG("[tx isr] Tx chain empty, stop!\r\n"); + } + + /* set event */ + rt_event_send(&tx_event, 0x01); + } + + /* wake up handler */ + if ( eir & EIR_WOLIF) + { + NET_DEBUG("EIR_WOLIF\r\n"); + eir_clr |= EIR_WOLIF; +// enc28j60_set_bank(spi_device, EIR); +// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_WOLIF); + } + + /* TX Error handler */ + if ((eir & EIR_TXERIF) != 0) + { + NET_DEBUG("EIR_TXERIF re-start tx chain!\r\n"); + enc28j60_set_bank(spi_device, ECON1); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); + eir_clr |= EIR_TXERIF; +// enc28j60_set_bank(spi_device, EIR); +// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF); + + /* re-init tx chain */ + _tx_chain_init(); + } + + /* RX Error handler */ + if ((eir & EIR_RXERIF) != 0) + { + NET_DEBUG("EIR_RXERIF re-start rx!\r\n"); + + NextPacketPtr = RXSTART_INIT; + enc28j60_set_bank(spi_device, ECON1); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXRST); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXRST); + /* switch to bank 0. */ + enc28j60_set_bank(spi_device, ECON1); + /* enable packet reception. */ + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + eir_clr |= EIR_RXERIF; +// enc28j60_set_bank(spi_device, EIR); +// spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_RXERIF); + } + + enc28j60_set_bank(spi_device, EIR); + spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, eir_clr); + + eir = spi_read(spi_device, EIR); + } + + /* read pkt */ + pk_counter = spi_read(spi_device, EPKTCNT); + if(pk_counter) + { + /* Set the read pointer to the start of the received packet. */ + spi_write(spi_device, ERDPTL, (NextPacketPtr)); + spi_write(spi_device, ERDPTH, (NextPacketPtr)>>8); + + /* read the next packet pointer. */ + NextPacketPtr = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0); + NextPacketPtr |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8; + + /* read the packet length (see datasheet page 43). */ + len = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0); //0x54 + len |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8; //5554 + + len-=4; //remove the CRC count + + // read the receive status (see datasheet page 43) + rxstat = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0); + rxstat |= ((rt_uint16_t)spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0))<<8; + + // check CRC and symbol errors (see datasheet page 44, table 7-3): + // The ERXFCON.CRCEN is set by default. Normally we should not + // need to check this. + if ((rxstat & 0x80)==0) + { + // invalid + len=0; + } + else + { + /* allocation pbuf */ + p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM); + if (p != RT_NULL) + { + struct pbuf* q; +#ifdef ETH_RX_DUMP + rt_size_t dump_count = 0; + rt_uint8_t * dump_ptr; + rt_size_t dump_i; + NET_DEBUG("rx_dump, size:%d\r\n", len); +#endif + for (q = p; q != RT_NULL; q= q->next) + { + uint8_t cmd = ENC28J60_READ_BUF_MEM; + rt_spi_send_then_recv(spi_device, &cmd, 1, q->payload, q->len); +#ifdef ETH_RX_DUMP + dump_ptr = q->payload; + for(dump_i=0; dump_i<q->len; dump_i++) + { + NET_DEBUG("%02x ", *dump_ptr); + if( ((dump_count+1)%8) == 0 ) + { + NET_DEBUG(" "); + } + if( ((dump_count+1)%16) == 0 ) + { + NET_DEBUG("\r\n"); + } + dump_count++; + dump_ptr++; + } +#endif + } +#ifdef ETH_RX_DUMP + NET_DEBUG("\r\n"); +#endif + } + } + + /* Move the RX read pointer to the start of the next received packet. */ + /* This frees the memory we just read out. */ + spi_write(spi_device, ERXRDPTL, (NextPacketPtr)); + spi_write(spi_device, ERXRDPTH, (NextPacketPtr)>>8); + + /* decrement the packet counter indicate we are done with this packet. */ + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + } + else + { + /* switch to bank 0. */ + enc28j60_set_bank(spi_device, ECON1); + /* enable packet reception. */ + spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + + level |= EIE_PKTIE; + } + + /* enable enc28j60 interrupt */ + enc28j60_interrupt_enable(spi_device, level); + + enc28j60_unlock(dev); + + return p; +} + +rt_err_t enc28j60_attach(const char * spi_device_name) +{ + struct rt_spi_device * spi_device; + + spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name); + if(spi_device == RT_NULL) + { + NET_DEBUG("spi device %s not found!\r\n", spi_device_name); + return -RT_ENOSYS; + } + + /* config spi */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = 20 * 1000 * 1000; /* SPI Interface with Clock Speeds Up to 20 MHz */ + rt_spi_configure(spi_device, &cfg); + } /* config spi */ + + memset(&enc28j60_dev, 0, sizeof(enc28j60_dev)); + + rt_event_init(&tx_event, "eth_tx", RT_IPC_FLAG_FIFO); + enc28j60_dev.spi_device = spi_device; + + /* detect device */ + { + uint16_t value; + + /* perform system reset. */ + spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); + rt_thread_delay(1); /* delay 20ms */ + + enc28j60_dev.emac_rev = spi_read(spi_device, EREVID); + value = enc28j60_phy_read(spi_device, PHHID2); + enc28j60_dev.phy_rev = value&0x0F; + enc28j60_dev.phy_pn = (value>>4)&0x3F; + enc28j60_dev.phy_id = (enc28j60_phy_read(spi_device, PHHID1) | ((value>>10)<<16))<<3; + + if(enc28j60_dev.phy_id != 0x00280418) + { + NET_DEBUG("ENC28J60 PHY ID not correct!\r\n"); + NET_DEBUG("emac_rev:%d\r\n", enc28j60_dev.emac_rev); + NET_DEBUG("phy_rev:%02X\r\n", enc28j60_dev.phy_rev); + NET_DEBUG("phy_pn:%02X\r\n", enc28j60_dev.phy_pn); + NET_DEBUG("phy_id:%08X\r\n", enc28j60_dev.phy_id); + return RT_EIO; + } + } + + /* OUI 00-04-A3 (hex): Microchip Technology, Inc. */ + enc28j60_dev.dev_addr[0] = 0x00; + enc28j60_dev.dev_addr[1] = 0x04; + enc28j60_dev.dev_addr[2] = 0xA3; + /* set MAC address, only for test */ + enc28j60_dev.dev_addr[3] = 0x12; + enc28j60_dev.dev_addr[4] = 0x34; + enc28j60_dev.dev_addr[5] = 0x56; + + /* init rt-thread device struct */ + enc28j60_dev.parent.parent.type = RT_Device_Class_NetIf; + enc28j60_dev.parent.parent.init = enc28j60_init; + enc28j60_dev.parent.parent.open = enc28j60_open; + enc28j60_dev.parent.parent.close = enc28j60_close; + enc28j60_dev.parent.parent.read = enc28j60_read; + enc28j60_dev.parent.parent.write = enc28j60_write; + enc28j60_dev.parent.parent.control = enc28j60_control; + + /* init rt-thread ethernet device struct */ + enc28j60_dev.parent.eth_rx = enc28j60_rx; + enc28j60_dev.parent.eth_tx = enc28j60_tx; + + rt_mutex_init(&enc28j60_dev.lock, "enc28j60", RT_IPC_FLAG_FIFO); + + eth_device_init(&(enc28j60_dev.parent), "e0"); + + return RT_EOK; +} + +#ifdef RT_USING_FINSH +#include <finsh.h> +/* + * Debug routine to dump useful register contents + */ +static void enc28j60(void) +{ + struct rt_spi_device * spi_device = enc28j60_dev.spi_device; + enc28j60_lock(&enc28j60_dev); + + rt_kprintf("-- enc28j60 registers:\n"); + rt_kprintf("HwRevID: 0x%02X\n", spi_read(spi_device, EREVID)); + + rt_kprintf("Cntrl: ECON1 ECON2 ESTAT EIR EIE\n"); + rt_kprintf(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", + spi_read(spi_device, ECON1), + spi_read(spi_device, ECON2), + spi_read(spi_device, ESTAT), + spi_read(spi_device, EIR), + spi_read(spi_device, EIE)); + + rt_kprintf("MAC : MACON1 MACON3 MACON4\n"); + rt_kprintf(" 0x%02X 0x%02X 0x%02X\n", + spi_read(spi_device, MACON1), + spi_read(spi_device, MACON3), + spi_read(spi_device, MACON4)); + + rt_kprintf("Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n"); + rt_kprintf(" 0x%04X 0x%04X 0x%04X 0x%04X ", + (spi_read(spi_device, ERXSTH) << 8) | spi_read(spi_device, ERXSTL), + (spi_read(spi_device, ERXNDH) << 8) | spi_read(spi_device, ERXNDL), + (spi_read(spi_device, ERXWRPTH) << 8) | spi_read(spi_device, ERXWRPTL), + (spi_read(spi_device, ERXRDPTH) << 8) | spi_read(spi_device, ERXRDPTL)); + + rt_kprintf("0x%02X 0x%02X 0x%04X\n", + spi_read(spi_device, ERXFCON), + spi_read(spi_device, EPKTCNT), + (spi_read(spi_device, MAMXFLH) << 8) | spi_read(spi_device, MAMXFLL)); + + rt_kprintf("Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\n"); + rt_kprintf(" 0x%04X 0x%04X 0x%02X 0x%02X 0x%02X\n", + (spi_read(spi_device, ETXSTH) << 8) | spi_read(spi_device, ETXSTL), + (spi_read(spi_device, ETXNDH) << 8) | spi_read(spi_device, ETXNDL), + spi_read(spi_device, MACLCON1), + spi_read(spi_device, MACLCON2), + spi_read(spi_device, MAPHSUP)); + + rt_kprintf("PHY : PHCON1 PHSTAT1\r\n"); + rt_kprintf(" 0x%04X 0x%04X\r\n", + enc28j60_phy_read(spi_device, PHCON1), + enc28j60_phy_read(spi_device, PHSTAT1)); + + enc28j60_unlock(&enc28j60_dev); +} +FINSH_FUNCTION_EXPORT(enc28j60, dump enc28j60 registers); +#endif diff --git a/components/drivers/spi/enc28j60.h b/components/drivers/spi/enc28j60.h new file mode 100644 index 0000000000..8c647d5fc2 --- /dev/null +++ b/components/drivers/spi/enc28j60.h @@ -0,0 +1,329 @@ +#ifndef EN28J60_H_INCLUDED +#define EN28J60_H_INCLUDED + +#include <stdint.h> + +#include <rtthread.h> +#include <drivers/spi.h> +#include <netif/ethernetif.h> + +// ENC28J60 Control Registers +// Control register definitions are a combination of address, +// bank number, and Ethernet/MAC/PHY indicator bits. +// - Register address (bits 0-4) +// - Bank number (bits 5-6) +// - MAC/PHY indicator (bit 7) +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 +// All-bank registers +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F +// Bank 0 registers +#define ERDPTL (0x00|0x00) +#define ERDPTH (0x01|0x00) +#define EWRPTL (0x02|0x00) +#define EWRPTH (0x03|0x00) +#define ETXSTL (0x04|0x00) +#define ETXSTH (0x05|0x00) +#define ETXNDL (0x06|0x00) +#define ETXNDH (0x07|0x00) +#define ERXSTL (0x08|0x00) +#define ERXSTH (0x09|0x00) +#define ERXNDL (0x0A|0x00) +#define ERXNDH (0x0B|0x00) +#define ERXRDPTL (0x0C|0x00) +#define ERXRDPTH (0x0D|0x00) +#define ERXWRPTL (0x0E|0x00) +#define ERXWRPTH (0x0F|0x00) +#define EDMASTL (0x10|0x00) +#define EDMASTH (0x11|0x00) +#define EDMANDL (0x12|0x00) +#define EDMANDH (0x13|0x00) +#define EDMADSTL (0x14|0x00) +#define EDMADSTH (0x15|0x00) +#define EDMACSL (0x16|0x00) +#define EDMACSH (0x17|0x00) +// Bank 1 registers +#define EHT0 (0x00|0x20) +#define EHT1 (0x01|0x20) +#define EHT2 (0x02|0x20) +#define EHT3 (0x03|0x20) +#define EHT4 (0x04|0x20) +#define EHT5 (0x05|0x20) +#define EHT6 (0x06|0x20) +#define EHT7 (0x07|0x20) +#define EPMM0 (0x08|0x20) +#define EPMM1 (0x09|0x20) +#define EPMM2 (0x0A|0x20) +#define EPMM3 (0x0B|0x20) +#define EPMM4 (0x0C|0x20) +#define EPMM5 (0x0D|0x20) +#define EPMM6 (0x0E|0x20) +#define EPMM7 (0x0F|0x20) +#define EPMCSL (0x10|0x20) +#define EPMCSH (0x11|0x20) +#define EPMOL (0x14|0x20) +#define EPMOH (0x15|0x20) +#define EWOLIE (0x16|0x20) +#define EWOLIR (0x17|0x20) +#define ERXFCON (0x18|0x20) +#define EPKTCNT (0x19|0x20) +// Bank 2 registers +#define MACON1 (0x00|0x40|0x80) +#define MACON2 (0x01|0x40|0x80) +#define MACON3 (0x02|0x40|0x80) +#define MACON4 (0x03|0x40|0x80) +#define MABBIPG (0x04|0x40|0x80) +#define MAIPGL (0x06|0x40|0x80) +#define MAIPGH (0x07|0x40|0x80) +#define MACLCON1 (0x08|0x40|0x80) +#define MACLCON2 (0x09|0x40|0x80) +#define MAMXFLL (0x0A|0x40|0x80) +#define MAMXFLH (0x0B|0x40|0x80) +#define MAPHSUP (0x0D|0x40|0x80) +#define MICON (0x11|0x40|0x80) +#define MICMD (0x12|0x40|0x80) +#define MIREGADR (0x14|0x40|0x80) +#define MIWRL (0x16|0x40|0x80) +#define MIWRH (0x17|0x40|0x80) +#define MIRDL (0x18|0x40|0x80) +#define MIRDH (0x19|0x40|0x80) +// Bank 3 registers +#define MAADR1 (0x00|0x60|0x80) +#define MAADR0 (0x01|0x60|0x80) +#define MAADR3 (0x02|0x60|0x80) +#define MAADR2 (0x03|0x60|0x80) +#define MAADR5 (0x04|0x60|0x80) +#define MAADR4 (0x05|0x60|0x80) +#define EBSTSD (0x06|0x60) +#define EBSTCON (0x07|0x60) +#define EBSTCSL (0x08|0x60) +#define EBSTCSH (0x09|0x60) +#define MISTAT (0x0A|0x60|0x80) +#define EREVID (0x12|0x60) +#define ECOCON (0x15|0x60) +#define EFLOCON (0x17|0x60) +#define EPAUSL (0x18|0x60) +#define EPAUSH (0x19|0x60) +// PHY registers +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 + +// ENC28J60 ERXFCON Register Bit Definitions +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_PMEN 0x10 +#define ERXFCON_MPEN 0x08 +#define ERXFCON_HTEN 0x04 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 +// ENC28J60 EIE Register Bit Definitions +#define EIE_INTIE 0x80 +#define EIE_PKTIE 0x40 +#define EIE_DMAIE 0x20 +#define EIE_LINKIE 0x10 +#define EIE_TXIE 0x08 +#define EIE_WOLIE 0x04 +#define EIE_TXERIE 0x02 +#define EIE_RXERIE 0x01 +// ENC28J60 EIR Register Bit Definitions +#define EIR_PKTIF 0x40 +#define EIR_DMAIF 0x20 +#define EIR_LINKIF 0x10 +#define EIR_TXIF 0x08 +#define EIR_WOLIF 0x04 +#define EIR_TXERIF 0x02 +#define EIR_RXERIF 0x01 +// ENC28J60 ESTAT Register Bit Definitions +#define ESTAT_INT 0x80 +#define ESTAT_LATECOL 0x10 +#define ESTAT_RXBUSY 0x04 +#define ESTAT_TXABRT 0x02 +#define ESTAT_CLKRDY 0x01 +// ENC28J60 ECON2 Register Bit Definitions +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 +#define ECON2_PWRSV 0x20 +#define ECON2_VRPS 0x08 +// ENC28J60 ECON1 Register Bit Definitions +#define ECON1_TXRST 0x80 +#define ECON1_RXRST 0x40 +#define ECON1_DMAST 0x20 +#define ECON1_CSUMEN 0x10 +#define ECON1_TXRTS 0x08 +#define ECON1_RXEN 0x04 +#define ECON1_BSEL1 0x02 +#define ECON1_BSEL0 0x01 +// ENC28J60 MACON1 Register Bit Definitions +#define MACON1_LOOPBK 0x10 +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_PASSALL 0x02 +#define MACON1_MARXEN 0x01 +// ENC28J60 MACON2 Register Bit Definitions +#define MACON2_MARST 0x80 +#define MACON2_RNDRST 0x40 +#define MACON2_MARXRST 0x08 +#define MACON2_RFUNRST 0x04 +#define MACON2_MATXRST 0x02 +#define MACON2_TFUNRST 0x01 +// ENC28J60 MACON3 Register Bit Definitions +#define MACON3_PADCFG2 0x80 +#define MACON3_PADCFG1 0x40 +#define MACON3_PADCFG0 0x20 +#define MACON3_TXCRCEN 0x10 +#define MACON3_PHDRLEN 0x08 +#define MACON3_HFRMLEN 0x04 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 +// ENC28J60 MACON4 Register Bit Definitions +#define MACON4_DEFER (1<<6) +#define MACON4_BPEN (1<<5) +#define MACON4_NOBKOFF (1<<4) +// ENC28J60 MICMD Register Bit Definitions +#define MICMD_MIISCAN 0x02 +#define MICMD_MIIRD 0x01 +// ENC28J60 MISTAT Register Bit Definitions +#define MISTAT_NVALID 0x04 +#define MISTAT_SCAN 0x02 +#define MISTAT_BUSY 0x01 +// ENC28J60 PHY PHCON1 Register Bit Definitions +#define PHCON1_PRST 0x8000 +#define PHCON1_PLOOPBK 0x4000 +#define PHCON1_PPWRSV 0x0800 +#define PHCON1_PDPXMD 0x0100 +// ENC28J60 PHY PHSTAT1 Register Bit Definitions +#define PHSTAT1_PFDPX 0x1000 +#define PHSTAT1_PHDPX 0x0800 +#define PHSTAT1_LLSTAT 0x0004 +#define PHSTAT1_JBSTAT 0x0002 +/* ENC28J60 PHY PHSTAT2 Register Bit Definitions */ +#define PHSTAT2_TXSTAT (1 << 13) +#define PHSTAT2_RXSTAT (1 << 12) +#define PHSTAT2_COLSTAT (1 << 11) +#define PHSTAT2_LSTAT (1 << 10) +#define PHSTAT2_DPXSTAT (1 << 9) +#define PHSTAT2_PLRITY (1 << 5) +// ENC28J60 PHY PHCON2 Register Bit Definitions +#define PHCON2_FRCLINK 0x4000 +#define PHCON2_TXDIS 0x2000 +#define PHCON2_JABBER 0x0400 +#define PHCON2_HDLDIS 0x0100 + +// ENC28J60 Packet Control Byte Bit Definitions +#define PKTCTRL_PHUGEEN 0x08 +#define PKTCTRL_PPADEN 0x04 +#define PKTCTRL_PCRCEN 0x02 +#define PKTCTRL_POVERRIDE 0x01 + +/* ENC28J60 Transmit Status Vector */ +#define TSV_TXBYTECNT 0 +#define TSV_TXCOLLISIONCNT 16 +#define TSV_TXCRCERROR 20 +#define TSV_TXLENCHKERROR 21 +#define TSV_TXLENOUTOFRANGE 22 +#define TSV_TXDONE 23 +#define TSV_TXMULTICAST 24 +#define TSV_TXBROADCAST 25 +#define TSV_TXPACKETDEFER 26 +#define TSV_TXEXDEFER 27 +#define TSV_TXEXCOLLISION 28 +#define TSV_TXLATECOLLISION 29 +#define TSV_TXGIANT 30 +#define TSV_TXUNDERRUN 31 +#define TSV_TOTBYTETXONWIRE 32 +#define TSV_TXCONTROLFRAME 48 +#define TSV_TXPAUSEFRAME 49 +#define TSV_BACKPRESSUREAPP 50 +#define TSV_TXVLANTAGFRAME 51 + +#define TSV_SIZE 7 +#define TSV_BYTEOF(x) ((x) / 8) +#define TSV_BITMASK(x) (1 << ((x) % 8)) +#define TSV_GETBIT(x, y) (((x)[TSV_BYTEOF(y)] & TSV_BITMASK(y)) ? 1 : 0) + +/* ENC28J60 Receive Status Vector */ +#define RSV_RXLONGEVDROPEV 16 +#define RSV_CARRIEREV 18 +#define RSV_CRCERROR 20 +#define RSV_LENCHECKERR 21 +#define RSV_LENOUTOFRANGE 22 +#define RSV_RXOK 23 +#define RSV_RXMULTICAST 24 +#define RSV_RXBROADCAST 25 +#define RSV_DRIBBLENIBBLE 26 +#define RSV_RXCONTROLFRAME 27 +#define RSV_RXPAUSEFRAME 28 +#define RSV_RXUNKNOWNOPCODE 29 +#define RSV_RXTYPEVLAN 30 + +#define RSV_SIZE 6 +#define RSV_BITMASK(x) (1 << ((x) - 16)) +#define RSV_GETBIT(x, y) (((x) & RSV_BITMASK(y)) ? 1 : 0) + +// SPI operation codes +#define ENC28J60_READ_CTRL_REG 0x00 +#define ENC28J60_READ_BUF_MEM 0x3A +#define ENC28J60_WRITE_CTRL_REG 0x40 +#define ENC28J60_WRITE_BUF_MEM 0x7A +#define ENC28J60_BIT_FIELD_SET 0x80 +#define ENC28J60_BIT_FIELD_CLR 0xA0 +#define ENC28J60_SOFT_RESET 0xFF + +// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata +// buffer boundaries applied to internal 8K ram +// the entire available packet buffer space is allocated +// + +#define MAX_TX_PACKAGE_SIZE (1536) + +// start with recbuf at 0/ +#define RXSTART_INIT 0x0 +// receive buffer end +#define RXSTOP_INIT (0x1FFF - MAX_TX_PACKAGE_SIZE*2) - 1 +// start TX buffer at 0x1FFF-0x0600, pace for one full ethernet frame (~1500 bytes) + +#define TXSTART_INIT (0x1FFF - MAX_TX_PACKAGE_SIZE*2) +// stp TX buffer at end of mem +#define TXSTOP_INIT 0x1FFF + +// max frame length which the conroller will accept: +#define MAX_FRAMELEN 1518 + +#define MAX_ADDR_LEN 6 + +struct net_device +{ + /* inherit from ethernet device */ + struct eth_device parent; + + /* interface address info. */ + rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */ + + rt_uint8_t emac_rev; + rt_uint8_t phy_rev; + rt_uint8_t phy_pn; + rt_uint32_t phy_id; + + /* spi device */ + struct rt_spi_device * spi_device; + struct rt_mutex lock; +}; + +/* export function */ +extern rt_err_t enc28j60_attach(const char * spi_device_name); +extern void enc28j60_isr(void); + +#endif // EN28J60_H_INCLUDED diff --git a/components/drivers/spi/spi_dev.c b/components/drivers/spi/spi_dev.c index b1f6e41a86..375a5e0fa1 100644 --- a/components/drivers/spi/spi_dev.c +++ b/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; diff --git a/components/drivers/spi/spi_flash_at45dbxx.c b/components/drivers/spi/spi_flash_at45dbxx.c new file mode 100644 index 0000000000..be474f7c65 --- /dev/null +++ b/components/drivers/spi/spi_flash_at45dbxx.c @@ -0,0 +1,437 @@ +/* + * File : rtdef.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-12-16 aozima the first version + */ + +#include <stdint.h> +#include "spi_flash_at45dbxx.h" + +#define FLASH_DEBUG +#define DMA_BUFFER_SIZE 512 + +#ifdef FLASH_DEBUG +#define FLASH_TRACE rt_kprintf +#else +#define FLASH_TRACE(...) +#endif /**< #ifdef FLASH_DEBUG */ + +/* JEDEC Manufacturer��s ID */ +#define MF_ID (0x1F) /* atmel */ +#define DENSITY_CODE_011D (0x02) /* AT45DB011D Density Code : 00010 = 1-Mbit */ +#define DENSITY_CODE_021D (0x03) /* AT45DB021D Density Code : 00011 = 2-Mbit */ +#define DENSITY_CODE_041D (0x04) /* AT45DB041D Density Code : 00100 = 4-Mbit */ +#define DENSITY_CODE_081D (0x05) /* AT45DB081D Density Code : 00101 = 8-Mbit */ +#define DENSITY_CODE_161D (0x06) /* AT45DB161D Density Code : 00110 = 16-Mbit */ +#define DENSITY_CODE_321D (0x07) /* AT45DB321D Density Code : 00111 = 32-Mbit */ +#define DENSITY_CODE_642D (0x08) /* AT45DB642D Density Code : 01000 = 64-Mbit */ + +struct JEDEC_ID +{ + uint8_t manufacturer_id; /* Manufacturer ID */ + uint8_t density_code:5; /* Density Code */ + uint8_t family_code:3; /* Family Code */ + uint8_t version_code:5; /* Product Version Code */ + uint8_t mlc_code:3; /* MLC Code */ + uint8_t byte_count; /* Byte Count */ +}; + +#define AT45DB_BUFFER_1_WRITE 0x84 +#define AT45DB_BUFFER_2_WRITE 0x87 +#define AT45DB_BUFFER_1_READ 0xD4 +#define AT45DB_BUFFER_2_READ 0xD6 +#define AT45DB_B1_TO_MM_PAGE_PROG_WITH_ERASE 0x83 +#define AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86 +#define AT45DB_MM_PAGE_TO_B1_XFER 0x53 +#define AT45DB_MM_PAGE_TO_B2_XFER 0x55 +#define AT45DB_PAGE_ERASE 0x81 +#define AT45DB_SECTOR_ERASE 0x7C +#define AT45DB_READ_STATE_REGISTER 0xD7 +#define AT45DB_MM_PAGE_READ 0xD2 +#define AT45DB_MM_PAGE_PROG_THRU_BUFFER1 0x82 +#define AT45DB_CMD_JEDEC_ID 0x9F + +static struct spi_flash_at45dbxx spi_flash_at45dbxx; + +/*****************************************************************************/ +/*Status Register Format: */ +/* ------------------------------------------------------------------------- */ +/* | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | */ +/* |--------|--------|--------|--------|--------|--------|--------|--------| */ +/* |RDY/BUSY| COMP | device density | X | X | */ +/* ------------------------------------------------------------------------- */ +/* 0:busy | | AT45DB041:0111 | protect|page size */ +/* 1:ready | | AT45DB161:1011 | */ +/* --------------------------------------------------------------------------*/ +/*****************************************************************************/ +static uint8_t AT45DB_StatusRegisterRead(void) +{ + return rt_spi_sendrecv8(spi_flash_at45dbxx.rt_spi_device, AT45DB_READ_STATE_REGISTER); +} + +static void wait_busy(void) +{ + uint16_t i = 0; + while (i++ < 10000) + { + if (AT45DB_StatusRegisterRead() & 0x80) + { + return; + } + } + FLASH_TRACE("\r\nSPI_FLASH timeout!!!\r\n"); +} + +/* RT-Thread Device Driver Interface */ +static rt_err_t AT45DB_flash_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t AT45DB_flash_open(rt_device_t dev, rt_uint16_t oflag) +{ + + return RT_EOK; +} + +static rt_err_t AT45DB_flash_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t AT45DB_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + RT_ASSERT(dev != RT_NULL); + + if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) + { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) return -RT_ERROR; + + geometry->bytes_per_sector = 512; + geometry->sector_count = 4096; + geometry->block_size = 4096; /* block erase: 4k */ + } + + return RT_EOK; +} + +static rt_size_t AT45DB_flash_read_page_256(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + uint32_t index, nr; + uint8_t * read_buffer = buffer; + + nr = size; + + for (index = 0; index < nr; index++) + { + uint32_t page = pos; + uint8_t send_buffer[8]; + uint32_t i; + + for(i=0; i<sizeof(send_buffer); i++) + { + send_buffer[i] = 0; + } + + send_buffer[0] = AT45DB_MM_PAGE_READ; + send_buffer[1] = (uint8_t)(page >> 7); + send_buffer[2] = (uint8_t)(page << 1); + + rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 256); + read_buffer += 256; + page++; + } + + return size; +} + +static rt_size_t AT45DB_flash_read_page_512(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + uint32_t index, nr; + uint8_t * read_buffer = buffer; + + nr = size; + + for (index = 0; index < nr; index++) + { + uint32_t page = pos; + uint8_t send_buffer[8]; + uint32_t i; + + for(i=0; i<sizeof(send_buffer); i++) + { + send_buffer[i] = 0; + } + + send_buffer[0] = AT45DB_MM_PAGE_READ; + send_buffer[1] = (uint8_t)(page >> 6); + send_buffer[2] = (uint8_t)(page << 2); + + rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 512); + read_buffer += 512; + page++; + } + + return size; +} + +static rt_size_t AT45DB_flash_read_page_1024(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + uint32_t index, nr; + uint8_t * read_buffer = buffer; + + nr = size; + + for (index = 0; index < nr; index++) + { + uint32_t page = pos; + uint8_t send_buffer[8]; + uint32_t i; + + for(i=0; i<sizeof(send_buffer); i++) + { + send_buffer[i] = 0; + } + + send_buffer[0] = AT45DB_MM_PAGE_READ; + send_buffer[1] = (uint8_t)(page >> 5); + send_buffer[2] = (uint8_t)(page << 3); + + rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 1024); + read_buffer += 1024; + page++; + } + + return size; +} + +static rt_size_t AT45DB_flash_write_page_256(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint32_t index, nr; + const uint8_t * write_buffer = buffer; + + nr = size; + + for (index = 0; index < nr; index++) + { + uint32_t page = pos; + uint8_t send_buffer[4]; + + send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1; + send_buffer[1] = (uint8_t) (page >> 7); + send_buffer[2] = (uint8_t) (page << 1); + send_buffer[3] = 0; + + rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 256); + + write_buffer += 256; + page++; + + wait_busy(); + } + + return size; +} + +static rt_size_t AT45DB_flash_write_page_512(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint32_t index, nr; + const uint8_t * write_buffer = buffer; + + nr = size; + + for (index = 0; index < nr; index++) + { + uint32_t page = pos; + uint8_t send_buffer[4]; + + send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1; + send_buffer[1] = (uint8_t) (page >> 6); + send_buffer[2] = (uint8_t) (page << 2); + send_buffer[3] = 0; + + rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 512); + + write_buffer += 512; + page++; + + wait_busy(); + } + + return size; +} + +static rt_size_t AT45DB_flash_write_page_1024(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint32_t index, nr; + const uint8_t * write_buffer = buffer; + + nr = size; + + for (index = 0; index < nr; index++) + { + uint32_t page = pos; + uint8_t send_buffer[4]; + + send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1; + send_buffer[1] = (uint8_t) (page >> 5); + send_buffer[2] = (uint8_t) (page << 3); + send_buffer[3] = 0; + + rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 1024); + + write_buffer += 1024; + page++; + + wait_busy(); + } + + return size; +} + +rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name) +{ + struct rt_spi_device * rt_spi_device; + struct JEDEC_ID * JEDEC_ID; + + rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name); + if(rt_spi_device == RT_NULL) + { + FLASH_TRACE("spi device %s not found!\r\n", spi_device_name); + return -RT_ENOSYS; + } + spi_flash_at45dbxx.rt_spi_device = rt_spi_device; + + /* config spi */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 and 3 */ + cfg.max_hz = 66000000; /* Atmel RapidS Serial Interface: 66MHz Maximum Clock Frequency */ + rt_spi_configure(spi_flash_at45dbxx.rt_spi_device, &cfg); + } + + /* read JEDEC ID */ + { + uint8_t cmd; + uint8_t id_recv[6]; + JEDEC_ID = (struct JEDEC_ID *)id_recv; + + cmd = AT45DB_CMD_JEDEC_ID; + rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, &cmd, 1, id_recv, 6); + + /**< 1FH = Atmel */ + /**< 001 = Atmel DataFlash */ + if(JEDEC_ID->manufacturer_id != 0x1F || JEDEC_ID->family_code != 0x01) + { + FLASH_TRACE("Manufacturer��s ID or Memory Type error!\r\n"); + FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]); + return -RT_ENOSYS; + } + + if(JEDEC_ID->density_code == DENSITY_CODE_011D) + { + /**< AT45DB011D Density Code : 00010 = 1-Mbit */ + FLASH_TRACE("AT45DB011D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */ + spi_flash_at45dbxx.geometry.sector_count = 512; /* 1-Mbit / 8 / 256 = 512 */ + spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */ + } + else if(JEDEC_ID->density_code == DENSITY_CODE_021D) + { + /**< AT45DB021D Density Code : 00011 = 2-Mbit */ + FLASH_TRACE("AT45DB021D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */ + spi_flash_at45dbxx.geometry.sector_count = 512*2; /* 2-Mbit / 8 / 256 = 1024 */ + spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */ + } + else if(JEDEC_ID->density_code == DENSITY_CODE_041D) + { + /**< AT45DB041D Density Code : 00100 = 4-Mbit */ + FLASH_TRACE("AT45DB041D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */ + spi_flash_at45dbxx.geometry.sector_count = 512*4; /* 4-Mbit / 8 / 256 = 2048 */ + spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */ + } + else if(JEDEC_ID->density_code == DENSITY_CODE_081D) + { + /**< AT45DB081D Density Code : 00101 = 8-Mbit */ + FLASH_TRACE("AT45DB081D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */ + spi_flash_at45dbxx.geometry.sector_count = 512*8; /* 8-Mbit / 8 / 256 = 4096 */ + spi_flash_at45dbxx.geometry.block_size = 1024*2; /* Block Erase (2-Kbytes) */ + } + else if(JEDEC_ID->density_code == DENSITY_CODE_161D) + { + /**< AT45DB161D Density Code : 00110 = 16-Mbit */ + FLASH_TRACE("AT45DB161D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */ + spi_flash_at45dbxx.geometry.sector_count = 256*16; /* 16-Mbit / 8 / 512 = 4096 */ + spi_flash_at45dbxx.geometry.block_size = 1024*4; /* Block Erase (4-Kbytes) */ + } + else if(JEDEC_ID->density_code == DENSITY_CODE_321D) + { + /**< AT45DB321D Density Code : 00111 = 32-Mbit */ + FLASH_TRACE("AT45DB321D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */ + spi_flash_at45dbxx.geometry.sector_count = 256*32; /* 32-Mbit / 8 / 512 = 8192 */ + spi_flash_at45dbxx.geometry.block_size = 1024*4; /* Block Erase (4-Kbytes) */ + } + else if(JEDEC_ID->density_code == DENSITY_CODE_642D) + { + /**< AT45DB642D Density Code : 01000 = 64-Mbit */ + FLASH_TRACE("AT45DB642D detection\r\n"); + spi_flash_at45dbxx.geometry.bytes_per_sector = 1024; /* Page Erase (1 Kbyte) */ + spi_flash_at45dbxx.geometry.sector_count = 128*64; /* 64-Mbit / 8 / 1024 = 8192 */ + spi_flash_at45dbxx.geometry.block_size = 1024*8; /* Block Erase (8 Kbytes) */ + } + else + { + FLASH_TRACE("Memory Capacity error!\r\n"); + return -RT_ENOSYS; + } + } + + /* register device */ + spi_flash_at45dbxx.flash_device.type = RT_Device_Class_Block; + spi_flash_at45dbxx.flash_device.init = AT45DB_flash_init; + spi_flash_at45dbxx.flash_device.open = AT45DB_flash_open; + spi_flash_at45dbxx.flash_device.close = AT45DB_flash_close; + spi_flash_at45dbxx.flash_device.control = AT45DB_flash_control; + + if(JEDEC_ID->density_code == DENSITY_CODE_642D) + { + spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_1024; + spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_1024; + } + else if(JEDEC_ID->density_code == DENSITY_CODE_161D + || JEDEC_ID->density_code == DENSITY_CODE_321D ) + { + spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_512; + spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_512; + } + else + { + spi_flash_at45dbxx.flash_device.read = AT45DB_flash_read_page_256; + spi_flash_at45dbxx.flash_device.write = AT45DB_flash_write_page_256; + } + + /* no private */ + spi_flash_at45dbxx.flash_device.user_data = RT_NULL; + + rt_device_register(&spi_flash_at45dbxx.flash_device, flash_device_name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); + + return RT_EOK; +} diff --git a/components/drivers/spi/spi_flash_at45dbxx.h b/components/drivers/spi/spi_flash_at45dbxx.h new file mode 100644 index 0000000000..9b72cf0a0f --- /dev/null +++ b/components/drivers/spi/spi_flash_at45dbxx.h @@ -0,0 +1,17 @@ +#ifndef SPI_FLASH_AT45DBXX_H_INCLUDED +#define SPI_FLASH_AT45DBXX_H_INCLUDED + +#include <rtthread.h> +#include <drivers/spi.h> + +struct spi_flash_at45dbxx +{ + struct rt_device flash_device; + struct rt_device_blk_geometry geometry; + struct rt_spi_device * rt_spi_device; +}; + +extern rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name); + + +#endif // SPI_FLASH_AT45DBXX_H_INCLUDED diff --git a/components/drivers/spi/spi_flash_sst25vfxx.c b/components/drivers/spi/spi_flash_sst25vfxx.c new file mode 100644 index 0000000000..f0e28b5584 --- /dev/null +++ b/components/drivers/spi/spi_flash_sst25vfxx.c @@ -0,0 +1,346 @@ +/* + * File : rtdef.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-12-16 aozima the first version + */ + +#include <stdint.h> +#include "spi_flash_sst25vfxx.h" + +#define FLASH_DEBUG + +#ifdef FLASH_DEBUG +#define FLASH_TRACE rt_kprintf +#else +#define FLASH_TRACE(...) +#endif /* #ifdef FLASH_DEBUG */ + +/* JEDEC Manufacturer��s ID */ +#define MF_ID (0xBF) +/* JEDEC Device ID : Memory Type */ +#define MT_ID (0x25) +/* JEDEC Device ID: Memory Capacity */ +#define MC_ID_SST25VF020B (0x8C) /* 2Mbit */ +#define MC_ID_SST25VF040B (0x8D) /* 4Mbit */ +#define MC_ID_SST25VF080B (0x8E) /* 8Mbit */ +#define MC_ID_SST25VF016B (0x41) /* 16Mbit */ +#define MC_ID_SST25VF032B (0x4A) /* 32Mbit */ +#define MC_ID_SST25VF064C (0x4B) /* 64Mbit */ + +/* command list */ +#define CMD_RDSR (0x05) +#define CMD_WRSR (0x01) +#define CMD_EWSR (0x50) +#define CMD_WRDI (0x04) +#define CMD_WREN (0x06) +#define CMD_READ (0x03) +#define CMD_FAST_READ (0x0B) +#define CMD_BP (0x02) +#define CMD_AAIP (0xAD) +#define CMD_ERASE_4K (0x20) +#define CMD_ERASE_32K (0x52) +#define CMD_ERASE_64K (0xD8) +#define CMD_ERASE_full (0xC7) +#define CMD_JEDEC_ID (0x9F) +#define CMD_EBSY (0x70) +#define CMD_DBSY (0x80) + +#define DUMMY (0xFF) + +static struct spi_flash_sst25vfxx spi_flash_sst25vfxx; + +static uint8_t sst25vfxx_read_status(struct spi_flash_sst25vfxx * spi_flash) +{ + return rt_spi_sendrecv8(spi_flash->rt_spi_device, CMD_RDSR); +} + +static void sst25vfxx_wait_busy(struct spi_flash_sst25vfxx * spi_flash) +{ + while( sst25vfxx_read_status(spi_flash) & (0x01)); +} + +/** \brief write N page on [page] + * + * \param page uint32_t unit : byte (4096 * N,1 page = 4096byte) + * \param buffer const uint8_t* + * \param size uint32_t unit : byte ( 4096*N ) + * \return uint32_t + * + */ +static uint32_t sst25vfxx_page_write(struct spi_flash_sst25vfxx * spi_flash, uint32_t page, const uint8_t * buffer, uint32_t size) +{ + uint32_t index; + uint32_t need_wirte = size; + uint8_t send_buffer[6]; + + page &= ~0xFFF; // page size = 4096byte + + send_buffer[0] = CMD_WREN; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_ERASE_4K; + send_buffer[1] = (page >> 16); + send_buffer[2] = (page >> 8); + send_buffer[3] = (page); + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 4); + + sst25vfxx_wait_busy(spi_flash); // wait erase done. + + send_buffer[0] = CMD_WREN; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_AAIP; + send_buffer[1] = (uint8_t)(page >> 16); + send_buffer[2] = (uint8_t)(page >> 8); + send_buffer[3] = (uint8_t)(page); + send_buffer[4] = *buffer++; + send_buffer[5] = *buffer++; + need_wirte -= 2; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 6); + + sst25vfxx_wait_busy(spi_flash); + + for(index=0; index < need_wirte/2; index++) + { + send_buffer[0] = CMD_AAIP; + send_buffer[1] = *buffer++; + send_buffer[2] = *buffer++; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 3); + sst25vfxx_wait_busy(spi_flash); + } + + send_buffer[0] = CMD_WRDI; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1); + + return size; +} + +/* RT-Thread device interface */ +static rt_err_t sst25vfxx_flash_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t sst25vfxx_flash_open(rt_device_t dev, rt_uint16_t oflag) +{ + rt_err_t result; + uint8_t send_buffer[2]; + struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev; + + /* lock spi flash */ + result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER); + if(result != RT_EOK) + { + return result; + } + + send_buffer[0] = CMD_DBSY; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_EWSR; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_WRSR; + send_buffer[1] = 0; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 2); + + /* release lock */ + rt_mutex_release(&(spi_flash->lock)); + + return RT_EOK; +} + +static rt_err_t sst25vfxx_flash_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t sst25vfxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + struct spi_flash_sst25vfxx * spi_flash; + + spi_flash = (struct spi_flash_sst25vfxx *)dev; + + RT_ASSERT(dev != RT_NULL); + + if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) + { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) return -RT_ERROR; + + geometry->bytes_per_sector = spi_flash->geometry.bytes_per_sector; + geometry->sector_count = spi_flash->geometry.sector_count; + geometry->block_size = spi_flash->geometry.block_size; + } + + return RT_EOK; +} + +static rt_size_t sst25vfxx_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_err_t result; + uint8_t send_buffer[4]; + struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev; + uint32_t offset = pos * spi_flash->geometry.bytes_per_sector; + + /* lock spi flash */ + result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER); + if(result != RT_EOK) + { + return 0; + } + + send_buffer[0] = CMD_WRDI; + rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_READ; + send_buffer[1] = (uint8_t)(offset>>16); + send_buffer[2] = (uint8_t)(offset>>8); + send_buffer[3] = (uint8_t)(offset); + rt_spi_send_then_recv(spi_flash->rt_spi_device, send_buffer, 4, buffer, size * spi_flash->geometry.bytes_per_sector); + + /* release lock */ + rt_mutex_release(&(spi_flash->lock)); + + return size; +} + +static rt_size_t sst25vfxx_flash_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + uint32_t i; + rt_err_t result; + const uint8_t * write_buffer = buffer; + struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev; + + /* lock spi flash */ + result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER); + if(result != RT_EOK) + { + return 0; + } + + for(i=0; i<size; i++) + { + sst25vfxx_page_write(spi_flash, + (pos + i) * spi_flash->geometry.bytes_per_sector, + write_buffer, + spi_flash->geometry.bytes_per_sector); + write_buffer += spi_flash->geometry.bytes_per_sector; + } + + /* release lock */ + rt_mutex_release(&(spi_flash->lock)); + + return size; +} + +rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name) +{ + struct rt_spi_device * rt_spi_device; + struct spi_flash_sst25vfxx * spi_flash = &spi_flash_sst25vfxx; + + rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name); + if(rt_spi_device == RT_NULL) + { + FLASH_TRACE("spi device %s not found!\r\n", spi_device_name); + return -RT_ENOSYS; + } + spi_flash->rt_spi_device = rt_spi_device; + + /* config spi */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */ + cfg.max_hz = 50000000; /* 50M */ + rt_spi_configure(spi_flash->rt_spi_device, &cfg); + } + + /* init flash */ + { + rt_uint8_t cmd; + rt_uint8_t id_recv[3]; + + cmd = CMD_WRDI; + rt_spi_send(spi_flash->rt_spi_device, &cmd, 1); + + /* read flash id */ + cmd = CMD_JEDEC_ID; + rt_spi_send_then_recv(spi_flash->rt_spi_device, &cmd, 1, id_recv, 3); + + if(id_recv[0] != MF_ID || id_recv[1] != MT_ID) + { + FLASH_TRACE("Manufacturer��s ID or Memory Type error!\r\n"); + FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]); + return -RT_ENOSYS; + } + + spi_flash->geometry.bytes_per_sector = 4096; + spi_flash->geometry.block_size = 4096; /* block erase: 4k */ + + if(id_recv[2] == MC_ID_SST25VF020B) + { + FLASH_TRACE("SST25VF020B detection\r\n"); + spi_flash->geometry.sector_count = 64; + } + else if(id_recv[2] == MC_ID_SST25VF040B) + { + FLASH_TRACE("SST25VF040B detection\r\n"); + spi_flash->geometry.sector_count = 128; + } + else if(id_recv[2] == MC_ID_SST25VF080B) + { + FLASH_TRACE("SST25VF080B detection\r\n"); + spi_flash->geometry.sector_count = 256; + } + else if(id_recv[2] == MC_ID_SST25VF016B) + { + FLASH_TRACE("SST25VF016B detection\r\n"); + spi_flash->geometry.sector_count = 512; + } + else if(id_recv[2] == MC_ID_SST25VF032B) + { + FLASH_TRACE("SST25VF032B detection\r\n"); + spi_flash->geometry.sector_count = 1024; + } + else if(id_recv[2] == MC_ID_SST25VF064C) + { + FLASH_TRACE("SST25VF064C detection\r\n"); + spi_flash->geometry.sector_count = 2048; + } + else + { + FLASH_TRACE("Memory Capacity error!\r\n"); + return -RT_ENOSYS; + } + } + + /* initialize mutex lock */ + rt_mutex_init(&spi_flash->lock, flash_device_name, RT_IPC_FLAG_PRIO); + + /* register device */ + spi_flash->flash_device.type = RT_Device_Class_Block; + spi_flash->flash_device.init = sst25vfxx_flash_init; + spi_flash->flash_device.open = sst25vfxx_flash_open; + spi_flash->flash_device.close = sst25vfxx_flash_close; + spi_flash->flash_device.read = sst25vfxx_flash_read; + spi_flash->flash_device.write = sst25vfxx_flash_write; + spi_flash->flash_device.control = sst25vfxx_flash_control; + /* no private */ + spi_flash->flash_device.user_data = RT_NULL; + + rt_device_register(&spi_flash->flash_device, flash_device_name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); + + return RT_EOK; +} diff --git a/components/drivers/spi/spi_flash_sst25vfxx.h b/components/drivers/spi/spi_flash_sst25vfxx.h new file mode 100644 index 0000000000..b4575c2b68 --- /dev/null +++ b/components/drivers/spi/spi_flash_sst25vfxx.h @@ -0,0 +1,32 @@ +/* + * File : rtdef.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-12-16 aozima the first version + */ + +#ifndef SPI_FLASH_SST25VFXX_H_INCLUDED +#define SPI_FLASH_SST25VFXX_H_INCLUDED + +#include <rtthread.h> +#include <drivers/spi.h> + +struct spi_flash_sst25vfxx +{ + struct rt_device flash_device; + struct rt_device_blk_geometry geometry; + struct rt_spi_device * rt_spi_device; + struct rt_mutex lock; +}; + +extern rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name); + + +#endif // SPI_FLASH_SST25VFXX_H_INCLUDED diff --git a/components/drivers/spi/spi_flash_w25qxx.c b/components/drivers/spi/spi_flash_w25qxx.c new file mode 100644 index 0000000000..bdcdbd83c1 --- /dev/null +++ b/components/drivers/spi/spi_flash_w25qxx.c @@ -0,0 +1,371 @@ +/* + * File : spi_flash_w25qxx.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-12-16 aozima the first version + * 2012-05-06 aozima can page write. + * 2012-08-23 aozima add flash lock. + * 2012-08-24 aozima fixed write status register BUG. + */ + +#include <stdint.h> +#include "spi_flash_w25qxx.h" + +#define FLASH_DEBUG + +#ifdef FLASH_DEBUG +#define FLASH_TRACE rt_kprintf +#else +#define FLASH_TRACE(...) +#endif /* #ifdef FLASH_DEBUG */ + +#define PAGE_SIZE 4096 + +/* JEDEC Manufacturer��s ID */ +#define MF_ID (0xEF) +/* JEDEC Device ID: Memory type and Capacity */ +#define MTC_W25Q16_BV_CL_CV (0x4015) /* W25Q16BV W25Q16CL W25Q16CV */ +#define MTC_W25Q16_DW (0x6015) /* W25Q16DW */ +#define MTC_W25Q32_BV (0x4016) /* W25Q32BV */ +#define MTC_W25Q32_DW (0x6016) /* W25Q32DW */ +#define MTC_W25Q64_BV_CV (0x4017) /* W25Q64BV W25Q64CV */ +#define MTC_W25Q64_DW (0x4017) /* W25Q64DW */ +#define MTC_W25Q128_BV (0x4018) /* W25Q128BV */ +#define MTC_W25Q256_FV (TBD) /* W25Q256FV */ + +/* command list */ +#define CMD_WRSR (0x01) /* Write Status Register */ +#define CMD_PP (0x02) /* Page Program */ +#define CMD_READ (0x03) /* Read Data */ +#define CMD_WRDI (0x04) /* Write Disable */ +#define CMD_RDSR1 (0x05) /* Read Status Register-1 */ +#define CMD_WREN (0x06) /* Write Enable */ +#define CMD_FAST_READ (0x0B) /* Fast Read */ +#define CMD_ERASE_4K (0x20) /* Sector Erase:4K */ +#define CMD_RDSR2 (0x35) /* Read Status Register-2 */ +#define CMD_ERASE_32K (0x52) /* 32KB Block Erase */ +#define CMD_JEDEC_ID (0x9F) /* Read JEDEC ID */ +#define CMD_ERASE_full (0xC7) /* Chip Erase */ +#define CMD_ERASE_64K (0xD8) /* 64KB Block Erase */ + +#define DUMMY (0xFF) + +static struct spi_flash_device spi_flash_device; + +static void flash_lock(struct spi_flash_device * flash_device) +{ + rt_mutex_take(&flash_device->lock, RT_WAITING_FOREVER); +} + +static void flash_unlock(struct spi_flash_device * flash_device) +{ + rt_mutex_release(&flash_device->lock); +} + +static uint8_t w25qxx_read_status(void) +{ + return rt_spi_sendrecv8(spi_flash_device.rt_spi_device, CMD_RDSR1); +} + +static void w25qxx_wait_busy(void) +{ + while( w25qxx_read_status() & (0x01)); +} + +/** \brief read [size] byte from [offset] to [buffer] + * + * \param offset uint32_t unit : byte + * \param buffer uint8_t* + * \param size uint32_t unit : byte + * \return uint32_t byte for read + * + */ +static uint32_t w25qxx_read(uint32_t offset, uint8_t * buffer, uint32_t size) +{ + uint8_t send_buffer[4]; + + send_buffer[0] = CMD_WRDI; + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_READ; + send_buffer[1] = (uint8_t)(offset>>16); + send_buffer[2] = (uint8_t)(offset>>8); + send_buffer[3] = (uint8_t)(offset); + + rt_spi_send_then_recv(spi_flash_device.rt_spi_device, + send_buffer, 4, + buffer, size); + + return size; +} + +/** \brief write N page on [page] + * + * \param page_addr uint32_t unit : byte (4096 * N,1 page = 4096byte) + * \param buffer const uint8_t* + * \return uint32_t + * + */ +uint32_t w25qxx_page_write(uint32_t page_addr, const uint8_t* buffer) +{ + uint32_t index; + uint8_t send_buffer[4]; + + RT_ASSERT((page_addr&0xFF) == 0); /* page addr must align to 256byte. */ + + send_buffer[0] = CMD_WREN; + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_ERASE_4K; + send_buffer[1] = (page_addr >> 16); + send_buffer[2] = (page_addr >> 8); + send_buffer[3] = (page_addr); + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 4); + + w25qxx_wait_busy(); // wait erase done. + + for(index=0; index < (PAGE_SIZE / 256); index++) + { + send_buffer[0] = CMD_WREN; + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_PP; + send_buffer[1] = (uint8_t)(page_addr >> 16); + send_buffer[2] = (uint8_t)(page_addr >> 8); + send_buffer[3] = (uint8_t)(page_addr); + + rt_spi_send_then_send(spi_flash_device.rt_spi_device, + send_buffer, + 4, + buffer, + 256); + + buffer += 256; + page_addr += 256; + w25qxx_wait_busy(); + } + + send_buffer[0] = CMD_WRDI; + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1); + + return PAGE_SIZE; +} + +/* RT-Thread device interface */ +static rt_err_t w25qxx_flash_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t w25qxx_flash_open(rt_device_t dev, rt_uint16_t oflag) +{ + uint8_t send_buffer[3]; + + flash_lock((struct spi_flash_device *)dev); + + send_buffer[0] = CMD_WREN; + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1); + + send_buffer[0] = CMD_WRSR; + send_buffer[1] = 0; + send_buffer[2] = 0; + rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 3); + + w25qxx_wait_busy(); + + flash_unlock((struct spi_flash_device *)dev); + + return RT_EOK; +} + +static rt_err_t w25qxx_flash_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t w25qxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + RT_ASSERT(dev != RT_NULL); + + if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) + { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) return -RT_ERROR; + + geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector; + geometry->sector_count = spi_flash_device.geometry.sector_count; + geometry->block_size = spi_flash_device.geometry.block_size; + } + + return RT_EOK; +} + +static rt_size_t w25qxx_flash_read(rt_device_t dev, + rt_off_t pos, + void* buffer, + rt_size_t size) +{ + flash_lock((struct spi_flash_device *)dev); + + w25qxx_read(pos*spi_flash_device.geometry.bytes_per_sector, + buffer, + size*spi_flash_device.geometry.bytes_per_sector); + + flash_unlock((struct spi_flash_device *)dev); + + return size; +} + +static rt_size_t w25qxx_flash_write(rt_device_t dev, + rt_off_t pos, + const void* buffer, + rt_size_t size) +{ + rt_size_t i = 0; + rt_size_t block = size; + const uint8_t * ptr = buffer; + + flash_lock((struct spi_flash_device *)dev); + + while(block--) + { + w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector, + ptr); + ptr += PAGE_SIZE; + i++; + } + + flash_unlock((struct spi_flash_device *)dev); + + return size; +} + +rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_name) +{ + struct rt_spi_device * rt_spi_device; + + /* initialize mutex */ + if (rt_mutex_init(&spi_flash_device.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK) + { + rt_kprintf("init sd lock mutex failed\n"); + return -RT_ENOSYS; + } + + rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name); + if(rt_spi_device == RT_NULL) + { + FLASH_TRACE("spi device %s not found!\r\n", spi_device_name); + return -RT_ENOSYS; + } + spi_flash_device.rt_spi_device = rt_spi_device; + + /* config spi */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */ + cfg.max_hz = 50 * 1000 * 1000; /* 50M */ + rt_spi_configure(spi_flash_device.rt_spi_device, &cfg); + } + + /* init flash */ + { + rt_uint8_t cmd; + rt_uint8_t id_recv[3]; + uint16_t memory_type_capacity; + + flash_lock(&spi_flash_device); + + cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */ + rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1); + + cmd = CMD_WRDI; + rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1); + + /* read flash id */ + cmd = CMD_JEDEC_ID; + rt_spi_send_then_recv(spi_flash_device.rt_spi_device, &cmd, 1, id_recv, 3); + + flash_unlock(&spi_flash_device); + + if(id_recv[0] != MF_ID) + { + FLASH_TRACE("Manufacturers ID error!\r\n"); + FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]); + return -RT_ENOSYS; + } + + spi_flash_device.geometry.bytes_per_sector = 4096; + spi_flash_device.geometry.block_size = 4096; /* block erase: 4k */ + + /* get memory type and capacity */ + memory_type_capacity = id_recv[1]; + memory_type_capacity = (memory_type_capacity << 8) | id_recv[2]; + + if(memory_type_capacity == MTC_W25Q128_BV) + { + FLASH_TRACE("W25Q128BV detection\r\n"); + spi_flash_device.geometry.sector_count = 4096; + } + else if(memory_type_capacity == MTC_W25Q64_BV_CV) + { + FLASH_TRACE("W25Q64BV or W25Q64CV detection\r\n"); + spi_flash_device.geometry.sector_count = 2048; + } + else if(memory_type_capacity == MTC_W25Q64_DW) + { + FLASH_TRACE("W25Q64DW detection\r\n"); + spi_flash_device.geometry.sector_count = 2048; + } + else if(memory_type_capacity == MTC_W25Q32_BV) + { + FLASH_TRACE("W25Q32BV detection\r\n"); + spi_flash_device.geometry.sector_count = 1024; + } + else if(memory_type_capacity == MTC_W25Q32_DW) + { + FLASH_TRACE("W25Q32DW detection\r\n"); + spi_flash_device.geometry.sector_count = 1024; + } + else if(memory_type_capacity == MTC_W25Q16_BV_CL_CV) + { + FLASH_TRACE("W25Q16BV or W25Q16CL or W25Q16CV detection\r\n"); + spi_flash_device.geometry.sector_count = 512; + } + else if(memory_type_capacity == MTC_W25Q16_DW) + { + FLASH_TRACE("W25Q16DW detection\r\n"); + spi_flash_device.geometry.sector_count = 512; + } + else + { + FLASH_TRACE("Memory Capacity error!\r\n"); + return -RT_ENOSYS; + } + } + + /* register device */ + spi_flash_device.flash_device.type = RT_Device_Class_Block; + spi_flash_device.flash_device.init = w25qxx_flash_init; + spi_flash_device.flash_device.open = w25qxx_flash_open; + spi_flash_device.flash_device.close = w25qxx_flash_close; + spi_flash_device.flash_device.read = w25qxx_flash_read; + spi_flash_device.flash_device.write = w25qxx_flash_write; + spi_flash_device.flash_device.control = w25qxx_flash_control; + /* no private */ + spi_flash_device.flash_device.user_data = RT_NULL; + + rt_device_register(&spi_flash_device.flash_device, flash_device_name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); + + return RT_EOK; +} diff --git a/components/drivers/spi/spi_flash_w25qxx.h b/components/drivers/spi/spi_flash_w25qxx.h new file mode 100644 index 0000000000..ebab35da33 --- /dev/null +++ b/components/drivers/spi/spi_flash_w25qxx.h @@ -0,0 +1,34 @@ +/* + * File : spi_flash_w25qxx.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-12-16 aozima the first version + * 2012-08-23 aozima add flash lock. + */ + +#ifndef SPI_FLASH_W25QXX_H_INCLUDED +#define SPI_FLASH_W25QXX_H_INCLUDED + +#include <rtthread.h> +#include <drivers/spi.h> + +struct spi_flash_device +{ + struct rt_device flash_device; + struct rt_device_blk_geometry geometry; + struct rt_spi_device * rt_spi_device; + struct rt_mutex lock; +}; + +extern rt_err_t w25qxx_init(const char * flash_device_name, + const char * spi_device_name); + + +#endif // SPI_FLASH_W25QXX_H_INCLUDED diff --git a/components/drivers/spi/spi_wifi_rw009.c b/components/drivers/spi/spi_wifi_rw009.c new file mode 100644 index 0000000000..f45d493717 --- /dev/null +++ b/components/drivers/spi/spi_wifi_rw009.c @@ -0,0 +1,590 @@ +/* + * File : spi_wifi_rw009.c + * This file is part of RT-Thread RTOS + * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-07-31 aozima the first version + */ + +#include <rtthread.h> +#include <drivers/spi.h> + +#include <netif/ethernetif.h> +#include <netif/etharp.h> +#include <lwip/icmp.h> +#include "lwipopts.h" + +#include "spi_wifi_rw009.h" + +#define SSID_NAME "AP_SSID" +#define SSID_PASSWORD "AP_passwd" + +//#define WIFI_DEBUG_ON +// #define ETH_RX_DUMP +// #define ETH_TX_DUMP + +#ifdef WIFI_DEBUG_ON +#define WIFI_DEBUG rt_kprintf("[WIFI] ");rt_kprintf +#else +#define WIFI_DEBUG(...) +#endif /* #ifdef WIFI_DEBUG_ON */ + +#define MAX_BUFFER_SIZE (sizeof(struct response) + MAX_DATA_LEN) +#define MAX_ADDR_LEN 6 +struct spi_wifi_eth +{ + /* inherit from ethernet device */ + struct eth_device parent; + + struct rt_spi_device *rt_spi_device; + + /* interface address info. */ + rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */ + rt_uint8_t active; + + struct rt_mempool spi_tx_mp; + struct rt_mempool spi_rx_mp; + + struct rt_mailbox spi_tx_mb; + struct rt_mailbox eth_rx_mb; + + int spi_tx_mb_pool[SPI_TX_POOL_SIZE]; + int eth_rx_mb_pool[SPI_TX_POOL_SIZE]; + + int spi_wifi_cmd_mb_pool[3]; + struct rt_mailbox spi_wifi_cmd_mb; + + ALIGN(4) + rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE]; + ALIGN(4) + rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE]; + + ALIGN(4) + uint8_t spi_hw_rx_buffer[MAX_BUFFER_SIZE]; +}; +static struct spi_wifi_eth spi_wifi_device; +static struct rt_event spi_wifi_data_event; + +static void resp_handler(struct spi_wifi_eth *wifi_device, struct spi_wifi_resp *resp) +{ + struct spi_wifi_resp *resp_return; + + switch (resp->cmd) + { + case SPI_WIFI_CMD_INIT: + WIFI_DEBUG("resp_handler SPI_WIFI_CMD_INIT\n"); + resp_return = (struct spi_wifi_resp *)rt_malloc(sizeof(struct spi_wifi_resp)); //TODO: + memcpy(resp_return, resp, 10); + rt_mb_send(&wifi_device->spi_wifi_cmd_mb, (rt_uint32_t)resp_return); + break; + + case SPI_WIFI_CMD_SCAN: + WIFI_DEBUG("resp_handler SPI_WIFI_CMD_SCAN\n"); + break; + + case SPI_WIFI_CMD_JOIN: + WIFI_DEBUG("resp_handler SPI_WIFI_CMD_JOIN\n"); + wifi_device->active = 1; + eth_device_linkchange(&wifi_device->parent, RT_TRUE); + break; + + default: + WIFI_DEBUG("resp_handler %d\n", resp->cmd); + break; + } + +} + +static rt_err_t spi_wifi_transfer(struct spi_wifi_eth *dev) +{ + struct pbuf *p = RT_NULL; + struct cmd_request cmd; + struct response resp; + + rt_err_t result; + const struct spi_data_packet *data_packet = RT_NULL; + + struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev; + struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device; + + spi_wifi_int_cmd(0); + while (spi_wifi_is_busy()); + WIFI_DEBUG("sequence start!\n"); + + memset(&cmd, 0, sizeof(struct cmd_request)); + cmd.magic1 = CMD_MAGIC1; + cmd.magic2 = CMD_MAGIC2; + + cmd.flag |= CMD_FLAG_MRDY; + + result = rt_mb_recv(&wifi_device->spi_tx_mb, + (rt_uint32_t *)&data_packet, + 0); + if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0)) + { + cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer); + //WIFI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len); + } + + rt_spi_send(rt_spi_device, &cmd, sizeof(cmd)); + while (spi_wifi_is_busy()); + + { + struct rt_spi_message message; + uint32_t max_data_len = 0; + + /* setup message */ + message.send_buf = RT_NULL; + message.recv_buf = &resp; + message.length = sizeof(resp); + message.cs_take = 1; + message.cs_release = 0; + + rt_spi_take_bus(rt_spi_device); + + /* transfer message */ + rt_spi_device->bus->ops->xfer(rt_spi_device, &message); + + if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2)) + { + WIFI_DEBUG("bad resp magic, abort!\n"); + goto _bad_resp_magic; + } + + if (resp.flag & RESP_FLAG_SRDY) + { + WIFI_DEBUG("RESP_FLAG_SRDY\n"); + max_data_len = cmd.M2S_len; + } + + if (resp.S2M_len) + { + WIFI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len); + if (resp.S2M_len > sizeof(struct spi_data_packet)) + { + WIFI_DEBUG("resp.S2M_len > sizeof(struct spi_data_packet), drop!\n"); + resp.S2M_len = 0;//drop + } + + if (resp.S2M_len > max_data_len) + max_data_len = resp.S2M_len; + } + + if (max_data_len == 0) + { + WIFI_DEBUG("no rx or tx data!\n"); + } + + //WIFI_DEBUG("max_data_len = %d\n", max_data_len); + +_bad_resp_magic: + /* setup message */ + message.send_buf = data_packet;//&tx_buffer; + message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer; + message.length = max_data_len; + message.cs_take = 0; + message.cs_release = 1; + + /* transfer message */ + rt_spi_device->bus->ops->xfer(rt_spi_device, &message); + + rt_spi_release_bus(rt_spi_device); + + if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY)) + { + rt_mp_free((void *)data_packet); + } + + if ((resp.S2M_len) && (resp.S2M_len <= MAX_DATA_LEN)) + { + data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer; + if (data_packet->data_type == data_type_eth_data) + { + + if (wifi_device->active) + { + p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM); + pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len); + + rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p); + eth_device_ready((struct eth_device *)dev); + } + else + { + WIFI_DEBUG("!active, RX drop.\n"); + } + } + else if (data_packet->data_type == data_type_resp) + { + WIFI_DEBUG("data_type_resp\n"); + resp_handler(dev, (struct spi_wifi_resp *)data_packet->buffer); + } + else + { + WIFI_DEBUG("data_type: %d, %dbyte\n", + data_packet->data_type, + data_packet->data_len); + } + } + } + spi_wifi_int_cmd(1); + + WIFI_DEBUG("sequence finish!\n\n"); + + if ((cmd.M2S_len == 0) && (resp.S2M_len == 0)) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP) +static void packet_dump(const char *msg, const struct pbuf *p) +{ + rt_uint32_t i; + rt_uint8_t *ptr = p->payload; + + rt_kprintf("%s %d byte\n", msg, p->tot_len); + + for (i = 0; i < p->tot_len; i++) + { + if ((i % 8) == 0) + { + rt_kprintf(" "); + } + if ((i % 16) == 0) + { + rt_kprintf("\r\n"); + } + rt_kprintf("%02x ", *ptr); + ptr++; + } + rt_kprintf("\n\n"); +} +#endif /* dump */ + +/* initialize the interface */ +static rt_err_t spi_wifi_eth_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t spi_wifi_eth_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t spi_wifi_eth_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_size_t spi_wifi_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_size_t spi_wifi_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + + +static rt_err_t spi_wifi_eth_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev; + struct spi_data_packet *data_packet; + struct spi_wifi_cmd *wifi_cmd; + struct spi_wifi_resp *resp; + + switch (cmd) + { + case NIOCTL_GADDR: + memcpy(args, wifi_device->dev_addr, 6); + break; + + case SPI_WIFI_CMD_INIT: + /* get mac address */ + if (args) + { + rt_err_t result; + + data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER); + // TODO: check result. + + wifi_cmd = (struct spi_wifi_cmd *)data_packet->buffer; + wifi_cmd->cmd = SPI_WIFI_CMD_INIT; + + data_packet->data_type = data_type_cmd; + data_packet->data_len = member_offset(struct spi_wifi_cmd, buffer) + 0; + + rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet); + rt_event_send(&spi_wifi_data_event, 1); + + result = rt_mb_recv(&wifi_device->spi_wifi_cmd_mb, + (rt_uint32_t *)&resp, + RT_WAITING_FOREVER); + + if ((result == RT_EOK) && (resp != RT_NULL)) + { + WIFI_DEBUG("resp cmd: %d\n", resp->cmd); + + rt_memcpy(args, resp->buffer, 6); + } + } + else return -RT_ERROR; + break; + + + case SPI_WIFI_CMD_SCAN: + + case SPI_WIFI_CMD_JOIN: + if (args) + { + struct cmd_join *cmd_join; + + data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER); + + wifi_cmd = (struct spi_wifi_cmd *)data_packet->buffer; + wifi_cmd->cmd = SPI_WIFI_CMD_JOIN; + cmd_join = (struct cmd_join *)wifi_cmd->buffer; + +#define WPA_SECURITY 0x00200000 +#define WPA2_SECURITY 0x00400000 + +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 + + + strncpy(cmd_join->ssid, SSID_NAME, SSID_NAME_LENGTH_MAX); + strncpy(cmd_join->passwd, SSID_PASSWORD, PASSWORD_LENGTH_MAX); + cmd_join->security = WPA2_SECURITY | TKIP_ENABLED | AES_ENABLED; + // cmd_join->security = WPA_SECURITY | TKIP_ENABLED; + data_packet->data_type = data_type_cmd; + data_packet->data_len = sizeof(struct cmd_join) + member_offset(struct spi_wifi_cmd, buffer); + + rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet); + rt_event_send(&spi_wifi_data_event, 1); + } + else return -RT_ERROR; + break; + + default : + break; + } + + return RT_EOK; +} + +/* transmit packet. */ +rt_err_t spi_wifi_eth_tx(rt_device_t dev, struct pbuf *p) +{ + rt_err_t result = RT_EOK; + struct spi_data_packet *data_packet; + struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev; + + if (!wifi_device->active) + { + WIFI_DEBUG("!active, TX drop!\n"); + return RT_EOK; + } + + /* get free tx buffer */ + data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER); + if (data_packet != RT_NULL) + { + data_packet->data_type = data_type_eth_data; + data_packet->data_len = p->tot_len; + + pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0); + + rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet); + eth_device_ready((struct eth_device *)dev); + } + else + return -RT_ERROR; + +#ifdef ETH_TX_DUMP + packet_dump("TX dump", p); +#endif /* ETH_TX_DUMP */ + + /* Return SUCCESS */ + return result; +} + +/* reception packet. */ +struct pbuf *spi_wifi_eth_rx(rt_device_t dev) +{ + struct pbuf *p = RT_NULL; + struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev; + + if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK) + { + return RT_NULL; + } + + + + return p; +} + +static void spi_wifi_data_thread_entry(void *parameter) +{ + rt_uint32_t e; + rt_err_t result; + + while (1) + { + /* receive first event */ + if (rt_event_recv(&spi_wifi_data_event, + 1, + RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, + RT_WAITING_FOREVER, + &e) != RT_EOK) + { + continue; + } + + result = spi_wifi_transfer(&spi_wifi_device); + + if (result == RT_EOK) + { + rt_event_send(&spi_wifi_data_event, 1); + } + } +} + +rt_err_t rt_hw_wifi_init(const char *spi_device_name) +{ + memset(&spi_wifi_device, 0, sizeof(struct spi_wifi_eth)); + + spi_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name); + + if (spi_wifi_device.rt_spi_device == RT_NULL) + { + WIFI_DEBUG("spi device %s not found!\r\n", spi_device_name); + return -RT_ENOSYS; + } + + /* config spi */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */ + cfg.max_hz = 1000000; /* 50M */ + rt_spi_configure(spi_wifi_device.rt_spi_device, &cfg); + } + + spi_wifi_device.parent.parent.init = spi_wifi_eth_init; + spi_wifi_device.parent.parent.open = spi_wifi_eth_open; + spi_wifi_device.parent.parent.close = spi_wifi_eth_close; + spi_wifi_device.parent.parent.read = spi_wifi_eth_read; + spi_wifi_device.parent.parent.write = spi_wifi_eth_write; + spi_wifi_device.parent.parent.control = spi_wifi_eth_control; + spi_wifi_device.parent.parent.user_data = RT_NULL; + + spi_wifi_device.parent.eth_rx = spi_wifi_eth_rx; + spi_wifi_device.parent.eth_tx = spi_wifi_eth_tx; + + rt_mp_init(&spi_wifi_device.spi_tx_mp, + "spi_tx", + &spi_wifi_device.spi_tx_mempool[0], + sizeof(spi_wifi_device.spi_tx_mempool), + sizeof(struct spi_data_packet)); + + rt_mp_init(&spi_wifi_device.spi_rx_mp, + "spi_rx", + &spi_wifi_device.spi_rx_mempool[0], + sizeof(spi_wifi_device.spi_rx_mempool), + sizeof(struct spi_data_packet)); + + rt_mb_init(&spi_wifi_device.spi_tx_mb, + "spi_tx", + &spi_wifi_device.spi_tx_mb_pool[0], + SPI_TX_POOL_SIZE, + RT_IPC_FLAG_PRIO); + + rt_mb_init(&spi_wifi_device.eth_rx_mb, + "eth_rx", + &spi_wifi_device.eth_rx_mb_pool[0], + SPI_TX_POOL_SIZE, + RT_IPC_FLAG_PRIO); + + rt_mb_init(&spi_wifi_device.spi_wifi_cmd_mb, + "wifi_cmd", + &spi_wifi_device.spi_wifi_cmd_mb_pool[0], + sizeof(spi_wifi_device.spi_wifi_cmd_mb_pool) / 4, + RT_IPC_FLAG_PRIO); + rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO); + + spi_wifi_hw_init(); + + { + rt_thread_t tid; + + + tid = rt_thread_create("wifi", + spi_wifi_data_thread_entry, + RT_NULL, + 2048, + RT_THREAD_PRIORITY_MAX - 2, + 20); + + if (tid != RT_NULL) + rt_thread_startup(tid); + } + + /* init: get mac address */ + { + WIFI_DEBUG("wifi_control SPI_WIFI_CMD_INIT\n"); + spi_wifi_eth_control((rt_device_t)&spi_wifi_device, + SPI_WIFI_CMD_INIT, + (void *)&spi_wifi_device.dev_addr[0]); + + } + /* register eth device */ + eth_device_init(&(spi_wifi_device.parent), "w0"); + eth_device_linkchange(&spi_wifi_device.parent, RT_FALSE); + + { + WIFI_DEBUG("wifi_control SPI_WIFI_CMD_JOIN\n"); + spi_wifi_eth_control((rt_device_t)&spi_wifi_device, + SPI_WIFI_CMD_JOIN, + (void *)&spi_wifi_device.dev_addr[0]); + + WIFI_DEBUG("wifi_control exit\n"); + } + + return RT_EOK; +} + +void spi_wifi_isr(int vector) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + WIFI_DEBUG("spi_wifi_isr\n"); + rt_event_send(&spi_wifi_data_event, 1); + + /* leave interrupt */ + rt_interrupt_leave(); +} diff --git a/components/drivers/spi/spi_wifi_rw009.h b/components/drivers/spi/spi_wifi_rw009.h new file mode 100644 index 0000000000..b609e7cb13 --- /dev/null +++ b/components/drivers/spi/spi_wifi_rw009.h @@ -0,0 +1,123 @@ +/* + * File : spi_wifi_rw009.h + * This file is part of RT-Thread RTOS + * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-07-31 aozima the first version + */ + +#ifndef SPI_WIFI_H_INCLUDED +#define SPI_WIFI_H_INCLUDED + +#include <stdint.h> + +// little-endian +struct cmd_request +{ + uint32_t flag; + uint32_t M2S_len; // master to slave data len. + uint32_t magic1; + uint32_t magic2; +}; + +#define CMD_MAGIC1 (0x67452301) +#define CMD_MAGIC2 (0xEFCDAB89) + +#define CMD_FLAG_MRDY (0x01) + +// little-endian +struct response +{ + uint32_t flag; + uint32_t S2M_len; // slave to master data len. + uint32_t magic1; + uint32_t magic2; +}; + +#define RESP_FLAG_SRDY (0x01) +#define RESP_MAGIC1 (0x98BADCFE) +#define RESP_MAGIC2 (0x10325476) + +/* spi slave configure. */ +#define MAX_DATA_LEN 1520 +#define SPI_TX_POOL_SIZE 2 + +// align check +#if (MAX_DATA_LEN & 0x03) != 0 +#error MAX_DATA_LEN must ALIGN to 4byte! +#endif + +typedef enum +{ + data_type_eth_data = 0, + data_type_cmd, + data_type_resp, +} +app_data_type_typedef; + +struct spi_data_packet +{ + uint32_t data_len; + uint32_t data_type; + char buffer[MAX_DATA_LEN]; +}; + +struct spi_wifi_cmd +{ + uint32_t cmd; + char buffer[128]; +}; + +struct spi_wifi_resp +{ + uint32_t cmd; + char buffer[128]; +}; + +#define SPI_WIFI_CMD_INIT 128 //wait +#define SPI_WIFI_CMD_SCAN 129 //no wait +#define SPI_WIFI_CMD_JOIN 130 //no wait + +/* porting */ +extern void spi_wifi_hw_init(void); +extern void spi_wifi_int_cmd(rt_bool_t cmd); +extern rt_bool_t spi_wifi_is_busy(void); + +/* tools */ +#define node_entry(node, type, member) \ + ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member))) +#define member_offset(type, member) \ + ((unsigned long)(&((type *)0)->member)) + +#define SSID_NAME_LENGTH_MAX (32) +#define PASSWORD_LENGTH_MAX (32) + +struct cmd_join +{ + char ssid[SSID_NAME_LENGTH_MAX]; + char passwd[PASSWORD_LENGTH_MAX]; + + uint8_t bssid[8]; // 6byte + 2byte PAD. + + uint32_t channel; + uint32_t security; +}; + + +#endif // SPI_WIFI_H_INCLUDED diff --git a/components/drivers/src/workqueue.c b/components/drivers/src/workqueue.c new file mode 100644 index 0000000000..d9062e6cdb --- /dev/null +++ b/components/drivers/src/workqueue.c @@ -0,0 +1,102 @@ +#include <rtthread.h> +#include <rtdevice.h> + +#ifdef RT_USING_HEAP +static void _workqueue_thread_entry(void* parameter) +{ + struct rt_work* work; + struct rt_workqueue* queue; + + queue = (struct rt_workqueue*) parameter; + RT_ASSERT(queue != RT_NULL); + + while (1) + { + if (rt_list_isempty(&(queue->work_list))) + { + /* no software timer exist, suspend self. */ + rt_thread_suspend(rt_thread_self()); + rt_schedule(); + } + + /* we have work to do with. */ + rt_enter_critical(); + work = rt_list_entry(queue->work_list.next, struct rt_work, list); + rt_list_remove(&(work->list)); + rt_exit_critical(); + + /* do work */ + work->work_func(work, work->work_data); + } +} + +struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority) +{ + struct rt_workqueue *queue = RT_NULL; + + queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue)); + if (queue != RT_NULL) + { + /* initialize work list */ + rt_list_init(&(queue->work_list)); + + /* create the work thread */ + queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10); + if (queue->work_thread == RT_NULL) + { + RT_KERNEL_FREE(queue); + return RT_NULL; + } + + rt_thread_startup(queue->work_thread); + } + + return queue; +} + +rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue) +{ + RT_ASSERT(queue != RT_NULL); + + rt_thread_delete(queue->work_thread); + RT_KERNEL_FREE(queue); + + return RT_EOK; +} + +rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work) +{ + RT_ASSERT(queue != RT_NULL); + RT_ASSERT(work != RT_NULL); + + rt_enter_critical(); + /* NOTE: the work MUST be initialized firstly */ + rt_list_remove(&(work->list)); + + rt_list_insert_after(queue->work_list.prev, &(work->list)); + if (queue->work_thread->stat != RT_THREAD_READY) + { + rt_exit_critical(); + /* resume work thread */ + rt_thread_resume(queue->work_thread); + rt_schedule(); + } + else rt_exit_critical(); + + return RT_EOK; +} + +rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work) +{ + RT_ASSERT(queue != RT_NULL); + RT_ASSERT(work != RT_NULL); + + rt_enter_critical(); + rt_list_remove(&(work->list)); + rt_exit_critical(); + + return RT_EOK; +} + +#endif + diff --git a/components/drivers/usb/usbdevice/class/cdc_vcom.c b/components/drivers/usb/usbdevice/class/cdc_vcom.c index 33f9f7abef..8916f3a084 100644 --- a/components/drivers/usb/usbdevice/class/cdc_vcom.c +++ b/components/drivers/usb/usbdevice/class/cdc_vcom.c @@ -280,7 +280,7 @@ static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) data->ep_out->request.buffer = data->ep_out->buffer; data->ep_out->request.size = EP_MAXPACKET(data->ep_out); - data->ep_out->request.req_type = UIO_REQUEST_READ_BEST; + data->ep_out->request.req_type = UIO_REQUEST_READ_MOST; rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); return RT_EOK; @@ -435,7 +435,7 @@ static rt_err_t _function_enable(ufunction_t func) data->ep_out->request.buffer = data->ep_out->buffer; data->ep_out->request.size = EP_MAXPACKET(data->ep_out); - data->ep_out->request.req_type = UIO_REQUEST_READ_BEST; + data->ep_out->request.req_type = UIO_REQUEST_READ_MOST; rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); return RT_EOK; diff --git a/components/drivers/usb/usbdevice/core/core.c b/components/drivers/usb/usbdevice/core/core.c index dadd81352b..b845b27c4c 100644 --- a/components/drivers/usb/usbdevice/core/core.c +++ b/components/drivers/usb/usbdevice/core/core.c @@ -772,10 +772,18 @@ static rt_err_t _data_notify(udevice_t device, struct ep_msg* ep_msg) size = dcd_ep_read(device->dcd, EP_ADDRESS(ep), ep->request.buffer); } - ep->request.remain_size -= size; - ep->request.buffer += size; - if(ep->request.req_type == UIO_REQUEST_READ_BEST) + if(size > ep->request.remain_size) + { + ep->request.remain_size = 0; + } + else + { + ep->request.remain_size -= size; + ep->request.buffer += size; + } + + if(ep->request.req_type == UIO_REQUEST_READ_MOST) { EP_HANDLER(ep, func, size); } @@ -881,6 +889,7 @@ static rt_err_t _stop_notify(udevice_t device) static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size) { rt_uint16_t maxpacket; + rt_size_t sent_size; RT_ASSERT(device != RT_NULL); RT_ASSERT(device->dcd != RT_NULL); @@ -889,18 +898,18 @@ static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_s maxpacket = EP_MAXPACKET(ep); if(ep->request.remain_size >= maxpacket) { - dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket); - ep->request.remain_size -= maxpacket; + sent_size = dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket); + ep->request.remain_size -= sent_size; ep->request.buffer += maxpacket; } else { - dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, + sent_size = dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size); - ep->request.remain_size = 0; + ep->request.remain_size -= sent_size; } - return size; + return sent_size; } static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size) @@ -1623,7 +1632,7 @@ rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req) { switch(req->req_type) { - case UIO_REQUEST_READ_BEST: + case UIO_REQUEST_READ_MOST: case UIO_REQUEST_READ_FULL: ep->request.remain_size = ep->request.size; size = rt_usbd_ep_read_prepare(device, ep, req->buffer, req->size); @@ -1757,7 +1766,8 @@ static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep) while(device->dcd->ep_pool[i].addr != 0xFF) { if(device->dcd->ep_pool[i].status == ID_UNASSIGNED && - ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type) + ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type && + ep->ep_desc->bEndpointAddress == device->dcd->ep_pool[i].dir) { EP_ADDRESS(ep) |= device->dcd->ep_pool[i].addr; ep->id = &device->dcd->ep_pool[i]; @@ -1786,7 +1796,7 @@ static rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep) return RT_EOK; } -rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup) +rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup) { struct udev_msg msg; rt_size_t size; @@ -1796,7 +1806,7 @@ rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup) if(setup == RT_NULL) { size = dcd_ep_read(dcd, EP0_OUT_ADDR, (void*)&msg.content.setup); - if(size != sizeof(struct ureqest)) + if(size != sizeof(struct urequest)) { rt_kprintf("read setup packet error\n"); return -RT_ERROR; @@ -1804,7 +1814,7 @@ rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup) } else { - rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct ureqest)); + rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct urequest)); } msg.type = USB_MSG_SETUP_NOTIFY; @@ -1935,6 +1945,7 @@ rt_err_t rt_usbd_sof_handler(udcd_t dcd) rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size) { uep_t ep0; + rt_size_t sent_size = 0; RT_ASSERT(device != RT_NULL); RT_ASSERT(device->dcd != RT_NULL); @@ -1947,17 +1958,17 @@ rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size) ep0->request.remain_size = size; if(ep0->request.remain_size >= ep0->id->maxpacket) { - dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->id->maxpacket); - ep0->request.remain_size -= ep0->id->maxpacket; + sent_size = dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->id->maxpacket); + ep0->request.remain_size -= sent_size; ep0->request.buffer += ep0->id->maxpacket; } else { - dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->request.remain_size); - ep0->request.remain_size = 0; + sent_size = dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->request.remain_size); + ep0->request.remain_size -= sent_size; } - return size; + return sent_size; } rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size, diff --git a/components/external/libpng/pngconf.h b/components/external/libpng/pngconf.h index bb0a189f9d..cca0657e4c 100644 --- a/components/external/libpng/pngconf.h +++ b/components/external/libpng/pngconf.h @@ -24,10 +24,10 @@ #define PNG_MAX_MALLOC_64K #define PNG_NO_STDIO #define PNG_NO_ERROR_NUMBERS +#define PNG_NO_WRITE_SUPPORTED #define PNG_ABORT() do { rt_kprintf("libpng abort.\n"); } while (0) #ifndef RT_USING_NEWLIB -#define PNG_NO_WRITE_SUPPORTED #define PNG_NO_SETJMP_SUPPORTED #define malloc rtgui_malloc #define free rtgui_free diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index 9a79ba396b..e449e0c2dc 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -471,17 +471,18 @@ static long _list_device(struct rt_list_node *list) "Unknown" }; - rt_kprintf("device type \n"); - rt_kprintf("-------- ---------- \n"); + rt_kprintf("device type ref count\n"); + rt_kprintf("-------- -------------------- ----------\n"); for (node = list->next; node != list; node = node->next) { device = (struct rt_device *)(rt_list_entry(node, struct rt_object, list)); - rt_kprintf("%-8.*s %-8s \n", + rt_kprintf("%-8.*s %-20s %-8d\n", RT_NAME_MAX, device->parent.name, (device->type <= RT_Device_Class_Unknown) ? device_type_str[device->type] : - device_type_str[RT_Device_Class_Unknown]); + device_type_str[RT_Device_Class_Unknown], + device->ref_count); } return 0; diff --git a/components/finsh/finsh.h b/components/finsh/finsh.h index cf7ee05808..0b270ddeaf 100644 --- a/components/finsh/finsh.h +++ b/components/finsh/finsh.h @@ -411,7 +411,6 @@ struct finsh_parser * * The basic data type in finsh shell */ - enum finsh_type { finsh_type_unknown = 0, /**< unknown data type */ finsh_type_void, /**< void */ diff --git a/components/finsh/msh_cmd.c b/components/finsh/msh_cmd.c index 3bbd46958f..7c67681833 100644 --- a/components/finsh/msh_cmd.c +++ b/components/finsh/msh_cmd.c @@ -88,8 +88,50 @@ int cmd_mv(int argc, char** argv) } else { + int fd; + char *dest = RT_NULL; + rt_kprintf("%s => %s\n", argv[1], argv[2]); - rename(argv[1], argv[2]); + + fd = open(argv[2], O_DIRECTORY, 0); + if (fd >= 0) + { + char *src; + + close(fd); + + /* it's a directory */ + dest = (char*)rt_malloc(DFS_PATH_MAX); + if (dest == RT_NULL) + { + rt_kprintf("out of memory\n"); + return -RT_ENOMEM; + } + + src = argv[1] + rt_strlen(argv[1]); + while (src != argv[1]) + { + if (*src == '/') break; + src --; + } + + rt_snprintf(dest, DFS_PATH_MAX - 1, "%s/%s", argv[2], src); + } + else + { + fd = open(argv[2], O_RDONLY, 0); + if (fd >= 0) + { + close(fd); + + unlink(argv[2]); + } + + dest = argv[2]; + } + + rename(argv[1], dest); + if (dest != RT_NULL && dest != argv[2]) rt_free(dest); } return 0; diff --git a/components/finsh/shell.c b/components/finsh/shell.c index 393d68713c..a9559954e6 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -112,7 +112,7 @@ void finsh_set_device(const char* device_name) /* check whether it's a same device */ if (dev == shell->device) return; /* open this device and set the new device in finsh shell */ - if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) == RT_EOK) + if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX) == RT_EOK) { if (shell->device != RT_NULL) { @@ -306,8 +306,8 @@ void finsh_thread_entry(void* parameter) #ifdef RT_USING_CONSOLE shell->device = rt_console_get_device(); RT_ASSERT(shell->device); - rt_device_open(shell->device, RT_DEVICE_OFLAG_RDWR); rt_device_set_rx_indicate(shell->device, finsh_rx_ind); + rt_device_open(shell->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX); #else RT_ASSERT(shell->device); #endif @@ -530,6 +530,12 @@ void finsh_thread_entry(void* parameter) ch = 0; shell->line_position ++; shell->line_curpos++; + if (shell->line_position >= 80) + { + /* clear command line */ + shell->line_position = 0; + shell->line_curpos = 0; + } } /* end of device read */ } } diff --git a/components/libc/armlibc/mem_std.c b/components/libc/armlibc/mem_std.c index 017ed77fef..6faf86555f 100644 --- a/components/libc/armlibc/mem_std.c +++ b/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); diff --git a/components/libc/armlibc/stubs.c b/components/libc/armlibc/stubs.c index 301f654182..1f9e01ba3c 100644 --- a/components/libc/armlibc/stubs.c +++ b/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> @@ -46,8 +48,10 @@ const char __stderr_name[] = "STDERR"; */ FILEHANDLE _sys_open(const char *name, int openmode) { +#ifdef RT_USING_DFS int fd; - +#endif + /* Register standard Input Output devices. */ if (strcmp(name, __stdin_name) == 0) return (STDIN); @@ -91,12 +95,13 @@ int _sys_close(FILEHANDLE fh) */ int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) { +#ifdef RT_USING_DFS int size; - +#endif + if (fh == STDIN) { /* TODO */ - return 0; } @@ -125,8 +130,10 @@ int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) */ int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) { +#ifdef RT_USING_DFS int size; - +#endif + if ((fh == STDOUT) || (fh == STDERR)) { #ifndef RT_USING_CONSOLE @@ -189,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) @@ -226,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 diff --git a/components/libc/minilibc/sys/types.h b/components/libc/minilibc/sys/types.h index 6d92d80826..a6860f2aee 100644 --- a/components/libc/minilibc/sys/types.h +++ b/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; diff --git a/components/libc/newlib/syscalls.c b/components/libc/newlib/syscalls.c index 5b829f4753..388d240c94 100644 --- a/components/libc/newlib/syscalls.c +++ b/components/libc/newlib/syscalls.c @@ -3,6 +3,14 @@ #include <sys/time.h> #include <rtthread.h> +#ifdef RT_USING_DFS +#include <dfs_posix.h> +#endif + +#ifdef RT_USING_PTHREADS +#include <pthread.h> +#endif + /* Reentrant versions of system calls. */ int diff --git a/components/net/lwip-1.3.2/apps/ping.c b/components/net/lwip-1.3.2/apps/ping.c index d3c3dd399b..1e595dce61 100644 --- a/components/net/lwip-1.3.2/apps/ping.c +++ b/components/net/lwip-1.3.2/apps/ping.c @@ -39,135 +39,140 @@ static u16_t ping_seq_num; struct _ip_addr { - rt_uint8_t addr0, addr1, addr2, addr3; + rt_uint8_t addr0, addr1, addr2, addr3; }; /** Prepare a echo ICMP request */ static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) { - size_t i; - size_t data_len = len - sizeof(struct icmp_echo_hdr); + size_t i; + size_t data_len = len - sizeof(struct icmp_echo_hdr); - ICMPH_TYPE_SET(iecho, ICMP_ECHO); - ICMPH_CODE_SET(iecho, 0); - iecho->chksum = 0; - iecho->id = PING_ID; - iecho->seqno = htons(++ping_seq_num); + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = PING_ID; + iecho->seqno = htons(++ping_seq_num); - /* fill the additional data buffer with some data */ - for(i = 0; i < data_len; i++) - { - ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; - } + /* fill the additional data buffer with some data */ + for(i = 0; i < data_len; i++) + { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } - iecho->chksum = inet_chksum(iecho, len); + iecho->chksum = inet_chksum(iecho, len); } /* Ping using the socket ip */ -static err_t ping_send(int s, struct ip_addr *addr) +static err_t ping_send(int s, struct ip_addr *addr, int size) { - int err; - struct icmp_echo_hdr *iecho; - struct sockaddr_in to; - size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; - LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); + int err; + struct icmp_echo_hdr *iecho; + struct sockaddr_in to; + size_t ping_size = sizeof(struct icmp_echo_hdr) + size; + LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); - iecho = rt_malloc(ping_size); - if (iecho == RT_NULL) - { - return ERR_MEM; - } + iecho = rt_malloc(ping_size); + if (iecho == RT_NULL) + { + return ERR_MEM; + } - ping_prepare_echo(iecho, (u16_t)ping_size); + ping_prepare_echo(iecho, (u16_t)ping_size); - to.sin_len = sizeof(to); - to.sin_family = AF_INET; - to.sin_addr.s_addr = addr->addr; + to.sin_len = sizeof(to); + to.sin_family = AF_INET; + to.sin_addr.s_addr = addr->addr; - err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)); - rt_free(iecho); + err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)); + rt_free(iecho); - return (err ? ERR_OK : ERR_VAL); + return (err ? ERR_OK : ERR_VAL); } static void ping_recv(int s) { - char buf[64]; - int fromlen, len; - struct sockaddr_in from; - struct ip_hdr *iphdr; - struct icmp_echo_hdr *iecho; - struct _ip_addr *addr; + char buf[64]; + int fromlen, len; + struct sockaddr_in from; + struct ip_hdr *iphdr; + struct icmp_echo_hdr *iecho; + struct _ip_addr *addr; - while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) - { - if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) - { - addr = (struct _ip_addr *)&(from.sin_addr); - rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) + { + if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) + { + addr = (struct _ip_addr *)&(from.sin_addr); + rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); - iphdr = (struct ip_hdr *)buf; - iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4)); - if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) - { - return; - } - else - { - rt_kprintf("ping: drop\n"); - } - } - } + iphdr = (struct ip_hdr *)buf; + iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4)); + if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) + { + return; + } + else + { + rt_kprintf("ping: drop\n"); + } + } + } - if (len <= 0) - { - rt_kprintf("ping: timeout\n"); - } + if (len <= 0) + { + rt_kprintf("ping: timeout\n"); + } } rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size) { - int s; - int timeout = PING_RCV_TIMEO; - struct ip_addr ping_target; - rt_uint32_t send_time; - struct _ip_addr - { - rt_uint8_t addr0, addr1, addr2, addr3; - } *addr; + int s; + int timeout = PING_RCV_TIMEO; + struct ip_addr ping_target; + rt_uint32_t send_time; + struct _ip_addr + { + rt_uint8_t addr0, addr1, addr2, addr3; + } *addr; send_time = 0; - if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR; - addr = (struct _ip_addr*)&ping_target; + if(size == 0) + size = PING_DATA_SIZE; - if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) - { - rt_kprintf("create socket failled\n"); - return -RT_ERROR; - } + if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR; + addr = (struct _ip_addr*)&ping_target; - lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) + { + rt_kprintf("create socket failled\n"); + return -RT_ERROR; + } - while (1) - { - if (ping_send(s, &ping_target) == ERR_OK) - { - rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); - ping_recv(s); - } - else - { - rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); - } + lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - send_time ++; - if (send_time >= time) break; /* send ping times reached, stop */ + while (1) + { + if (ping_send(s, &ping_target, size) == ERR_OK) + { + rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + ping_recv(s); + } + else + { + rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + } - rt_thread_delay(PING_DELAY); /* take a delay */ - } + send_time ++; + if (send_time >= time) break; /* send ping times reached, stop */ - return RT_EOK; + rt_thread_delay(PING_DELAY); /* take a delay */ + } + + lwip_close(s); + + return RT_EOK; } #ifdef RT_USING_FINSH #include <finsh.h> diff --git a/components/net/lwip-1.4.1/src/arch/sys_arch.c b/components/net/lwip-1.4.1/src/arch/sys_arch.c index ee1d952410..287c861f04 100644 --- a/components/net/lwip-1.4.1/src/arch/sys_arch.c +++ b/components/net/lwip-1.4.1/src/arch/sys_arch.c @@ -29,6 +29,11 @@ #include <string.h> +/* + * Initialize the network interface device + * + * @return the operation status, ERR_OK on OK, ERR_IF on error + */ static err_t netif_device_init(struct netif *netif) { struct eth_device *ethif; @@ -53,7 +58,9 @@ static err_t netif_device_init(struct netif *netif) return ERR_IF; } - +/* + * Initialize the ethernetif layer and set network interface device up + */ static void tcpip_init_done_callback(void *arg) { rt_device_t device; @@ -108,7 +115,7 @@ static void tcpip_init_done_callback(void *arg) netif_set_up(ethif->netif); } -#ifdef LWIP_NETIF_LINK_CALLBACK +#if LWIP_NETIF_LINK_CALLBACK netif_set_link_up(ethif->netif); #endif @@ -182,6 +189,11 @@ void lwip_sys_init(void) lwip_system_init(); } +/* + * Create a new semaphore + * + * @return the operation status, ERR_OK on OK; others on error + */ err_t sys_sem_new(sys_sem_t *sem, u8_t count) { static unsigned short counter = 0; @@ -204,17 +216,31 @@ err_t sys_sem_new(sys_sem_t *sem, u8_t count) } } +/* + * Deallocate a semaphore + */ void sys_sem_free(sys_sem_t *sem) { RT_DEBUG_NOT_IN_INTERRUPT; rt_sem_delete(*sem); } +/* + * Signal a semaphore + */ void sys_sem_signal(sys_sem_t *sem) { rt_sem_release(*sem); } +/* + * Block the thread while waiting for the semaphore to be signaled + * + * @return If the timeout argument is non-zero, it will return the number of milliseconds + * spent waiting for the semaphore to be signaled; If the semaphore isn't signaled + * within the specified time, it will return SYS_ARCH_TIMEOUT; If the thread doesn't + * wait for the semaphore, it will return zero + */ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { rt_err_t ret; @@ -354,6 +380,11 @@ void sys_mutex_set_invalid(sys_mutex_t *mutex) /* ====================== Mailbox ====================== */ +/* + * Create an empty mailbox for maximum "size" elements + * + * @return the operation status, ERR_OK on OK; others on error + */ err_t sys_mbox_new(sys_mbox_t *mbox, int size) { static unsigned short counter = 0; @@ -376,6 +407,9 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int size) return ERR_MEM; } +/* + * Deallocate a mailbox + */ void sys_mbox_free(sys_mbox_t *mbox) { RT_DEBUG_NOT_IN_INTERRUPT; @@ -399,6 +433,11 @@ void sys_mbox_post(sys_mbox_t *mbox, void *msg) return; } +/* + * Try to post the "msg" to the mailbox + * + * @return return ERR_OK if the "msg" is posted, ERR_MEM if the mailbox is full + */ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { if (rt_mb_send(*mbox, (rt_uint32_t)msg) == RT_EOK) @@ -502,6 +541,11 @@ void sys_mbox_set_invalid(sys_mbox_t *mbox) /* ====================== System ====================== */ +/* + * Start a new thread named "name" with priority "prio" that will begin + * its execution in the function "thread()". The "arg" argument will be + * passed as an argument to the thread() function + */ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, diff --git a/components/net/lwip-1.4.1/src/include/netif/ethernetif.h b/components/net/lwip-1.4.1/src/include/netif/ethernetif.h index 53dacf2270..2019df7017 100644 --- a/components/net/lwip-1.4.1/src/include/netif/ethernetif.h +++ b/components/net/lwip-1.4.1/src/include/netif/ethernetif.h @@ -5,7 +5,11 @@ #include <rtthread.h> #define NIOCTL_GADDR 0x01 +#ifndef RT_LWIP_ETH_MTU #define ETHERNET_MTU 1500 +#else +#define ETHERNET_MTU RT_LWIP_ETH_MTU +#endif struct eth_device { diff --git a/components/net/lwip-1.4.1/src/lwipopts.h b/components/net/lwip-1.4.1/src/lwipopts.h index 10cb7893a7..bff172e280 100644 --- a/components/net/lwip-1.4.1/src/lwipopts.h +++ b/components/net/lwip-1.4.1/src/lwipopts.h @@ -38,8 +38,9 @@ #define LWIP_PLATFORM_BYTESWAP 0 #define BYTE_ORDER LITTLE_ENDIAN -/* Enable SO_RCVTIMEO processing. */ +/* Enable SO_RCVTIMEO/LWIP_SO_SNDTIMEO processing. */ #define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_SNDTIMEO 1 /* #define RT_LWIP_DEBUG */ @@ -117,6 +118,8 @@ /* the number of simultaneously queued TCP */ #ifdef RT_LWIP_TCP_SEG_NUM +#define MEMP_NUM_TCP_SEG RT_LWIP_TCP_SEG_NUM +#else #define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN #endif @@ -135,12 +138,12 @@ /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #ifdef RT_LWIP_PBUF_NUM -#define PBUF_POOL_SIZE RT_LWIP_PBUF_NUM +#define PBUF_POOL_SIZE RT_LWIP_PBUF_NUM #endif /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #ifdef RT_LWIP_PBUF_POOL_BUFSIZE -#define PBUF_POOL_BUFSIZE RT_LWIP_PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE RT_LWIP_PBUF_POOL_BUFSIZE #endif /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a @@ -176,7 +179,7 @@ /* TCP sender buffer space (bytes). */ #ifdef RT_LWIP_TCP_SND_BUF -#define TCP_SND_BUF RT_LWIP_TCP_SND_BUF +#define TCP_SND_BUF RT_LWIP_TCP_SND_BUF #else #define TCP_SND_BUF (TCP_MSS * 2) #endif @@ -230,10 +233,15 @@ /* IP reassembly and segmentation.These are orthogonal even * if they both deal with IP fragments */ -#define IP_REASSEMBLY 0 +#ifdef RT_LWIP_REASSEMBLY_FRAG +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 #define IP_REASS_MAX_PBUFS 10 #define MEMP_NUM_REASSDATA 10 +#else +#define IP_REASSEMBLY 0 #define IP_FRAG 0 +#endif /* ---------- ICMP options ---------- */ #define ICMP_TTL 255 @@ -307,7 +315,7 @@ * in this file. */ #ifdef RT_LWIP_PPPOE -#define PPPOE_SUPPORT 1 +#define PPPOE_SUPPORT 1 #else #define PPPOE_SUPPORT 0 #endif @@ -315,7 +323,7 @@ #ifdef RT_LWIP_PPPOS #define PPPOS_SUPPORT 1 #else -#define PPPOS_SUPPORT 0 +#define PPPOS_SUPPORT 0 #endif #define PAP_SUPPORT 1 /* Set > 0 for PAP. */ diff --git a/components/net/lwip-1.4.1/src/netif/ethernetif.c b/components/net/lwip-1.4.1/src/netif/ethernetif.c index 2853fdcd7c..ab7743290a 100644 --- a/components/net/lwip-1.4.1/src/netif/ethernetif.c +++ b/components/net/lwip-1.4.1/src/netif/ethernetif.c @@ -67,6 +67,7 @@ #define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL) #define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL) +#ifndef LWIP_NO_TX_THREAD /** * Tx message structure for Ethernet interface */ @@ -85,7 +86,9 @@ static char eth_tx_thread_stack[512]; static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4]; static char eth_tx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE]; #endif +#endif +#ifndef LWIP_NO_RX_THREAD static struct rt_mailbox eth_rx_thread_mb; static struct rt_thread eth_rx_thread; #ifndef RT_LWIP_ETHTHREAD_PRIORITY @@ -97,12 +100,15 @@ static char eth_rx_thread_stack[1024]; static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4]; static char eth_rx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE]; #endif +#endif static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p) { +#ifndef LWIP_NO_TX_THREAD struct eth_tx_msg msg; struct eth_device* enetif; + RT_ASSERT(netif != RT_NULL); enetif = (struct eth_device*)netif->state; /* send a message to eth tx thread */ @@ -113,7 +119,17 @@ static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p) /* waiting for ack */ rt_sem_take(&(enetif->tx_ack), RT_WAITING_FOREVER); } +#else + struct eth_device* enetif; + RT_ASSERT(netif != RT_NULL); + enetif = (struct eth_device*)netif->state; + + if (enetif->eth_tx(&(enetif->parent), p) != RT_EOK) + { + return ERR_IF; + } +#endif return ERR_OK; } @@ -241,6 +257,7 @@ rt_err_t eth_device_init(struct eth_device * dev, char *name) return eth_device_init_with_flag(dev, name, flags); } +#ifndef LWIP_NO_RX_THREAD rt_err_t eth_device_ready(struct eth_device* dev) { if (dev->netif) @@ -267,7 +284,20 @@ rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up) /* post message to ethernet thread */ return rt_mb_send(ð_rx_thread_mb, (rt_uint32_t)dev); } +#else +/* NOTE: please not use it in interrupt when no RxThread exist */ +rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up) +{ + if (up == RT_TRUE) + netifapi_netif_set_link_up(dev->netif); + else + netifapi_netif_set_link_down(dev->netif); + + return RT_EOK; +} +#endif +#ifndef LWIP_NO_TX_THREAD /* Ethernet Tx Thread */ static void eth_tx_thread_entry(void* parameter) { @@ -297,7 +327,9 @@ static void eth_tx_thread_entry(void* parameter) } } } +#endif +#ifndef LWIP_NO_RX_THREAD /* Ethernet Rx Thread */ static void eth_rx_thread_entry(void* parameter) { @@ -349,13 +381,15 @@ static void eth_rx_thread_entry(void* parameter) } } } +#endif int eth_system_device_init(void) { rt_err_t result = RT_EOK; - /* initialize Rx thread. - * initialize mailbox and create Ethernet Rx thread */ + /* initialize Rx thread. */ +#ifndef LWIP_NO_RX_THREAD + /* initialize mailbox and create Ethernet Rx thread */ result = rt_mb_init(ð_rx_thread_mb, "erxmb", ð_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/4, RT_IPC_FLAG_FIFO); @@ -367,8 +401,10 @@ int eth_system_device_init(void) RT_ASSERT(result == RT_EOK); result = rt_thread_startup(ð_rx_thread); RT_ASSERT(result == RT_EOK); +#endif /* initialize Tx thread */ +#ifndef LWIP_NO_TX_THREAD /* initialize mailbox and create Ethernet Tx thread */ result = rt_mb_init(ð_tx_thread_mb, "etxmb", ð_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/4, @@ -382,8 +418,9 @@ int eth_system_device_init(void) result = rt_thread_startup(ð_tx_thread); RT_ASSERT(result == RT_EOK); - - return 0; +#endif + + return (int)result; } INIT_DEVICE_EXPORT(eth_system_device_init); diff --git a/components/net/lwip/apps/ping.c b/components/net/lwip/apps/ping.c index d3c3dd399b..1e595dce61 100644 --- a/components/net/lwip/apps/ping.c +++ b/components/net/lwip/apps/ping.c @@ -39,135 +39,140 @@ static u16_t ping_seq_num; struct _ip_addr { - rt_uint8_t addr0, addr1, addr2, addr3; + rt_uint8_t addr0, addr1, addr2, addr3; }; /** Prepare a echo ICMP request */ static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) { - size_t i; - size_t data_len = len - sizeof(struct icmp_echo_hdr); + size_t i; + size_t data_len = len - sizeof(struct icmp_echo_hdr); - ICMPH_TYPE_SET(iecho, ICMP_ECHO); - ICMPH_CODE_SET(iecho, 0); - iecho->chksum = 0; - iecho->id = PING_ID; - iecho->seqno = htons(++ping_seq_num); + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = PING_ID; + iecho->seqno = htons(++ping_seq_num); - /* fill the additional data buffer with some data */ - for(i = 0; i < data_len; i++) - { - ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; - } + /* fill the additional data buffer with some data */ + for(i = 0; i < data_len; i++) + { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } - iecho->chksum = inet_chksum(iecho, len); + iecho->chksum = inet_chksum(iecho, len); } /* Ping using the socket ip */ -static err_t ping_send(int s, struct ip_addr *addr) +static err_t ping_send(int s, struct ip_addr *addr, int size) { - int err; - struct icmp_echo_hdr *iecho; - struct sockaddr_in to; - size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; - LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); + int err; + struct icmp_echo_hdr *iecho; + struct sockaddr_in to; + size_t ping_size = sizeof(struct icmp_echo_hdr) + size; + LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); - iecho = rt_malloc(ping_size); - if (iecho == RT_NULL) - { - return ERR_MEM; - } + iecho = rt_malloc(ping_size); + if (iecho == RT_NULL) + { + return ERR_MEM; + } - ping_prepare_echo(iecho, (u16_t)ping_size); + ping_prepare_echo(iecho, (u16_t)ping_size); - to.sin_len = sizeof(to); - to.sin_family = AF_INET; - to.sin_addr.s_addr = addr->addr; + to.sin_len = sizeof(to); + to.sin_family = AF_INET; + to.sin_addr.s_addr = addr->addr; - err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)); - rt_free(iecho); + err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)); + rt_free(iecho); - return (err ? ERR_OK : ERR_VAL); + return (err ? ERR_OK : ERR_VAL); } static void ping_recv(int s) { - char buf[64]; - int fromlen, len; - struct sockaddr_in from; - struct ip_hdr *iphdr; - struct icmp_echo_hdr *iecho; - struct _ip_addr *addr; + char buf[64]; + int fromlen, len; + struct sockaddr_in from; + struct ip_hdr *iphdr; + struct icmp_echo_hdr *iecho; + struct _ip_addr *addr; - while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) - { - if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) - { - addr = (struct _ip_addr *)&(from.sin_addr); - rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) + { + if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) + { + addr = (struct _ip_addr *)&(from.sin_addr); + rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); - iphdr = (struct ip_hdr *)buf; - iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4)); - if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) - { - return; - } - else - { - rt_kprintf("ping: drop\n"); - } - } - } + iphdr = (struct ip_hdr *)buf; + iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4)); + if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) + { + return; + } + else + { + rt_kprintf("ping: drop\n"); + } + } + } - if (len <= 0) - { - rt_kprintf("ping: timeout\n"); - } + if (len <= 0) + { + rt_kprintf("ping: timeout\n"); + } } rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size) { - int s; - int timeout = PING_RCV_TIMEO; - struct ip_addr ping_target; - rt_uint32_t send_time; - struct _ip_addr - { - rt_uint8_t addr0, addr1, addr2, addr3; - } *addr; + int s; + int timeout = PING_RCV_TIMEO; + struct ip_addr ping_target; + rt_uint32_t send_time; + struct _ip_addr + { + rt_uint8_t addr0, addr1, addr2, addr3; + } *addr; send_time = 0; - if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR; - addr = (struct _ip_addr*)&ping_target; + if(size == 0) + size = PING_DATA_SIZE; - if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) - { - rt_kprintf("create socket failled\n"); - return -RT_ERROR; - } + if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR; + addr = (struct _ip_addr*)&ping_target; - lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) + { + rt_kprintf("create socket failled\n"); + return -RT_ERROR; + } - while (1) - { - if (ping_send(s, &ping_target) == ERR_OK) - { - rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); - ping_recv(s); - } - else - { - rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); - } + lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - send_time ++; - if (send_time >= time) break; /* send ping times reached, stop */ + while (1) + { + if (ping_send(s, &ping_target, size) == ERR_OK) + { + rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + ping_recv(s); + } + else + { + rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + } - rt_thread_delay(PING_DELAY); /* take a delay */ - } + send_time ++; + if (send_time >= time) break; /* send ping times reached, stop */ - return RT_EOK; + rt_thread_delay(PING_DELAY); /* take a delay */ + } + + lwip_close(s); + + return RT_EOK; } #ifdef RT_USING_FINSH #include <finsh.h> diff --git a/components/pthreads/mqueue.c b/components/pthreads/mqueue.c index c1303ae6b1..7b669dc367 100644 --- a/components/pthreads/mqueue.c +++ b/components/pthreads/mqueue.c @@ -119,6 +119,7 @@ mqd_t mq_open(const char *name, int oflag, ...) { mqd_t mqdes; va_list arg; + mode_t mode; struct mq_attr *attr = RT_NULL; /* lock posix mqueue list */ @@ -128,6 +129,8 @@ mqd_t mq_open(const char *name, int oflag, ...) if (oflag & O_CREAT) { va_start(arg, oflag); + mode = (mode_t)va_arg(arg, unsigned int); + mode = mode; attr = (struct mq_attr *)va_arg(arg, struct mq_attr *); va_end(arg); diff --git a/components/pthreads/pthread_cond.c b/components/pthreads/pthread_cond.c index e5342dd775..25628fc2b3 100644 --- a/components/pthreads/pthread_cond.c +++ b/components/pthreads/pthread_cond.c @@ -98,7 +98,11 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) rt_snprintf(cond_name, sizeof(cond_name), "cond%02d", cond_num++); - cond->attr = *attr; + if (attr == RT_NULL) /* use default value */ + cond->attr = PTHREAD_PROCESS_PRIVATE; + else + cond->attr = *attr; + result = rt_sem_init(&cond->sem, cond_name, 0, RT_IPC_FLAG_FIFO); if (result != RT_EOK) return EINVAL; diff --git a/components/pthreads/semaphore.c b/components/pthreads/semaphore.c index 726246c95f..ae69e0d1bc 100644 --- a/components/pthreads/semaphore.c +++ b/components/pthreads/semaphore.c @@ -224,6 +224,7 @@ sem_t *sem_open(const char *name, int oflag, ...) { sem_t* sem; va_list arg; + mode_t mode; unsigned int value; sem = RT_NULL; @@ -233,6 +234,7 @@ sem_t *sem_open(const char *name, int oflag, ...) if (oflag & O_CREAT) { va_start(arg, oflag); + mode = (mode_t) va_arg( arg, unsigned int); mode = mode; value = va_arg( arg, unsigned int); va_end(arg); diff --git a/components/utilities/ymodem/ymodem.c b/components/utilities/ymodem/ymodem.c index fdd1950cc0..f5ebeab832 100644 --- a/components/utilities/ymodem/ymodem.c +++ b/components/utilities/ymodem/ymodem.c @@ -70,18 +70,23 @@ static enum rym_code _rym_read_code( struct rym_ctx *ctx, rt_tick_t timeout) { - /* consume the available sem and read the data in buffer if possible */ - while (rt_sem_trytake(&ctx->sem) == RT_EOK) - ; + /* Fast path */ if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1) return *ctx->buf; - /* no data yet, wait for one */ - if (rt_sem_take(&ctx->sem, timeout) != RT_EOK) - return RYM_CODE_NONE; - /* read one */ - if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1) - return *ctx->buf; - return RYM_CODE_NONE; + + /* Slow path */ + do { + rt_size_t rsz; + + /* No data yet, wait for one */ + if (rt_sem_take(&ctx->sem, timeout) != RT_EOK) + return RYM_CODE_NONE; + + /* Try to read one */ + rsz = rt_device_read(ctx->dev, 0, ctx->buf, 1); + if (rsz == 1) + return *ctx->buf; + } while (1); } /* the caller should at least alloc _RYM_STX_PKG_SZ buffer */ diff --git a/components/utilities/ymodem/ymodem.h b/components/utilities/ymodem/ymodem.h index daed61d15f..43ee6f5c10 100644 --- a/components/utilities/ymodem/ymodem.h +++ b/components/utilities/ymodem/ymodem.h @@ -52,7 +52,7 @@ enum rym_code { #endif /* how many ticks between two handshake code. */ #ifndef RYM_CHD_INTV_TICK -#define RYM_CHD_INTV_TICK (RT_TICK_PER_SECOND / 4) +#define RYM_CHD_INTV_TICK (RT_TICK_PER_SECOND * 3) #endif enum rym_stage { |
