1、概述

本文档主要介绍SylixOS中字符设备驱动框架,适用于在SylixOS集成开发环境下进行字符设备驱动开发的学习。

注:文中xxx是指具体设备名,编写对应驱动时,自行命名(如RTCCOMPASS等)。

2SylixOS字符设备驱动简介

字符设备是指只能以字节为单位进行读写的设备,读取数据需按照先后顺序,不能随机读取设备内存中某一数据。常见的字符设备如:鼠标、键盘、串口等。

SylixOS中,每个字符设备都会在/dev目录下对应一个设备文件,用户程序可通过设备文件(或设备节点)来使用驱动程序进行字符设备的读写、IO控制等操作。

3SylixOS字符设备驱动框架

3.1字符设备驱动模型

SylixOS中,使用PLW_xxx_DEV结构体来描述字符设备,该结构体由LW_DEV_HDRPLW_xxx_FUNCS两个成员组成。其中,LW_DEV_HDR为设备头,包含设备管理链表、驱动程序索引号、设备名、设备类型、设备打开次数等,PLW_xxx_FUNCS是指对应设备的操作函数集(如设备打开、关闭、读写、IO控制等)。其字符设备驱动模型如图 3.1所示。

3.1字符设备驱动模型

    以下对驱动模型中各模块进行解析。

3.2驱动函数安装

如图 3.1所示,步骤①~②,调用__xxxDrvInstall函数安装设备驱动函数,通过系统API函数API_IosDrvInstall注册设备驱动程序,包括设备创建、删除、打开、关闭、读写、IO控制等,该函数返回该设备的驱动函数索引号_G_ixxxDrvNum,用于创建设备时关联具体的设备操作函数集。具体流程如程序清单 3.1所示。

程序清单 3.1驱动函数安装

INT  __xxxDrvInstall (VOID)
{
   /*
    *  注册设备驱动程序,获取驱动程序索引号
    */
    _G_ixxxDrvNum = iosDrvInstall( __xxxCreate,                         /*  驱动程序中的创建函数       */
                                   __xxxDelete,                         /*  驱动程序中的删除函数       */
                                   __xxxOpen,                           /*  驱动程序中的打开函数       */
                                   __xxxClose,                          /*  驱动程序中的关闭函数       */
                                   __xxxRead,                           /*  驱动程序中的读函数         */
                                   __xxxWrite,                          /*  驱动程序中的写函数         */
                                   __xxxIoctl);                         /*  驱动程序中的IO控制函数     */

    DRIVER_LICENSE(_G_ixxxDrvNum,     "GPL->Ver 2.0");
    DRIVER_AUTHOR(_G_ixxxDrvNum,      "xx.xx.xx");
    DRIVER_DESCRIPTION(_G_ixxxDrvNum, "hardware xxx.");

    return  ((_G_ixxxDrvNum > 0) ? (ERROR_NONE) : (PX_ERROR));
}



3.3字符设备创建

如图 3.1所示,步骤③~④,调用函数__xxxDevCreate创建设备,传入参数为设备操作函数集__xxxDevFuncs,将该操作函数集赋给设备结构体成员PLW_xxx_FUNCS进行管理。然后通过系统API函数API_IosDevAddEx将该设备添加进内核设备管理链表,并将该设备与上小节中获取的设备驱动程序索引号相关联。具体流程如程序清单 3.2所示。

程序清单 3.2字符设备创建

INT  __xxxDevCreate (PLW_xxx_FUNCS    pxxxfuncs)
{
    PLW_xxx_DEV     pxxxdev;

    if (pxxxfuncs == LW_NULL) {
        _ErrorHandle(EINVAL);
        return  (PX_ERROR);
    }

    if (_G_ixxxDrvNum <= 0) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "no driver.\r\n");
        _ErrorHandle(ERROR_IO_NO_DRIVER);
        return  (PX_ERROR);
    }

    pxxxdev = (PLW_xxx_DEV)__SHEAP_ALLOC(sizeof(LW_xxx_DEV));
    if (pxxxdev == LW_NULL) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "system low memory.\r\n");
        _ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
        return  (PX_ERROR);
    }
    lib_bzero(pxxxdev, sizeof(LW_xxx_DEV));

    pxxxdev->xxxDEV_pxxxfuncs = pxxxfuncs;

    /*
     *  向系统中添加一个设备 (可以设置设备的 mode)
     */
    if (iosDevAddEx(&pxxxdev->xxxDEV_devhdr, __LW_xxx_DEV_NAME, _G_ixxxDrvNum, DT_CHR) != ERROR_NONE) {
        __SHEAP_FREE((PVOID)pxxxdev);
        return  (PX_ERROR);
    }

    return  (ERROR_NONE);
}



3.4模块加载和卸载

如图 3.1所示,步骤⑤~⑥,字符设备驱动编写完成后,经IDE编译并将生成的驱动模块部署到板卡上,然后通过moduleregmoduleunreg命令可以进行驱动模块的加载和卸载。如图 3.2所示,详细操作请参照《RealEvo_IDE使用手册》。

3.2驱动模块加载和卸载操作说明

3.5应用层调用

如图 3.1所示,步骤⑦~⑨,应用层可以通过open函数,打开/dev目录下对应的设备节点,通过匹配设备名和设备驱动程序索引号,获得该设备的管理结构,之后对该设备的读写和IO控制即可以调用到管理结构内具体的设备操作函数,实现硬件操作。用户程序的编写具体参照《SylixOS应用开发手册》。