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

    posted @   相对维度  阅读(267)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
    · 地球OL攻略 —— 某应届生求职总结
    · 周边上新:园子的第一款马克杯温暖上架
    · 提示词工程——AI应用必不可少的技术
    · Open-Sora 2.0 重磅开源!
    点击右上角即可分享
    微信分享提示