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

这一节中,我们重点分析一下驱动安装函数_io_dev_install_ext(xxx),看看驱动安装到底都做了些什么工作,又会遇到哪些新的东西!

文件:Io_instx.c (source\io)中

/*FUNCTION*-------------------------------------------------------------------
* 
* Function Name    : _io_dev_install_ext
* Returned Value   : _mqx_uint a task error code or MQX_OK
* Comments         :
*    Install a device dynamically, so tasks can fopen to it. Different from
* _io_dev_install since this function also installs an unstall function.
*
*END*----------------------------------------------------------------------*/

_mqx_uint _io_dev_install_ext
   (
      /* [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 un-install function */
      _mqx_int (_CODE_PTR_ io_uninstall)(IO_DEVICE_STRUCT_PTR),

      /* [IN] The I/O initialization data */
      pointer              io_init_data_ptr
   )
{ /* Body */
   KERNEL_DATA_STRUCT_PTR kernel_data;
   IO_DEVICE_STRUCT_PTR   dev_ptr;
#if MQX_CHECK_ERRORS
   _mqx_uint              i;
   _mqx_uint              found = 0;
#endif

   _GET_KERNEL_DATA(kernel_data);

#if MQX_CHECK_ERRORS
   if ((io_open == NULL) || (io_close == NULL)){
      return(MQX_INVALID_PARAMETER);
   } /* Endif */

   /* Search for delimiter */
   for (i = 0; i < IO_MAXIMUM_NAME_LENGTH; i++) 
   	{
      if (identifier[i] == IO_DEV_DELIMITER) 
	  {
         found++;
      }
	  else if (identifier[i] == '\0') 
	  {
         break;
      } /* Endif */
   } /* Endfor */
      
   /* 
   ** Return an error if more than 1 delimiter found, no delimiter was found
   ** or the identifier was composed of a single delimiter only.
   */
   if ((found != 1) || (i == 1)) {
      return(MQX_INVALID_PARAMETER);
   } /* Endif */
/* START CR-169 */
#endif

   /* Check to see if device already installed */
   _lwsem_wait((LWSEM_STRUCT_PTR)&kernel_data->IO_LWSEM);
   if (kernel_data->IO_DEVICES.NEXT == NULL) {
      /* Set up the device driver queue */
      _QUEUE_INIT(&kernel_data->IO_DEVICES, 0);
   } /* Endif */

#if MQX_CHECK_ERRORS
   dev_ptr = (IO_DEVICE_STRUCT_PTR)((pointer)kernel_data->IO_DEVICES.NEXT);
   while (dev_ptr != (pointer)&kernel_data->IO_DEVICES.NEXT) {
      if (!strncmp(identifier, dev_ptr->IDENTIFIER, IO_MAXIMUM_NAME_LENGTH)) {
         _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->IO_LWSEM);
         return(IO_DEVICE_EXISTS);
      } /* Endif */
      dev_ptr = (IO_DEVICE_STRUCT_PTR)((pointer)dev_ptr->QUEUE_ELEMENT.NEXT);
   } /* Endwhile */
#endif
   _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->IO_LWSEM);
/* END CR-169 */
   
   dev_ptr = (IO_DEVICE_STRUCT_PTR)_mem_alloc_system_zero((_mem_size)
      sizeof(IO_DEVICE_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
   if (dev_ptr == NULL) {
      return(MQX_OUT_OF_MEMORY);
   }/* Endif */
#endif
   _mem_set_type(dev_ptr, MEM_TYPE_IO_DEVICE);
      
   dev_ptr->IDENTIFIER      = identifier;
   dev_ptr->IO_OPEN         = io_open;
   dev_ptr->IO_CLOSE        = io_close;
   dev_ptr->IO_READ         = io_read;
   dev_ptr->IO_WRITE        = io_write;
   dev_ptr->IO_IOCTL        = io_ioctl;
   dev_ptr->IO_UNINSTALL    = io_uninstall;
   dev_ptr->DRIVER_INIT_PTR = io_init_data_ptr;

   _lwsem_wait((LWSEM_STRUCT_PTR)&kernel_data->IO_LWSEM);
   _QUEUE_ENQUEUE(&kernel_data->IO_DEVICES, dev_ptr);
   _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->IO_LWSEM);

   return MQX_OK;

} /* Endbody */

分析:

        首先传递参数有gpio的驱动标示符identifier,一般是“gpio:”,还有驱动操作函数指针,这个上次已经讲过了,剩下的那个就是初始化数据的指针,一般是传递一些特殊数据,这里设为NULL。

        然后定义了两个变量:内核数据kernel_data和io设备指针dev_ptr,内核数据指针指向的数据主要包含系统内核状态信息,是一个全局变量,供各个模块使用。设备指针主要包含我们马上就要初始化的一些数据信息,下面会看到初始化的过程就是初始化这个dev_ptr指针,然后把这个指针链接进kernel_data的过程,这样系统就获得了GPIO的操作函数,完成初始化。

       紧接着是宏定义MQX_CHECK_ERRORS,用户可以打开这个宏,进行参数的有效性校验,对不符合的参数进行错误处理,一般这个宏都是打开的,这才符合高质量编程的规范嘛!

        下一步,获得信号量来保证初始化操作的互斥性,进一步检测kernel_data中的io设备结构体队列是否初始化,如果没有初始化(IO_DEVICES.NEXT = NULL),则先进行io设备队列的初始化。下面这个while循环,主要是判断在IO列表上是否已经存在初始化好的的io设备结构体,判断的根据就是传递过来的identifier标示符“GPIO:”。如果存在,就返回错误信息。

         信号量使用完成后一定要释放,这是特别要注意的。当入口校验完毕,下一步就是进行dev_ptr结构体的初始化了,首先以初始化为0的方式分配内存空间,空间IO设备结构体大小。注意,一般在分配内存空间时,都需要进行空间分配是否成功的判断,因为分配内存会有分配失败的可能存在。但是我记得在学习linux时,linux也需要判断,而且linux返回的值也都是几乎都正确,因为linux在分配时,分配的并不是实际地址,而是一个逻辑地址,当对该空间操作时,才进行逻辑地址向屋里地址的映射。这里不是mqx是不是这样,不管是不是都需要判断,这是少不了的。

        最后,进行dev_ptr结构体的初始化,给里边的各个变量赋值,把相关的io操作函数进行绑定。绑定完成后,再把设备结构体链接到内核数据结构上,这样内核数据结构就可以根据一个io结构体,找到对应的io操作函数,这样就完成了GPIO驱动函数与MQX内核之间的数据映射,下一步要做的工作就是根据GPIO硬件属性,完成对应驱动函数的功能实现了。

至于MQX内核是怎样进行相关函数调用,组合内部逻辑的,这个我们暂时还看不到迹象,或许以后可以看到!另:该函数里边用到了许多队列相关知识,而且大概看了一下,队列的使用中有好多技巧值得我们学习,故下一步要详细分析一下啦!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值