史上最详细Linux 虚拟文件系统sysfs之属性文件attribute 整理(一)

做为专业工程师,对自我基本要求:从事的工作必定不能丝毫马虎。

一、以led灯 的android 系统架构作为实例

开门见山,我们知道在Android operation system 的四层架构;见右图

 


其中HAL层以下,即kernel层运行在system space,HAL-》framework一直以上运行在user space。

HAL (Hardware abstract layout)就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。

二、HAL层对驱动层的调用最终都是通过对给出的设备节点操作

 上层对驱动的操作通常为file operation read & write 读写操作《=对应于函数show & store==》

static int
write_int(char const* path, int value)
{
    int fd;
    static int already_warned = 0;

    ALOGD("entry write_int path = %s, value=%d\n", path,value);
    
    fd = open(path, O_RDWR);
    if (fd >= 0) {

    ALOGD("entry write_int_open fd=%d\n", fd);
        char buffer[20];
        int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
        ssize_t amt = write(fd, buffer, (size_t)bytes);
        
	close(fd);
        return amt == -1 ? -errno : 0;
    } else {
        if (already_warned == 0) {
            ALOGE("write_int failed to open %s\n", path);
            already_warned = 1;
        }
        return -errno;
    }
}
其中path 变量即为sysfs 下的文件路径;

char const*const RED_LED_FILE
        = "/sys/class/leds/red/brightness";

而write函数对 RED_LED_FILE文件的操作实际上是调用了static ssize_t brightness_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)函数;(至于为什么,怎么来的后续分析)

来看下函数brightness_store();在led-class.c文件中

static ssize_t brightness_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	unsigned long state;
	ssize_t ret;

	mutex_lock(&led_cdev->led_access);

	if (led_sysfs_is_disabled(led_cdev)) {
		ret = -EBUSY;
		goto unlock;
	}

	ret = kstrtoul(buf, 10, &state);
	if (ret)
		goto unlock;

	led_cdev->usr_brightness_req = state;
	__led_set_brightness(led_cdev, state);

	ret = size;
unlock:
	mutex_unlock(&led_cdev->led_access);
	return ret;
}
继续往下走——~! 你所见到的,都是有根据和原因的,只是没有找打代码对应的地方而已。

最后函数在进行容错判断(增强程序健壮性)之后,实际上执行的是led_cdev->brightness_set(led_cdev,value)

对一些重要的数据结构要了解:一般数据结构都是对被模拟的object进行抽象,struct led_classdev代表的意思是led灯类的设备;

	enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);

看下代码:这里brightness_set是函数指针类型(有点类似面向对象语言中的虚函数、抽象函数的概念),它的定义根据不同的指向的函数来实现;我Kconfig配置使用xxled.C文件在probe()函数下将该函数指向

		INIT_WORK(&led->brightness_work, aw2013_brightness_work);
		printk("zhufeng: aw2013 INIT_WORK end\n");

		led->cdev.brightness_set = aw2013_set_brightness;

		rc = led_classdev_register(&led->client->dev, &led->cdev);
		if (rc) {
			dev_err(&led->client->dev,
				"unable to register led %d,rc=%d\n",
				led->id, rc);
			goto free_pdata;
		}
所以最终实现在函数aw2013_set_brightness()当中;每个平台不同,具体的实现细节会不同,
 唤醒工作队列schedule_work(&led->brightness_work);在aw2013_brightness_work()中真正实现。

三、adb调试下的异曲同工

上面所述的上层代码流程通过对设备节点操作;adb(android debug bridge)调试也是一样;




四、小结

       本文主要讲述的是:以led 驱动为例从用户空间的HAL层,通过对设备节点的操作,走到kernel 空间,通过对属性文件的读写操作,操作相应的硬件。

那么问题来了:这些属性文件提供了什么机制,小透露;通过向sysfs 系统中注册到特定的目录下,为上层提供服务(直白些被上层调用)。见整理二。







猜你喜欢

转载自blog.csdn.net/clam_zxf/article/details/74012056
今日推荐