linux固件升级接口使用总结

Linux Firmware API 应用总结

简介

Linux内核开发过程中,开发人员调试外设驱动设备,比如触控,充电,线性马达,存储,WIFI设备等,均存在需要更新固件的情况。在Linux系统中,设备驱动程序处于内核态,而固件文件处于用户态,因此需要一个安全稳定可靠的机制,用来确保设备驱动程序成功加载固件文件。
为了解决设备驱动程序从内核态稳定加载用户态固件文件的问题,Linux系统提供了固件子系统。
固件API使内核代码可以从用户空间请求功能所需的文件,比如:

  • 设备驱动文件
  • 设备驱动程序信息数据(驱动层需要调用的用户侧数据均可通过此方式获取)

固件升级流程

Linux固件子系统基于sysfs和Uevent机制实现。
驱动程序调用固件系统函数接口申请固件之后,固件子系统使用固件编译内核的方式去获取固件;如果获取失败,就使用固件缓存的方式去获取固件;如果仍然获取失败,就使用默认路径内核直接查找的方式去获取固件。如果还是获取失败,就通过上报uevent消息给init进程。init进程则接收到uevent消息,过滤出subsystem类型为firmware的消息。init进程根据uevent消息内指向的固件信息去查找固件,通过sysfs提供的文件节点接口,把获取的固件内容从用户态写入内核态,从而使驱动程序,获取到固件文件的数据。
Linux固件系统提供了多种在不同场景下获取固件文件的方法:

  • 直接编译到内核的方式;

  • 固件缓存的方式;

  • 直接根据内核指定路径的方式:

  • 通过init进程来协助处理的方式;

固件存放路径一

以下搜索路径用于在根文件系统上查找固件

  • fw_path_para - 模块参数 - 默认为空,因此被忽略
  • /lib/firmware/updates/UTS_RELEASE/
  • /lib/firmware/updates/
  • /lib/firmware/UTS_RELEASE/
  • /lib/firmware/
    模块参数’PATH’可以传递给firmware_class模块来激活第一个可选的fw_path_para。自定义路径最多包含256个字符。传递的内核参数将是:‘firmware_class.path=$CUSTOMIZED_PATH’

可以根据需要自行增加固件路径

方法一:在kernel/drivers/base/firmware_class.c中添加文件目录。添加的位置在以下路径数组中:

如下示例,在数组中新增/system/firmware路径。

static const char* const fw_path[]={
    +"/system/firmware",
}

方法二:修改fw_path_para参数

  • 添加固件临时存放地址 /vendor/firmware
    echo -n “/vendor/firmware” > /sys/module/firmware_class/parameters/path。
  • 添加永久地址
    在系统初始化该变量的时候改为自己需要的地址:
    对应的修改在~/rk3399-android-10/device/rockchip/common/BoardConfig.mk:

固件存放路径二

将固件存放于uevent默认的固件搜索路径,来自 ueventd.rc文件内指定的firmware_directory:

 /etc/firmware/     
 /odm/firmware/  
 /vendor/firmware/  
 /firmware.image/

固件回退机制

固件回退机制是针对在指定路径固件查找失败的情况。
对于部分linux系统可能不存在以上固件路径一种指定的固件路径或者不允许用户在以上路径放置文件,这种情况下就需要使用固件回退机制,通过其他路径来升级固件。
启用固件回退机制的方法:

  • CONFIG_FW_LOADER_USER_HELPER:配置该项使能固件回退机制。
  • CONFIG_FW_LOADER_USER_HELPER_FALLBACK:同时配置使能该项。
    但是一般情况下第二项配置是禁用的。所以只能使用自定义的备用机制,即用request_firmware_nowait()接口,将第二个参数设置为false.

固件请求流程

request_firmware实现流程

  • 当我们调用固件接口进行固件升级时,固件接口首先调用_request_firmware_prepare函数,该函数通过调用fw_get_builtin_firmware函数判断固件文件是否编译到内核中。
  • 若固件未编译到内核,则通过 fw_get_filesystem_firmware函数在默认固件路径(即上述提到的固件存放路径一)搜索固件文件

USER_HELPER模式

  • 若默认固件路径也搜索不到固件,则检测是否打开固件回退机制(USER_HELPER模式),前提是需要在内核打开CONFIG_FW_LOADER_USER_HELPER。
    流程是:通过kernel上报Uevent消息到init进程,通过init进程获取固件信息,并写入sysfs节点中。

固件请求接口

通常情况下我们使用异步接口加载固件,此处只介绍异步固件加载接口。

  • 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) )  
    
     参数
    
      struct module *module
      模块请求固件
      bool uevent
      如果此标志非零,则发送 uevent 以复制固件映像,否则必须手动完成固件复制。
      const char *name
      固件文件名
      struct device *device
      正在为其加载固件的设备
      gfp_t gfp
      分配标志
      void *context
      将传递给cont, 如果固件请求失败,则fw可能会传递。NULL
      void (*cont)(const struct firmware *fw, void *context)
      当固件请求结束时,函数将被异步调用
    
    • 应用实例
      /**
      * @brief    fml_firmware_config_cb
      * @param
      * @retval   none
      */
      static void fml_firmware_config_cb(const struct firmware *cfg, void *ctx)
      {
          int fw_error = 0;
    
          if(cfg)
          {
              fw_error = fml_firmware_send_data((unsigned char*)cfg->data, cfg->size);
              if(fw_error)
              {
                  LOG_ERR("firmware send data err:%d\n", fw_error);
                  goto err_release_cfg;
              }
          }
      err_release_cfg:
          release_firmware(cfg);
          LOG_ERR("end\n");
      }
    
      /**
      * @brief    firmware update by file
      * @param
      * @retval 0:success, -1: fail,1:no need update
      */
      int fml_fw_update_by_file(void)
      {
          int ret_error = 0;
          struct cs_dev *fw_st = NULL;
    
          fw_st = devm_kzalloc(&(g_cs_dev.client->dev), sizeof(*fw_st), GFP_KERNEL);
          if(!fw_st)
          {
              LOG_ERR("devm_kzalloc failed\n");
              return -1;
          }
          fw_st->client = g_cs_dev.client;
          ret_error = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, FW_FILE_NAME,\
                                          &(g_cs_dev.client->dev), GFP_KERNEL, fw_st, fml_firmware_config_cb);
          devm_kfree(&(g_cs_dev.client->dev), fw_st);
          if(ret_error)
          {
              LOG_ERR("request_firmware_nowait failed:%d\n",ret_error);
              return -1;
          }
          LOG_ERR("end\n");
          return 0;
      }
    

    参考链接

    http://t.zoukankan.com/hellokitty2-p-14594987.html
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
吉利新金刚linux车机的升级方法如下: 首先,您需要准备一个空白的USB闪存盘,最好是16GB或更大容量的。确保闪存盘中没有任何重要的文件,因为这个过程会格式化闪存盘并删除其中的所有数据。 然后,您需要访问吉利汽车官方网站,找到新金刚车机的升级固件文件。通常,固件文件以压缩包的形式提供,您需要将其下载到您的计算机中。在下载过程中,确保您选择与您的车载设备完全相匹配的固件版本。 接下来,将USB闪存盘插入计算机的USB接口,然后解压缩下载的固件文件到闪存盘中。请确保将文件解压缩到闪存盘的根目录,而不是将其保存在任何文件夹中。 等待解压缩完成后,将USB闪存盘从计算机中安全移除。 现在,您可以将USB闪存盘插入吉利新金刚车机的USB接口。系统会自动检测到闪存盘中的升级文件,并显示升级提示。 按照屏幕上的指示,选择升级选项并确认开始升级过程。在升级过程中,请确保不要拔出USB闪存盘或关闭车机电源,以免导致升级失败或损坏设备。 升级完成后,车机将自动重新启动并加载新的固件。您可以根据需要重新设置一些个性化的配置,例如音量、屏幕亮度等等。 这就是吉利新金刚linux车机的升级方法。升级车机固件可以提供更好的性能、更稳定的运行以及一些新的功能和改进。在开始升级之前,请确保您按照以上步骤进行操作,并备份车载设备上的所有重要信息,以免因升级过程中的意外情况导致数据丢失。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值