分类: LINUX
2014-05-20 12:40:08
固件一般存放在设备上的flash存储器中,但出于成本和灵活性考虑,许多设备都将固件的映像(image)以文件的形式存放在硬盘中,设备驱动程序初始化时再装载到设备内部的存储器中。这样,方便了固件的升级,并省略了设备的flash存储器。
本章分析了驱动程序加载固件映像文件的过程。
目录 [] |
Linux 内核对设备固件的装载和清除提供了支持接口,可将固件映像文件加载到设备指定的存储地址,固件映像文件的内容由设备自身来解析,Linux内核只将映像文 件当件未知的二进制文件。Linux内核用结构firmware描述固件映像文件的内容,该结构列出如下(在include/linux /firmware.h中):
固件函数接口原型说明如下:
函 数request_firmware向用户空间请求提供一个名为name固件映像文件并等待完成。参数device为固件装载的设备。文件内容存入 request_firmware 返回,如果固件请求成功,返回0。该函数从用户空间得到的数据未做任何检查,用户在编写驱动程序时,应对固件映像做数据安全检查,检查方向由设备固件提供 商确定,通常有检查标识符、校验和等方法。
int request_firmware(const struct firmware **firmware_p, const char *name, struct device *device)
函数release_firmware在完成固件装载后,释放所申请的内存块fw。
void release_firmware(struct firmware *fw);
函 数request_firmware_nowait是函数request_firmware的异步请求版本,用于不能睡眠的内核线程中调用。参数 module为请求固件的模块;参数uevent为非0时,表示发送uevent事件用于自动拷贝固件映像,否则,必须人工拷贝映像;参数name为固件 映像文件的名字;参数device为装载固件的设备;参数cont为固件请求完成时调用的函数;参数context为函数cont的参数。该函数的原型列 出如下:
当驱动程序需要使用固件驱动时,在驱动程序的初始化化过程中需要加下如下的代码:
用户还需要在用户空间提供脚本通过文件系统sysfs中的文件data将固件映像文件读入到内核的缓冲区中。脚本样例列出如下:
函数request_firmware请求从用户空间拷贝固件映像文件到内核缓冲区。该函数的工作流程列出如下:
(1) 在文件系统sysfs中创建文件/sys/class/firmware/xxx/loading和data,"xxx"表示固件的名字,给文件 loading和data附加读写函数,设置文件属性,文件loading表示开/关固件映像文件装载功能;文件data的写操作将映像文件的数据写入内 核缓冲区,读操作从内核缓冲区读取数据。
(2)将添加固件的uevent事件(即"add")通过内核对象模型发送到用户空间。
(3)用户空间管理uevent事件的后台进程udevd接收到事件后,查找udev规则文件,运行规则所定义的动作,与固件相关的规则列出如下:
从上述规则可以看出,固件添加事件将引起运行脚本firmware.sh。
(4)脚本firmware.sh打开"装载"功能,同命令"cat 映像文件 > /sys/class/firmware/xxx/data"将映像文件数据写入到内核的缓冲区。
(5)映像数据拷贝完成后,函数request_firmware从文件系统/sysfs注销固件设备对应的目录"xxx"。如果请求成功,函数返回0。
(6)用户就将内核缓冲区的固件映像数据拷贝到固件的内存中。然后,调用函数release_firmware(fw_entry)释放给固件映像分配的缓冲区。
函 数request_firmware的调用层次图如图3所示。它先设置uevent事件为1,然后调用设备驱动程序模型:函数 device_register在文件系统sysfs中创建目录"xxx",函数kobject_uevent发送事件,函数 device_unregister在装载完固件映像数据后清除目录"xxx"。
函数request_firmware列出如下(在drivers/base/firmware_class.c中):
函数fw_setup_device在文件系统sysfs中创建固件设备的目录和文件,其列出如下:
函数fw_register_device注册设备,在文件系统sysfs中创建固件设备对应的设备类,存放固件驱动程序私有数据。其列出如下: