driver/sensor rc: use mm/circbuf manage intermediate buffer

N/A

Change-Id: Ifdd8117da9d20ac2f48f04b7b383449e6dd03f06
Signed-off-by: dongjiuzhu <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu 2020-11-12 18:40:37 +08:00 committed by Xiang Xiao
parent 23ddeaf3be
commit 8f9ca79ffc
4 changed files with 57 additions and 304 deletions

View file

@ -5,6 +5,7 @@
menuconfig DRIVERS_RC
bool "Remote Control Device Support"
select MM_CIRCBUF
default n
---help---
Drivers for various remote control

View file

@ -30,6 +30,7 @@
#include <fcntl.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mm/circbuf.h>
#include <nuttx/rc/lirc_dev.h>
/****************************************************************************
@ -56,23 +57,13 @@ struct lirc_upperhalf_s
uint64_t gap_duration; /* duration of initial gap */
};
/* This structure describes lirc circular buffer */
struct lirc_buffer_s
{
uint32_t head;
uint32_t tail;
uint32_t size;
FAR void *data;
};
/* The structure describes an open lirc file */
struct lirc_fh_s
{
struct list_node node; /* list of open file handles */
FAR struct lirc_lowerhalf_s *lower; /* the pointer to lirc_lowerhalf_s */
FAR struct lirc_buffer_s *buffer; /* buffer for incoming IR */
struct circbuf_s buffer; /* buffer for incoming IR */
FAR struct pollfd *fd; /* poll structures of threads waiting for driver events */
sem_t waitsem; /* sem of wait buffer for ready */
int carrier_low; /* when setting the carrier range, first the low end must be
@ -117,96 +108,6 @@ static const struct file_operations g_lirc_fops =
* Private Functions
****************************************************************************/
static void lirc_buffer_free(FAR struct lirc_buffer_s *buffer)
{
kmm_free(buffer);
}
static uint32_t lirc_buffer_len(FAR struct lirc_buffer_s *buffer)
{
return buffer->head - buffer->tail;
}
static uint32_t lirc_buffer_empty(FAR struct lirc_buffer_s *buffer)
{
return !lirc_buffer_len(buffer);
}
static uint32_t lirc_buffer_unused(FAR struct lirc_buffer_s *buffer)
{
return buffer->size - lirc_buffer_len(buffer);
}
static uint32_t lirc_buffer_read(FAR struct lirc_buffer_s *buffer,
FAR void *dest, uint32_t bytes)
{
uint32_t len = lirc_buffer_len(buffer);
uint32_t off = buffer->tail % buffer->size;
if (bytes > len)
{
bytes = len;
}
len = buffer->size - off;
if (bytes < len)
{
len = bytes;
}
memcpy(dest, buffer->data + off, len);
memcpy(dest + len, buffer->data, bytes - len);
buffer->tail += bytes;
return bytes;
}
static uint32_t lirc_buffer_write(FAR struct lirc_buffer_s *buffer,
FAR const void *src, uint32_t bytes)
{
uint32_t space = lirc_buffer_unused(buffer);
uint32_t off = buffer->head % buffer->size;
if (bytes > space)
{
bytes = space;
}
space = buffer->size - off;
if (bytes < space)
{
space = bytes;
}
memcpy(buffer->data + off, src, space);
memcpy(buffer->data, src + space, bytes - space);
buffer->head += bytes;
return bytes;
}
static int lirc_buffer_create(FAR struct lirc_buffer_s **buffer,
uint32_t bytes)
{
FAR struct lirc_buffer_s *tmp;
tmp = kmm_malloc(sizeof((*tmp)) + bytes);
if (!tmp)
{
rcerr("Faild to malloc memory for circular buffer\n");
return -ENOMEM;
}
tmp->size = bytes;
tmp->data = tmp + 1;
tmp->head = 0;
tmp->tail = 0;
*buffer = tmp;
return 0;
}
static void lirc_pollnotify(FAR struct lirc_fh_s *fh,
pollevent_t eventset)
{
@ -263,9 +164,9 @@ static int lirc_open(FAR struct file *filep)
fh->send_mode = LIRC_MODE_PULSE;
}
if (lirc_buffer_create(&fh->buffer, lower->buffer_bytes))
ret = circbuf_init(&fh->buffer, NULL, lower->buffer_bytes);
if (ret < 0)
{
ret = -ENOMEM;
goto buffer_err;
}
@ -293,7 +194,7 @@ static int lirc_open(FAR struct file *filep)
open_err:
nxsem_destroy(&fh->waitsem);
lirc_buffer_free(fh->buffer);
circbuf_uninit(&fh->buffer);
buffer_err:
kmm_free(fh);
return ret;
@ -312,7 +213,7 @@ static int lirc_close(FAR struct file *filep)
leave_critical_section(flags);
nxsem_destroy(&fh->waitsem);
lirc_buffer_free(fh->buffer);
circbuf_uninit(&fh->buffer);
kmm_free(fh);
if (list_is_empty(&upper->fh))
@ -343,7 +244,7 @@ static int lirc_poll(FAR struct file *filep,
fh->fd = fds;
fds->priv = &fh->fd;
if (!lirc_buffer_empty(fh->buffer))
if (!circbuf_is_empty(&fh->buffer))
{
eventset = (fds->events & (POLLIN | POLLRDNORM));
}
@ -787,7 +688,7 @@ static ssize_t lirc_read_scancode(FAR struct file *filep, FAR char *buffer,
flags = enter_critical_section();
do
{
if (lirc_buffer_empty(fh->buffer))
if (circbuf_is_empty(&fh->buffer))
{
if (filep->f_oflags & O_NONBLOCK)
{
@ -802,9 +703,9 @@ static ssize_t lirc_read_scancode(FAR struct file *filep, FAR char *buffer,
}
}
len = lirc_buffer_read(fh->buffer, buffer, length);
len = circbuf_read(&fh->buffer, buffer, length);
}
while (len == 0);
while (len <= 0);
err:
leave_critical_section(flags);
@ -827,7 +728,7 @@ static ssize_t lirc_read_mode2(FAR struct file *filep, FAR char *buffer,
flags = enter_critical_section();
do
{
if (lirc_buffer_empty(fh->buffer))
if (circbuf_is_empty(&fh->buffer))
{
if (filep->f_oflags & O_NONBLOCK)
{
@ -842,9 +743,9 @@ static ssize_t lirc_read_mode2(FAR struct file *filep, FAR char *buffer,
}
}
len = lirc_buffer_read(fh->buffer, buffer, length);
len = circbuf_read(&fh->buffer, buffer, length);
}
while (len == 0);
while (len <= 0);
err:
leave_critical_section(flags);
@ -1035,7 +936,7 @@ void lirc_raw_event(FAR struct lirc_lowerhalf_s *lower,
list_for_every_safe(&upper->fh, node, tmp)
{
fh = (FAR struct lirc_fh_s *)node;
if (lirc_buffer_write(fh->buffer, &gap, sizeof(int)))
if (circbuf_write(&fh->buffer, &gap, sizeof(int)) > 0)
{
lirc_pollnotify(fh, POLLIN | POLLRDNORM);
nxsem_get_value(&fh->waitsem, &semcount);
@ -1063,7 +964,7 @@ void lirc_raw_event(FAR struct lirc_lowerhalf_s *lower,
continue;
}
if (lirc_buffer_write(fh->buffer, &sample, sizeof(unsigned int)))
if (circbuf_write(&fh->buffer, &sample, sizeof(unsigned int)) > 0)
{
lirc_pollnotify(fh, POLLIN | POLLRDNORM);
nxsem_get_value(&fh->waitsem, &semcount);
@ -1107,7 +1008,7 @@ void lirc_scancode_event(FAR struct lirc_lowerhalf_s *lower,
list_for_every_safe(&upper->fh, node, tmp)
{
fh = (FAR struct lirc_fh_s *)node;
if (lirc_buffer_write(fh->buffer, lsc, sizeof(*lsc)))
if (circbuf_write(&fh->buffer, lsc, sizeof(*lsc)) > 0)
{
lirc_pollnotify(fh, POLLIN | POLLRDNORM);
nxsem_get_value(&fh->waitsem, &semcount);
@ -1153,7 +1054,7 @@ void lirc_sample_event(FAR struct lirc_lowerhalf_s *lower,
list_for_every_safe(&upper->fh, node, tmp)
{
fh = (FAR struct lirc_fh_s *)node;
if (lirc_buffer_write(fh->buffer, &sample, sizeof(unsigned int)))
if (circbuf_write(&fh->buffer, &sample, sizeof(unsigned int)) > 0)
{
lirc_pollnotify(fh, POLLIN | POLLRDNORM);
nxsem_get_value(&fh->waitsem, &semcount);

View file

@ -5,6 +5,7 @@
menuconfig SENSORS
bool "Sensor Device Support"
select MM_CIRCBUF
default n
---help---
Drivers for various sensors

View file

@ -34,6 +34,7 @@
#include <poll.h>
#include <fcntl.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mm/circbuf.h>
#include <nuttx/sensors/sensor.h>
/****************************************************************************
@ -59,16 +60,6 @@ struct sensor_info
FAR char *name;
};
/* This structure describes sensor circular buffer */
struct sensor_buffer_s
{
uint32_t head;
uint32_t tail;
uint32_t size;
FAR void *data;
};
/* This structure describes the state of the upper half driver */
struct sensor_upperhalf_s
@ -77,7 +68,7 @@ struct sensor_upperhalf_s
FAR struct pollfd *fds[CONFIG_SENSORS_NPOLLWAITERS];
FAR struct sensor_lowerhalf_s *lower; /* the handle of lower half driver */
FAR struct sensor_buffer_s *buffer; /* The circualr buffer of sensor device */
struct circbuf_s buffer; /* The circular buffer of sensor device */
uint8_t crefs; /* Number of times the device has been opened */
sem_t exclsem; /* Manages exclusive access to file operations */
sem_t buffersem; /* Wakeup user waiting for data in circular buffer */
@ -148,154 +139,6 @@ static const struct file_operations g_sensor_fops =
* Private Functions
****************************************************************************/
static bool sensor_buffer_is_empty(FAR struct sensor_buffer_s *buffer)
{
return buffer->head == buffer->tail;
}
static uint32_t sensor_buffer_len(FAR struct sensor_buffer_s *buffer)
{
return buffer->head - buffer->tail;
}
static uint32_t sensor_buffer_unused(FAR struct sensor_buffer_s *buffer)
{
return buffer->size - sensor_buffer_len(buffer);
}
static void sensor_buffer_reset(FAR struct sensor_buffer_s *buffer)
{
buffer->head = buffer->tail = 0;
}
static void sensor_buffer_push(FAR struct sensor_buffer_s *buffer,
FAR const void *data, uint32_t bytes)
{
uint32_t space = sensor_buffer_unused(buffer);
uint32_t off = buffer->head % buffer->size;
uint32_t overwrite = 0;
/* If buffer is full or there is not enough space, overwriting of old
* data will occur, we should move tail point after pushing data
* completely.
*/
if (bytes > buffer->size)
{
data += bytes - buffer->size;
bytes = buffer->size;
}
if (bytes > space)
{
overwrite = bytes - space;
}
space = buffer->size - off;
if (bytes < space)
{
space = bytes;
}
memcpy(buffer->data + off, data, space);
memcpy(buffer->data, data + space, bytes - space);
buffer->head += bytes;
buffer->tail += overwrite;
}
static uint32_t sensor_buffer_pop(FAR struct sensor_buffer_s *buffer,
FAR void *data, uint32_t bytes)
{
uint32_t len = sensor_buffer_len(buffer);
uint32_t off;
if (bytes > len)
{
bytes = len;
}
if (!data)
{
goto skip;
}
off = buffer->tail % buffer->size;
len = buffer->size - off;
if (bytes < len)
{
len = bytes;
}
memcpy(data, buffer->data + off, len);
memcpy(data + len, buffer->data, bytes - len);
skip:
buffer->tail += bytes;
return bytes;
}
static int sensor_buffer_resize(FAR struct sensor_buffer_s **buffer,
int type, uint32_t bytes)
{
FAR struct sensor_buffer_s *tmp;
int len = sensor_buffer_len(*buffer);
int skipped;
bytes = ROUNDUP(bytes, g_sensor_info[type].esize);
tmp = kmm_malloc(sizeof(*tmp) + bytes);
if (!tmp)
{
snerr("Faild to alloc memory for circular buffer\n");
return -ENOMEM;
}
tmp->data = tmp + 1;
skipped = (bytes > len) ? 0 : len - bytes;
len -= skipped;
sensor_buffer_pop(*buffer, NULL, skipped);
sensor_buffer_pop(*buffer, tmp->data, len);
tmp->size = bytes;
tmp->head = len;
tmp->tail = 0;
kmm_free(*buffer);
*buffer = tmp;
return 0;
}
static int sensor_buffer_create(FAR struct sensor_buffer_s **buffer,
int type, uint32_t bytes)
{
FAR struct sensor_buffer_s *tmp;
bytes = ROUNDUP(bytes, g_sensor_info[type].esize);
tmp = kmm_malloc(sizeof(*tmp) + bytes);
if (!tmp)
{
snerr("Faild to malloc memory for circular buffer\n");
return -ENOMEM;
}
tmp->size = bytes;
tmp->data = tmp + 1;
tmp->head = 0;
tmp->tail = 0;
*buffer = tmp;
return 0;
}
static void sensor_buffer_release(FAR struct sensor_buffer_s *buffer)
{
kmm_free(buffer);
}
static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper,
pollevent_t eventset)
{
@ -328,6 +171,8 @@ static int sensor_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct sensor_upperhalf_s *upper = inode->i_private;
FAR struct sensor_lowerhalf_s *lower = upper->lower;
size_t bytes;
uint8_t tmp;
int ret;
@ -347,7 +192,14 @@ static int sensor_open(FAR struct file *filep)
}
else if (tmp == 1)
{
sensor_buffer_reset(upper->buffer);
/* Initialize sensor buffer */
bytes = ROUNDUP(lower->buffer_size, g_sensor_info[lower->type].esize);
ret = circbuf_init(&upper->buffer, NULL, bytes);
if (ret < 0)
{
goto err;
}
}
upper->crefs = tmp;
@ -376,6 +228,7 @@ static int sensor_close(FAR struct file *filep)
if (ret >= 0)
{
upper->enabled = false;
circbuf_uninit(&upper->buffer);
}
}
@ -390,6 +243,7 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
FAR struct sensor_upperhalf_s *upper = inode->i_private;
FAR struct sensor_lowerhalf_s *lower = upper->lower;
ssize_t ret;
size_t bytes;
if (!buffer || !len)
{
@ -430,7 +284,7 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
* that have just entered the buffer.
*/
while (sensor_buffer_is_empty(upper->buffer))
while (circbuf_is_empty(&upper->buffer))
{
if (filep->f_oflags & O_NONBLOCK)
{
@ -454,7 +308,7 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
}
}
ret = sensor_buffer_pop(upper->buffer, buffer, len);
ret = circbuf_read(&upper->buffer, buffer, len);
/* Release some buffer space when current mode isn't batch mode
* and last mode is batch mode, and the number of bytes avaliable
@ -462,11 +316,12 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
*/
if (upper->latency == 0 &&
upper->buffer->size > lower->buffer_size &&
sensor_buffer_len(upper->buffer) <= lower->buffer_size)
circbuf_size(&upper->buffer) > lower->buffer_size &&
circbuf_used(&upper->buffer) <= lower->buffer_size)
{
sensor_buffer_resize(&upper->buffer, lower->type,
lower->buffer_size);
bytes = ROUNDUP(lower->buffer_size,
g_sensor_info[lower->type].esize);
ret = circbuf_resize(&upper->buffer, bytes);
}
}
@ -481,6 +336,7 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
FAR struct sensor_upperhalf_s *upper = inode->i_private;
FAR struct sensor_lowerhalf_s *lower = upper->lower;
FAR unsigned int *val = (unsigned int *)(uintptr_t)arg;
size_t bytes;
int ret;
sninfo("cmd=%x arg=%08x\n", cmd, arg);
@ -547,11 +403,13 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
/* Adjust length of buffer in batch mode */
sensor_buffer_resize(&upper->buffer, lower->type,
lower->buffer_size +
ROUNDUP(*val, upper->interval) /
upper->interval *
g_sensor_info[lower->type].esize);
bytes = ROUNDUP(ROUNDUP(*val, upper->interval) /
upper->interval *
g_sensor_info[lower->type].esize +
lower->buffer_size,
g_sensor_info[lower->type].esize);
ret = circbuf_resize(&upper->buffer, bytes);
}
}
}
@ -569,9 +427,13 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
lower->buffer_size = ROUNDUP(*val,
g_sensor_info[lower->type].esize);
sensor_buffer_resize(&upper->buffer, lower->type,
lower->buffer_size);
*val = lower->buffer_size;
bytes = ROUNDUP(lower->buffer_size,
g_sensor_info[lower->type].esize);
ret = circbuf_resize(&upper->buffer, bytes);
if (ret >= 0)
{
*val = lower->buffer_size;
}
}
}
break;
@ -650,7 +512,7 @@ static int sensor_poll(FAR struct file *filep,
}
}
}
else if (!sensor_buffer_is_empty(upper->buffer))
else if (!circbuf_is_empty(&upper->buffer))
{
eventset |= (fds->events & POLLIN);
}
@ -689,7 +551,7 @@ static void sensor_push_event(FAR void *priv, FAR const void *data,
return;
}
sensor_buffer_push(upper->buffer, data, bytes);
circbuf_overwrite(&upper->buffer, data, bytes);
sensor_pollnotify(upper, POLLIN);
nxsem_get_value(&upper->buffersem, &semcount);
if (semcount < 1)
@ -799,15 +661,6 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno)
lower->notify_event = sensor_notify_event;
}
/* Initialize sensor buffer */
ret = sensor_buffer_create(&upper->buffer,
lower->type, lower->buffer_size);
if (ret)
{
goto buf_err;
}
snprintf(path, DEVNAME_MAX, DEVNAME_FMT,
g_sensor_info[lower->type].name,
lower->uncalibrated ? DEVNAME_UNCAL : "",
@ -823,8 +676,6 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno)
return ret;
drv_err:
sensor_buffer_release(upper->buffer);
buf_err:
nxsem_destroy(&upper->exclsem);
nxsem_destroy(&upper->buffersem);
@ -867,6 +718,5 @@ void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno)
nxsem_destroy(&upper->exclsem);
nxsem_destroy(&upper->buffersem);
sensor_buffer_release(upper->buffer);
kmm_free(upper);
}