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句柄参数指针
//用于设置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_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 */
/** * @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