linux gpio_to_irq()源码分析

【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) 

linux gpio_to_irq()源码分析

背景说明:
  在Linux设备树(linux 3.x版本引入)中, 设备的中断号不再在"irq.h"中硬编码定义, 而是在需要时自己手动去申请获得对应的硬件中断的软件中断号.( 前提是GPIO的相关模块已经被编入内核 )

1. gpio_to_irq()的函数作用

/**
 * include/linux/gpio.h
 * 
 * @param gpio 为要操作的GPIO编号, 该编号等于GPIO组号*8 + 组内偏移号, 例如GPIO4_2的编号为4*8 + 2 = 34 (每组GPIO有8个GPIO管脚)
 */ 
static inline int gpio_to_irq(unsigned int gpio)
{
	return __gpio_to_irq(gpio);
}

   通过GPIO号得到对应的软件中断号, 该中断号是request_irq()函数的第一个参数.

2. gpio_to_irq()的源码分析

/**
 * include/asm-generic/gpio.h
 */
static inline int __gpio_to_irq(unsigned gpio)
{
	return gpiod_to_irq(gpio_to_desc(gpio));
}
2.1 首先, 我们来看看gpio_to_desc(gpio)的含义:
/**
 * list_for_each_entry	-	iterate over list of given type
	迭代给定类型的列表, head为typeof(*pos)结构体中的其中一员且为一个双向链表, 我们通过
遍历这个链表循环得到每一个typeof(*pos)结构体.
 * @pos:	the type * to use as a loop cursor.
	用作循环游标, 每一次得到typeof(*pos)类型的变量.
 * @head:	the head for your list.
	列表头, 该变量为typeof(*pos)结构体中的其中一员.
 * @member:	the name of the list_head within the struct.
	在结构体中list_head的名称
 */
#define list_for_each_entry(pos, head, member)				\
	for (pos = list_first_entry(head, typeof(*pos), member);	\
	     &pos->member != (head);					\
	     pos = list_next_entry(pos, member))


/**
 * Convert a GPIO number to its descriptor
 */
struct gpio_desc *gpio_to_desc(unsigned gpio)
{
	struct gpio_device *gdev;
	unsigned long flags;

	/**
	 * 内核同步自旋锁.
	 * 禁止内核抢占, 关闭中断, 保存中断状态寄存器的标志位.
	 */
	spin_lock_irqsave(&gpio_lock, flags);

	list_for_each_entry(gdev, &gpio_devices, list) {
		if (gdev->base <= gpio &&
		    gdev->base + gdev->ngpio > gpio) {
		    /**
		     * 当查找到gpio所属的组时, 返回该GPIO的descs, 即&gdev->descs[gpio - gdev->base]
		     */
			spin_unlock_irqrestore(&gpio_lock, flags);
			return &gdev->descs[gpio - gdev->base];
		}
	}

	spin_unlock_irqrestore(&gpio_lock, flags);

	if (!gpio_is_valid(gpio))
		WARN(1, "invalid GPIO %d\n", gpio);

	return NULL;
}

关键处: 当查找到gpio所属的组时, 返回该GPIO的descs, 即&gdev->descs[gpio - gdev->base].
在这里, 我们拿到了该GPIO的描述信息. 该结构体的定义如下:(drivers/gpio/gpiolib.h)

/**
 * GPIO设备的内部状态容器.
 */
struct gpio_device {
	int			id;
	struct device		dev;
	struct cdev		chrdev;
	struct device		*mockdev;
	struct module		*owner;
	struct gpio_chip	*chip;
	struct gpio_desc	*descs;
	int			base;
	u16			ngpio;
	char			*label;
	void			*data;
	struct list_head        list;

#ifdef CONFIG_PINCTRL
	/*
	 * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
	 * describe the actual pin range which they serve in an SoC. This
	 * information would be used by pinctrl subsystem to configure
	 * corresponding pins for gpio usage.
	 */
	struct list_head pin_ranges;
#endif
};



struct gpio_desc {
	struct gpio_device	*gdev;
	unsigned long		flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED	0
#define FLAG_IS_OUT	1
#define FLAG_EXPORT	2	/* protected by sysfs_lock */
#define FLAG_SYSFS	3	/* exported via /sys/class/gpio/control */
#define FLAG_ACTIVE_LOW	6	/* value has active low */
#define FLAG_OPEN_DRAIN	7	/* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8	/* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9	/* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED	11	/* GPIO is hogged */

	/* Connection label */
	const char		*label;
	/* Name of the GPIO */
	const char		*name;
};
2.2 然后, 我们来看看gpiod_to_irq(const struct gpio_desc *desc);的含义:
/**
 * gpiod_to_irq() - return the IRQ corresponding to a GPIO
 * @desc: gpio whose IRQ will be returned (already requested)
 *
 * Return the IRQ corresponding to the passed GPIO, or an error code in case of
 * error.
 */
int gpiod_to_irq(const struct gpio_desc *desc)
{
	struct gpio_chip *chip;
	int offset;

	/*
	 * Cannot VALIDATE_DESC() here as gpiod_to_irq() consumer semantics
	 * requires this function to not return zero on an invalid descriptor
	 * but rather a negative error number.
	 */
	if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip)
		return -EINVAL;

	chip = desc->gdev->chip;
	offset = gpio_chip_hwgpio(desc);
	if (chip->to_irq) {
		int retirq = chip->to_irq(chip, offset);

		/* Zero means NO_IRQ */
		if (!retirq)
			return -ENXIO;

		return retirq;
	}
	return -ENXIO;
}
发布了68 篇原创文章 · 获赞 22 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/MACMACip/article/details/105549516