韌體上傳 API¶
向韌體載入器註冊的裝置驅動程式將公開持久的 sysfs 節點,以使使用者能夠啟動該裝置的韌體更新。裝置驅動程式和/或裝置本身有責任對接收到的資料執行任何驗證。韌體上傳使用韌體回退文件中描述的相同loading和data sysfs 檔案。它還添加了額外的 sysfs 檔案,以提供韌體映像傳輸到裝置的狀態。
註冊韌體上傳¶
裝置驅動程式透過呼叫 firmware_upload_register() 註冊韌體上傳。引數列表中有一個名稱來標識 /sys/class/firmware 下的裝置。使用者可以透過將 1 回顯到目標裝置的 loading sysfs 檔案來啟動韌體上傳。接下來,使用者將韌體映像寫入 data sysfs 檔案。寫入韌體資料後,使用者將 0 回顯到 loading sysfs 檔案以表示完成。將 0 回顯到 loading 也會觸發韌體在核心工作執行緒上下文中傳輸到較低級別的裝置驅動程式。
要使用韌體上傳 API,請編寫一個實現一組 ops 的驅動程式。探針函式呼叫 firmware_upload_register(),刪除函式呼叫 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指向韌體上傳 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 的指標
韌體上傳 Ops¶
-
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() op 接收要寫入的剩餘大小,並且必須返回實際寫入的大小或負錯誤程式碼。write() op 將被重複呼叫,直到寫入所有資料。
poll_complete必需:檢查硬體身份驗證/程式設計過程的完成情況。
cancel必需:請求取消更新。此 op 從不同的核心執行緒上下文中呼叫,因此需要考慮競爭條件。
cleanup可選:補充 prepare() 函式,並在更新完成時(成功或失敗)呼叫,如果 prepare 函式成功。
韌體上傳進度程式碼¶
以下進度程式碼由韌體載入器內部使用。相應的字串透過下面描述的狀態 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最大進度程式碼標記
韌體上傳錯誤程式碼¶
如果發生故障,驅動程式 ops 可能會返回以下錯誤程式碼
-
enum fw_upload_err¶
韌體上傳錯誤程式碼
常量
FW_UPLOAD_ERR_NONE返回以指示成功
FW_UPLOAD_ERR_HW_ERROR硬體發出的錯誤訊號,請參閱核心日誌
FW_UPLOAD_ERR_TIMEOUT軟體與硬體/韌體握手超時
FW_UPLOAD_ERR_CANCELED上傳被使用者取消
FW_UPLOAD_ERR_BUSY已經有一個上傳操作正在進行中
FW_UPLOAD_ERR_INVALID_SIZE韌體映像大小無效
FW_UPLOAD_ERR_RW_ERROR讀取或寫入硬體失敗,請參閱核心日誌
FW_UPLOAD_ERR_WEAROUT快閃記憶體裝置即將耗盡,請等待並重試
FW_UPLOAD_ERR_FW_INVALID韌體檔案無效
FW_UPLOAD_ERR_MAX最大錯誤程式碼標記
Sysfs 屬性¶
除了 loading 和 data sysfs 檔案之外,還有額外的 sysfs 檔案來監視資料傳輸到目標裝置的狀態,並確定傳輸的最終透過/失敗狀態。根據裝置和韌體映像的大小,韌體更新可能需要幾毫秒或幾分鐘。
額外的 sysfs 檔案是
status - 提供韌體更新進度的指示
error - 為失敗的韌體更新提供錯誤資訊
remaining_size - 跟蹤更新的資料傳輸部分
cancel - 將 1 回顯到此檔案以取消更新