热插拔子系统分析

更新时间:
2024-01-09
下载文档

热插拔子系统分析

系统与驱动

热插拔子系统中,系统与驱动层的交互分为热插拔事件和循环检测。热插拔事件是针对设备能够产生热插拔中断通知的情况,SylixOS 可以将通知以异步的方式来处理;而循环检测是设备不能产生一个热插拔中断通知的情况,需要轮询检测某些事件标志,来获取设备的插入或拔出状态。

热插拔事件

能够产生热插拔事件的设备,在驱动层调用 API_HotplugEvent 函数即可,SylixOS 热插拔系统中对热插拔事件处理是通过 JobQueue 来实现,SylixOS 定义工作队列如下:

static  LW_JOB_QUEUE                _G_jobqHotplug;
static  LW_JOB_MSG                  _G_jobmsgHotplug[LW_CFG_HOTPLUG_MAX_MSGS];

热插拔事件通过 API_HotplugEvent 函数中向工作队列中添加工作:

#include <SylixOS.h>
INT  API_HotplugEvent (VOIDFUNCPTR  pfunc, 
                       PVOID        pvArg0,
                       PVOID        pvArg1,
                       PVOID        pvArg2,
                       PVOID        pvArg3,
                       PVOID        pvArg4,
                       PVOID        pvArg5)
{
……
        if (_jobQueueAdd(&_G_jobqHotplug,
                         pfunc,
                         pvArg0,
                         pvArg1,
                         pvArg2,
                         pvArg3,
                         pvArg4,
                         pvArg5)) {
            _ErrorHandle(ERROR_EXCE_LOST);
            return  (PX_ERROR);
        }
    ……
}

函数 API_HotplugEvent 原型分析:

  • 函数成功返回 ERROR_NONE ,失败返回 PX_ERROE
  • 参数 pfunc 表示函数指针。
  • 参数 pvArg0 ~ pvArg5 为函数参数。

设备驱动创建时,驱动层调用 API_HotplugEvent 函数完成工作队列的添加,热插拔内核线程在检测该工作队列时会检测到工作,并调用其中的执行函数,向应用层提供热插拔消息。

循环检测

针对不能产生一个热插拔中断事件的设备,驱动层可调用 API_HotplugPollAdd 函数将驱动中的轮询检测函数来添加到系统中,这样系统会在一个确定的时间间隔轮询检测设备状态。

轮询检测节点结构如下,函数指针和函数参数两个成员是驱动设计者所要关心的,也就是驱动的轮询检测函数,全局链表头 _G_plineHotplugPoll 连接所有的热插拔节点。

typedef struct {
    LW_LIST_LINE         HPPN_lineManage;             /*  节点链表                     */
    VOIDFUNCPTR          HPPN_pfunc;                  /*  函数指针                     */
    PVOID                HPPN_pvArg;                  /*  函数参数                     */
    LW_RESOURCE_RAW      HPPN_resraw;                 /*  资源管理节点                  */
} LW_HOTPLUG_POLLNODE;

SylixOS 下热插拔驱动支持提供 API_HotplugPollAdd 接口添加轮询检测函数,如下:

#include <SylixOS.h>
INT  API_HotplugPollAdd (VOIDFUNCPTR   pfunc, PVOID  pvArg)
{
        ……
        phppn->HPPN_pfunc = pfunc;
        phppn->HPPN_pvArg = pvArg;
        ……
}

函数 API_HotplugPollAdd 原型分析:

  • 函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 pfunc 表示函数指针。
  • 参数 pvArg 为函数参数。

内核线程

SylixOS 下热插拔子系统中会创建“t_hotplug”内核线程,内核线程代码实现如下:

#include <SylixOS.h>
static VOID  _hotplugThread (VOID)
{
        ……
        for (;;) {
            ulError = _jobQueueExec(&_G_jobqHotplug, LW_HOTPLUG_SEC * LW_TICK_HZ);
            if (ulError) {
                ……
                for (plineTemp  = _G_plineHotplugPoll;
                     plineTemp  != LW_NULL;
                     plineTemp   = _list_line_get_next(plineTemp)) {
                    if (phppn->HPPN_pfunc) {
                        phppn->HPPN_pfunc(phppn->HPPN_pvArg);
                    }
                }
                ……
            }
        }
}

“t_hotplug”内核线程每隔“LW_HOTPLUG_SEC * LW_TICK_HZ”时间间隔会遍历执行工作队列中的工作,若工作队列中没有工作则内核线程遍历循环检测链表,检测到节点则调用其中的循环检测函数。

系统与应用层

系统与应用层的交互是系统将热插拔消息通知给应用层,这样用户层可以感知到设备的插入和拔出。应用层通过调用函数 API_HotplugEventMessage 即可将热插拔消息通知出去,然后应用层通过读设备“/dev/hotplug”即可获得热插拔消息。

实现原理分两部分,一是热插拔设备部分,二是消息传递部分。

热插拔设备部分

热插拔设备的创建涉及到 SylixOS 设备驱动的知识,这里不再详述,在之后的设备驱动文章中将做详细介绍。

消息传递部分

消息传递部分调用 HotplugEventMessage 函数将热插拔消息存放在设备缓存区中,代码片段如下:

#include <SylixOS.h>
INT  API_HotplugEventMessage (INT           iMsg,
                              BOOL          bInsert,
                              CPCHAR        pcPath,
                              UINT32        uiArg0,
                              UINT32        uiArg1,
                              UINT32        uiArg2,
                              UINT32        uiArg3)
{
    ……
    _hotplugDevPutMsg(iMsg, ucBuffer, i);
    ……
}

函数 API_HotplugEventMessage 原型分析:

  • 函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 iMsg 为消息号。
  • 参数 bInsert 表示是否为插入,否则为拔出。
  • 参数 pcPath 表示设备路径或名称。
  • 参数 uiArg0 ~ uiArg3 为附加参数。

函数 HotplugEventMessage 根据 SylixOS 定义的热插拔消息格式,将传入参数封装为热插拔消息,并调用 _hotplugDevPutMsg 函数将热插拔消息保存至缓存区。

文档内容是否对您有所帮助?
有帮助
没帮助