As a driver author, you may find that you face a device that must download the firmware into it before it can support work. The competition in many parts of the hardware market is so strong that even a bit of the cost of the EEPROM used for device control firmware is not willing to spend. So the firmware is released on a CD along with the hardware, and the operating system is responsible for transmitting the firmware to the device itself .
Hardware is becoming more and more complex, many of the functions of the hardware use the program implementation, compared with the direct hardware implementation, the firmware has the flexibility to handle complex things and easy to upgrade, maintenance and so on . firmware (firmware) is such a program in the device hardware itself, through the firmware standard driver to achieve the operation of a specific machine, such as: optical drives, recorders, etc. have internal firmware.
The firmware is typically stored in flash memory on the device, but for cost and flexibility, many devices store the firmware image (image) as a file on the hard disk, and the device driver is initialized and then loaded into memory inside the device. This facilitates the firmware upgrade and omits the device's flash memory .
One, the difference between the driver and the firmware
From the computer field, the driver and firmware have never been clearly defined, as if today we say memory, most people use to express SDRAM, but also someone put Android "cured flash/storage" called "Memory", you can not say that it is wrong, because it is really a " Internal storage ".
But in Linux kernel, driver and firmware have a definite meaning,
1. Drive
Driver is a code snippet that controls external devices (device) that are managed by the operating system . Many times driver will be implemented as LKM, but this is not a requirement. The driver is registered to the bus (bus_type) via Driver_register (), which represents the system's ability to drive a device. When a device is registered to the same bus (which is usually found at the time of the bus enumeration), the bus driver binds the driver and the device through a certain policy (i.e. to match), and if the binding succeeds, The bus driver invokes driver's probe () function, transmits the device's information (such as a port, interrupt number, etc.) to the driver, and the driver can initialize the real physical part and register the control interface of the device with other subsystems of Linux (such as character devices, v4l2 subsystems, etc.). This allows other parts of the operating system to access the device through these common interfaces.
2. Firmware
Firmware is a program that runs on a non-"control processor"(a processor that does not run the operating system directly, such as a processor in a peripheral, or some of the cores that are used for bare metal's main processor). These programs often use a completely different set of instructions than the processor the operating system is running on. These programs exist in binary form in the Linux kernel's source tree, and are usually copied in the/lib/firmware directory when generating the target system. When the driver device is initialized, through the Request_firmware () and other interfaces, with the help of a user-state helper program, the specified firmware can be loaded into memory by the drive to the specified device.
So, in general, in fact, driver and firmware have no direct relationship, but firmware usually by the driver to load . The OS we're talking about doesn't really need to understand what firmware is, just think of it as data. Firmware is the only device that uses this data to know. Like you use a phone, the phone has a software, this software you do not care how to work, you change this software, you can call this software is "firmware", but if you use a smart phone, you have to carefully relate to what is the above application, Android platform, plug-ins and other details of the content, You may not call this thing "firmware".
How to solve the firmware problem? You may want to solve the firmware problem using a statement like this:
static char my_firmware[] = {0x34, 0x78, 0xa4, ...};
However, this approach is almost certainly a mistake. Coding the firmware to a driver expands the driver's code, makes the firmware upgrade difficult, and is likely to produce licensing issues. The vendor cannot already release the firmware image under the GPL, so mixing with the gpl-licensed code is often a mistake. For this reason, drivers that contain embedded firmware cannot be accepted into the mainstream kernel or included by Linux publishers.
Second, the kernel firmware interface
The right approach is to get it from the user space when you need it. However, resist the temptation to attempt to open the file containing the firmware directly from the kernel space; It is an error-prone operation, and it places a policy (in the form of a file name) into the kernel. Instead, the correct method uses the firmware interface, which is created for this purpose:
#include <linux/firmware.h>int request_firmware (const struct firmware **fw, char *name, struct device *device);
The function Request_firmware provides a user-space request with a firmware image file called name and waits for completion. The device that the parameter device loads for the firmware . The contents of the file are Request_firmware returned, and if the firmware request succeeds, 0 is returned. The function from the user space to obtain the data did not do any checks, the user when writing the driver, the firmware image should do a data security check, the direction of inspection is determined by the device firmware provider, usually has a check identifier, checksum and other methods.
calling Request_firmware requires the user to locate the space and provide a firmware image to the kernel ; We'll see for a moment how it works in detail. Name should identify the required firmware; The normal usage is the firmware file name supplied by the provider. Some of the names like My_firmware.bin are typical. If the firmware is successfully loaded, the return value is 0 (the usual error codes are returned), and the FW parameters point to one of these structures:
struct firmware {size_t size; U8 *data;};
The structure contains the actual firmware, which can now be downloaded to the device. Be careful that this firmware is an unchecked data from the user's space; You should use any and all the checks you can think of before you send it to the hardware. It is the correct firmware image. Device firmware often contains identification strings, checksums, and so on; Check them all before trusting the data.
Before you send the firmware to the device, you should release the In-kernel structure using:
void Release_firmware (struct firmware *fw);
Because Request_firmware requests user space to help, it guarantees sleep before returning. If your driver is not in the sleep position when it must request firmware, an asynchronous workaround might be used:
int request_firmware_nowait (struct module *module, char *name, struct device *device, void *context, void (*cont ) (const struct firmware *fw, void *context));
The additional parameter here is Moudle (which will always be this_module), the context (a private data pointer not used by a firmware subsystem), and Cont. If all goes well, request_firmware_nowait starts the firmware loading process and returns 0 . At some point in the future, Cont will be called with the result of the load. If for some reason the firmware fails to load, the FW is NULL.
Third, how the firmware works
The firmware subsystem uses SYSFS and hot-swap mechanisms. When calling Request_firmware, a new directory is created under/sys/class/firmware using your driver's name. That directory contains 3 properties:
Loading
This property should be set to 1 for the user-space process that loads the firmware. When the loading process is complete, it should be set to 0. Writing a value of 1 to loading will abort the firmware loading process.
Data
Data is a binary property of the receiving firmware data itself. After setting the loading, the user space process should write the firmware to this property.
Device
This property is a symbol that is connected to the/sys/devices entry under the link.
Once the SYSFS entry is created, the kernel generates a hot swap event for your device. The environment passed to the hot-pluggable processor includes a variable FIRMWARE, which is set to provide the name of the Request_firmware. The processor should locate the firmware file and copy it to the kernel using the provided properties. If this file cannot be found, the processor should set the loading property to-1.
If a firmware request is not serviced within 10 seconds, the kernel discards and returns a failed state to the driver. The timeout period can be changed by the Sysfs property/sys/class/firmware/timeout property.
Using the Request_firmware interface allows you to publish device firmware with your driver. When properly integrated into the hot-swap mechanism, the firmware loading subsystem allows the device to streamline its work "outside the box" Obviously this is the best way to deal with the problem.
However, let us ask one more warning: The device firmware does not have to be published without the manufacturer's license. Many manufacturers agree to license their firmware under reasonable terms, if requested politely; Some of the others may not be. In any case, copying and distributing their firmware without permission is a breach of copyright law and incurs trouble.
Iv. How to use the Firmware interface function
When the driver needs to use the firmware driver, the following code should be added during the initialization of the driver:
if (Request_firmware (&fw_entry, $FIRMWARE, device) = = 0)/ * Request image data from user space *//* copy the firmware image to the hardware memory, the copy function is written by the user */COPY_FW _to_device (Fw_entry->data, fw_entry->size); Release (Fw_entry);
The user also needs to provide a script in the user space to read the firmware image file into the kernel buffer through the file data in the file system Sysfs. The script sample is listed below:
#变量 $DEVPATH (the path to the firmware device) and $firmware (firmware image name) should already be provided in the environment variable hotplug_fw_dir=/usr/lib/hotplug/firmware/ #固件映像文件所在目录 echo 1 >/sys/$DEVPATH/loadingcat $HOTPLUG _fw_dir/$FIRMWARE >/sysfs/$DEVPATH/dataecho 0 >/sys/$DEVPATH/loading
V. Firmware request function Request_firmware
The function Request_firmware requests a copy of the firmware image file from the user space to the kernel buffer. The workflow for this function is listed as follows:
A--Create files in file system Sysfs/sys/class/firmware/xxx/loading and data, "xxx" means the name of the firmware, to the file loading and data additional read and write functions, set the file properties, file loading The file data writes the image file to the kernel buffer, and the read operation reads the data from the kernel buffer.
B-The Uevent event ("add") that adds the firmware is sent to the user space through the kernel object model.
C--User space management uevent event background process UDEVD after receiving an event, look for Udev rule files, run the actions defined by the rules, and the firmware-related rules are listed below:
$/etc/udev/rules.d/50-udev-default.rules......# Firmware class requestssubsystem== "firmware", action== "Add", run+= " Firmware.sh "...
As can be seen from the above rules, the firmware addition event will cause the script firmware.sh to run.
D--Script firmware.sh opens the "Mount" function, with the command "cat image File >/sys/class/firmware/xxx/data" to write the image file data to the kernel buffer.
E--After the image data copy is complete, the function request_firmware the directory "xxx" corresponding to the firmware device from the file system/sysfs. If the request succeeds, the function returns 0.
F – The user copies the firmware image data of the kernel buffer into the memory of the firmware. Then, the calling function Release_firmware (fw_entry) releases the buffer allocated to the firmware image.
The
Function Request_firmware is listed as follows (in DRIVERS/BASE/FIRMWARE_CLASS.C):
int Request_firmware (const struct firmware **firmware_p, const char *name, struct device *device) { int uevent = 1; Return _request_firmware (firmware_p, name, device, uevent);} static int _request_firmware (const struct firmware **firmware_p, const char *name, struct device *device, int uevent {struct device *f_dev;struct firmware_priv *fw_priv;struct firmware *firmware;struct builtin_fw *builtin;int retval;& Nbsp;if (!firmware_p) return-einval; *firmware_p = firmware = Kzalloc (sizeof (*firmware), Gfp_kernel), ...//Omit Error protection & nbsp /* If the firmware image is in the internal __START_BUILTIN_FW address, copy the data to the buffer */for (builtin = __START_BUILTIN_FW; Builtin! = __END_BUILTIN_FW; builtin++) {if (strcmp (name, builtin->name)) Continue;dev_info (device, "firmware:using built-in firmware %s\n ", name); /* Print information */firmware->size = Builtin->size;firmware->data = Builtin->data;return 0;} ...//Omit printing information * * In file system Sysfs establish XXX directory and file */retval = Fw_setup_device (firmware, &f_dev, name, DeviCE, uevent); if (retval) goto Error_kfree_fw; fw_priv = Dev_get_drvdata (F_dev); if (uevent) {if (Loading_timeout > 0) {/ * Load Timer */fw_priv->timeout.expires = jiffies + loading_timeout * Hz;add_timer (&fw_priv->timeout);} kobject_uevent (&f_dev->kobj, Kobj_add); /* Send event Kobj_add*/wait_for_completion (&fw_priv->completion); Set_bit (Fw_status_done, &fw_priv-> Status);d El_timer_sync (&fw_priv->timeout);} Elsewait_for_completion (&fw_priv->completion); /* Wait for loading */ mutex_lock (&fw_lock) to complete the firmware image data; /* If mount error, release buffer */if (!fw_priv->fw->size | | test_bit (fw_status_abort, &fw_priv->status)) {retval =-enoent ; Release_firmware (FW_PRIV->FW); *firmware_p = NULL;} FW_PRIV->FW = Null;mutex_unlock (&fw_lock);d evice_unregister (F_dev); /* Unregister the XXX directory on the file system Sysfs */goto out; error_kfree_fw:kfree (firmware); *firmware_p = Null;out:return retval;}
The function Fw_setup_device creates a directory and file for the firmware device in the file system Sysfs, which is listed as follows:
static int Fw_setup_device (struct firmware *fw, struct device **dev_p, const char *fw_name, struct device *device,
int uevent) {struct device *f_dev;struct firmware_priv *fw_priv;int retval; *dev_p = Null;retval = Fw_register_device (&am P;f_dev, fw_name, device); if (retval) goto out; ... fw_priv = Dev_get_drvdata (F_dev); /* Get private data structures from the device structure */FW_PRIV->FW = Fw;retval = Sysfs_create_bin_file (&f_dev->kobj, &fw_priv->attr_ data); /* Create an executable file in Sysfs */... Omit error Protection retval = Device_create_file (F_dev, &dev_attr_loading); /* Create a generic file in Sysfs */... Omit error protection if (uevent) f_dev->uevent_suppress = 0;*dev_p = F_dev;goto out; Error_unreg:device_unregister (F_dev); Out:return retval;}
The
Function Fw_register_device registers the device, creates the device class corresponding to the firmware device in the file system Sysfs, and stores the firmware driver private data. It is listed as follows:
static int fw_register_device (struct device **dev_p, const char *fw_name, struct device *device) {int retval;struct fi Rmware_priv *fw_priv = kzalloc (sizeof (*FW_PRIV), gfp_kernel), struct device *f_dev = kzalloc (sizeof (*f_dev), Gfp_kernel) ; *dev_p = null; //Omit Error protection init_completion (&fw_priv->completion); /* Initialize the completion mechanism's wait queue */fw_priv->attr_data = Firmware_attr_data_tmpl; /* Set the property structure of the file */strlcpy (fw_priv->fw_id, Fw_name, firmware_name_max); fw_priv->timeout.function = Firmware_ Class_timeout; /* Timeout load Exit Function */fw_priv->timeout.data = (u_long) fw_priv;init_timer (&fw_priv->timeout); /* Initialize Timer */ fw_setup_device_id (F_dev, device); /* copy device->bus_id to F_dev */f_dev->parent = device; F_dev->class = &firmware_class; /* Device class instance */dev_set_drvdata (F_dev, Fw_priv); /* Store device-driven private data: F_dev->driver_data = fw_priv*/f_dev->uevent_suppress = 1;retval = Device_register (F_dev); if ( retval) {Dev_err (device, "%s:device_register failed\n", __func__); goto Error_kfree;} *dev_p = F_dev;return 0; ...//Omit error protection}
/* File attribute structure instance, set the schema of the data file in file system Sysfs and read/write function */static struct Bin_attribute Firmware_attr_data_tmpl = {. attr = {. Name = "Data", . mode = 0644},.size = 0,.read = Firmware_data_read,/ * Read data from the kernel buffer */.write = firmware_data_write,/ * Used to write data from the firmware image file to the kernel buffer */}; /* Device class structure instance, containing the function to send Uevent event function and release device */static struct class Firmware_class = {. Name= "firmware",/ * Name of the device class */.dev_uevent = firmware_uevent,/* Device Send uevent event function */.dev_release= fw_dev_release,/* Release the function of the device */};
Linux device-driven firmware loading