未验证 提交 1a3b7461 编写于 作者: B Bernard Xiong 提交者: GitHub

Merge pull request #997 from JasonJiaJie/master

[DeviceDriver][serial]1.Fix poll rx issue when data is full. 2.Add TCFLSH and FIONREAD support.
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
* 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0. * 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-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-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.
*/ */
#include <rthw.h> #include <rthw.h>
...@@ -141,7 +143,7 @@ static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count) ...@@ -141,7 +143,7 @@ static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count)
device = (rt_device_t)fd->data; device = (rt_device_t)fd->data;
do do
{ {
size = rt_device_read(device, -1, buf, count); size = rt_device_read(device, -1, buf, count);
if (size <= 0) if (size <= 0)
...@@ -173,7 +175,7 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req) ...@@ -173,7 +175,7 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
int flags = 0; int flags = 0;
rt_device_t device; rt_device_t device;
struct rt_serial_device *serial; struct rt_serial_device *serial;
device = (rt_device_t)fd->data; device = (rt_device_t)fd->data;
RT_ASSERT(device != RT_NULL); RT_ASSERT(device != RT_NULL);
...@@ -187,11 +189,11 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req) ...@@ -187,11 +189,11 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
struct rt_serial_rx_fifo* rx_fifo; struct rt_serial_rx_fifo* rx_fifo;
rt_poll_add(&(device->wait_queue), req); rt_poll_add(&(device->wait_queue), req);
rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx; rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
if (rx_fifo->get_index != rx_fifo->put_index) if ((rx_fifo->get_index != rx_fifo->put_index) || (rx_fifo->get_index == rx_fifo->put_index && rx_fifo->is_full == RT_TRUE))
mask |= POLLIN; mask |= POLLIN;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
} }
...@@ -199,7 +201,7 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req) ...@@ -199,7 +201,7 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
return mask; return mask;
} }
const static struct dfs_file_ops _serial_fops = const static struct dfs_file_ops _serial_fops =
{ {
serial_fops_open, serial_fops_open,
serial_fops_close, serial_fops_close,
...@@ -286,19 +288,25 @@ rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, ...@@ -286,19 +288,25 @@ rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data,
/* disable interrupt */ /* disable interrupt */
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
if (rx_fifo->get_index != rx_fifo->put_index)
{ /* there's no data: */
ch = rx_fifo->buffer[rx_fifo->get_index]; if ((rx_fifo->get_index == rx_fifo->put_index) && (rx_fifo->is_full == RT_FALSE))
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 */ /* no data, enable interrupt and break out */
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
break; break;
} }
/* otherwise there's the data: */
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;
if (rx_fifo->is_full == RT_TRUE)
{
rx_fifo->is_full = RT_FALSE;
}
/* enable interrupt */ /* enable interrupt */
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
...@@ -334,34 +342,85 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t * ...@@ -334,34 +342,85 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
return size - length; return size - length;
} }
/** static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial)
* Calculate DMA received data length.
*
* @param serial serial device
*
* @return length
*/
static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial)
{ {
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL); RT_ASSERT(rx_fifo != RT_NULL);
if (rx_fifo->put_index > rx_fifo->get_index) if (rx_fifo->put_index == rx_fifo->get_index)
return rx_fifo->put_index - rx_fifo->get_index; {
else if (rx_fifo->put_index < rx_fifo->get_index) return (rx_fifo->is_full == RT_FALSE ? 0 : serial->config.bufsz);
return serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index); }
else else
{ {
if (rx_fifo->is_full) if (rx_fifo->put_index > rx_fifo->get_index)
return serial->config.bufsz; {
return rx_fifo->put_index - rx_fifo->get_index;
}
else else
return 0; {
return serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index);
}
} }
} }
static void _serial_flush(struct rt_serial_device *serial, int queue)
{
int ch = -1;
struct rt_serial_rx_fifo *rx_fifo = RT_NULL;
struct rt_device *device = RT_NULL;
RT_ASSERT(serial != RT_NULL);
device = &(serial->parent);
rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
switch(queue)
{
case TCIFLUSH:
case TCIOFLUSH:
RT_ASSERT(rx_fifo != RT_NULL);
if((device->open_flag & RT_DEVICE_FLAG_INT_RX) || (device->open_flag & RT_DEVICE_FLAG_DMA_RX))
{
RT_ASSERT(RT_NULL != rx_fifo);
rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
rx_fifo->put_index = 0;
rx_fifo->get_index = 0;
rx_fifo->is_full = RT_FALSE;
}
else
{
while (1)
{
ch = serial->ops->getc(serial);
if (ch == -1) break;
}
}
break;
case TCOFLUSH:
break;
}
}
/** /**
* Read data finish by DMA mode then update the gut index for receive fifo. * Calculate DMA received data length.
*
* @param serial serial device
*
* @return length
*/
static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial)
{
return _serial_fifo_calc_recved_len(serial);
}
/**
* Read data finish by DMA mode then update the get index for receive fifo.
* *
* @param serial serial device * @param serial serial device
* @param len get data length for this operate * @param len get data length for this operate
...@@ -552,7 +611,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) ...@@ -552,7 +611,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
RT_ASSERT(dev != RT_NULL); RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev; serial = (struct rt_serial_device *)dev;
dbg_log(DBG_LOG, "open serial device: 0x%08x with open flag: 0x%04x\n", dbg_log(DBG_LOG, "open serial device: 0x%08x with open flag: 0x%04x\n",
dev, oflag); dev, oflag);
/* check device flag with the open flag */ /* check device flag with the open flag */
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX)) if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
...@@ -612,6 +671,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) ...@@ -612,6 +671,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
rx_fifo->put_index = 0; rx_fifo->put_index = 0;
rx_fifo->get_index = 0; rx_fifo->get_index = 0;
rx_fifo->is_full = RT_FALSE;
serial->serial_rx = rx_fifo; serial->serial_rx = rx_fifo;
dev->open_flag |= RT_DEVICE_FLAG_INT_RX; dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
...@@ -790,13 +850,13 @@ static rt_size_t rt_serial_write(struct rt_device *dev, ...@@ -790,13 +850,13 @@ static rt_size_t rt_serial_write(struct rt_device *dev,
} }
#ifdef RT_USING_POSIX_TERMIOS #ifdef RT_USING_POSIX_TERMIOS
struct speed_baudrate_item struct speed_baudrate_item
{ {
speed_t speed; speed_t speed;
int baudrate; int baudrate;
}; };
const static struct speed_baudrate_item _tbl[] = const static struct speed_baudrate_item _tbl[] =
{ {
{B2400, BAUD_RATE_2400}, {B2400, BAUD_RATE_2400},
{B4800, BAUD_RATE_4800}, {B4800, BAUD_RATE_4800},
...@@ -963,11 +1023,30 @@ static rt_err_t rt_serial_control(struct rt_device *dev, ...@@ -963,11 +1023,30 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
} }
break; break;
case TCFLSH: case TCFLSH:
{
int queue = (int)args;
_serial_flush(serial, queue);
}
break; break;
case TCXONC: case TCXONC:
break; break;
#endif #endif
#ifdef RT_USING_POSIX
case FIONREAD:
{
rt_size_t recved = 0;
rt_base_t level;
level = rt_hw_interrupt_disable();
recved = _serial_fifo_calc_recved_len(serial);
rt_hw_interrupt_enable(level);
*(rt_size_t *)args = recved;
}
break;
#endif
default : default :
/* control device */ /* control device */
ret = serial->ops->control(serial, cmd, args); ret = serial->ops->control(serial, cmd, args);
...@@ -1046,6 +1125,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) ...@@ -1046,6 +1125,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
if (rx_fifo->put_index == rx_fifo->get_index) if (rx_fifo->put_index == rx_fifo->get_index)
{ {
rx_fifo->get_index += 1; rx_fifo->get_index += 1;
rx_fifo->is_full = RT_TRUE;
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册