在之前的文章有说到,使用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;
}