读书人

MQX3.8源代码分析:GPIO(五)驱动安装

发布时间: 2012-11-23 00:03:43 作者: rapoo

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

读书人网 >移动开发

热点推荐