再说sysfs文件系统的gpio export功能

在之前的文章有说到,使用sysfs对gpio口进行操作调试,非常方便,想看如何进行操作的,可以看我之前的文章:

CSDNhttps://mp.csdn.net/mp_blog/creation/editor/119946350所有关于gpio sysfs的功能都在 drivers/gpio/gpiolib.c 中实现,入口函数是:gpiolib_sysfs_init()

现在先来追踪一下,在代码中使用gpio_export()函数的功能代码:

1、函数定义:gpio_export()

   gpio_export()实际是调用了函数:gpiod_export()

static int gpiod_export(struct gpio_desc *desc, bool direction_may_change);

  而函数“gpiod_export()”定义如下:

  参数 @gpio 用于指定是哪个gpio;
  参数 @direction_may_change 用来标记这个gpio的输入输出方向是否可以改变;

/**
 * gpio_export - export a GPIO through sysfs
 * @gpio: gpio to make available, already requested
 * @direction_may_change: true if userspace may change gpio direction
 * Context: arch_initcall or later
 *
 * When drivers want to make a GPIO accessible to userspace after they
 * have requested it -- perhaps while debugging, or as part of their
 * public interface -- they may use this routine.  If the GPIO can
 * change direction (some can't) and the caller allows it, userspace
 * will see "direction" sysfs attribute which may be used to change
 * the gpio's direction.  A "value" attribute will always be provided.
 *
 * Returns zero on success, else an error.
 */
static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
	unsigned long		flags;
	int			status;
	const char		*ioname = NULL;
	struct device		*dev;
	int			offset;
    
    // 条件及变量检查
	/* can't export until sysfs is available ... */
	if (!gpio_class.p) {
		pr_debug("%s: called too early!\n", __func__);
		return -ENOENT;
	}

	if (!desc) {
		pr_debug("%s: invalid gpio descriptor\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&sysfs_lock);

	spin_lock_irqsave(&gpio_lock, flags);
	if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
	     test_bit(FLAG_EXPORT, &desc->flags)) {
		spin_unlock_irqrestore(&gpio_lock, flags);
		pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n",
				__func__, desc_to_gpio(desc),
				test_bit(FLAG_REQUESTED, &desc->flags),
				test_bit(FLAG_EXPORT, &desc->flags));
		status = -EPERM;
		goto fail_unlock;
	}

    // 如果该gpio已经设置了输入或者输出,那么它的direction_may_change为false
	if (!desc->chip->direction_input || !desc->chip->direction_output)
		direction_may_change = false;
	spin_unlock_irqrestore(&gpio_lock, flags);

	offset = gpio_chip_hwgpio(desc);
	if (desc->chip->names && desc->chip->names[offset])
		ioname = desc->chip->names[offset];

    // 创建目录 /sys/class/gpio/gpiox/
	dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
			    desc, ioname ? ioname : "gpio%u",
			    desc_to_gpio(desc));
	if (IS_ERR(dev)) {
		status = PTR_ERR(dev);
		goto fail_unlock;
	}

    // 创建目录 /sys/class/gpio/gpio11/ 的相关控制属性
    // 这里面固定两个属性:active_low 和 value,并且有对应的 show() 和 store() 方法
	status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
	if (status)
		goto fail_unregister_device;

    // 如果这个gpio可以设置输入输出方向,那么要创建 direction() 的控制属性
	if (direction_may_change) {
		status = device_create_file(dev, &dev_attr_direction);
		if (status)
			goto fail_unregister_device;
	}

    // 如果这是一个中断的gpio,那么要创建中断触发边沿 edge() 的控制属性
	if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
				       !test_bit(FLAG_IS_OUT, &desc->flags))) {
		status = device_create_file(dev, &dev_attr_edge);
		if (status)
			goto fail_unregister_device;
	}

	set_bit(FLAG_EXPORT, &desc->flags);
	mutex_unlock(&sysfs_lock);
	return 0;

fail_unregister_device:
	device_unregister(dev);
fail_unlock:
	mutex_unlock(&sysfs_lock);
	pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
		 status);
	return status;
}

而对于在sysfs中使用export的功能代码,则由函数 export_store() 实现,这个是 /sys/class/gpio/ 下 export 的控制属性:

/*
 * /sys/class/gpio/export ... write-only
 *	integer N ... number of GPIO to export (full access)
 * /sys/class/gpio/unexport ... write-only
 *	integer N ... number of GPIO to unexport
 */
// 使用 /sys/class/gpio/export 的功能(也有与之相反的unexport),将相关引脚XX给export出来。
// 之后可以在 /sys/class/gpio/ 目录下就会创建 gpioXX/ 的目录,并且该目录有相关的对XX引脚的操作了
static ssize_t export_store(struct class *class,
				struct class_attribute *attr,
				const char *buf, size_t len)
{
	long			gpio;
	struct gpio_desc	*desc;
	int			status;

	status = strict_strtol(buf, 0, &gpio);
	if (status < 0)
		goto done;

	desc = gpio_to_desc(gpio);
	/* reject invalid GPIOs */
	if (!desc) {
		pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
		return -EINVAL;
	}

	/* No extra locking here; FLAG_SYSFS just signifies that the
	 * request and export were done by on behalf of userspace, so
	 * they may be undone on its behalf too.
	 */

	status = gpiod_request(desc, "sysfs");// 
	if (status < 0) {
		if (status == -EPROBE_DEFER)
			status = -ENODEV;
		goto done;
	}
	status = gpiod_export(desc, true); // 
	if (status < 0)
		gpiod_free(desc);
	else
		set_bit(FLAG_SYSFS, &desc->flags);

done:
	if (status)
		pr_debug("%s: status %d\n", __func__, status);
	return status ? : len;
}

你可能感兴趣的:(#,GPIO,与,PinCtrl子系统,linux,gpio,驱动程序)