GPIO driver: Add support for receiving signals from interrupt pins.
This commit is contained in:
parent
9b9b721406
commit
a932578e76
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@ -53,6 +54,7 @@
|
|||||||
* Private Function Prototypes
|
* Private Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int gpio_handler(FAR struct gpio_dev_s *dev);
|
||||||
static int gpio_open(FAR struct file *filep);
|
static int gpio_open(FAR struct file *filep);
|
||||||
static int gpio_close(FAR struct file *filep);
|
static int gpio_close(FAR struct file *filep);
|
||||||
static ssize_t gpio_read(FAR struct file *filep, FAR char *buffer,
|
static ssize_t gpio_read(FAR struct file *filep, FAR char *buffer,
|
||||||
@ -66,23 +68,7 @@ static int gpio_ioctl(FAR struct file *filep, int cmd,
|
|||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static const struct file_operations g_gpio_input_ops =
|
static const struct file_operations g_gpio_drvrops =
|
||||||
{
|
|
||||||
gpio_open, /* open */
|
|
||||||
gpio_close, /* close */
|
|
||||||
gpio_read, /* read */
|
|
||||||
NULL, /* write */
|
|
||||||
NULL, /* seek */
|
|
||||||
gpio_ioctl /* ioctl */
|
|
||||||
#ifndef CONFIG_DISABLE_POLL
|
|
||||||
, NULL /* poll */
|
|
||||||
#endif
|
|
||||||
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
|
||||||
, NULL /* unlink */
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations g_gpio_output_ops =
|
|
||||||
{
|
{
|
||||||
gpio_open, /* open */
|
gpio_open, /* open */
|
||||||
gpio_close, /* close */
|
gpio_close, /* close */
|
||||||
@ -102,6 +88,21 @@ static const struct file_operations g_gpio_output_ops =
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: gpio_handler
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Standard character driver open method.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int gpio_handler(FAR struct gpio_dev_s *dev)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(dev != NULL);
|
||||||
|
kill(dev->gp_pid, dev->gp_signo);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: gpio_open
|
* Name: gpio_open
|
||||||
*
|
*
|
||||||
@ -167,7 +168,7 @@ static ssize_t gpio_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
FAR struct inode *inode;
|
FAR struct inode *inode;
|
||||||
FAR struct gpio_common_dev_s *dev;
|
FAR struct gpio_dev_s *dev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||||
@ -177,20 +178,16 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
/* Command: GPIO_WRITE
|
/* Command: GPIOC_WRITE
|
||||||
* Description: Set the value of an output GPIO
|
* Description: Set the value of an output GPIO
|
||||||
* Argument: 0=output a low value; 1=outut a high value
|
* Argument: 0=output a low value; 1=outut a high value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case GPIO_WRITE:
|
case GPIOC_WRITE:
|
||||||
if (dev->gp_output)
|
if (dev->gp_pintype == GPIO_OUTPUT_PIN)
|
||||||
{
|
{
|
||||||
FAR struct gpio_output_dev_s *outdev =
|
DEBUGASSERT(arg == 0ul || arg == 1ul);
|
||||||
(FAR struct gpio_output_dev_s *)dev;
|
ret = dev->gp_ops->go_write(dev, (int)arg);
|
||||||
|
|
||||||
DEBUGASSERT(outdev->gpout_write != NULL &&
|
|
||||||
((arg == 0UL) || (arg == 1UL)));
|
|
||||||
ret = outdev->gpout_write(outdev, (int)arg);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -198,38 +195,64 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Command: GPIO_READ
|
/* Command: GPIOC_READ
|
||||||
* Description: Read the value of an input or output GPIO
|
* Description: Read the value of an input or output GPIO
|
||||||
* Argument: A pointer to an integer value to receive the result:
|
* Argument: A pointer to an integer value to receive the result:
|
||||||
* 0=low value; 1=high value.
|
* 0=low value; 1=high value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case GPIO_READ:
|
case GPIOC_READ:
|
||||||
{
|
{
|
||||||
FAR int *ptr = (FAR int *)((uintptr_t)arg);
|
FAR int *ptr = (FAR int *)((uintptr_t)arg);
|
||||||
DEBUGASSERT(ptr != NULL);
|
DEBUGASSERT(ptr != NULL);
|
||||||
|
|
||||||
if (dev->gp_output)
|
ret = dev->gp_ops->go_read(dev, ptr);
|
||||||
{
|
|
||||||
FAR struct gpio_output_dev_s *outdev =
|
|
||||||
(FAR struct gpio_output_dev_s *)dev;
|
|
||||||
|
|
||||||
DEBUGASSERT(outdev->gpout_read != NULL);
|
|
||||||
ret = outdev->gpout_read(outdev, ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FAR struct gpio_input_dev_s *indev =
|
|
||||||
(FAR struct gpio_input_dev_s *)dev;
|
|
||||||
|
|
||||||
DEBUGASSERT(indev->gpin_read != NULL);
|
|
||||||
ret = indev->gpin_read(indev, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGASSERT(ret < 0 || *ptr == 0 || *ptr == 1);
|
DEBUGASSERT(ret < 0 || *ptr == 0 || *ptr == 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Command: GPIOC_REGISTER
|
||||||
|
* Description: Register to receive a signal whenever there an
|
||||||
|
* interrupt is received on an input gpio pin. This
|
||||||
|
* feature, of course, depends upon interrupt GPIO
|
||||||
|
* support from the platform.
|
||||||
|
* Argument: The number of signal to be generated when the
|
||||||
|
* interrupt occurs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
case GPIOC_REGISTER:
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* Save signal information */
|
||||||
|
|
||||||
|
DEBUGASSERT(GOOD_SIGNO(arg));
|
||||||
|
|
||||||
|
dev->gp_pid = getpid();
|
||||||
|
dev->gp_signo = (uint8_t)arg;
|
||||||
|
|
||||||
|
/* Register our handler */
|
||||||
|
|
||||||
|
ret = dev->gp_ops->go_attach(dev,
|
||||||
|
(pin_interrupt_t)gpio_handler);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
/* Enable pin interrupts */
|
||||||
|
|
||||||
|
ret = dev->gp_ops->go_enable(dev, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = -EACCES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
/* Unrecognized command */
|
/* Unrecognized command */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -245,41 +268,63 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: gpio_input_register
|
* Name: gpio_pin_register
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Register GPIO input pin device driver.
|
* Register GPIO pin device driver.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int gpio_input_register(FAR struct gpio_input_dev_s *dev, int minor)
|
int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor)
|
||||||
{
|
{
|
||||||
|
FAR const char *fmt;
|
||||||
char devname[16];
|
char devname[16];
|
||||||
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(dev != NULL && !dev->gpin_output && dev->gpin_read != NULL &&
|
DEBUGASSERT(dev != NULL && dev->gp_ops != NULL && (unsigned int)minor < 100);
|
||||||
(unsigned int)minor < 100);
|
|
||||||
|
|
||||||
snprintf(devname, 16, "/dev/gpin%u", (unsigned int)minor);
|
switch (dev->gp_pintype)
|
||||||
return register_driver(devname, &g_gpio_input_ops, 0444, dev);
|
{
|
||||||
}
|
case GPIO_INPUT_PIN:
|
||||||
|
{
|
||||||
|
DEBUGASSERT(dev->gp_ops->go_read != NULL);
|
||||||
|
fmt = "/dev/gpin%u";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
/****************************************************************************
|
case GPIO_OUTPUT_PIN:
|
||||||
* Name: gpio_output_register
|
{
|
||||||
*
|
DEBUGASSERT(dev->gp_ops->go_read != NULL &&
|
||||||
* Description:
|
dev->gp_ops->go_write != NULL);
|
||||||
* Register GPIO output pin device driver.
|
fmt = "/dev/gpout%u";
|
||||||
*
|
|
||||||
****************************************************************************/
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
int gpio_output_register(FAR struct gpio_output_dev_s *dev, int minor)
|
case GPIO_INTERRUPT_PIN:
|
||||||
{
|
{
|
||||||
char devname[16];
|
DEBUGASSERT(dev->gp_ops->go_read != NULL &&
|
||||||
|
dev->gp_ops->go_attach != NULL &&
|
||||||
|
dev->gp_ops->go_enable != NULL);
|
||||||
|
|
||||||
DEBUGASSERT(dev != NULL && dev->gpout_output && dev->gpout_read != NULL &&
|
/* Make sure that the pin interrupt is disabled */
|
||||||
dev->gpout_write != NULL &&(unsigned int)minor < 100);
|
|
||||||
|
|
||||||
snprintf(devname, 16, "/dev/gpout%u", (unsigned int)minor);
|
ret = dev->gp_ops->go_enable(dev, false);
|
||||||
return register_driver(devname, &g_gpio_output_ops, 0222, dev);
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = "/dev/gpint%u";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(devname, 16, fmt, (unsigned int)minor);
|
||||||
|
return register_driver(devname, &g_gpio_drvrops, 0666, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_DEV_GPIO */
|
#endif /* CONFIG_DEV_GPIO */
|
||||||
|
@ -47,64 +47,80 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Command: GPIO_WRITE
|
/* Command: GPIOC_WRITE
|
||||||
* Description: Set the value of an output GPIO
|
* Description: Set the value of an output GPIO
|
||||||
* Argument: 0=output a low value; 1=outut a high value
|
* Argument: 0=output a low value; 1=outut a high value
|
||||||
*
|
*
|
||||||
* Command: GPIO_READ
|
* Command: GPIOC_READ
|
||||||
* Description: Read the value of an input or output GPIO
|
* Description: Read the value of an input or output GPIO
|
||||||
* Argument: A pointer to an integer value to receive the result:
|
* Argument: A pointer to an integer value to receive the result:
|
||||||
* 0=low value; 1=high value.
|
* 0=low value; 1=high value.
|
||||||
|
*
|
||||||
|
* Command: GPIOC_REGISTER
|
||||||
|
* Description: Register to receive a signal whenever there an interrupt
|
||||||
|
* is received on an input gpio pin. This feature, of course,
|
||||||
|
* depends upon interrupt GPIO support from the platform.
|
||||||
|
* Argument: The number of signal to be generated when the interrupt
|
||||||
|
* occurs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define GPIO_WRITE _GPIOC(1)
|
#define GPIOC_WRITE _GPIOC(1)
|
||||||
#define GPIO_READ _GPIOC(2)
|
#define GPIOC_READ _GPIOC(2)
|
||||||
|
#define GPIOC_REGISTER _GPIOC(3)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Common interface definition. Must be cast-compatible with struct
|
/* Identifies the type of the GPIO pin */
|
||||||
* gpio_input_dev_s and struct gpio_output_dev_s
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct gpio_common_dev_s
|
enum gpio_pintype_e
|
||||||
{
|
{
|
||||||
bool gp_output;
|
GPIO_INPUT_PIN = 0,
|
||||||
uint8_t gp_unused[3];
|
GPIO_OUTPUT_PIN,
|
||||||
|
GPIO_INTERRUPT_PIN
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The interface to a GPIO input pin */
|
/* Interrupt callback */
|
||||||
|
|
||||||
struct gpio_input_dev_s
|
typedef CODE int (*pin_interrupt_t)(FAR struct gpio_dev_s *dev);
|
||||||
|
|
||||||
|
/* Pin interface definition. */
|
||||||
|
|
||||||
|
struct gpio_dev_s;
|
||||||
|
struct gpio_operations_s
|
||||||
{
|
{
|
||||||
/* Common fields */
|
/* Interface methods */
|
||||||
|
|
||||||
bool gpin_output;
|
CODE int (*go_read)(FAR struct gpio_dev_s *dev, FAR int *value);
|
||||||
uint8_t gpin_unused[3];
|
CODE int (*go_write)(FAR struct gpio_dev_s *dev, int value);
|
||||||
|
CODE int (*go_attach)(FAR struct gpio_dev_s *dev,
|
||||||
/* Fields unique to input pins */
|
pin_interrupt_t callback);
|
||||||
|
CODE int (*go_enable)(FAR struct gpio_dev_s *dev, bool enable);
|
||||||
CODE int (*gpin_read)(FAR struct gpio_input_dev_s *dev, FAR int *value);
|
|
||||||
|
|
||||||
/* Lower-half private definitions may follow */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The interface to a GPIO input pin */
|
/* Pin interface definition. */
|
||||||
|
|
||||||
struct gpio_output_dev_s
|
struct gpio_dev_s
|
||||||
{
|
{
|
||||||
/* Common fields */
|
/* Information provided from the lower half driver to the upper half
|
||||||
|
* driver when gpio_pin_register() is called.
|
||||||
|
*/
|
||||||
|
|
||||||
bool gpout_output;
|
uint8_t gp_pintype; /* See enum gpio_pintype_e */;
|
||||||
uint8_t gpout_unused[3];
|
|
||||||
|
|
||||||
/* Fields unique to output pins */
|
/* Writable storage used by the upper half driver */
|
||||||
|
|
||||||
CODE int (*gpout_read)(FAR struct gpio_output_dev_s *dev, FAR int *value);
|
uint8_t gp_signo; /* signo to use when signaling a GPIO interrupt */
|
||||||
CODE int (*gpout_write)(FAR struct gpio_output_dev_s *dev, int value);
|
pid_t gp_pid; /* The task to be signalled */
|
||||||
|
|
||||||
/* Lower-half private definitions may follow */
|
/* Read-only pointer to GPIO device operations (also provided by the
|
||||||
|
* lower half driver).
|
||||||
|
*/
|
||||||
|
|
||||||
|
FAR const struct gpio_operations_s *gp_ops;
|
||||||
|
|
||||||
|
/* Device specific information may follow */
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -120,24 +136,14 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: gpio_input_register
|
* Name: gpio_pin_register
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Register GPIO input pin device driver.
|
* Register GPIO pin device driver.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int gpio_input_register(FAR struct gpio_input_dev_s *dev, int minor);
|
int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor);
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: gpio_output_register
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Register GPIO output pin device driver.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
int gpio_output_register(FAR struct gpio_output_dev_s *dev, int minor);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user