drivers/ioexpander: Support multiple registrations of GPIO signal events.
This commit is contained in:
parent
a9ff43d93c
commit
71a6244198
|
@ -181,6 +181,14 @@ config DEV_GPIO
|
|||
Enables a simple GPIO input/output driver to support application-
|
||||
space testing of hardware.
|
||||
|
||||
config DEV_GPIO_NSIGNALS
|
||||
int "Max number of signals"
|
||||
default 1
|
||||
depends on DEV_GPIO
|
||||
---help---
|
||||
The maximum number of signals that can be registered with the GPIO
|
||||
driver
|
||||
|
||||
config GPIO_LOWER_HALF
|
||||
bool "GPIO Lower Half"
|
||||
default n
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
@ -99,8 +100,22 @@ static const struct file_operations g_gpio_drvrops =
|
|||
|
||||
static int gpio_handler(FAR struct gpio_dev_s *dev, uint8_t pin)
|
||||
{
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
(void)nxsig_kill(dev->gp_pid, dev->gp_signo);
|
||||
|
||||
for (i = 0; i < CONFIG_DEV_GPIO_NSIGNALS; i++)
|
||||
{
|
||||
FAR struct gpio_signal_s *signal = &dev->gp_signals[i];
|
||||
|
||||
if (signal->gp_pid == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
nxsig_notification(signal->gp_pid, &signal->gp_event, SI_QUEUE);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -170,7 +185,11 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
{
|
||||
FAR struct inode *inode;
|
||||
FAR struct gpio_dev_s *dev;
|
||||
irqstate_t flags;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||
inode = filep->f_inode;
|
||||
|
@ -237,20 +256,28 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
*/
|
||||
|
||||
case GPIOC_REGISTER:
|
||||
if (dev->gp_pintype == GPIO_INTERRUPT_PIN)
|
||||
if (arg && dev->gp_pintype == GPIO_INTERRUPT_PIN)
|
||||
{
|
||||
/* Make sure that the pin interrupt is disabled */
|
||||
|
||||
ret = dev->gp_ops->go_enable(dev, false);
|
||||
if (ret >= 0)
|
||||
pid = getpid();
|
||||
flags = spin_lock_irqsave();
|
||||
for (i = 0; i < CONFIG_DEV_GPIO_NSIGNALS; i++)
|
||||
{
|
||||
/* Save signal information */
|
||||
FAR struct gpio_signal_s *signal = &dev->gp_signals[i];
|
||||
|
||||
DEBUGASSERT(GOOD_SIGNO(arg));
|
||||
if (signal->gp_pid == 0 || signal->gp_pid == pid)
|
||||
{
|
||||
memcpy(&signal->gp_event, (FAR void *)arg,
|
||||
sizeof(signal->gp_event));
|
||||
signal->gp_pid = pid;
|
||||
ret = OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dev->gp_pid = getpid();
|
||||
dev->gp_signo = (uint8_t)arg;
|
||||
spin_unlock_irqrestore(flags);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
/* Register our handler */
|
||||
|
||||
ret = dev->gp_ops->go_attach(dev,
|
||||
|
@ -262,6 +289,10 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
ret = dev->gp_ops->go_enable(dev, true);
|
||||
}
|
||||
}
|
||||
else if (i == CONFIG_DEV_GPIO_NSIGNALS)
|
||||
{
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -277,17 +308,49 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
case GPIOC_UNREGISTER:
|
||||
if (dev->gp_pintype == GPIO_INTERRUPT_PIN)
|
||||
{
|
||||
/* Make sure that the pin interrupt is disabled */
|
||||
|
||||
ret = dev->gp_ops->go_enable(dev, false);
|
||||
if (ret >= 0)
|
||||
pid = getpid();
|
||||
flags = spin_lock_irqsave();
|
||||
for (i = 0; i < CONFIG_DEV_GPIO_NSIGNALS; i++)
|
||||
{
|
||||
/* Detach the handler */
|
||||
if (pid == dev->gp_signals[i].gp_pid)
|
||||
{
|
||||
for (j = i + 1; j < CONFIG_DEV_GPIO_NSIGNALS; j++)
|
||||
{
|
||||
if (dev->gp_signals[j].gp_pid == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = dev->gp_ops->go_attach(dev, NULL);
|
||||
if (i != --j)
|
||||
{
|
||||
memcpy(&dev->gp_signals[i], &dev->gp_signals[j],
|
||||
sizeof(dev->gp_signals[i]));
|
||||
}
|
||||
|
||||
dev->gp_pid = 0;
|
||||
dev->gp_signo = 0;
|
||||
dev->gp_signals[j].gp_pid = 0;
|
||||
ret = OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(flags);
|
||||
|
||||
if (i == 0 && j == 0)
|
||||
{
|
||||
/* Make sure that the pin interrupt is disabled */
|
||||
|
||||
ret = dev->gp_ops->go_enable(dev, false);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Detach the handler */
|
||||
|
||||
ret = dev->gp_ops->go_attach(dev, NULL);
|
||||
}
|
||||
}
|
||||
else if (i == CONFIG_DEV_GPIO_NSIGNALS)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
|
@ -138,6 +139,14 @@ struct gpio_operations_s
|
|||
enum gpio_pintype_e pintype);
|
||||
};
|
||||
|
||||
/* Signal information */
|
||||
|
||||
struct gpio_signal_s
|
||||
{
|
||||
struct sigevent gp_event;
|
||||
pid_t gp_pid; /* The task to be signaled */
|
||||
};
|
||||
|
||||
/* Pin interface definition. Must lie in writable memory. */
|
||||
|
||||
struct gpio_dev_s
|
||||
|
@ -150,8 +159,7 @@ struct gpio_dev_s
|
|||
|
||||
/* Writable storage used by the upper half driver */
|
||||
|
||||
uint8_t gp_signo; /* signo to use when signaling a GPIO interrupt */
|
||||
pid_t gp_pid; /* The task to be signalled */
|
||||
struct gpio_signal_s gp_signals[CONFIG_DEV_GPIO_NSIGNALS];
|
||||
|
||||
/* Read-only pointer to GPIO device operations (also provided by the
|
||||
* lower half driver).
|
||||
|
|
Loading…
Reference in New Issue