固件上传 API¶
向固件加载器注册的设备驱动程序将公开持久性 sysfs 节点,使用户能够启动该设备的固件更新。设备驱动程序和/或设备本身负责对接收到的数据执行任何验证。固件上传使用固件回退文档中描述的相同loading 和 data sysfs 文件。它还添加了额外的 sysfs 文件,以提供固件映像传输到设备的状态。
注册固件上传¶
设备驱动程序通过调用 firmware_upload_register()
来注册固件上传。参数列表中有一个名称,用于标识 /sys/class/firmware 下的设备。用户可以通过将 1 回显到目标设备的 loading sysfs 文件来启动固件上传。接下来,用户将固件映像写入 data sysfs 文件。写入固件数据后,用户将 0 回显到 loading sysfs 文件以表示完成。将 0 回显到 loading 还会触发在内核工作线程的上下文中将固件传输到较低级别的设备驱动程序。
要使用固件上传 API,请编写一个实现一组操作的驱动程序。probe 函数调用 firmware_upload_register()
,而 remove 函数调用 firmware_upload_unregister()
,例如
static const struct fw_upload_ops m10bmc_ops = {
.prepare = m10bmc_sec_prepare,
.write = m10bmc_sec_write,
.poll_complete = m10bmc_sec_poll_complete,
.cancel = m10bmc_sec_cancel,
.cleanup = m10bmc_sec_cleanup,
};
static int m10bmc_sec_probe(struct platform_device *pdev)
{
const char *fw_name, *truncate;
struct m10bmc_sec *sec;
struct fw_upload *fwl;
unsigned int len;
sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
if (!sec)
return -ENOMEM;
sec->dev = &pdev->dev;
sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
dev_set_drvdata(&pdev->dev, sec);
fw_name = dev_name(sec->dev);
truncate = strstr(fw_name, ".auto");
len = (truncate) ? truncate - fw_name : strlen(fw_name);
sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL);
fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name,
&m10bmc_ops, sec);
if (IS_ERR(fwl)) {
dev_err(sec->dev, "Firmware Upload driver failed to start\n");
kfree(sec->fw_name);
return PTR_ERR(fwl);
}
sec->fwl = fwl;
return 0;
}
static int m10bmc_sec_remove(struct platform_device *pdev)
{
struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
firmware_upload_unregister(sec->fwl);
kfree(sec->fw_name);
return 0;
}
firmware_upload_register¶
-
struct fw_upload *firmware_upload_register(struct module *module, struct device *parent, const char *name, const struct fw_upload_ops *ops, void *dd_handle)¶
注册固件上传 sysfs API
参数
struct module *module
此设备的内核模块
struct device *parent
实例化固件上传的父设备
const char *name
要与此设备关联的固件名称
const struct fw_upload_ops *ops
指向固件上传操作结构的指针
void *dd_handle
指向父驱动程序私有数据的指针
name 在固件上传的所有用户中必须是唯一的。此设备的固件 sysfs 文件将在 /sys/class/firmware/name 中找到。
返回
struct fw_upload 指针或 ERR_PTR()
firmware_upload_unregister¶
参数
struct fw_upload *fw_upload
指向 struct fw_upload 的指针
固件上传操作¶
-
struct fw_upload_ops¶
支持固件上传的设备特定操作
定义:
struct fw_upload_ops {
enum fw_upload_err (*prepare)(struct fw_upload *fw_upload, const u8 *data, u32 size);
enum fw_upload_err (*write)(struct fw_upload *fw_upload,const u8 *data, u32 offset, u32 size, u32 *written);
enum fw_upload_err (*poll_complete)(struct fw_upload *fw_upload);
void (*cancel)(struct fw_upload *fw_upload);
void (*cleanup)(struct fw_upload *fw_upload);
};
成员
prepare
必需:准备安全更新
write
必需:write() 操作接收要写入的剩余大小,并且必须返回实际写入的大小或负错误代码。将重复调用 write() 操作,直到写入所有数据。
poll_complete
必需:检查硬件身份验证/编程过程是否完成。
cancel
必需:请求取消更新。此操作是从不同的内核线程的上下文中调用的,因此需要考虑竞争条件。
cleanup
可选:补充 prepare() 函数,并在更新成功或失败时在 prepare 函数成功后调用。
固件上传进度代码¶
以下进度代码由固件加载器在内部使用。相应的字符串通过下面描述的 status sysfs 节点报告,并在 ABI 文档中记录。
-
enum fw_upload_prog¶
固件上传进度代码
常量
FW_UPLOAD_PROG_IDLE
没有正在进行的固件上传
FW_UPLOAD_PROG_RECEIVING
工作线程正在接收固件数据
FW_UPLOAD_PROG_PREPARING
目标设备正在准备固件上传
FW_UPLOAD_PROG_TRANSFERRING
数据正在复制到设备
FW_UPLOAD_PROG_PROGRAMMING
设备正在执行固件更新
FW_UPLOAD_PROG_MAX
最大进度代码标记
固件上传错误代码¶
如果失败,驱动程序操作可能会返回以下错误代码
-
enum fw_upload_err¶
固件上传错误代码
常量
FW_UPLOAD_ERR_NONE
返回以表示成功
FW_UPLOAD_ERR_HW_ERROR
硬件发出的错误信号,请参阅内核日志
FW_UPLOAD_ERR_TIMEOUT
SW 在与硬件/固件握手时超时
FW_UPLOAD_ERR_CANCELED
上传被用户取消
FW_UPLOAD_ERR_BUSY
已有上传操作正在进行中
FW_UPLOAD_ERR_INVALID_SIZE
无效的固件映像大小
FW_UPLOAD_ERR_RW_ERROR
读取或写入硬件失败,请参阅内核日志
FW_UPLOAD_ERR_WEAROUT
FLASH 设备正在接近耗损,请等待并重试
FW_UPLOAD_ERR_FW_INVALID
无效的固件文件
FW_UPLOAD_ERR_MAX
最大错误代码标记
Sysfs 属性¶
除了 loading 和 data sysfs 文件之外,还有其他 sysfs 文件来监视数据传输到目标设备的状态,并确定传输的最终通过/失败状态。根据设备和固件映像的大小,固件更新可能需要几毫秒到几分钟。
其他 sysfs 文件是
status - 提供固件更新进度的指示
error - 提供失败固件更新的错误信息
remaining_size - 跟踪更新的数据传输部分
cancel - 将 1 回显到此文件以取消更新