通过sysfs操作gpio

GPIO子系统架构分析(一)
GPIO子系统架构分析(二)
通过sysf操作gpio

在gpio-sysfs.c驱动文件的入口函数:

static struct class_attribute gpio_class_attrs[] = {
	__ATTR(export, 0200, NULL, export_store),
	__ATTR(unexport, 0200, NULL, unexport_store),
	__ATTR_NULL,
};

static struct class gpio_class = {
	.name =		"gpio",
	.owner =	THIS_MODULE,

	.class_attrs =	gpio_class_attrs,
};


static int __init gpiolib_sysfs_init(void)
{
	int		status;
	unsigned long	flags;
	struct gpio_device *gdev;

	/* 在/sys/class目录下创建一个gpio目录,
	   并在/sys/class/gpio目录下创建两个属性文件export和unexport
   */
	status = class_register(&gpio_class);
	if (status < 0)
		return status;

	spin_lock_irqsave(&gpio_lock, flags);

	/* 遍历gpio_devices链表,调用gpiochip_sysfs_register,
	   即在/sys/class/gpio目录下,为每个gpio控制器创建一个sysfs目录
   */
	list_for_each_entry(gdev, &gpio_devices, list) {
		if (gdev->mockdev)
			continue;


		spin_unlock_irqrestore(&gpio_lock, flags);

		status = gpiochip_sysfs_register(gdev);

		spin_lock_irqsave(&gpio_lock, flags);
	}
	spin_unlock_irqrestore(&gpio_lock, flags);

	return status;
}

那么在/sys/class/gpio目录下:
在这里插入图片描述
export属性文件用于导出控制的GPIO引脚,unexport用于取消导出。
如下使用方法:

echo 131 > export //将131号的gpio导出到用户空间

导出gpio引脚后,如下图:
在这里插入图片描述
进入gpio131目录:
在这里插入图片描述
有direction 、value等属性文件。

echo out > direction  //可以将gpio引脚设为输出模式
echo in  > direction  //可以将gpio引脚设为输入模式
echo 1 > value        //设置设为高电平
echo 0 > value        //设置设为低电平

源码分析

那么执行命令:echo 131 > export,究竟发生了什么?

//echo 131 > export 最终调用到export_store函数,buf指向"131"这个字符串 
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;

	//把字符串转换为long型数据(131)
	status = kstrtol(buf, 0, &gpio);
	......

	//通过gpio号获得对应的gpio_desc
	desc = gpio_to_desc(gpio);
	......

	//申请gpio
	status = gpiod_request(desc, "sysfs");
	if (status < 0) {
		if (status == -EPROBE_DEFER)
			status = -ENODEV;
		goto done;
	}

  	//导出gpio,创建gpio131目录等
	status = gpiod_export(desc, true);
	if (status < 0)
		gpiod_free(desc);
	else
		set_bit(FLAG_SYSFS, &desc->flags);

	......

}

gpiod_export:


int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
	struct gpio_chip	*chip;
	struct gpio_device	*gdev;
	struct gpiod_data	*data;
	unsigned long		flags;
	int			status;
	const char		*ioname = NULL;
	struct device		*dev;
	int			offset;

	......

	gdev = desc->gdev;
	chip = gdev->chip;

	mutex_lock(&sysfs_lock);

	......

	//如果已经该gpio引脚已申请或者已导出,则返回错误
	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);
		......
		status = -EPERM;
		goto err_unlock;
	}
	......

	//创建一个struct gpiod_data
	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) {
		status = -ENOMEM;
		goto err_unlock;
	}

	//设置gpiod_data
	data->desc = desc;
	mutex_init(&data->mutex);
	......

  /* 在/sys/class/gpio/目录下创建导出的gpio引脚的sysfs目录
    并在该目录下创建属性文件,属性文件name、store/show函数在属性组gpio_groups里描述
 */
	dev = device_create_with_groups(&gpio_class, &gdev->dev,
					MKDEV(0, 0), data, gpio_groups,
					ioname ? ioname : "gpio%u",
					desc_to_gpio(desc));
	......

	//设置已导出标志位
	set_bit(FLAG_EXPORT, &desc->flags);

	......
}

重点在于这个属性组,gpio_groups,定义了direction、value等属性及操作函数:

static struct attribute *gpio_attrs[] = {
	&dev_attr_direction.attr,  //direction属性
	&dev_attr_edge.attr,       //edge属性
	&dev_attr_value.attr,      //value属性
	&dev_attr_active_low.attr, //active属性
	NULL,
};

static const struct attribute_group gpio_group = {
	.attrs = gpio_attrs,
	.is_visible = gpio_is_visible,
};

static const struct attribute_group *gpio_groups[] = {
	&gpio_group,
	NULL
};

以direction属性文件为例,打开direction属性文件会调用direction_show函数:

/* drivers/gpio/gpiolib-sysfs.c */
static ssize_t direction_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct gpiod_data *data = dev_get_drvdata(dev);
	struct gpio_desc *desc = data->desc;
	ssize_t			status;

	mutex_lock(&data->mutex);

	//获取方向,返回状态
	gpiod_get_direction(desc);
	status = sprintf(buf, "%s\n",
			test_bit(FLAG_IS_OUT, &desc->flags)
				? "out" : "in");

	mutex_unlock(&data->mutex);

	return status;
}

打开direction属性文件如下图:
在这里插入图片描述
对direction属性文件写,调用direction_store函数:

/* drivers/gpio/gpiolib-sysfs.c */
static ssize_t direction_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct gpiod_data *data = dev_get_drvdata(dev);
	struct gpio_desc *desc = data->desc;
	ssize_t			status;

	mutex_lock(&data->mutex);
  
	if (sysfs_streq(buf, "high"))
		status = gpiod_direction_output_raw(desc, 1);
	else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
		//设置为输出模式
		status = gpiod_direction_output_raw(desc, 0);
	else if (sysfs_streq(buf, "in"))
		//设置为输入模式
		status = gpiod_direction_input(desc);
	else
		status = -EINVAL;

	mutex_unlock(&data->mutex);

	return status ? : size;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值