diff --git a/drivers/power/battery_gauge.c b/drivers/power/battery_gauge.c index eecfefc2f75..66fe97bb38c 100644 --- a/drivers/power/battery_gauge.c +++ b/drivers/power/battery_gauge.c @@ -28,9 +28,13 @@ #include #include +#include #include +#include +#include #include +#include #include #include @@ -46,9 +50,18 @@ ****************************************************************************/ /**************************************************************************** - * Private + * Private type ****************************************************************************/ +struct battery_gauge_priv_s +{ + struct list_node node; + sem_t lock; + sem_t wait; + uint32_t mask; + FAR struct pollfd *fds; +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -65,6 +78,8 @@ static ssize_t bat_gauge_write(FAR struct file *filep, size_t buflen); static int bat_gauge_ioctl(FAR struct file *filep, int cmd, unsigned long arg); +static int bat_gauge_poll(FAR struct file *filep, + FAR struct pollfd *fds, bool setup); /**************************************************************************** * Private Data @@ -78,13 +93,48 @@ static const struct file_operations g_batteryops = bat_gauge_write, NULL, bat_gauge_ioctl, - NULL + bat_gauge_poll }; /**************************************************************************** * Private Functions ****************************************************************************/ +static int battery_gauge_notify(FAR struct battery_gauge_priv_s *priv, + uint32_t mask) +{ + FAR struct pollfd *fd = priv->fds; + int semcnt; + int ret; + + ret = nxsem_wait_uninterruptible(&priv->lock); + if (ret < 0) + { + return ret; + } + + priv->mask |= mask; + if (priv->mask) + { + fd->revents |= POLLIN; + nxsem_get_value(fd->sem, &semcnt); + if (semcnt < 1) + { + nxsem_post(fd->sem); + } + + nxsem_get_value(&priv->wait, &semcnt); + if (semcnt < 1) + { + nxsem_post(&priv->wait); + } + } + + nxsem_post(&priv->lock); + + return OK; +} + /**************************************************************************** * Name: bat_gauge_open * @@ -95,7 +145,31 @@ static const struct file_operations g_batteryops = static int bat_gauge_open(FAR struct file *filep) { - return OK; + FAR struct battery_gauge_priv_s *priv; + FAR struct battery_gauge_dev_s *dev = filep->f_inode->i_private; + int ret; + + priv = kmm_zalloc(sizeof(*priv)); + if (priv == NULL) + { + return -ENOMEM; + } + + ret = nxsem_wait(&dev->batsem); + if (ret < 0) + { + kmm_free(priv); + return ret; + } + + nxsem_init(&priv->lock, 0, 1); + nxsem_init(&priv->wait, 0, 0); + nxsem_set_protocol(&priv->wait, SEM_PRIO_NONE); + list_add_tail(&dev->flist, &priv->node); + nxsem_post(&dev->batsem); + filep->f_priv = priv; + + return ret; } /**************************************************************************** @@ -108,7 +182,23 @@ static int bat_gauge_open(FAR struct file *filep) static int bat_gauge_close(FAR struct file *filep) { - return OK; + FAR struct battery_gauge_priv_s *priv = filep->f_priv; + FAR struct battery_gauge_dev_s *dev = filep->f_inode->i_private; + int ret; + + ret = nxsem_wait(&dev->batsem); + if (ret < 0) + { + return ret; + } + + list_delete(&priv->node); + nxsem_post(&dev->batsem); + nxsem_destroy(&priv->lock); + nxsem_destroy(&priv->wait); + kmm_free(priv); + + return ret; } /**************************************************************************** @@ -118,9 +208,46 @@ static int bat_gauge_close(FAR struct file *filep) static ssize_t bat_gauge_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { - /* Return nothing read */ + FAR struct battery_gauge_priv_s *priv = filep->f_priv; + int ret; - return 0; + if (buflen < sizeof(priv->mask)) + { + return -EINVAL; + } + + ret = nxsem_wait(&priv->lock); + if (ret < 0) + { + return ret; + } + + while (priv->mask == 0) + { + nxsem_post(&priv->lock); + if (filep->f_oflags & O_NONBLOCK) + { + return -EAGAIN; + } + + ret = nxsem_wait(&priv->wait); + if (ret < 0) + { + return ret; + } + + ret = nxsem_wait(&priv->lock); + if (ret < 0) + { + return ret; + } + } + + memcpy(buffer, &priv->mask, sizeof(priv->mask)); + priv->mask = 0; + + nxsem_post(&priv->lock); + return sizeof(priv->mask); } /**************************************************************************** @@ -211,10 +338,80 @@ static int bat_gauge_ioctl(FAR struct file *filep, return ret; } +/**************************************************************************** + * Name: bat_gauge_poll + ****************************************************************************/ + +static ssize_t bat_gauge_poll(FAR struct file *filep, + struct pollfd *fds, bool setup) +{ + FAR struct battery_gauge_priv_s *priv = filep->f_priv; + int ret; + + ret = nxsem_wait(&priv->lock); + if (ret < 0) + { + return ret; + } + + if (setup) + { + if (priv->fds == NULL) + { + priv->fds = fds; + fds->priv = &priv->fds; + } + else + { + ret = -EBUSY; + } + } + else if (fds->priv != NULL) + { + priv->fds = NULL; + fds->priv = NULL; + } + + nxsem_post(&priv->lock); + + if (setup) + { + battery_gauge_notify(priv, 0); + } + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: battery_gauge_changed + ****************************************************************************/ + +int battery_gauge_changed(FAR struct battery_gauge_dev_s *dev, + uint32_t mask) +{ + FAR struct battery_gauge_priv_s *priv; + int ret; + + ret = nxsem_wait_uninterruptible(&dev->batsem); + if (ret < 0) + { + return ret; + } + + list_for_every_entry(&dev->flist, priv, + struct battery_gauge_priv_s, node) + { + battery_gauge_notify(priv, mask); + } + + nxsem_post(&dev->batsem); + return OK; +} + /**************************************************************************** * Name: battery_gauge_register * @@ -237,9 +434,10 @@ int battery_gauge_register(FAR const char *devpath, { int ret; - /* Initialize the semaphore */ + /* Initialize the semaphore and list */ nxsem_init(&dev->batsem, 0, 1); + list_initialize(&dev->flist); /* Register the character driver */ diff --git a/include/nuttx/power/battery_gauge.h b/include/nuttx/power/battery_gauge.h index f03ce6ca246..c1e074f06e4 100644 --- a/include/nuttx/power/battery_gauge.h +++ b/include/nuttx/power/battery_gauge.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -109,6 +110,8 @@ struct battery_gauge_dev_s FAR const struct battery_gauge_operations_s *ops; /* Battery operations */ sem_t batsem; /* Enforce mutually exclusive access */ + struct list_node flist; + /* Data fields specific to the lower-half driver may follow */ }; @@ -130,6 +133,13 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: battery_gauge_changed + ****************************************************************************/ + +int battery_gauge_changed(FAR struct battery_gauge_dev_s *dev, + uint32_t mask); + /**************************************************************************** * Name: battery_gauge_register * diff --git a/include/nuttx/power/battery_ioctl.h b/include/nuttx/power/battery_ioctl.h index 237918d1c17..edb1318ec7f 100644 --- a/include/nuttx/power/battery_ioctl.h +++ b/include/nuttx/power/battery_ioctl.h @@ -68,7 +68,8 @@ #define BATTERY_ONLINE_CHANGED (1U << 2) #define BATTERY_VOLTAGE_CHANGED (1U << 3) #define BATTERY_CURRENT_CHANGED (1U << 4) -#define BATTERY_INPUT_CURRENT_CHANGED (1U << 5) +#define BATTERY_CAPACITY_CHANGED (1U << 5) +#define BATTERY_TEMPERATURE_CHANGED (1U << 6) /**************************************************************************** * Public Types