Linux GPIO驱动 - GPIO通用层

如果在内核配置的时候有打开CONFIG_GPIO_SYSFS标志,内核就会在/sys目录下导出GPIO的用户空间操作接口。gpiolib_sysfs_init(drivers/gpio/gpiolib.c)是gpio lib的初始化函数,该函数首先在/sys/class/目录下面创建一个gpio的class,然后把所有注册到gpio lib的控制器导出到/sys/class/gpio/目录下面。

static int __init gpiolib_sysfs_init(void)

{

......

status = class_register(&gpio_class);

......

for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {

......

status = gpiochip_export(chip);

......

}

......

}

gpio_class的name定义为gpio,所以我们可以在/sys/class/下面看到gpio的目录。class_attr被定义为gpio_class_attrs,里面定义了class的两个属性export和unexport,该属性最终会在用户空间生成对应的文件。class_attribute包含一个attribute变量和show/sotre两个方法,其中attribute用来标示该属性的名字和操作权限,show/store是对该属性进行操作的函数,对应用户空间的cat/echo操作。所以在/sys/class/gpio目录下面可以看到两个文件分别为export和unexport,同时可以看到这两个文件的属性为所有者可写,即对应创建时定义的0200。所以这两个文件只能用echo向文件写内容,而不能通过cat显示文件的内容。从export和unexport的定义也可以验证这点,它们的show都定义为NULL,shore分别定义export_store和unexport_store,由此可以得知这两个函数就是用户空间操作的最终执行函数。先跳过这两个函数,继续看gpiolib_sysfs_init的第二部分工作。

static struct class_attribute gpio_class_attrs[] = {

__ATTR(export, 0200, NULL, export_store),

__ATTR(unexport, 0200, NULL, unexport_store),

__ATTR_NULL,

};

#define __ATTR(_name,_mode,_show,_store) { \

.attr = {.name = __stringify(_name), .mode = _mode },\

.show = _show,

.store = _store,

}

第二部分的工作就是遍历每一个注册的gpio pin,然后把注册到gpio lib的GPIO控制器导出到用户空间。首先在创建一个名为gpiochip*的设备,所以可以在/sys/class/gpio目录下面看到对应的gpiochip*目录,以及该目录下面的subsystem和uevent两个属性文件。然后再在该目录下面创建定义的属性文件,从属性数组gpiochip_attrs可以看到总共定义了三个属性,分别为base,label和ngpio,属性的权限为所有用户可读。最后把该控制器的exported标志设置为1,表示已经导出到用户空间。

static int gpiochip_export(struct gpio_chip *chip)

{

......

dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,"gpiochip%d", chip->base);

status = sysfs_create_group(&dev->kobj,&gpiochip_attr_group);

......

}

回到第一部分来看export_store函数,该函数同样分成gpio_request()和gpio_export()两个阶段。在gpio_request中,首先判断该pin的有效性,即该pin的pin num不能超过最大的GPIO pin脚数,然后把FLAG_REQUESTED标记设为1,表示该pin已被申请使用,同时把label属性设置为sysfs,最后调用gpio chip注册时定义的request函数,由前面的硬件驱动分析可知,该函数直接返回一个0值。gpio_export()的执行过程和gpiochip_export比较类似,先创建一个gpio*的设备,该过程会在用户空间的/sys/class/gpio目录下面导出gpio*的目录和该目录下面的subsytem/uevent属性文件。

int gpio_export(unsigned gpio, bool direction_may_change)

{

......

dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),desc, ioname ? ioname : "gpio%u", gpio);

status = sysfs_create_group(&dev->kobj,&gpio_attr_group);

if (!status && direction_may_change)

status = device_create_file(dev,&dev_attr_direction);

f (!status && gpio_to_irq(gpio) >= 0&& (direction_may_change|| !test_bit(FLAG_IS_OUT,&desc->flags)))  

status = device_create_file(dev,&dev_attr_edge);

......

set_bit(FLAG_EXPORT, &desc->flags);

......

}

在/sys/class/gpio/目录下面导出gpio*目录后,再在该目录下生成各种属性文件。首先创建的是gpio_attr_group属性组,该组里面包含value和active_low两个属性,这两个属性用DEVICE_ATTR来定义,从定义可以看出,属性文件的权限是0644,即所有者可读可写可执行,用户组和其他用户是可读。在用户空间可以通过value查看和设置GPIO pin的值,通过active_low来查看和设置pin的active_low的标志位。如果注册的GPIO chip有定义GPIO方向操作的函数,则创建direction属性,该属性同样是用DEVICE_ATTR宏来创建,属性的权限也为0644,用户可以利用/sys/class/gpio/gpio*/direction文件来控制gpio pin的操作方向。如果要导出的Pin可以作中断使用,同时该pin没有设置FLAG_IS_OUT位,则用创建edge属性;当该pin作为中断pin使用时,用户可以利用/sys/class/gpio/gpio*/edge文件设置中断触发的方式。

static const DEVICE_ATTR(active_low, 0644,gpio_active_low_show, gpio_active_low_store);

static const DEVICE_ATTR(value, 0644,gpio_value_show, gpio_value_store);

static /* const */ DEVICE_ATTR(direction, 0644,gpio_direction_show, gpio_direction_store);

static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);

以value属性来分析属性文件的具体操作,当用户在用户空间用cat打开value文件查看gpio pin的值时,gpio_value_show()会被调用。该函数的主要调用路径为  gpio_get_value_cansleep()->gpio_to_chip()->chip->get,即通过gpio pin找到该pin对应的gpio chip,然后利用该chip的get函数从GPIO控制器的寄存器里面读到具体的值。

当用户在用户空间用ehco把值写到value文件时,gpio_value_store会被调用,该函数的作用跟gpio_value_show相反,是把用户空间传递过来的值写到GPIO控制器的寄存器。调用路径为gpio_set_value_cansleep()->gpio_to_chip()->chip->set。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值