Commit b2f93cdf authored by Michael Gloff's avatar Michael Gloff
Browse files

Initial commit of Vortex86 RTDM GPIO driver.


Signed-off-by: Michael Gloff's avatarMichael Gloff <mgloff@emacinc.com>
parents
obj-m += xeno_gpio.o
xeno_gpio-y := gpio.o
SRC := $(shell pwd)
#Set KERNEL_SRC to the built Xenomai kernel
#KERNEL_SRC := /home/developer/xeno-kernel/build-3.18.20-xeno
all:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symvers
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <rtdm/driver.h>
#include <rtdm/rtdm.h>
#include "gpio.h"
MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
MODULE_DESCRIPTION("RTDM GPIO driver");
MODULE_VERSION("0.0.0");
MODULE_LICENSE("GPL");
struct gpio_priv {
int gpio;
int irq;
int dir;
int val;
rtdm_irq_t irq_handle;
rtdm_event_t irq_event;
};
static int gpio_irq_handler(rtdm_irq_t *irq_handle)
{
struct gpio_priv *ctx = rtdm_irq_get_arg(irq_handle, struct gpio_priv);
rtdm_event_signal(&ctx->irq_event);
return RTDM_IRQ_HANDLED;
}
static int gpio_ioctl_rt(struct rtdm_fd *fd, unsigned int request,
void __user *arg)
{
struct gpio_priv *ctx = rtdm_fd_to_private(fd);
int err = 0;
int irq;
switch(request) {
case GPIO_IRQ_BIND:
ctx->irq = (int) arg;
irq = gpio_to_irq(ctx->irq);
irq_set_irq_type(irq, IRQF_TRIGGER_LOW);
err = rtdm_irq_request(&ctx->irq_handle, irq, gpio_irq_handler,
0, "rtdm_gpio", ctx);
if (err < 0) {
ctx->irq = -1;
return err;
}
rtdm_event_init(&ctx->irq_event, 0);
err = rtdm_irq_enable(&ctx->irq_handle);
if (err < 0) {
ctx->irq = -1;
return err;
}
break;
case GPIO_IRQ_WAIT:
err = rtdm_event_wait(&ctx->irq_event);
break;
case GPIO_PIN_SET:
ctx->gpio = (int) arg;
if (gpio_cansleep(ctx->gpio))
return -EINVAL;
err = gpio_request(ctx->gpio, "rtdm_gpio");
if (err < 0) {
ctx->gpio = -1;
break;
}
ctx->dir = gpiod_get_direction(gpio_to_desc(ctx->gpio)) ? 1 : 0;
ctx->val = gpiod_get_raw_value(gpio_to_desc(ctx->gpio));
break;
case GPIO_PIN_GET:
if (!rtdm_rw_user_ok(fd, arg, sizeof(ctx->gpio)))
return -EFAULT;
err = rtdm_copy_to_user(fd, arg, &ctx->gpio, sizeof(ctx->gpio));
break;
case GPIO_DIR_SET:
if (ctx->gpio == -1)
return -ENODEV;
ctx->dir = ((int) arg == 0) ? 0 : 1;
if (ctx->dir)
gpio_direction_output(ctx->gpio, ctx->val);
else
gpio_direction_input(ctx->gpio);
break;
case GPIO_DIR_GET:
if (ctx->gpio == -1)
return -ENODEV;
ctx->dir = gpiod_get_direction(gpio_to_desc(ctx->gpio)) ? 1 : 0;
if (!rtdm_rw_user_ok(fd, arg, sizeof(ctx->dir)))
return -EFAULT;
err = rtdm_copy_to_user(fd, arg, &ctx->dir, sizeof(ctx->dir));
break;
case GPIO_VAL_SET:
if (ctx->gpio == -1)
return -ENODEV;
ctx->val = (int) arg;
if (ctx->dir)
gpio_set_value(ctx->gpio, ctx->val);
break;
case GPIO_VAL_GET:
if (ctx->gpio == -1)
return -ENODEV;
ctx->val = gpiod_get_raw_value(gpio_to_desc(ctx->gpio));
if (!rtdm_rw_user_ok(fd, arg, sizeof(ctx->val)))
return -EFAULT;
err = rtdm_copy_to_user(fd, arg, &ctx->val, sizeof(ctx->val));
break;
default:
return -EINVAL;
}
return err;
}
static int gpio_open(struct rtdm_fd *fd, int oflags)
{
struct gpio_priv *ctx = rtdm_fd_to_private(fd);
ctx->gpio = -1;
ctx->irq = -1;
return 0;
}
static void gpio_close(struct rtdm_fd *fd)
{
struct gpio_priv *ctx = rtdm_fd_to_private(fd);
if (ctx->irq >= 0) {
rtdm_irq_disable(&ctx->irq_handle);
rtdm_irq_free(&ctx->irq_handle);
rtdm_event_destroy(&ctx->irq_event);
}
if (ctx->gpio >= 0)
gpio_free(ctx->gpio);
}
static struct rtdm_driver gpio_driver = {
.profile_info = RTDM_PROFILE_INFO(gpio,
RTDM_CLASS_EXPERIMENTAL,
RTDM_SUBCLASS_GENERIC,
RTGPIO_PROFILE_VER),
.device_flags = RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
.device_count = 32,
.context_size = sizeof(struct gpio_priv),
.ops = {
.open = gpio_open,
.close = gpio_close,
.ioctl_rt = gpio_ioctl_rt,
},
};
static struct rtdm_device device[32] = {
[0 ... 31] = {
.driver = &gpio_driver,
.label = "rtgpio%d",
}
};
static int __init __gpio_init(void)
{
int i, ret;
if (!realtime_core_enabled())
return -ENODEV;
for (i = 0; i < ARRAY_SIZE(device); i++) {
ret = rtdm_dev_register(device + i);
if (ret)
goto fail;
}
return 0;
fail:
while (i-- > 0)
rtdm_dev_unregister(device + i);
return ret;
}
static void __exit __gpio_exit(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(device); i++)
rtdm_dev_unregister(device + i);
}
module_init(__gpio_init);
module_exit(__gpio_exit);
#include <linux/ioctl.h>
#define RTGPIO_PROFILE_VER 1
#define GPIO_IOC_MAGIC 'r'
#define GPIO_PIN_SET _IOW(GPIO_IOC_MAGIC, 1, int)
#define GPIO_PIN_GET _IOR(GPIO_IOC_MAGIC, 2, int)
#define GPIO_DIR_SET _IOW(GPIO_IOC_MAGIC, 3, int)
#define GPIO_DIR_GET _IOR(GPIO_IOC_MAGIC, 4, int)
#define GPIO_VAL_SET _IOW(GPIO_IOC_MAGIC, 5, int)
#define GPIO_VAL_GET _IOR(GPIO_IOC_MAGIC, 6, int)
#define GPIO_IRQ_BIND _IOW(GPIO_IOC_MAGIC, 7, int)
#define GPIO_IRQ_WAIT _IO(GPIO_IOC_MAGIC, 8)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment