drivers/gpio/gpiolib-sysfs.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpiolib-sysfs.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpiolib-sysfs.c
Extension
.c
Size
28410 bytes
Lines
1110
Domain
Driver Families
Bucket
drivers/gpio
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct gpiod_data {
	struct list_head list;

	struct gpio_desc *desc;
	struct device *dev;

	struct mutex mutex;
#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
	struct kernfs_node *value_kn;
	int irq;
	unsigned char irq_flags;
#endif /* CONFIG_GPIO_SYSFS_LEGACY */

	bool direction_can_change;

	struct kobject *parent;
	struct device_attribute dir_attr;
	struct device_attribute val_attr;

#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
	struct device_attribute edge_attr;
	struct device_attribute active_low_attr;

	struct attribute *class_attrs[GPIO_SYSFS_LINE_CLASS_ATTR_SIZE];
	struct attribute_group class_attr_group;
	const struct attribute_group *class_attr_groups[2];
#endif /* CONFIG_GPIO_SYSFS_LEGACY */

	struct attribute *chip_attrs[GPIO_SYSFS_LINE_CHIP_ATTR_SIZE];
	struct attribute_group chip_attr_group;
	const struct attribute_group *chip_attr_groups[2];
};

struct gpiodev_data {
	struct list_head exported_lines;
	struct gpio_device *gdev;
	struct device *cdev_id; /* Class device by GPIO device ID */
#if IS_ENABLED(CONFIG_GPIO_SYSFS_LEGACY)
	struct device *cdev_base; /* Class device by GPIO base */
#endif /* CONFIG_GPIO_SYSFS_LEGACY */
};

/*
 * Lock to serialise gpiod export and unexport, and prevent re-export of
 * gpiod whose chip is being unregistered.
 */
static DEFINE_MUTEX(sysfs_lock);

/*
 * /sys/class/gpio/gpioN... only for GPIOs that are exported
 *   /direction
 *      * MAY BE OMITTED if kernel won't allow direction changes
 *      * is read/write as "in" or "out"
 *      * may also be written as "high" or "low", initializing
 *        output value as specified ("out" implies "low")
 *   /value
 *      * always readable, subject to hardware behavior
 *      * may be writable, as zero/nonzero
 *   /edge
 *      * configures behavior of poll(2) on /value
 *      * available only if pin can generate IRQs on input
 *      * is read/write as "none", "falling", "rising", or "both"
 *   /active_low
 *      * configures polarity of /value
 *      * is read/write as zero/nonzero
 *      * also affects existing and subsequent "falling" and "rising"
 *        /edge configuration
 */

static ssize_t direction_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{
	struct gpiod_data *data = container_of(attr, struct gpiod_data,
					       dir_attr);
	struct gpio_desc *desc = data->desc;
	int value;

	scoped_guard(mutex, &data->mutex) {
		gpiod_get_direction(desc);
		value = !!test_bit(GPIOD_FLAG_IS_OUT, &desc->flags);
	}

	return sysfs_emit(buf, "%s\n", value ? "out" : "in");
}

static ssize_t direction_store(struct device *dev,
			       struct device_attribute *attr, const char *buf,
			       size_t size)
{
	struct gpiod_data *data = container_of(attr, struct gpiod_data,

Annotation

Implementation Notes