全志平台boot框架中增加设备驱动过程分析

来源:互联网 发布:公民网络身份识别系统 编辑:程序博客网 时间:2024/06/05 10:02

全志平台boot框架中增加设备驱动过程分析

 

       在boot启动阶段,大家都知道他的主要目的就是引导uboot,uboot在引导内核,从而让整个系统运作起来。全志的boot阶段,对应平板这一块,它会驱动LCD,显示一些开机LOGO,这个过程很快,也就1-2秒钟的时间。然而对于车载行业应用来说,可能需要再boot阶段做一些事情。比如,机器冷启动,大家都知道android启动时间还是比较长的,那么怎么使得客户能快速的用上倒车影像的功能呢?这就需要动脑筋了。

/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/edsam49原创,转载请注明出处,谢谢!
/*****************************************************************************************************/

         我们可以肯定的是不能等到系统启动完成,应该在最早我们能控制的地方增加我们的特定代码。倒车影像说白了,就是一个视频信号输入到系统,在LCD上再显示出来的事。但是如果要在boot阶段就把视频输入信号正常的显示在LCD上的话,我们需要做什么呢?

        首先,我们需要做倒车信号的检测。倒车信号的检测一般来说都是一个GPIO的高低电平来评判,而直接连接倒车线的IC一般是单片机,单片机处理识别以后再告诉主控芯片,告诉的通道其实也就是控制一个GPIO,主控这边来监控这个GPIO的变化,通常是设置成中断模式来检测。全志平台最方便的就是驱动的高度可配置化,非常灵活。我们可以把倒车检测的GPIO配置放在配置文件里面,也就是sys_config.fex文件里面,放在这里面的话就很灵活,不同项目如果使用的IO脚步一样,轻松一配,不用改boot的代码,相当不错。简单示例代码如下:

 ret = wBoot_script_parser_fetch("custom_design_cfg", "ReverseCarDetectGPIO", (int *)&gpio_reverse, sizeof(user_gpio_set_t)/4); if(!ret) { gpio_reverse.mul_sel = 0; //set input type gpio_handle = wBoot_GPIO_Request(&gpio_reverse, 1); if(gpio_handle) { gpio_value = wBoot_GPIO_Read_One_PIN_Value(gpio_handle, 0); } } if(1 == gpio_value)     { //__inf("Reverse signal come\n");return 1;     }     else      { __inf("Not enter reverse!!!\n");return 0;     }

        接下来我们就要做倒车显示处理了。做过全志平台的人都知道,里面有一个TVD的module来负责视频输入信号的处理。那么,我们就需要把TVD给打通。为了日后的管理方便,在boot里面这些驱动也都已经模块化,因此我们也要取其精华,把好的做法延续下去。就是单独做一个模块化的驱动。那怎么说呢?我教你,告诉你我也是从它已有的代码堆里模仿处理的,但是里面还是有几个地方要注意了,不要全抄了啊,免得老师发现你考试的卷子把别人的名字都抄过来了就不好了。

言归正传。搭框架,学样子。在boot1目录下的driver目录里,先增加一个tvd驱动的目录。把drv_de目录下的make.cfg、makefile、config.lds、magic.c先直接copy过来。先把make.cfg修改一下,主要是改名字,基本如下:

#定义生成的目标文件(输出/本地)LTARGET     = drv_tvd.drvTARGET0     = $(WORKSPACEPATH)/wboot/bootfs/drv_tvd.drvTARGET1     = $(LICHEEPATH)/wboot/bootfs/drv_tvd.drvTARGET2     = $(SDKROOT)/pack/chips/sun7i/wboot/bootfs/drv_tvd.drvLOCALTARGET = __image.axf

         Makefile写的比较好适配,不用修改。Config.lds这可得说到说到,哥在里面吃了亏的,当时也是直接拷过来的,后面再多个驱动一起运作的时候,工作不正常,查了半天才想起这个破绽,就是程序的加载地址。说出来了,感觉很容易是不是,没搞懂之前那还真不是太好找。就是0x42960000这一串数字,你得看其他模块的这个对应位置的值是多少,根据driver的大小,留一段给上一个程序。Tvd的如下:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)SECTIONS{. = 0x42960000; EGON2_MAGIC : { magic.o(.rodata) }.text : { *(.text) *(.rodata)}.data   : { *(.data)   }.bss    : { *(.bss)    }}

      剩下的我们就得改magic.c这个文件了,在这个文件里面也就是依葫芦画瓢了。需要改的就是模块的ID编号,其他就是对应改改函数接口的名字,如下:

const eGon2_mod_t modinfo ={    {'e','G','o','n','2','d','r','v'},//.magic    0x01000000,                //.version    EGON2_EMOD_TYPE_DRV_TVD,                //.mod id    0,                                      //.入口地址,驱动(模块)应该填空{                                       //.mif    &DRV_TVD_INIT,    &DRV_TVD_EXIT,    &DRV_TVD_OPEN,    &DRV_TVD_CLOSE,    &DRV_TVD_READ,        &DRV_TVD_WRITE,    &DRV_TVD_IOCTRL,    &DRV_TVD_Standby}};

     接下来,我们就该写驱动的实体了吧!也即是magic.c里面的各个函数。在这里可以先都只写一行打印信息,其他为空的函数。

格式就按下面的要求来就好了,如下:

struct eGon2_drv_func{    int          (* eGon2_init  )(void                                                                         );    int          (* eGon2_exit  )(void                                                                         );    unsigned int (* eGon2_open  )(unsigned int  mid, void   * open_arg                                         );    int          (* eGon2_close )(unsigned int  hd                                                             );    unsigned int (* eGon2_read  )(void       *pdata, unsigned int size, unsigned int n  , unsigned int  hd     );    unsigned int (* eGon2_write )(const void *pdata, unsigned int size, unsigned int n  , unsigned int  hd     );    int          (* eGon2_ioctl )(unsigned int  hd , unsigned int cmd , signed int aux,   void         *pbuffer);    int (* eGon2_standby)(unsigned int cmd ,void    *pbuffer   );};//eGon2里用到的模块数据结构,里面区分了是一个驱动还是一个应用typedef struct _eGon2_mod_section{    char                     magic[8];                          //MAGIC字符,用于标识是eGON2的驱动/应用代码    unsigned int             version;                           //版本数字    unsigned int             mod_id;                            //模块的ID,每个elf都应该有一个模块ID,不论驱动还是应用,且各不相同    int                     (*main)(int argc, char **argv);     //pcb里第一个任务的首地址    struct  eGon2_drv_func   demo_func;                         //驱动函数列表,列出了驱动所必要的7个函数}eGon2_mod_t;

      然后编译一下整个模块,可以加到boot的整体编译里面,也就是在boot目录下的Makefile 里面增加一行     “make -Cboot1/driver/drv_tvd -j8”即可。这样make一下,就会去编译这个新增加的模块,编译没有问题就会有一个二进制文件出来。

        这样整个驱动模块的框架是已经搭建好了。可以在bootmain里面去调用这个驱动了。加载驱动也是用的boot框架代码里支持的wBoot_driver_install("c:\\drv_tvd.drv");, 当然还有其他ioctl,close这些接口,就不详细在此描述。本文只是重点讲述模块的生成。关于模块的使用,已经TVD怎么工作的,显示控制怎么管理,笔者计划在下一篇文章中再做叙述,敬请关注。

2 0
原创粉丝点击