Linux核心子產品使用固件程式時,正确的做法是使用request_firmware_nowait()一類固件接口來擷取固件資料。
在使用firmware前,必須對核心做如下配置。
Device Drivers —>
Generic Driver Options —>
<*> Userspace firmware loading support
否則會出現: Unknown symbol release_firmware 和: Unknown symbol request_firmware 的錯誤。
下面是request_firmware_nowait函數的原型
int
request_firmware_nowait(
struct module *module, bool uevent,
const char *name, struct device *device, gfp_t gfp, void *context,
void (*cont)(const struct firmware *fw, void *context))
如果一切正常,request_firmware_nowait 開始固件加載過程并傳回0。随後會調用驅動程式的回調函數cont并将儲存有firmware的fw作為函數cont的參數。
如果找不到對應位置的檔案,過了一段時間後(預設60秒),将用fw=NULL作為參數調用cont。
其中struct firmware定義如下:
struct firmware {
size_t size;
u8 *data;
};
這個結構包含實際的固件,它現在可被下載下傳到裝置中。但是請注意:在發送它到硬體之前,必須檢查這個檔案以確定它是正确的固件映象(裝置固件常常包含辨別字元串、校驗和等等)
跟蹤request_firmware_nowait的實作過程:
request_firmware_nowait
_request_firmware_nowait
request_firmware_work_func
_request_firmware(desc);
desc->cont(fw, desc->context);//調用傳入的回調函數
static int _request_firmware(struct fw_desc *desc)
{
// 為固件配置設定記憶體,拷貝固件名到firmware->priv->fw_id
ret = _request_firmware_prepare(&fw, desc);
// 傳回骨架加載逾時時間,預設是60s
timeout = firmware_loading_timeout();
timeout = usermodehelper_read_lock_wait(timeout);
// 從檔案系統讀固件資料
ret = fw_get_filesystem_firmware(desc->device, fw->priv,
desc->dest_addr, desc->dest_size);
usermodehelper_read_unlock();
if (ret < 0) {
release_firmware(fw);
fw = NULL;
}
*desc->firmware_p = fw;
}
我們首先關注fw_get_filesystem_firmware函數,這個函數從檔案系統指定路徑讀取固件資料。
static int fw_get_filesystem_firmware(struct device *device,
struct firmware_buf *buf,
phys_addr_t dest_addr, size_t dest_size)
{
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
struct file *file;
/* skip the unset customized path */
if (!fw_path[i][0])
continue;
// 獲得固件在檔案系統的路徑
snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id);
// open檔案
file = filp_open(path, O_RDONLY, 0);
rc = fw_read_file_contents(file, buf);
fput(file);
}
}
fw_get_filesystem_firmware從檔案系統檔案中讀取到固件資訊儲存到核心的firmware_buf變量中,最後将資料傳遞給最開始的回調函數,給對應的子產品使用。
fw_path是核心子產品中指定的固件位置,我們可以增加自己的檔案目錄到該數組中,使核心可以找到更多目錄下的固件。
/* direct firmware loading support */
static char fw_path_para[256];
static const char * const fw_path[] = {
fw_path_para,
"/lib/firmware/updates/" UTS_RELEASE,
"/lib/firmware/updates",
"/lib/firmware/" UTS_RELEASE,
"/lib/firmware",
"/firmware/image"
};