做为专业工程师,对自我基本要求:从事的工作必定不能丝毫马虎。
一、以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 系统中注册到特定的目录下,为上层提供服务(直白些被上层调用)。见整理二。