MQX3.8源代码分析:GPIO(四)驱动安装函数 _io_gpio_install()

MQX3.8源代码分析:GPIO(4)驱动安装函数 _io_gpio_install()

        关于GPIO的内部基准时钟已经打开,下一步就是给GPIO安装操作函数了,只有安装了操作函数,才能够利用的标准的接口访问GPIO.

1、文件:Io_gpio.c (source\io\gpio)中

/*FUNCTION*-------------------------------
 * 
 * Function Name    : _io_gpio_install
 * Returned Value   : _mqx_uint a task error code or MQX_OK
 * Comments         :
 *    Install a gpio driver.
 *
 *END*----------------------------------*/
 
 _mqx_uint _io_gpio_install
    (
       /* [IN] A string that identifies the device for fopen */
       /* input values are those identifiers defined in io_gpio.h file */
       char_ptr            identifier
    ) 
 { /* Body */
     if (IO_OK == gpio_cpu_init())
         return _io_dev_install(identifier,  _io_gpio_open, _io_gpio_close, _io_gpio_read, _io_gpio_write, gpio_cpu_ioctl,  NULL);
     return (_mqx_uint)IO_ERROR;
 } /* Endbody */

 分析:

          gpio_cpu_init()函数,我们已经知道是为了实现硬件层gpio操作时钟的使能控制的。那么_io_dev_install(xxxx)函数,就是给gpio模块安装驱动函数的,驱动函数类似于linux方式,包括:打开、关闭、读、写、控制。这些控制函数都在本文件内实现,当我们调用fopen、fclose、fread、fwrite、ioctl等系统统一接口时,mqx会在内部通过映射表,调用gpio模块对应的功能函数。例如:fopen -> _io_gpio_open。


2、文件:Io_inst.c (source\io)中

/*FUNCTION*-------------------------------
 * 
 * Function Name    : _io_dev_install
 * Returned Value   : _mqx_uint a task error code or MQX_OK
 * Comments         :
 *    Install a device dynamically, so tasks can fopen to it.
 *
 *END*----------------------------------*/
 
 _mqx_uint  _io_dev_install
    (
       /* [IN] A string that identifies the device for fopen */
       char_ptr             identifier,
   
       /* [IN] The I/O open function */
       _mqx_int (_CODE_PTR_ io_open)(MQX_FILE_PTR, char _PTR_, char _PTR_),
 
       /* [IN] The I/O close function */
       _mqx_int (_CODE_PTR_ io_close)(MQX_FILE_PTR),
 
       /* [IN] The I/O read function */
       _mqx_int (_CODE_PTR_ io_read)(MQX_FILE_PTR, char _PTR_, _mqx_int),
 
       /* [IN] The I/O write function */
       _mqx_int (_CODE_PTR_ io_write)(MQX_FILE_PTR, char _PTR_, _mqx_int),
 
       /* [IN] The I/O ioctl function */
       _mqx_int (_CODE_PTR_ io_ioctl)(MQX_FILE_PTR, _mqx_uint, pointer),
 
       /* [IN] The I/O initialization data */
       pointer              io_init_data_ptr
    )
 { /* Body */
 
    return (_io_dev_install_ext(identifier, io_open, io_close, io_read, io_write, io_ioctl, (_mqx_int (_CODE_PTR_)(IO_DEVICE_STRUCT_PTR))NULL,   io_init_data_ptr));
 
 } /* Endbody */

分析:

        GPIO的设备驱动安装函数,该函数接收5个函数指针和一个void型指针。调用带函数指针形参的函数时,我们只需要把对应函数实参的名字传递过去就可以了,不用对函数名称取地址&,因为在C语言内部,函数名称指的就是函数的入口地址,即:该函数运行的首地址,关于这个不再多说。最后一个void*指针,是给该函数传递初始化数据的,这里传递了一个NULL。

         该函数经过了一层封装,调用了_io_dev_install_ext(xxx)函数,进行具体的安装工作,与外层函数相比,它多了一个形参:

 (_mqx_int  (_CODE_PTR_) (IO_DEVICE_STRUCT_PTR)) NULL。主体是一个NULL,前面的是一个强制类型转换,转换成了什么,转换成了一个函数指针,该函数返回_mqx_int数值,形参IO_DEVICE_STRUCT_PTR。详细分析进入该函数即可看到。

         可能有人会问:传递一个空数据,干嘛还要再进行一次函数调用?这其中就涉及到函数维护的知识了,可能_io_dev_install_ext()函数出现较早,而那个参数随着版本升级,不再需要,但是为了保持一致性,又不能轻易修改已经成型的函数,这时候怎么办。办法就是再增加一层函数,利用这层函数屏蔽掉这个变化,使上层看不到无效数据。以后,当维护函数数据较多时,肯定会用到这个方法。

对_io_dev_install_ext(xx)函数的分析,估计需要的信息较多,我们留在下一节吧!