Linux device-driven firmware loading

Source: Internet
Author: User
Tags builtin

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 as a device control firmware is not willing to spend. So the firmware is advertised 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 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 other advantages .

The firmware (firmware) is a program that runs on the device hardware itself, enabling the operation of specific machines through firmware standard drivers, such as: optical drives, recorders, etc., with 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 the memory inside the device. Such It facilitates firmware upgrades 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 understood the definition, as if today we say memory, most people use to express SDRAM, but also some people put Android "cured flash/storage" called "Memory". You can't say that it's wrong. Since this is indeed an "internal storage".

But in Linux kernel, driver and firmware have a clear meaning.

1. Drive

Driver is a code snippet that controls external devices (device) that are managed by the operating system .

Very often driver will be implemented as LKM, but this is not a requirement. Driver via Driver_register () to the bus (bus_type). Represents a system with the ability to drive a device. This device is discovered when a device is registered to the same bus (typically a bus enumeration). The bus driver binds the driver and the device through a certain strategy (that is, to match). Assume that the binding succeeds. The bus driver invokes driver's probe () function, transmits the device's information (such as port, interrupt number, etc.) to the driver, and the driver is able to initialize the actual physical part and register the control interface of the device on other Linux subsystems (such as the character device). V4L2 subsystem, etc.). This allows other parts of the operating system to access the device through these common interfaces.

2. Firmware

Firmware is a processor that is executed on a non-"control processor"(that is, processors that do not directly execute the operating system, such as peripherals. Or a program that is used in some of the cores in bare metal's main processor). Many of these programs use a completely different set of instructions than the processor that the operating system executes. These programs exist in binary form in the Linux kernel's source tree, when the target system is generated. Typically copied under the/lib/firmware folder.

When driver initializes the device, it passes through an interface such as Request_firmware (). With the help of a user-configured helper program. The ability to load the specified firmware into memory. Transferred from the drive to the specified device.

So, in general, the fact that driver and firmware have no direct relationship, but firmware is usually driven to load .

The OS we're talking about doesn't have to understand what firmware is, just think of it as data.

What is firmware, only the device that uses the data to know. Like you use a phone, the phone has a software, this software you do not care how to work, when you change the software, you can call this software is "firmware", but suppose 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 a firmware problem using this one statement:

static char my_firmware[] = {0x34, 0x78, 0xa4, ...};

However, this approach almost certainly is a mistake. Coding the firmware to a driver expands the driver's code, making firmware upgrades difficult, and is likely to create licensing issues. The vendor cannot already publish the firmware image under the GPL, so mixing with the gpl-licensed code is often a mistake. For this reason, drivers that include embedded firmware cannot be accepted into the mainstream kernel or included by Linux Publisher.

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 name for the firmware image file and waits for completion. The device that the parameter device loads for the firmware .

The contents of the file are deposited Request_firmware returned. Assuming the firmware request succeeds, return 0. The data obtained from the user space is not checked by the function, the user should do a data security check on the firmware image when writing the driver, and the inspection direction is determined by the device firmware provider. There are often methods for checking identifiers, checksums, and so on.

calling Request_firmware requires the user to locate the space and provide a firmware image to the kernel ; We'll see the details of how it works in a moment. Name should identify the required firmware; The normal use method is the name of the firmware file supplied by the provider. Some of the names like My_firmware.bin are typical. Assuming the firmware is loaded successfully, the return value is 0 (the error code that is responsible for frequent use is returned), and the FW parameters point to one of these structures:

struct firmware {size_t size; U8 *data;};

That structure includes 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 whatever and all the checks you can think of before sending it to the hardware. It is the correct firmware image. Device firmware often includes identification strings, checksums, and so on; All check them 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. Assuming that 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 reference here is Moudle (which will always be this_module), the context (a private data pointer not used by a firmware subsystem), and Cont. Assuming all goes well, request_firmware_nowait starts the firmware onboarding process and returns 0 . At some point in the future, Cont will be invoked with the loaded result. Assume that 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 folder is created under/sys/class/firmware using your driver's name. The folder consists of 3 properties:

Loading

This property should be set to 1 for the user-space process loaded into the firmware. When the onboarding process is complete, it should be set to 0. Writing a value of 1 to loading will abort the firmware onboarding 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 connected to the/sys/devices entry that is below the link.

Once the SYSFS entry is created, the kernel generates a hot swap event for your device. The environment passed to the hot-swappable processor contains 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. Assuming this file cannot be found, the processor should set the loading property to-1.

Assuming 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.

Use the Request_firmware interface to agree to advertise your device firmware with your driver. When properly integrated into the hot-swap mechanism, the firmware loading subsystem agrees that the device simplifies the work "outside the box" and obviously this is the best way to deal with the problem.

However, please allow us to ask one more warning: The device firmware does not have to be published without the manufacturer's permission. Many manufacturers will allow their firmware to be licensed under reasonable terms, assuming a polite request; Some of the other possibilities are not. In any case, copying and publishing their firmware without permission is a breach of copyright law and incurs trouble.


Four, the use of firmware interface functions

When the driver needs to use a firmware driver, it is necessary to add code such as the following during the initialization of the driver:

if (Request_firmware (&fw_entry, $FIRMWARE, device) = = 0)/  * Requests image data from the user space *//* copy the firmware image to the hardware's storage. 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 examples are listed below for example:

#变量 $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 lists such as the following:

A--Create file/sys/class/firmware/xxx/loading and data in file system SYSFS, "xxx" means the name of the firmware, add read and write function to file loading and data, set file properties. The file loading represents the on/off firmware image file loading function, and the write operation of the file data writes the data of the image file to the kernel buffer. Read operation reads data from the kernel buffer.

B--The Uevent event ("add") that joins the firmware is sent to the user space through the kernel object model.

C-the background process of the user space management Uevent event UDEVD After the event is received. Find Udev rules files, perform the actions defined by the rules, and list firmware-related rules such as the following:

$/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 join event will cause the execution of script firmware.sh.

D--Script firmware.sh to open the "load" function. The same command as "cat image File >/sys/class/firmware/xxx/data" writes the image file data to the kernel buffer.

E-After the image data copy is complete. The function request_firmware the corresponding folder "XXX" from the file system/SYSFS logoff firmware device. Suppose 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 lists such as the following (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     /* Assume that the firmware image is in the internal __START_BUILTIN_FW-pointing 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); /* Information Print */firmware->size = Builtin->size;firmware->data = Builtin->data;return 0;} ...//Omit information print/* in file system Sysfs establish XXX folder 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 the load */ mutex_lock (&fw_lock) of the firmware image data to complete; /* Assuming mount error, release buffer */if (!fw_priv->fw->size | | test_bit (fw_status_abort, &fw_priv->status)) {retval =-enoent ; Release_firmware (FW_PRIV-&GT;FW); *firmware_p = NULL;}   FW_PRIV-&GT;FW = Null;mutex_unlock (&fw_lock);d evice_unregister (F_dev); /* Unregister the XXX folder */goto out; error_kfree_fw:kfree (firmware) in file system sysfs; *firmware_p = Null;out:return retval;}

The Fw_setup_device function creates a folder and file for the firmware device in the file system SYSFS, which lists the following:

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 a running 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 the device class in the file system Sysfs to create the corresponding equipment for the firmware device. Store the firmware driver private data.

It lists such as the following:

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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.