RTDM中断请求函数原型:
int rtdm_irq_request (rtdm_irq_t *irq_handle, unsigned int irq_no,
rtdm_irq_handler_t handler, unsigned long flags,
const char *device_name, void *arg)
参数介绍:
irq_handle , IRQ句柄
irq_no: IRQ的中断号
handler:中断处理的句柄
flags:注册的标志位,细节查看宏定义 RTDM_IRQTYPE_xxx
device_name:设备名称,将显示在实时IRQ列表中
arg:在调用时传递给中断处理程序的参数指针
注册标志位介绍:
RTDM_IRQ_NONE 未处理的中断。
RTDM_IRQ_HANDLED 表示处理中断.
RTDM_IRQ_DISABLE 退出时请求中断禁用。
int rtdm_irq_enable (rtdm_irq_t *irq_handle) //使能IRQ中断,此服务只能在次要模式使用。
int rtdm_irq_free(rtdm_irq_t * irq_handle) //释放已申请的中断句柄
//获取IRQ句柄参数指针
define rtdm_irq_get_arg ( irq_handle, type ) ((type *)irq_handle->cookie)
//用于设置irq对应的中断的触发类型.
int irq_set_irq_type(unsigned int irq, unsigned int type)
中断方式type定义如下: (linux-2.6.21.7/include/linux/interrupt.h )
define IRQF_TRIGGER_NONE 0x00000000/无触发中断/
#define IRQF_TRIGGER_RISING 0x00000001/*指定中断触发类型:上升沿有效*/
#define IRQF_TRIGGER_FALLING 0x00000002/*中断触发类型:下降沿有效*/
#define IRQF_TRIGGER_HIGH 0x00000004/*指定中断触发类型:高电平有效*/
#define IRQF_TRIGGER_LOW 0x00000008/*指定中断触发类型:低电平有效*/
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW |
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE 0x00000010/*触发式检测中断*/
#define IRQF_DISABLED 0x00000020 //使用这个时为快速中断
#define IRQF_SAMPLE_RANDOM 0x00000040 /*供系统产生随机数使用*/
#define IRQF_SHARED 0x00000080 /*中断可以在设备之间可共享*/
#define IRQF_PROBE_SHARED 0x00000100/*探测共享中断*/
#define IRQF_TIMER 0x00000200/*专用于时钟中断*/
#define IRQF_PERCPU 0x00000400/*每CPU周期执行中断*/
#define IRQF_NOBALANCING 0x00000800/*复位中断*/
#define IRQF_IRQPOLL 0x00001000/*共享中断中根据注册时间判断*/
#define IRQF_ONESHOT 0x00002000/*硬件中断处理完后触发*/
##########例程用到的函数介绍##################
//检测是否启动实时内核
static inline int realtime_core_enabled(void) {
return atomic_read(&cobalt_runstate) != COBALT_STATE_DISABLED;
}
int class_create(owner,name)//动态创建设备的逻辑类,创建的逻辑类位于/sys/class/
class_destroy(struct class *cls)//注销类,与create_class配对使用
int rtdm_drv_set_sysclass(struct rtdm_driver *drv, struct class *cls) //设置RTDM驱动程序的内核设备类。
RTDM驱动程序默认属于Linux的RTDM设备类,在/dev/ rtdm上创建设备节点,在/sys/class/ RTDM下创建系统文件节点。
int gpiod_get_raw_value(const struct gpio_desc *desc) //获取设备GPIO实际电平,非逻辑电平
void gpiod_set_raw_value(struct gpio_desc *desc, int value) ///设置设备GPIO实际电平,非逻辑电平
int gpio_request(unsigned gpio, const char *label) //系统分别GPIO,label为引脚的名称定义
int gpio_export(unsigned gpio, bool direction_may_change); //导出gpio到用户空间
int gpio_direction_input(unsigned gpio); //设置io为输入
int gpio_direction_output(unsigned gpio, int value); //设置io为输出,并设置初始值
void rtdm_event_init(rtdm_event_t *event, unsigned long pending) //初始化一个事件,pending非0则挂起
void rtdm_event_signal (rtdm_event_t * event) //产生一个事件信号
void rtdm_event_clear(rtdm_event_t * event) //清空一个事件
void rtdm_event_destroy(rtdm_event_t * event) //销毁一个事件
//将给定的选择器绑定到事件,以便当有事件发生通知到绑定器
int rtdm_event_select(rtdm_event_t *event, rtdm_selector_t *selector,
enum rtdm_selecttype type, unsigned int fd_index)
wait_event_interruptible( waitQueue , condition ) //等待中断事件,并进入休眠
void wake_up(wait_queue_head_t *q) //唤醒一个等待队列
成功地唤醒一个被wait_event_interruptible()的进程,需要同时满足:
1)condition为真的前提下 2) 调用wake_up()。
rtdm_lock_get_irqsave(..) //通过停止头域,获取锁和禁用抢占
rtdm_lock_put_irqrestore(..) //恢复抢占状态。
rtdm_safe_copy_from_user()和rtdm_copy_from_user()的区别:
两者都有类似的功能,将用户空间内存块复制到指定的缓冲区
rtdm_copy_from_user()实现是 __xn_copy_from_user(dst, src, size) ? -EFAULT : 0;
rtdm_safe_copy_from_user()是在上面函数增加access_rok(src, size)地址读权限判断
rtdm_lock_get_irqsave(__lock, __context) //获取锁定和禁用抢占,通过停止头域。
rtdm_lock_put_irqrestore (rtdm_lock_t *lock, rtdm_lockctx_t context) //释放锁并恢复抢占状态
#######gpio-core.c 所使用的中断机制 (xenomai3/kernel/drivers/gpio)##################
点击查看代码
/**
* @note Copyright (C) 2016 Philippe Gerum <rpm@xenomai.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/err.h>
#include "gpio-core.h"
struct rtdm_gpio_pin {
struct rtdm_device dev;
struct list_head next;
rtdm_irq_t irqh;
rtdm_event_t event;
char *name;
struct gpio_desc *desc;
};
struct rtdm_gpio_chan {
int requested : 1,
has_direction : 1,
is_output : 1 ;
};
static int gpio_pin_interrupt(rtdm_irq_t *irqh)
{
struct rtdm_gpio_pin *pin;
pin = rtdm_irq_get_arg(irqh, struct rtdm_gpio_pin);
rtdm_event_signal(&pin->event);
return RTDM_IRQ_HANDLED;
}
static int request_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin,
struct rtdm_gpio_chan *chan,
int trigger)
{
int ret, irq_trigger;
unsigned int irq;
if (trigger & ~GPIO_TRIGGER_MASK)
return -EINVAL;
ret = gpio_request(gpio, pin->name);
if (ret) {
if (ret != -EPROBE_DEFER)
printk(XENO_ERR "cannot request GPIO%d/n", gpio);
return ret;
}
ret = gpio_direction_input(gpio);
if (ret) {
printk(XENO_ERR "cannot set GPIO%d as input/n", gpio);
goto fail;
}
chan->has_direction = true;
gpio_export(gpio, true);
rtdm_event_clear(&pin->event);
irq = gpio_to_irq(gpio);
irq_trigger = 0;
if (trigger & GPIO_TRIGGER_EDGE_RISING)
irq_trigger |= IRQ_TYPE_EDGE_RISING;
if (trigger & GPIO_TRIGGER_EDGE_FALLING)
irq_trigger |= IRQ_TYPE_EDGE_FALLING;
if (trigger & GPIO_TRIGGER_LEVEL_HIGH)
irq_trigger |= IRQ_TYPE_LEVEL_HIGH;
if (trigger & GPIO_TRIGGER_LEVEL_LOW)
irq_trigger |= IRQ_TYPE_LEVEL_LOW;
if (irq_trigger)
irq_set_irq_type(irq, irq_trigger);
ret = rtdm_irq_request(&pin->irqh, irq, gpio_pin_interrupt,
0, pin->name, pin);
if (ret) {
printk(XENO_ERR "cannot request GPIO%d interrupt/n", gpio);
goto fail;
}
chan->requested = true;
rtdm_irq_enable(&pin->irqh);
return 0;
fail:
gpio_free(gpio);
return ret;
}
static void release_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin,
struct rtdm_gpio_chan *chan)
{
rtdm_irq_free(&pin->irqh);
gpio_free(gpio);
chan->requested = false;
}
static int gpio_pin_ioctl_nrt(struct rtdm_fd *fd,
unsigned int request, void *arg)
{
struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
struct rtdm_device *dev = rtdm_fd_device(fd);
unsigned int gpio = rtdm_fd_minor(fd);
int ret = 0, val, trigger;
struct rtdm_gpio_pin *pin;
pin = container_of(dev, struct rtdm_gpio_pin, dev);
switch (request) {
case GPIO_RTIOC_DIR_OUT:
ret = rtdm_safe_copy_from_user(fd, &val, arg, sizeof(val));
if (ret)
return ret;
ret = gpio_direction_output(gpio, val);
if (ret == 0) {
chan->has_direction = true;
chan->is_output = true;
}
break;
case GPIO_RTIOC_DIR_IN:
ret = gpio_direction_input(gpio);
if (ret == 0)
chan->has_direction = true;
break;
case GPIO_RTIOC_IRQEN:
if (chan->requested)
return -EBUSY;
ret = rtdm_safe_copy_from_user(fd, &trigger,
arg, sizeof(trigger));
if (ret)
return ret;
ret = request_gpio_irq(gpio, pin, chan, trigger);
break;
case GPIO_RTIOC_IRQDIS:
release_gpio_irq(gpio, pin, chan);
chan->requested = false;
break;
default:
return -EINVAL;
}
return ret;
}
static ssize_t gpio_pin_read_rt(struct rtdm_fd *fd,
void __user *buf, size_t len)
{
struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
struct rtdm_device *dev = rtdm_fd_device(fd);
struct rtdm_gpio_pin *pin;
int value, ret;
if (len < sizeof(value))
return -EINVAL;
if (!chan->has_direction)
return -EAGAIN;
if (chan->is_output)
return -EINVAL;
pin = container_of(dev, struct rtdm_gpio_pin, dev);
if (!(fd->oflags & O_NONBLOCK)) {
ret = rtdm_event_wait(&pin->event);
if (ret)
return ret;
}
value = gpiod_get_raw_value(pin->desc);
ret = rtdm_safe_copy_to_user(fd, buf, &value, sizeof(value));
return ret ?: sizeof(value);
}
static ssize_t gpio_pin_write_rt(struct rtdm_fd *fd,
const void __user *buf, size_t len)
{
struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
struct rtdm_device *dev = rtdm_fd_device(fd);
struct rtdm_gpio_pin *pin;
int value, ret;
if (len < sizeof(value))
return -EINVAL;
if (!chan->has_direction)
return -EAGAIN;
if (!chan->is_output)
return -EINVAL;
ret = rtdm_safe_copy_from_user(fd, &value, buf, sizeof(value));
if (ret)
return ret;
pin = container_of(dev, struct rtdm_gpio_pin, dev);
gpiod_set_raw_value(pin->desc, value);
return sizeof(value);
}
static int gpio_pin_select(struct rtdm_fd *fd, struct xnselector *selector,
unsigned int type, unsigned int index)
{
struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
struct rtdm_device *dev = rtdm_fd_device(fd);
struct rtdm_gpio_pin *pin;
if (!chan->has_direction)
return -EAGAIN;
if (chan->is_output)
return -EINVAL;
pin = container_of(dev, struct rtdm_gpio_pin, dev);
return rtdm_event_select(&pin->event, selector, type, index);
}
static void gpio_pin_close(struct rtdm_fd *fd)
{
struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
struct rtdm_device *dev = rtdm_fd_device(fd);
unsigned int gpio = rtdm_fd_minor(fd);
struct rtdm_gpio_pin *pin;
if (chan->requested) {
pin = container_of(dev, struct rtdm_gpio_pin, dev);
release_gpio_irq(gpio, pin, chan);
}
}
static void delete_pin_devices(struct rtdm_gpio_chip *rgc)
{
struct rtdm_gpio_pin *pin, *n;
struct rtdm_device *dev;
rtdm_lockctx_t s;
rtdm_lock_get_irqsave(&rgc->lock, s);
list_for_each_entry_safe(pin, n, &rgc->pins, next) {
list_del(&pin->next);
rtdm_lock_put_irqrestore(&rgc->lock, s);
dev = &pin->dev;
rtdm_dev_unregister(dev);
rtdm_event_destroy(&pin->event);
kfree(dev->label);
kfree(pin->name);
kfree(pin);
rtdm_lock_get_irqsave(&rgc->lock, s);
}
rtdm_lock_put_irqrestore(&rgc->lock, s);
}
static int create_pin_devices(struct rtdm_gpio_chip *rgc)
{
struct gpio_chip *gc = rgc->gc;
struct rtdm_gpio_pin *pin;
struct rtdm_device *dev;
rtdm_lockctx_t s;
int n, ret;
for (n = gc->base; n < gc->base + gc->ngpio - 1; n++) {
ret = -ENOMEM;
pin = kzalloc(sizeof(*pin), GFP_KERNEL);
if (pin == NULL)
goto fail;
pin->name = kasprintf(GFP_KERNEL, "gpio%d", n);
if (pin->name == NULL)
goto fail_name;
pin->desc = gpio_to_desc(n);
if (pin->desc == NULL) {
ret = -ENODEV;
goto fail_desc;
}
dev = &pin->dev;
dev->driver = &rgc->driver;
dev->label = kasprintf(GFP_KERNEL, "%s/gpio%%d", gc->label);
if (dev->label == NULL)
goto fail_label;
dev->minor = n;
dev->device_data = rgc;
ret = rtdm_dev_register(dev);
if (ret)
goto fail_register;
rtdm_event_init(&pin->event, 0);
rtdm_lock_get_irqsave(&rgc->lock, s);
list_add_tail(&pin->next, &rgc->pins);
rtdm_lock_put_irqrestore(&rgc->lock, s);
}
return 0;
fail_register:
kfree(dev->label);
fail_desc:
fail_label:
kfree(pin->name);
fail_name:
kfree(pin);
fail:
delete_pin_devices(rgc);
return ret;
}
static char *gpio_pin_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "rtdm/%s/%s",
dev->class->name,
dev_name(dev));
}
int rtdm_gpiochip_add(struct rtdm_gpio_chip *rgc,
struct gpio_chip *gc, int gpio_subclass)
{
int ret;
if (!realtime_core_enabled())
return 0;
rgc->devclass = class_create(gc->owner, gc->label);
if (IS_ERR(rgc->devclass)) {
printk(XENO_ERR "cannot create sysfs class/n");
return PTR_ERR(rgc->devclass);
}
rgc->devclass->devnode = gpio_pin_devnode;
rgc->driver.profile_info = (struct rtdm_profile_info)
RTDM_PROFILE_INFO(rtdm_gpio_chip,
RTDM_CLASS_GPIO,
gpio_subclass,
0);
rgc->driver.device_flags = RTDM_NAMED_DEVICE|RTDM_FIXED_MINOR;
rgc->driver.base_minor = gc->base;
rgc->driver.device_count = gc->ngpio;
rgc->driver.context_size = sizeof(struct rtdm_gpio_chan);
rgc->driver.ops = (struct rtdm_fd_ops){
.close = gpio_pin_close,
.ioctl_nrt = gpio_pin_ioctl_nrt,
.read_rt = gpio_pin_read_rt,
.write_rt = gpio_pin_write_rt,
.select = gpio_pin_select,
};
rtdm_drv_set_sysclass(&rgc->driver, rgc->devclass);
rgc->gc = gc;
INIT_LIST_HEAD(&rgc->pins);
rtdm_lock_init(&rgc->lock);
ret = create_pin_devices(rgc);
if (ret)
class_destroy(rgc->devclass);
return ret;
}
EXPORT_SYMBOL_GPL(rtdm_gpiochip_add);
void rtdm_gpiochip_remove(struct rtdm_gpio_chip *rgc)
{
if (!realtime_core_enabled())
return;
delete_pin_devices(rgc);
class_destroy(rgc->devclass);
}
EXPORT_SYMBOL_GPL(rtdm_gpiochip_remove);
static int gpiochip_match_name(struct gpio_chip *chip, void *data)
{
const char *name = data;
return !strcmp(chip->label, name);
}
static struct gpio_chip *find_chip_by_name(const char *name)
{
return gpiochip_find((void *)name, gpiochip_match_name);
}
int rtdm_gpiochip_add_by_name(struct rtdm_gpio_chip *rgc,
const char *label, int gpio_subclass)
{
struct gpio_chip *gc = find_chip_by_name(label);
if (gc == NULL)
return -EPROBE_DEFER;
return rtdm_gpiochip_add(rgc, gc, gpio_subclass);
}
EXPORT_SYMBOL_GPL(rtdm_gpiochip_add_by_name);
#ifdef CONFIG_OF
#include <linux/of_platform.h>
LIST_HEAD(rtdm_gpio_chips);
static DEFINE_MUTEX(chip_lock);
static int match_gpio_chip(struct gpio_chip *gc, void *data)
{
struct device *dev = data;
return gc->dev == dev;
}
static int add_gpio_chip(struct gpio_chip *gc, int type)
{
struct rtdm_gpio_chip *rgc;
int ret;
rgc = kzalloc(sizeof(*rgc), GFP_KERNEL);
if (rgc == NULL)
return -ENOMEM;
ret = rtdm_gpiochip_add(rgc, gc, type);
if (ret) {
kfree(rgc);
return ret;
}
mutex_lock(&chip_lock);
list_add(&rgc->next, &rtdm_gpio_chips);
mutex_unlock(&chip_lock);
return 0;
}
int rtdm_gpiochip_scan_of(struct device_node *from, const char *compat,
int type)
{
struct device_node *np = from;
struct platform_device *pdev;
struct gpio_chip *gc;
int ret = -ENODEV;
for (;;) {
np = of_find_compatible_node(np, NULL, compat);
if (np == NULL)
break;
pdev = of_find_device_by_node(np);
of_node_put(np);
if (pdev == NULL)
break;
gc = gpiochip_find(&pdev->dev, match_gpio_chip);
if (gc) {
ret = add_gpio_chip(gc, type);
if (ret)
return ret;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(rtdm_gpiochip_scan_of);
void rtdm_gpiochip_remove_of(int type)
{
struct rtdm_gpio_chip *rgc, *n;
list_for_each_entry_safe(rgc, n, &rtdm_gpio_chips, next) {
if (rgc->driver.profile_info.subclass_id == type) {
mutex_lock(&chip_lock);
list_del(&rgc->next);
mutex_unlock(&chip_lock);
rtdm_gpiochip_remove(rgc);
kfree(rgc);
}
}
}
EXPORT_SYMBOL_GPL(rtdm_gpiochip_remove_of);
#endif /* CONFIG_OF */
####################gpio-core.h########################
点击查看代码
/**
* @note Copyright (C) 2016 Philippe Gerum <rpm@xenomai.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RTDM_GPIO_CORE_H
#define _RTDM_GPIO_CORE_H
#include <linux/list.h>
#include <rtdm/driver.h>
#include <rtdm/uapi/gpio.h>
struct class;
struct device_node;
struct rtdm_gpio_chip {
struct gpio_chip *gc;
struct rtdm_driver driver;
struct class *devclass;
struct list_head pins;
struct list_head next;
rtdm_lock_t lock;
};
int rtdm_gpiochip_add(struct rtdm_gpio_chip *rgc,
struct gpio_chip *gc,
int gpio_subclass);
void rtdm_gpiochip_remove(struct rtdm_gpio_chip *rgc);
int rtdm_gpiochip_add_by_name(struct rtdm_gpio_chip *rgc,
const char *label, int gpio_subclass);
#ifdef CONFIG_OF
int rtdm_gpiochip_scan_of(struct device_node *from,
const char *compat, int type);
void rtdm_gpiochip_remove_of(int type);
extern struct list_head rtdm_gpio_chips;
#endif
#endif /* !_RTDM_GPIO_CORE_H */
————————————————
版权声明:本文为CSDN博主「wabil」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wabil/article/details/104313726
原创文章,作者:dweifng,如若转载,请注明出处:https://blog.ytso.com/tech/aiops/271874.html