driver/sensor: add fetch api to read sensor data directly

1.use userspace buffer rather than intermediate buffer of upperhalf driver
2.support block and non-block ways.

Change-Id: I1d0cecfaa20ce54961c58713d8f2f8857e349791
Signed-off-by: dongjiuzhu <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu 2020-11-04 11:23:39 +08:00 committed by Xiang Xiao
parent 2cda16b606
commit 089b1c17f6
2 changed files with 166 additions and 47 deletions

View file

@ -73,7 +73,6 @@ struct sensor_buffer_s
struct sensor_upperhalf_s
{
/* poll structures of threads waiting for driver events. */
FAR struct pollfd *fds[CONFIG_SENSORS_NPOLLWAITERS];
@ -403,24 +402,13 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
return ret;
}
/* We must make sure that when the semaphore is equal to 1, there must
* be events avaliable in the buffer, so we use a while statement to
* synchronize this case that other read operations consume events
* that have just entered the buffer.
*/
while (sensor_buffer_is_empty(upper->buffer))
if (lower->ops->fetch)
{
if (filep->f_oflags & O_NONBLOCK)
{
ret = -EAGAIN;
goto again;
}
else
if (!(filep->f_oflags & O_NONBLOCK))
{
nxsem_post(&upper->exclsem);
ret = nxsem_wait_uninterruptible(&upper->buffersem);
if (ret)
if (ret < 0)
{
return ret;
}
@ -431,21 +419,55 @@ static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer,
return ret;
}
}
ret = lower->ops->fetch(lower, buffer, len);
}
ret = sensor_buffer_pop(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
* in buffer is less than the number of bytes origin.
*/
if (upper->latency == 0 &&
upper->buffer->size > lower->buffer_size &&
sensor_buffer_len(upper->buffer) <= lower->buffer_size)
else
{
sensor_buffer_resize(&upper->buffer, lower->type,
lower->buffer_size);
/* We must make sure that when the semaphore is equal to 1, there must
* be events avaliable in the buffer, so we use a while statement to
* synchronize this case that other read operations consume events
* that have just entered the buffer.
*/
while (sensor_buffer_is_empty(upper->buffer))
{
if (filep->f_oflags & O_NONBLOCK)
{
ret = -EAGAIN;
goto again;
}
else
{
nxsem_post(&upper->exclsem);
ret = nxsem_wait_uninterruptible(&upper->buffersem);
if (ret < 0)
{
return ret;
}
ret = nxsem_wait(&upper->exclsem);
if (ret < 0)
{
return ret;
}
}
}
ret = sensor_buffer_pop(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
* in buffer is less than the number of bytes origin.
*/
if (upper->latency == 0 &&
upper->buffer->size > lower->buffer_size &&
sensor_buffer_len(upper->buffer) <= lower->buffer_size)
{
sensor_buffer_resize(&upper->buffer, lower->type,
lower->buffer_size);
}
}
again:
@ -579,7 +601,9 @@ static int sensor_poll(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;
pollevent_t eventset = 0;
int semcount;
int ret;
int i;
@ -609,7 +633,24 @@ static int sensor_poll(FAR struct file *filep,
goto errout;
}
if (!sensor_buffer_is_empty(upper->buffer))
if (lower->ops->fetch)
{
/* Always return POLLIN for fetch data directly(non-block) */
if (filep->f_oflags & O_NONBLOCK)
{
eventset |= (fds->events & POLLIN);
}
else
{
nxsem_get_value(&upper->buffersem, &semcount);
if (semcount > 0)
{
eventset |= (fds->events & POLLIN);
}
}
}
else if (!sensor_buffer_is_empty(upper->buffer))
{
eventset |= (fds->events & POLLIN);
}
@ -638,7 +679,7 @@ errout:
}
static void sensor_push_event(FAR void *priv, FAR const void *data,
uint32_t bytes)
size_t bytes)
{
FAR struct sensor_upperhalf_s *upper = priv;
int semcount;
@ -659,6 +700,26 @@ static void sensor_push_event(FAR void *priv, FAR const void *data,
nxsem_post(&upper->exclsem);
}
static void sensor_notify_event(FAR void *priv)
{
FAR struct sensor_upperhalf_s *upper = priv;
int semcount;
if (nxsem_wait(&upper->exclsem) < 0)
{
return;
}
sensor_pollnotify(upper, POLLIN);
nxsem_get_value(&upper->buffersem, &semcount);
if (semcount < 1)
{
nxsem_post(&upper->buffersem);
}
nxsem_post(&upper->exclsem);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -723,11 +784,19 @@ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno)
/* Bind the lower half data structure member */
lower->priv = upper;
lower->push_event = sensor_push_event;
if (!lower->buffer_size)
if (!lower->ops->fetch)
{
lower->buffer_size = g_sensor_info[lower->type].esize;
if (!lower->buffer_size)
{
lower->buffer_size = g_sensor_info[lower->type].esize;
}
lower->push_event = sensor_push_event;
}
else
{
lower->notify_event = sensor_notify_event;
}
/* Initialize sensor buffer */

View file

@ -497,6 +497,38 @@ struct sensor_ops_s
CODE int (*batch)(FAR struct sensor_lowerhalf_s *lower,
FAR unsigned int *latency_us);
/**************************************************************************
* Name: fetch
*
* Fetch sensor register data by this function. It will use buffer of
* userspace provided and disables intermediate buffer of upper half. It's
* recommend that the lowerhalf driver writer to use this function for
* slower sensor ODR (output data rate) of sensor because this way saves
* space and it's simple.
*
* If fetch isn't NULL, upper half driver will disable intermediate
* buffer and userspace can't set buffer size by ioctl.
*
* You can call this function to read sensor register data by I2C/SPI bus
* when open mode is non-block, and poll are always successful.
* When you call this function and open mode is block, you will wait
* until sensor data ready, then read sensor data.
*
* Input Parameters:
* lower - The instance of lower half sensor driver.
* buffer - The buffer of receive sensor event, it's provided by
* file_operation::sensor_read.
* buflen - The size of buffer.
*
* Returned Value:
* The size of read buffer returned on success; a negated errno value
* on failure.
*
**************************************************************************/
CODE int (*fetch)(FAR struct sensor_lowerhalf_s *lower,
FAR char *buffer, size_t buflen);
/**************************************************************************
* Name: control
*
@ -552,21 +584,39 @@ struct sensor_lowerhalf_s
FAR const struct sensor_ops_s *ops;
/**************************************************************************
* Name: push_event
*
* Description:
* Lower half driver push sensor event by calling this function.
* It is provided by upper half driver to lower half driver.
*
* Input Parameters:
* priv - Upper half driver handle
* data - The buffer of event, it can be all type of sensor events.
* bytes - The number of bytes of sensor event
**************************************************************************/
union
{
/**********************************************************************
* Name: push_event
*
* Description:
* Lower half driver push sensor event by calling this function.
* It is provided by upper half driver to lower half driver.
*
* Input Parameters:
* priv - Upper half driver handle
* data - The buffer of event, it can be all type of sensor events.
* bytes - The number of bytes of sensor event
**********************************************************************/
CODE void (*push_event)(FAR void *priv, FAR const void *data,
uint32_t bytes);
CODE void (*push_event)(FAR void *priv, FAR const void *data,
size_t bytes);
/**********************************************************************
* Name: notify_event
*
* Description:
* Lower half driver notify sensor data ready and can read by fetch.
* It is provided by upper half driver to lower half driver.
*
* This api is used when sensor_ops_s::fetch isn't NULL.
*
* Input Parameters:
* priv - Upper half driver handle
**********************************************************************/
CODE void (*notify_event)(FAR void *priv);
};
/* The private opaque pointer to be passed to upper-layer during callback */