gpio_export_with_name

对于Linux 内核中的gpio操作,想必大家都很清楚,一般的做法是通过 gpio 的 sysfs文件系统

cd /sys/class/gpio
echo 11 > export
cd gpio11
xxxxxxxxx......

这种方法,可以直接操作GPIO口,但是当我们需要将类似刚刚例子里面的gpio11替换为我们使用引脚的具体定义时,如PWR_EN,这样的方法就行不通了,
所以这里我们要重写 Linux 的gpio_exportgpio_export_with_name

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index d9fa7985..3d539600 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -604,6 +604,111 @@ fail_unlock:
 }
 EXPORT_SYMBOL_GPL(gpiod_export);
 
+/**
+ * gpiod_export_with_name - export a GPIO through sysfs
+ * @gpio: gpio to make available, already requested
+ * @direction_may_change: true if userspace may change gpio direction
+ * @name: gpio name
+ * 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.
+ */
+int gpiod_export_with_name(struct gpio_desc *desc, bool direction_may_change,
+                            const char *name)
+{
+	struct gpio_chip	*chip;
+	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;
+	}
+
+	chip = desc->chip;
+
+	mutex_lock(&sysfs_lock);
+
+	/* check if chip is being removed */
+	if (!chip || !chip->exported) {
+		status = -ENODEV;
+		goto fail_unlock;
+	}
+
+	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);
+		gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
+				__func__,
+				test_bit(FLAG_REQUESTED, &desc->flags),
+				test_bit(FLAG_EXPORT, &desc->flags));
+		status = -EPERM;
+		goto fail_unlock;
+	}
+
+	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];
+	ioname = name;			//这里最关键
+
+	dev = device_create_with_groups(&gpio_class, desc->chip->dev,
+					MKDEV(0, 0), desc, gpio_groups,
+					ioname ? ioname : "gpio%u",
+					desc_to_gpio(desc));
+	if (IS_ERR(dev)) {
+		status = PTR_ERR(dev);
+		goto fail_unlock;
+	}
+
+	if (direction_may_change) {
+		status = device_create_file(dev, &dev_attr_direction);
+		if (status)
+			goto fail_unregister_device;
+	}
+
+	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_remove_attr_direction;
+	}
+
+	set_bit(FLAG_EXPORT, &desc->flags);
+	mutex_unlock(&sysfs_lock);
+	return 0;
+
+fail_remove_attr_direction:
+	device_remove_file(dev, &dev_attr_direction);
+fail_unregister_device:
+	device_unregister(dev);
+fail_unlock:
+	mutex_unlock(&sysfs_lock);
+	gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+	return status;
+}
+EXPORT_SYMBOL_GPL(gpiod_export_with_name);
+
 static int match_export(struct device *dev, const void *data)
 {
 	return dev_get_drvdata(dev) == data;

头文件相关

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d38a2948..ccdbe493 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -113,7 +113,8 @@ static inline int __gpio_to_irq(unsigned gpio)
 extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
 extern int gpio_request_array(const struct gpio *array, size_t num);
 extern void gpio_free_array(const struct gpio *array, size_t num);
-
+extern int gpiod_export_with_name(struct gpio_desc *desc, bool direction_may_change,
+                                    const char *name);
 /*
  * A sysfs interface can be exported by individual drivers if they want,
  * but more typically is configured entirely from userspace.
@@ -123,6 +124,12 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
 	return gpiod_export(gpio_to_desc(gpio), direction_may_change);
 }
 
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change,
+                                        const char *name)
+{
+	return gpiod_export_with_name(gpio_to_desc(gpio), direction_may_change, name);
+}
+
 static inline int gpio_export_link(struct device *dev, const char *name,
 				   unsigned gpio)
 {
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 85aa5d0b..a43c7e6b 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -188,6 +188,14 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
 	return -EINVAL;
 }
 
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change,
+                                        const char *name)
+{
+	/* GPIO can never have been requested or set as {in,out}put */
+	WARN_ON(1);
+	return -EINVAL;
+}
+
 static inline int gpio_export_link(struct device *dev, const char *name,
 				unsigned gpio)
 {

你可能感兴趣的:(Linux)