xenomai中断事件等api


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

(0)
上一篇 2022年7月8日 04:41
下一篇 2022年7月8日 04:42

相关推荐

发表回复

登录后才能评论