875 lines
34 KiB
C
875 lines
34 KiB
C
/*
|
|
* Copyright (c) 2006-2018, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2006-03-13 bernard first version
|
|
* 2012-05-15 lgnq modified according bernard's implementation.
|
|
* 2012-05-28 bernard code cleanup
|
|
* 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
|
|
* 2014-12-31 bernard use open_flag for poll_tx stream mode.
|
|
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
|
|
* in open function.
|
|
* 2015-11-10 bernard fix the poll rx issue when there is no data.
|
|
* 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0.
|
|
* 2017-01-19 aubr.cool prevent change serial rx bufsz when serial is opened.
|
|
* 2017-11-07 JasonJia fix data bits error issue when using tcsetattr.
|
|
* 2017-11-15 JasonJia fix poll rx issue when data is full.
|
|
* add TCFLSH and FIONREAD support.
|
|
* 2018-12-08 Ernest Chen add DMA choice
|
|
* 2020-09-14 WillianChan add a line feed to the carriage return character
|
|
* when using interrupt tx
|
|
*/
|
|
|
|
/**
|
|
* @file dev_serial.c
|
|
* @brief register serial dev function using bus driver framework
|
|
* @version 1.0
|
|
* @author AIIT XUOS Lab
|
|
* @date 2021-04-24
|
|
*/
|
|
|
|
/*************************************************
|
|
File name: dev_serial.c
|
|
Description: support serial dev INT and DMA configure、transfer data
|
|
Others: take RT-Thread v4.0.2/components/driver/serial/serial.c for references
|
|
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
|
History:
|
|
1. Date: 2021-04-24
|
|
Author: AIIT XUOS Lab
|
|
Modification:
|
|
1. support serial dev register, configure, write and read
|
|
2. add bus driver framework support, include INT and DMA mode
|
|
*************************************************/
|
|
|
|
#include <bus_serial.h>
|
|
#include <dev_serial.h>
|
|
|
|
static DoubleLinklistType serialdev_linklist;
|
|
|
|
static int SerialWorkModeCheck(struct SerialDevParam *serial_dev_param)
|
|
{
|
|
if (SIGN_OPER_INT_TX & serial_dev_param->serial_set_mode) {
|
|
if (SIGN_OPER_INT_TX & serial_dev_param->serial_work_mode) {
|
|
return EOK;
|
|
} else {
|
|
KPrintf("SerialWorkModeCheck set mode 0x%x work mode error 0x%x\n",
|
|
serial_dev_param->serial_set_mode, serial_dev_param->serial_work_mode);
|
|
return ERROR;
|
|
}
|
|
} else if (SIGN_OPER_INT_RX & serial_dev_param->serial_set_mode) {
|
|
if (SIGN_OPER_INT_RX & serial_dev_param->serial_work_mode) {
|
|
return EOK;
|
|
} else {
|
|
KPrintf("SerialWorkModeCheck set mode 0x%x work mode error 0x%x\n",
|
|
serial_dev_param->serial_set_mode, serial_dev_param->serial_work_mode);
|
|
return ERROR;
|
|
}
|
|
} else if (SIGN_OPER_DMA_TX & serial_dev_param->serial_set_mode) {
|
|
if (SIGN_OPER_DMA_TX & serial_dev_param->serial_work_mode) {
|
|
return EOK;
|
|
} else {
|
|
KPrintf("SerialWorkModeCheck set mode 0x%x work mode error 0x%x\n",
|
|
serial_dev_param->serial_set_mode, serial_dev_param->serial_work_mode);
|
|
return ERROR;
|
|
}
|
|
} else if (SIGN_OPER_DMA_RX & serial_dev_param->serial_set_mode) {
|
|
if (SIGN_OPER_DMA_RX & serial_dev_param->serial_work_mode) {
|
|
return EOK;
|
|
} else {
|
|
KPrintf("SerialWorkModeCheck set mode 0x%x work mode error 0x%x\n",
|
|
serial_dev_param->serial_set_mode, serial_dev_param->serial_work_mode);
|
|
return ERROR;
|
|
}
|
|
} else {
|
|
serial_dev_param->serial_set_mode = serial_dev_param->serial_work_mode;
|
|
return EOK;
|
|
}
|
|
}
|
|
|
|
static inline int SerialDevIntWrite(struct SerialHardwareDevice *serial_dev, struct BusBlockWriteParam *write_param)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
NULL_PARAM_CHECK(write_param);
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
const uint8 *write_data = (const uint8 *)write_param->buffer;
|
|
x_size_t write_length = write_param->size;
|
|
|
|
while (write_length)
|
|
{
|
|
if (EOK != hwdev_done->put_char(serial_dev, *(char *)write_data)) {
|
|
KSemaphoreObtain(serial_dev->serial_fifo.serial_tx->serial_txfifo_sem, WAITING_FOREVER);
|
|
continue;
|
|
}
|
|
|
|
KPrintf("SerialDevIntWrite data %d write_length %u\n", *(char *)write_data, write_length);
|
|
|
|
write_data++;
|
|
write_length--;
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static inline int SerialDevIntRead(struct SerialHardwareDevice *serial_dev, struct BusBlockReadParam *read_param)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
NULL_PARAM_CHECK(read_param);
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
uint8 *read_data = (uint8 *)read_param->buffer;
|
|
x_size_t read_length = read_param->size;
|
|
|
|
while (read_length)
|
|
{
|
|
uint8 get_char;
|
|
x_base lock;
|
|
|
|
lock = CriticalAreaLock();
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num == serial_dev->serial_fifo.serial_rx->serial_send_num) {
|
|
if (RET_FALSE == serial_dev->serial_fifo.serial_rx->serial_rx_full) {
|
|
CriticalAreaUnLock(lock);
|
|
break;
|
|
}
|
|
}
|
|
|
|
get_char = serial_dev->serial_fifo.serial_rx->serial_rx_buffer[serial_dev->serial_fifo.serial_rx->serial_recv_num];
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num += 1;
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num >= serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num = 0;
|
|
}
|
|
|
|
if (RET_TRUE == serial_dev->serial_fifo.serial_rx->serial_rx_full) {
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_FALSE;
|
|
}
|
|
|
|
CriticalAreaUnLock(lock);
|
|
|
|
*read_data = get_char;
|
|
read_data++;
|
|
read_length--;
|
|
read_param->read_length++;
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
#ifdef SERIAL_USING_DMA
|
|
static inline int SerialDevDMAWrite(struct SerialHardwareDevice *serial_dev, struct BusBlockWriteParam *write_param)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
NULL_PARAM_CHECK(write_param);
|
|
|
|
x_err_t ret = EOK;
|
|
x_base lock;
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
const uint8 *write_data = (const uint8 *)write_param->buffer;
|
|
x_size_t write_length = write_param->size;
|
|
|
|
ret = ((DataQueueDoneType*)serial_dev->serial_fifo.serial_tx->serial_dma_queue.done)->PushDataqueue((DataQueueType *)serial_dev->serial_fifo.serial_tx->serial_dma_queue.property, write_param->buffer, write_param->size, WAITING_FOREVER);
|
|
if (EOK != ret) {
|
|
KUpdateExstatus(ret);
|
|
return ERROR;
|
|
}
|
|
|
|
lock = CriticalAreaLock();
|
|
if (RET_FALSE == serial_dev->serial_fifo.serial_tx->serial_dma_enable) {
|
|
serial_dev->serial_fifo.serial_tx->serial_dma_enable = RET_TRUE;
|
|
CriticalAreaUnLock(lock);
|
|
|
|
hwdev_done->dmatransfer(serial_dev, (uint8 *)write_data, write_length, SERIAL_DMA_TX);
|
|
} else {
|
|
CriticalAreaUnLock(lock);
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static x_size_t SerialGetRxFifoLength(struct SerialHardwareDevice *serial_dev)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
|
|
x_size_t length;
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num == serial_dev->serial_fifo.serial_rx->serial_send_num) {
|
|
if (serial_dev->serial_fifo.serial_rx->serial_rx_full) {
|
|
length = serial_cfg->data_cfg.serial_buffer_size;
|
|
} else {
|
|
length = 0;
|
|
}
|
|
} else {
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num > serial_dev->serial_fifo.serial_rx->serial_send_num) {
|
|
length = serial_cfg->data_cfg.serial_buffer_size - serial_dev->serial_fifo.serial_rx->serial_recv_num + serial_dev->serial_fifo.serial_rx->serial_send_num;
|
|
} else {
|
|
length = serial_dev->serial_fifo.serial_rx->serial_send_num - serial_dev->serial_fifo.serial_rx->serial_recv_num;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SerialDmaRxSetRecvLength(struct SerialHardwareDevice *serial_dev, x_size_t length)
|
|
{
|
|
CHECK(length <= SerialGetRxFifoLength(serial_dev));
|
|
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
if ((serial_dev->serial_fifo.serial_rx->serial_rx_full) && (length)) {
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_FALSE;
|
|
}
|
|
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num += length;
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num >= serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num %= serial_cfg->data_cfg.serial_buffer_size;
|
|
}
|
|
}
|
|
|
|
static void SerialDmaRxSetSendLength(struct SerialHardwareDevice *serial_dev, x_size_t length)
|
|
{
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num > serial_dev->serial_fifo.serial_rx->serial_send_num) {
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num += length;
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num <= serial_dev->serial_fifo.serial_rx->serial_send_num) {
|
|
if (serial_dev->serial_fifo.serial_rx->serial_send_num >= serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num %= serial_cfg->data_cfg.serial_buffer_size;
|
|
}
|
|
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_TRUE;
|
|
}
|
|
} else {
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num += length;
|
|
if (serial_dev->serial_fifo.serial_rx->serial_send_num >= serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num %= serial_cfg->data_cfg.serial_buffer_size;
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_send_num >= serial_dev->serial_fifo.serial_rx->serial_recv_num) {
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RET_TRUE == serial_dev->serial_fifo.serial_rx->serial_rx_full) {
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num = serial_dev->serial_fifo.serial_rx->serial_send_num;
|
|
}
|
|
}
|
|
|
|
static inline int SerialDevDMARead(struct SerialHardwareDevice *serial_dev, struct BusBlockReadParam *read_param)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
NULL_PARAM_CHECK(read_param);
|
|
|
|
x_err_t ret = EOK;
|
|
x_base lock;
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
uint8 *read_data = (uint8 *)read_param->buffer;
|
|
x_size_t read_length = read_param->size;
|
|
x_size_t read_dma_length;
|
|
x_size_t read_dma_size = SerialGetRxFifoLength(serial_dev);
|
|
|
|
if (serial_cfg->data_cfg.serial_buffer_size) {
|
|
if(read_length < (int)read_dma_size)
|
|
read_dma_length = read_length;
|
|
else
|
|
read_dma_length = read_dma_size;
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num + read_dma_length < serial_cfg->data_cfg.serial_buffer_size) {
|
|
memcpy(read_data,
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_buffer + serial_dev->serial_fifo.serial_rx->serial_recv_num, read_dma_length);
|
|
} else {
|
|
memcpy(read_data, serial_dev->serial_fifo.serial_rx->serial_rx_buffer + serial_dev->serial_fifo.serial_rx->serial_recv_num,
|
|
serial_cfg->data_cfg.serial_buffer_size - serial_dev->serial_fifo.serial_rx->serial_recv_num);
|
|
memcpy(read_data + serial_cfg->data_cfg.serial_buffer_size - serial_dev->serial_fifo.serial_rx->serial_recv_num,
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_buffer, read_dma_length + serial_dev->serial_fifo.serial_rx->serial_recv_num - serial_cfg->data_cfg.serial_buffer_size);
|
|
}
|
|
SerialDmaRxSetRecvLength(serial_dev, read_dma_length);
|
|
CriticalAreaUnLock(lock);
|
|
return EOK;
|
|
} else {
|
|
if (RET_FALSE == serial_dev->serial_fifo.serial_rx->serial_dma_enable) {
|
|
serial_dev->serial_fifo.serial_rx->serial_dma_enable = RET_TRUE;
|
|
hwdev_done->dmatransfer(serial_dev, read_data, read_length, SERIAL_DMA_RX);
|
|
} else {
|
|
ret = ERROR;
|
|
KUpdateExstatus(ret);
|
|
}
|
|
|
|
CriticalAreaUnLock(lock);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static inline int SerialDevPollingWrite(struct SerialHardwareDevice *serial_dev, struct BusBlockWriteParam *write_param, uint16 serial_stream_mode)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
NULL_PARAM_CHECK(write_param);
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
const uint8 *write_data = (const uint8 *)write_param->buffer;
|
|
x_size_t write_length = write_param->size;
|
|
|
|
while (write_length)
|
|
{
|
|
if ((*write_data == '\n') && (SIGN_OPER_STREAM == serial_stream_mode)) {
|
|
hwdev_done->put_char(serial_dev, '\r');
|
|
}
|
|
|
|
hwdev_done->put_char(serial_dev, *write_data);
|
|
|
|
++write_data;
|
|
--write_length;
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static inline int SerialDevPollingRead(struct SerialHardwareDevice *serial_dev, struct BusBlockReadParam *read_param)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev);
|
|
NULL_PARAM_CHECK(read_param);
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
uint8 *read_data = (uint8 *)read_param->buffer;
|
|
x_size_t read_length = read_param->size;
|
|
|
|
uint8 get_char;
|
|
x_err_t ret = EOK;
|
|
|
|
while (read_length)
|
|
{
|
|
ret = hwdev_done->get_char(serial_dev);
|
|
if (-ERROR == ret) {
|
|
break;
|
|
}
|
|
|
|
*read_data = get_char;
|
|
read_data++;
|
|
read_length--;
|
|
|
|
if ('\n' == get_char) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static uint32 SerialDevOpen(void *dev)
|
|
{
|
|
NULL_PARAM_CHECK(dev);
|
|
|
|
int serial_operation_cmd;
|
|
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)dev;
|
|
struct Driver *drv = serial_dev->haldev.owner_bus->owner_driver;
|
|
struct SerialDriver *serial_drv = (struct SerialDriver *)drv;
|
|
struct SerialDevParam *serial_dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data;
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
if (EOK != SerialWorkModeCheck(serial_dev_param)) {
|
|
KPrintf("SerialDevOpen error!\n");
|
|
return ERROR;
|
|
}
|
|
|
|
if (NONE == serial_dev->serial_fifo.serial_rx) {
|
|
if (SIGN_OPER_INT_RX & serial_dev_param->serial_set_mode) {
|
|
serial_dev->serial_fifo.serial_rx = (struct SerialRx *)malloc(sizeof(struct SerialRx));
|
|
if (NONE == serial_dev->serial_fifo.serial_rx) {
|
|
KPrintf("SerialDevOpen malloc serial_rx error\n");
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
return ERROR;
|
|
}
|
|
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_buffer = (uint8 *)malloc(serial_cfg->data_cfg.serial_buffer_size);
|
|
if (NONE == serial_dev->serial_fifo.serial_rx->serial_rx_buffer) {
|
|
KPrintf("SerialDevOpen malloc serial_rx_buffer error\n");
|
|
free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
return ERROR;
|
|
}
|
|
|
|
memset(serial_dev->serial_fifo.serial_rx->serial_rx_buffer, 0, serial_cfg->data_cfg.serial_buffer_size);
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num = 0;
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num = 0;
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_FALSE;
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_INT_RX;
|
|
|
|
serial_operation_cmd = OPER_SET_INT;
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (SIGN_OPER_DMA_RX & serial_dev_param->serial_set_mode) {
|
|
if (0 == serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx = (struct SerialRx *)malloc(sizeof(struct SerialRx));
|
|
if (NONE == serial_dev->serial_fifo.serial_rx) {
|
|
KPrintf("SerialDevOpen DMA buffer 0 malloc serial_rx error\n");
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
return ERROR;
|
|
}
|
|
serial_dev->serial_fifo.serial_rx->serial_dma_enable = RET_FALSE;
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_DMA_RX;
|
|
} else {
|
|
serial_dev->serial_fifo.serial_rx = (struct SerialRx *)malloc(sizeof(struct SerialRx));
|
|
if (NONE == serial_dev->serial_fifo.serial_rx) {
|
|
KPrintf("SerialDevOpen DMA malloc serial_rx error\n");
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
return ERROR;
|
|
}
|
|
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_buffer = (uint8 *)malloc(serial_cfg->data_cfg.serial_buffer_size);
|
|
if (NONE == serial_dev->serial_fifo.serial_rx->serial_rx_buffer) {
|
|
KPrintf("SerialDevOpen DMA malloc serial_rx_buffer error\n");
|
|
free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
return ERROR;
|
|
}
|
|
|
|
memset(serial_dev->serial_fifo.serial_rx->serial_rx_buffer, 0, serial_cfg->data_cfg.serial_buffer_size);
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num = 0;
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num = 0;
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_FALSE;
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_DMA_RX;
|
|
|
|
int serial_dma_operation = OPER_CONFIG;
|
|
serial_drv->drv_done->configure(serial_drv, serial_dma_operation);
|
|
}
|
|
}
|
|
#endif
|
|
else {
|
|
serial_dev->serial_fifo.serial_rx = NONE;
|
|
}
|
|
} else {
|
|
if (SIGN_OPER_INT_RX & serial_dev_param->serial_set_mode) {
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_INT_RX;
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (SIGN_OPER_DMA_RX & serial_dev_param->serial_set_mode) {
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_DMA_RX;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (NONE == serial_dev->serial_fifo.serial_tx) {
|
|
if (SIGN_OPER_INT_TX & serial_dev_param->serial_set_mode) {
|
|
serial_dev->serial_fifo.serial_tx = (struct SerialTx *)malloc(sizeof(struct SerialTx));
|
|
if (NONE == serial_dev->serial_fifo.serial_tx) {
|
|
KPrintf("SerialDevOpen malloc serial_tx error\n");
|
|
free(serial_dev->serial_fifo.serial_tx);
|
|
return ERROR;
|
|
}
|
|
|
|
serial_dev->serial_fifo.serial_tx->serial_txfifo_sem = KSemaphoreCreate(0);
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_INT_TX;
|
|
|
|
serial_operation_cmd = OPER_SET_INT;
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (SIGN_OPER_DMA_TX & serial_dev_param->serial_set_mode) {
|
|
serial_dev->serial_fifo.serial_tx = (struct SerialTx *)malloc(sizeof(struct SerialTx));
|
|
if (NONE == serial_dev->serial_fifo.serial_tx) {
|
|
KPrintf("SerialDevOpen DMA malloc serial_tx error\n");
|
|
free(serial_dev->serial_fifo.serial_tx);
|
|
return ERROR;
|
|
}
|
|
|
|
serial_dev->serial_fifo.serial_tx->serial_dma_enable = RET_FALSE;
|
|
serial_dev->serial_fifo.serial_tx->serial_dma_queue.done = g_queue_done[DATA_QUEUE];
|
|
serial_dev->serial_fifo.serial_tx->serial_dma_queue.property = x_malloc(sizeof(DataQueueType));
|
|
((DataQueueDoneType*)serial_dev->serial_fifo.serial_tx->serial_dma_queue.done)->InitDataqueue((DataQueueType *)serial_dev->serial_fifo.serial_tx->serial_dma_queue.property, 8);
|
|
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_DMA_TX;
|
|
serial_operation_cmd = OPER_CONFIG;
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#endif
|
|
else {
|
|
serial_dev->serial_fifo.serial_tx = NONE;
|
|
}
|
|
} else {
|
|
if (SIGN_OPER_INT_TX & serial_dev_param->serial_set_mode) {
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_INT_TX;
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (SIGN_OPER_DMA_TX & serial_dev_param->serial_set_mode) {
|
|
serial_dev_param->serial_work_mode |= SIGN_OPER_DMA_TX;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
serial_dev->haldev.dev_sem = KSemaphoreCreate(0);
|
|
if (serial_dev->haldev.dev_sem < 0) {
|
|
KPrintf("SerialDevOpen create sem failed .\n");
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_rx_buffer) {
|
|
free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
}
|
|
if (serial_dev->serial_fifo.serial_rx) {
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
}
|
|
if (serial_dev->serial_fifo.serial_tx) {
|
|
free(serial_dev->serial_fifo.serial_tx);
|
|
}
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static uint32 SerialDevClose(void *dev)
|
|
{
|
|
NULL_PARAM_CHECK(dev);
|
|
|
|
int serial_operation_cmd = OPER_CLR_INT;
|
|
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)dev;
|
|
struct Driver *drv = serial_dev->haldev.owner_bus->owner_driver;
|
|
struct SerialDriver *serial_drv = (struct SerialDriver *)drv;
|
|
struct SerialDevParam *serial_dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data;
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
if (SIGN_OPER_INT_RX & serial_dev_param->serial_work_mode) {
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_rx);
|
|
free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (SIGN_OPER_DMA_RX & serial_dev_param->serial_work_mode) {
|
|
if(0 == serial_cfg->data_cfg.serial_buffer_size)
|
|
{
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_rx);
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
} else {
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_rx);
|
|
free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer);
|
|
free(serial_dev->serial_fifo.serial_rx);
|
|
}
|
|
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#endif
|
|
|
|
if (SIGN_OPER_INT_TX & serial_dev_param->serial_work_mode) {
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_tx);
|
|
free(serial_dev->serial_fifo.serial_tx);
|
|
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (SIGN_OPER_DMA_TX & serial_dev_param->serial_work_mode) {
|
|
NULL_PARAM_CHECK(serial_dev->serial_fifo.serial_tx);
|
|
free(serial_dev->serial_fifo.serial_tx);
|
|
|
|
serial_drv->drv_done->configure(serial_drv, serial_operation_cmd);
|
|
}
|
|
#endif
|
|
|
|
KSemaphoreDelete(serial_dev->haldev.dev_sem);
|
|
return EOK;
|
|
}
|
|
|
|
static uint32 SerialDevWrite(void *dev, struct BusBlockWriteParam *write_param)
|
|
{
|
|
NULL_PARAM_CHECK(dev);
|
|
NULL_PARAM_CHECK(write_param);
|
|
|
|
x_err_t ret = EOK;
|
|
|
|
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)dev;
|
|
struct SerialDevParam *serial_dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data;
|
|
|
|
if (serial_dev_param->serial_work_mode & SIGN_OPER_INT_TX) {
|
|
ret = SerialDevIntWrite(serial_dev, write_param);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDevIntWrite error %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (serial_dev_param->serial_work_mode & SIGN_OPER_DMA_TX) {
|
|
ret = SerialDevDMAWrite(serial_dev, write_param);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDevDMAWrite error %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
else {
|
|
ret = SerialDevPollingWrite(serial_dev, write_param, serial_dev_param->serial_stream_mode);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDevPollingWrite error %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
return EOK;
|
|
}
|
|
|
|
static uint32 SerialDevRead(void *dev, struct BusBlockReadParam *read_param)
|
|
{
|
|
NULL_PARAM_CHECK(dev);
|
|
NULL_PARAM_CHECK(read_param);
|
|
|
|
x_err_t ret = EOK;
|
|
|
|
struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)dev;
|
|
struct SerialDevParam *serial_dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data;
|
|
|
|
if (EOK == KSemaphoreObtain(serial_dev->haldev.dev_sem, WAITING_FOREVER)) {
|
|
if (serial_dev_param->serial_work_mode & SIGN_OPER_INT_RX) {
|
|
ret = SerialDevIntRead(serial_dev, read_param);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDevIntRead error %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
else if (serial_dev_param->serial_work_mode & SIGN_OPER_DMA_RX) {
|
|
ret = SerialDevDMARead(serial_dev, read_param);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDevDMARead error %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
else {
|
|
ret = SerialDevPollingRead(serial_dev, read_param);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDevPollingRead error %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
}
|
|
return EOK;
|
|
}
|
|
|
|
void SerialSetIsr(struct SerialHardwareDevice *serial_dev, int event)
|
|
{
|
|
switch (event & 0xff)
|
|
{
|
|
case SERIAL_EVENT_RX_IND:
|
|
{
|
|
int get_char;
|
|
x_base lock;
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
while (1)
|
|
{
|
|
get_char = hwdev_done->get_char(serial_dev);
|
|
if (-ERROR == get_char) {
|
|
break;
|
|
}
|
|
|
|
lock = CriticalAreaLock();
|
|
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_buffer[serial_dev->serial_fifo.serial_rx->serial_send_num] = (uint8)get_char;
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num += 1;
|
|
if (serial_dev->serial_fifo.serial_rx->serial_send_num >= serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx->serial_send_num = 0;
|
|
}
|
|
|
|
if (serial_dev->serial_fifo.serial_rx->serial_send_num == serial_dev->serial_fifo.serial_rx->serial_recv_num) {
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num += 1;
|
|
serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_TRUE;
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num >= serial_cfg->data_cfg.serial_buffer_size) {
|
|
serial_dev->serial_fifo.serial_rx->serial_recv_num = 0;
|
|
}
|
|
}
|
|
CriticalAreaUnLock(lock);
|
|
}
|
|
|
|
x_size_t serial_rx_length;
|
|
|
|
lock = CriticalAreaLock();
|
|
if (serial_dev->serial_fifo.serial_rx->serial_recv_num > serial_dev->serial_fifo.serial_rx->serial_send_num) {
|
|
serial_rx_length = serial_cfg->data_cfg.serial_buffer_size - serial_dev->serial_fifo.serial_rx->serial_recv_num + serial_dev->serial_fifo.serial_rx->serial_send_num;
|
|
} else {
|
|
serial_rx_length = serial_dev->serial_fifo.serial_rx->serial_send_num - serial_dev->serial_fifo.serial_rx->serial_recv_num;
|
|
}
|
|
CriticalAreaUnLock(lock);
|
|
|
|
if (serial_rx_length) {
|
|
if (serial_dev->haldev.dev_recv_callback) {
|
|
serial_dev->haldev.dev_recv_callback((void *)serial_dev, serial_rx_length);
|
|
}
|
|
|
|
KSemaphoreAbandon(serial_dev->haldev.dev_sem);
|
|
}
|
|
break;
|
|
}
|
|
case SERIAL_event_id_tX_DONE:
|
|
{
|
|
KSemaphoreAbandon(serial_dev->serial_fifo.serial_tx->serial_txfifo_sem);
|
|
break;
|
|
}
|
|
#ifdef SERIAL_USING_DMA
|
|
case SERIAL_event_id_tX_DMADONE:
|
|
{
|
|
const void *data_ptr;
|
|
x_size_t DataSize;
|
|
const void *last_data_ptr;
|
|
|
|
struct SerialHwDevDone *hwdev_done = serial_dev->hwdev_done;
|
|
|
|
((DataQueueDoneType*)serial_dev->serial_fifo.serial_tx->serial_dma_queue.done)->PopDataqueue((DataQueueType *)serial_dev->serial_fifo.serial_tx->serial_dma_queue.property, &last_data_ptr, &DataSize, 0);
|
|
if (EOK == ((DataQueueDoneType*)serial_dev->serial_fifo.serial_tx->serial_dma_queue.done)->DataqueuePeak((DataQueueType *)serial_dev->serial_fifo.serial_tx->serial_dma_queue.property, &data_ptr, &DataSize)) {
|
|
serial_dev->serial_fifo.serial_tx->serial_dma_enable = RET_TRUE;
|
|
hwdev_done->dmatransfer(serial_dev, (uint8 *)data_ptr, DataSize, SERIAL_DMA_TX);
|
|
} else {
|
|
serial_dev->serial_fifo.serial_tx->serial_dma_enable = RET_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
case SERIAL_EVENT_RX_DMADONE:
|
|
{
|
|
int length;
|
|
x_base lock;
|
|
|
|
struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data;
|
|
|
|
length = (event & (~0xff)) >> 8;
|
|
|
|
if (serial_cfg->data_cfg.serial_buffer_size) {
|
|
lock = CriticalAreaLock();
|
|
|
|
SerialDmaRxSetSendLength(serial_dev, length);
|
|
|
|
length = SerialGetRxFifoLength(serial_dev);
|
|
|
|
CriticalAreaUnLock(lock);
|
|
if (serial_dev->haldev.dev_recv_callback) {
|
|
serial_dev->haldev.dev_recv_callback((void *)serial_dev, length);
|
|
}
|
|
KSemaphoreAbandon(serial_dev->haldev.dev_sem);
|
|
} else {
|
|
serial_dev->serial_fifo.serial_rx->serial_dma_enable = RET_FALSE;
|
|
if (serial_dev->haldev.dev_recv_callback) {
|
|
serial_dev->haldev.dev_recv_callback((void *)serial_dev, length);
|
|
}
|
|
KSemaphoreAbandon(serial_dev->haldev.dev_sem);
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
const struct SerialDevDone dev_done =
|
|
{
|
|
.open = SerialDevOpen,
|
|
.close = SerialDevClose,
|
|
.write = SerialDevWrite,
|
|
.read = SerialDevRead,
|
|
};
|
|
|
|
/*Create the serial device linklist*/
|
|
static void SerialDeviceLinkInit()
|
|
{
|
|
InitDoubleLinkList(&serialdev_linklist);
|
|
}
|
|
|
|
HardwareDevType SerialDeviceFind(const char *dev_name, enum DevType dev_type)
|
|
{
|
|
NULL_PARAM_CHECK(dev_name);
|
|
|
|
struct HardwareDev *device = NONE;
|
|
|
|
DoubleLinklistType *node = NONE;
|
|
DoubleLinklistType *head = &serialdev_linklist;
|
|
|
|
for (node = head->node_next; node != head; node = node->node_next) {
|
|
device = SYS_DOUBLE_LINKLIST_ENTRY(node, struct HardwareDev, dev_link);
|
|
if ((!strcmp(device->dev_name, dev_name)) && (dev_type == device->dev_type)) {
|
|
return device;
|
|
}
|
|
}
|
|
|
|
KPrintf("SerialDeviceFind cannot find the %s device.return NULL\n", dev_name);
|
|
return NONE;
|
|
}
|
|
|
|
int SerialDeviceRegister(struct SerialHardwareDevice *serial_device, void *serial_param, const char *device_name)
|
|
{
|
|
NULL_PARAM_CHECK(serial_device);
|
|
NULL_PARAM_CHECK(device_name);
|
|
|
|
x_err_t ret = EOK;
|
|
static x_bool dev_link_flag = RET_FALSE;
|
|
|
|
if (!dev_link_flag) {
|
|
SerialDeviceLinkInit();
|
|
dev_link_flag = RET_TRUE;
|
|
}
|
|
|
|
if (DEV_INSTALL != serial_device->haldev.dev_state) {
|
|
strncpy(serial_device->haldev.dev_name, device_name, NAME_NUM_MAX);
|
|
serial_device->haldev.dev_type = TYPE_SERIAL_DEV;
|
|
serial_device->haldev.dev_state = DEV_INSTALL;
|
|
|
|
if (serial_device->ext_serial_mode) {
|
|
serial_device->haldev.dev_done = (struct HalDevDone *)serial_device->dev_done;
|
|
} else {
|
|
serial_device->haldev.dev_done = (struct HalDevDone *)&dev_done;
|
|
}
|
|
|
|
serial_device->private_data = serial_param;
|
|
|
|
DoubleLinkListInsertNodeAfter(&serialdev_linklist, &(serial_device->haldev.dev_link));
|
|
} else {
|
|
KPrintf("SerialDeviceRegister device has been register state%u\n", serial_device->haldev.dev_state);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int SerialDeviceAttachToBus(const char *dev_name, const char *bus_name)
|
|
{
|
|
NULL_PARAM_CHECK(dev_name);
|
|
NULL_PARAM_CHECK(bus_name);
|
|
|
|
x_err_t ret = EOK;
|
|
|
|
struct Bus *bus;
|
|
struct HardwareDev *device;
|
|
|
|
bus = BusFind(bus_name);
|
|
if (NONE == bus) {
|
|
KPrintf("SerialDeviceAttachToBus find serial bus error!name %s\n", bus_name);
|
|
return ERROR;
|
|
}
|
|
|
|
if (TYPE_SERIAL_BUS == bus->bus_type) {
|
|
device = SerialDeviceFind(dev_name, TYPE_SERIAL_DEV);
|
|
if (NONE == device) {
|
|
KPrintf("SerialDeviceAttachToBus find serial device error!name %s\n", dev_name);
|
|
return ERROR;
|
|
}
|
|
|
|
if (TYPE_SERIAL_DEV == device->dev_type) {
|
|
ret = DeviceRegisterToBus(bus, device);
|
|
if (EOK != ret) {
|
|
KPrintf("SerialDeviceAttachToBus DeviceRegisterToBus error %u\n", ret);
|
|
return ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EOK;
|
|
}
|