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:
parent
2cda16b606
commit
089b1c17f6
2 changed files with 166 additions and 47 deletions
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue