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)函數的分析,估計需要的信息較多,我們留在下一節吧!





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章