Linux device driver firmware load - reprint

As a driver author, you may find that you have to download firmware into a device before it can work Competition in many parts of the hardware market is so intense that manufacturers are reluctant to spend even a little of the cost of EEPROM used as device control firmware Therefore, the firmware is released on a CD 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 hardware are realized by program. Compared with direct hardware implementation, firmware has the advantages of flexibility to deal with complex things and easy upgrade and maintenance. Firmware is such a program executed in the device hardware itself. The operation of a specific machine can be realized through the firmware standard driver, such as optical drive, recorder and so on.

Firmware is generally stored in the flash memory on the device, but for the sake of cost and flexibility, many devices store the firmware image in the hard disk in the form of file, and then load it into the internal memory of the device when the device driver is initialized. In this way, it is convenient to upgrade the firmware and omit the flash memory of the device.


1, Difference between driver and firmware

In the computer field, drivers and firmware have never been clearly defined. It's like today we say that memory is used by most people to represent SDRAM, but some people call "solidified Flash/Storage" in Android "memory". You can't say that this is wrong, because it is really an "internal storage".

But in Linux In Kernel, Driver and Firmware have clear meanings,

1. Drive

Driver is a code segment that controls an external device managed by the operating system. Many times, the driver will be implemented as LKM, but this is not a necessary condition. Driver through driver_register() is registered on the bus_type, which means that the system has the ability to drive a device. When a device is registered to the same bus (usually the device is found during bus enumeration), the bus driver will bind (i.e. match) the driver and device through certain policies. If the binding is successful, the bus driver will call the probe() function of the driver to pass the device information (such as port, interrupt number, etc.) to the driver, The driver can initialize the real physical components and register the control interface of the device to other subsystems of Linux (such as character device, v4l2 subsystem, etc.). In this way, other parts of the operating system can access the device through these common interfaces.

2. Firmware

Firmware refers to a program running in a non "control processor" (referring to a processor that does not directly run the operating system, such as a processor in peripherals, or some of the cores used in the main processor of bare metal). These programs often use a completely different set of instructions from the processor running the operating system. These programs exist in the source code tree of the Linux kernel in binary form. When generating the target system, they are usually copied in the / lib/firmware directory. When the driver initializes the device, it uses request_ With the help of a user helper program, the specified firmware can be loaded into memory and transferred to the specified device by the driver.

Therefore, generally speaking, there is no direct relationship between driver and firmware, but firmware is usually loaded by driver. The OS we discussed generally does not need to understand what firmware is, but just takes it as data. Only the device that uses this data knows what firmware is. For example, if you use a phone, there is a software in the phone. You don't care how the software works. When you change the software, you can call the software "firmware". However, if you use a smart phone, you should carefully relate to the details of the above applications, Android platform and plug-ins, You may not call this thing "firmware".


How to solve the firmware problem? You may want to solve the firmware problem using a statement:

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

However, this method is almost certainly a mistake Coding firmware into a driver enlarges the code of the driver, makes it difficult to upgrade firmware, and is likely to cause licensing problems Vendors cannot have released firmware mapped under the GPL, so mixing with GPL licensed code is often an error For this reason, drivers with embedded firmware cannot be accepted into the mainstream kernel or included by Linux publishers

2, Kernel firmware interface

The correct way is to get it from user space when you need it However, resist the temptation of trying to open a file containing firmware directly from kernel space; That is an error - prone operation, and it places the policy (in the form of a file name) into the kernel On the contrary, the correct method is to use the firmware interface, which is created for this purpose:

    
  1. #include <linux/firmware.h>
  2. int request_firmware(const struct firmware **fw, char *name, struct device *device);

Function request_firmware provides a firmware image file named name to the user space request and waits for completion. The parameter device is the firmware loaded device. Save the file contents in request_firmware returns 0 if the firmware request is successful. The data obtained by this function from the user space is not checked. When writing the driver, the user should check the data security of the firmware image. The check direction is determined by the device firmware provider. There are usually methods such as check identifier, checksum, etc.

Call request_firmware requires users to locate and provide a firmware image to the kernel; We'll see the details of how it works later Name should identify the required firmware; The normal usage is the firmware file name provided by the supplier Some like my_firmware.bin's name is typical If the firmware is loaded successfully, the return value is 0 (responsible for the common error code being returned), and the fw parameter points to one of these structures:

    
  1. struct firmware {
  2. size_t size;
  3. u8 *data;
  4. };

That structure contains the actual firmware, which can now be downloaded to the device Be careful that this firmware is unchecked data from user space; You should use any and all the checks you can think of to convince yourself that it is the correct firmware image before sending it to the hardware Device firmware often includes identification string, checksum, etc; Check all data before trusting them

Before you have sent firmware to the device, you should release the in kernel structure and use:

void release_firmware(struct firmware *fw);
    

Because request_firmware requests user space to help, and it guarantees sleep before returning If your driver is not in a sleep position when it must request firmware, an asynchronous alternative may be used:
    
  1. int request_firmware_nowait(struct module *module,
  2. char *name, struct device *device, void *context,
  3. void (*cont)( const struct firmware *fw, void *context));

The additional parameters here are moudle (it will always be THIS_MODULE), context (a private data pointer not used by the firmware subsystem), and cont. if all go well, request_firmware_nowait starts the firmware loading process and returns 0 At some point in the future, cont will be called with the loaded results If firmware loading fails for some reason, fw is NULL


3, How does the firmware work

The firmware subsystem uses sysfs and hot plug mechanism When calling request_firmware, a new directory is created under / sys/class/firmware using the name of your driver That directory contains three attributes:

loading

This property should be set to 1. 0 by 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 attribute that receives firmware data itself After setting loading, the user space process should write firmware to this property

device

This attribute is a symbolic connection to the associated entry under / sys/devices

Once the sysfs entry is created, the kernel generates a hot plug event for your device The environment passed to the hot plug processor includes a variable FIRMWARE, which is set to be provided to the request_ The name of FIRMWARE The processor should locate the FIRMWARE file and copy it to the kernel using the provided properties If the file cannot be found, the handler should set the loading property to - 1

If a firmware request is not serviced within 10 seconds, the kernel gives up and returns a failed state to the driver The timeout period can be changed through the sysfs attribute / sys/class/firmware/timeout attribute

Use request_ The firmware interface allows you to publish device firmware with your driver When properly integrated into the hot plug mechanism, the firmware loading subsystem allows the device to simplify work "out of the box", which is obviously the best way to deal with the problem

However, please allow us to give one more warning: the device firmware should not be released without the permission of the manufacturer Many manufacturers agree to license their firmware on reasonable terms if requested politely; Some others may not be there In any case, copying and distributing their firmware without a license is a violation of copyright law and causes trouble


4, Usage of firmware interface function

When the driver needs to be driven by firmware, the following code needs to be added during the initialization of the driver:

    
  1. if( request_firmware(&fw_entry, $FIRMWARE, device) == 0) /*Request image data from user space*/
  2. /*Copy the firmware image to the memory of the hardware, and the copy function is written by the user*/
  3. copy_fw_to_device(fw_entry->data, fw_entry->size);
  4. 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. Sample scripts are listed below:

    
  1. #The variables $DEVPATH (path to FIRMWARE device) and $FIRMWARE (FIRMWARE image name) should already be provided in the environment variable
  2.  
  3. HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ #Directory of firmware image file
  4.  
  5. echo 1 > /sys/$DEVPATH/loading
  6. cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
  7. echo 0 > /sys/$DEVPATH/loading

    

5, Firmware request function request_firmware

Function request_firmware requests that the firmware image file be copied from user space to the kernel buffer. The workflow of this function is listed below:

a -- create files / sys/class/firmware/xxx/loading and data in the file system sysfs, "XXX" represents the name of the firmware, attach read-write functions to the files loading and data, set file attributes, and file loading represents turning on / off the firmware image file loading function; The write operation of the file data writes the data of the image file into the kernel buffer, and the read operation reads the data from the kernel buffer.

b -- send the uevent event (i.e. "add") of adding firmware to user space through the kernel object model.

c -- after receiving the event, udevd, the background process of user space management uevent event, finds the udev rule file and runs the actions defined by the rule. The rules related to firmware are listed as follows:

    
  1. $ /etc/udev/rules.d/ 50-udev- default.rules
  2. ......
  3. # firmware class requests
  4. SUBSYSTEM== "firmware", ACTION== "add", RUN+= "firmware.sh"
  5. ......

As can be seen from the above rules, the firmware addition event will cause the script firmware to run sh.

d -- script firmware SH opens the "load" function and writes the image file data to the kernel buffer with the command "cat image file > / sys / class / firmware / xxx / data".

e -- after the image data copy is completed, the function request_firmware unregisters the directory "xxx" corresponding to the firmware device from the file system / sysfs. If the request is successful, the function returns 0.

f -- the user copies the firmware image data of the kernel buffer to the firmware memory. Then, call the function release_. Firmware (fw_entry) releases the buffer allocated to the firmware image.


Function request_firmware is listed below (in drivers/base/firmware_class.c):

    
  1. int request_firmware(const struct firmware **firmware_p, const char *name,
  2. struct device *device)
  3. {
  4. int uevent = 1;
  5. return _request_firmware(firmware_p, name, device, uevent);
  6. }
  7.  
  8. static int _request_firmware( const struct firmware **firmware_p, const char *name,
  9. struct device *device, int uevent)
  10. {
  11. struct device *f_dev;
  12. struct firmware_priv *fw_priv;
  13. struct firmware *firmware;
  14. struct builtin_fw *builtin;
  15. int retval;
  16.  
  17. if (!firmware_p)
  18. return -EINVAL;
  19.  
  20. *firmware_p = firmware = kzalloc( sizeof(*firmware), GFP_KERNEL);
  21. ...... //Omit error protection
  22.  
  23. /*If the firmware image is internal__ start_builtin_fw refers to the address and copies the data to the buffer*/
  24. for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
  25. builtin++) {
  26. if ( strcmp(name, builtin->name))
  27. continue;
  28. dev_info(device, "firmware: using built-in firmware %s\n", name); /*Print information*/
  29. firmware->size = builtin->size;
  30. firmware->data = builtin->data;
  31. return 0;
  32. }
  33. ...... //Omit print information
  34. /*Create xxx directory and files in file system sysfs*/
  35. retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
  36. if (retval)
  37. goto error_kfree_fw;
  38.  
  39. fw_priv = dev_get_drvdata(f_dev);
  40.  
  41. if (uevent) {
  42. if (loading_timeout > 0) { /*Load timer*/
  43. fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
  44. add_timer(&fw_priv->timeout);
  45. }
  46.  
  47. kobject_uevent(&f_dev->kobj, KOBJ_ADD); /*Send event KOBJ_ADD*/
  48. wait_for_completion(&fw_priv->completion);
  49. set_bit(FW_STATUS_DONE, &fw_priv->status);
  50. del_timer_sync(&fw_priv->timeout);
  51. } else
  52. wait_for_completion(&fw_priv->completion); /*Wait for the firmware image data to finish loading*/
  53.  
  54. mutex_lock(&fw_lock);
  55. /*If a load error occurs, the buffer is released*/
  56. if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
  57. retval = -ENOENT;
  58. release_firmware(fw_priv->fw);
  59. *firmware_p = NULL;
  60. }
  61. fw_priv->fw = NULL;
  62. mutex_unlock(&fw_lock);
  63. device_unregister(f_dev); /*Unregister xxx directory in file system sysfs*/
  64. goto out;
  65.  
  66. error_kfree_fw:
  67. kfree(firmware);
  68. *firmware_p = NULL;
  69. out:
  70. return retval;
  71. }

Function fw_setup_device creates directories and files of firmware devices in the file system sysfs, which are listed as follows:

    
  1. static int fw_setup_device(struct firmware *fw, struct device **dev_p,
  2. const char *fw_name, struct device *device,
  3. int uevent)
  4. {
  5. struct device *f_dev;
  6. struct firmware_priv *fw_priv;
  7. int retval;
  8.  
  9. *dev_p = NULL;
  10. retval = fw_register_device(&f_dev, fw_name, device);
  11. if (retval)
  12. goto out;
  13.  
  14. ......
  15. fw_priv = dev_get_drvdata(f_dev); /*Get private data structure from device structure*/
  16.  
  17. fw_priv->fw = fw;
  18. retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data); /*Create executable in sysfs*/
  19. ...... //Omit error protection
  20.  
  21. retval = device_create_file(f_dev, &dev_attr_loading); /*Create generic files in sysfs*/
  22. ...... //Omit error protection
  23.  
  24. if (uevent)
  25. f_dev->uevent_suppress = 0;
  26. *dev_p = f_dev;
  27. goto out;
  28.  
  29. error_unreg:
  30. device_unregister(f_dev);
  31. out:
  32. return retval;
  33. }

Function fw_register_device registers the device, creates the device class corresponding to the firmware device in the file system sysfs, and stores the private data of the firmware driver. They are listed below:

    
  1. static int fw_register_device(struct device **dev_p, const char *fw_name,
  2. struct device *device)
  3. {
  4. int retval;
  5. struct firmware_priv *fw_priv = kzalloc( sizeof(*fw_priv),
  6. GFP_KERNEL);
  7. struct device *f_dev = kzalloc( sizeof(*f_dev), GFP_KERNEL);
  8.  
  9. *dev_p = NULL;
  10.  
  11. ...... //Omit error protection
  12. init_completion(&fw_priv->completion); /*Initialize the waiting queue of the completion mechanism*/
  13. fw_priv->attr_data = firmware_attr_data_tmpl; /*Set the attribute structure of the file*/
  14. strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
  15.  
  16. fw_priv->timeout.function = firmware_class_timeout; /*Timeout load exit function*/
  17. fw_priv->timeout.data = (u_long) fw_priv;
  18. init_timer(&fw_priv->timeout); /*Initialization timer*/
  19.  
  20. fw_setup_device_id(f_dev, device); /*Copy device - > bus_ ID to f_ In dev*/
  21. f_dev->parent = device;
  22. f_dev-> class = &firmware_class; /*Device class instance*/
  23. dev_set_drvdata(f_dev, fw_priv); /*Store private data of device driver: F_ dev ->driver_ data = fw_ priv*/
  24. f_dev->uevent_suppress = 1;
  25. retval = device_register(f_dev);
  26. if (retval) {
  27. dev_err(device, "%s: device_register failed\n", __func__);
  28. goto error_kfree;
  29. }
  30. *dev_p = f_dev;
  31. return 0;
  32. ...... //Error protection is omitted
  33. }

    
  1. /*The file attribute structure instance sets the mode and read / write function of the data file in the file system sysfs*/
  2. static struct bin_attribute firmware_attr_data_tmpl = {
  3. .attr = {.name = "data", .mode = 0644},
  4. .size = 0,
  5. .read = firmware_data_read, /*Read data from kernel buffer*/
  6. .write = firmware_data_write, /*Used to write the data of the firmware image file to the kernel buffer*/
  7. };
  8.  
  9. /*An instance of the device class structure, which contains functions for sending uevent events and releasing devices*/
  10. static struct class firmware_class = {
  11. .name = "firmware", /*Name of the device class*/
  12. .dev_uevent = firmware_uevent, /*Function of device to send uevent event*/
  13. .dev_release = fw_dev_release, /*Function to release the device*/
  14. };


</article>**Linux Device driver firmware loading**

Keywords: Linux Operation & Maintenance Linux Driver

Added by Eric_Ryk on Fri, 14 Jan 2022 15:57:18 +0200