QNX驱动开发——应用层与resource manger交互

        QNX操作系统是一个类Unix实时操作系统,遵从POSIX规范,驱动程序具有良好的可移植性。

        编写任何驱动程序都会遇到同样的一个问题:应用程序与驱动程序之间是如何进行交互的。其实这个问题很简单,QNX有大量资料说明这一点。

        当客户端调用fd = open(“dev/mydevice,O_RDWR)打开设备mydevice,并期望从设定的地址上读写数据时,这个问题就产生了。实际上QNX提供了一套灵活的消息交互机制,大致上可以分为以下三个步骤:

        第一,加载驱动程序,创建服务线程,把底层IO函数与POSIX函数进行连接,在命名空间注册设备名,通过Event loopThread pool等待消息的接收,同时使父进程在后台运行以加载其他应用程序。

        第二,当应用程序调用open()函数时,process manger受到请求在命名空间中找到名为dev/mydeviceresource mangerQNX内核库打开它,应用程序通过返回的句柄与之建立连接。

        第三,随后当调用read (fd, buf, 512)函数时,内核库发送了一个_IO_READ的消息,此时之前建立的Event loopThread pool就可以接收到这个消息,通过判断消息的类型调用到相应的IO函数,比如:

int io_read (resmgr_context_t *ctp,  io_read_t *msg  RESMGR_OCB_T*ocb);

其实可以看出来了,fd, buf, 512这几个参数主要就是通过io_read_t *msg这个参数传过来的。其实client主要指定了一个设备,希望向这个设备的某个地址读取长度为512字节的数据,然后放到buf当中。

        接下来发生的事情就比较简单了,就是在自己实现的io_read函数中解析这个消息传递来的参数,并给出回复。在client-server消息交互模型中,此时client就处在了reply blocked的状态等待server的回复。在io_read中做了哪些事情呢?首先要验证下传来的消息是否是正确的io_read消息,同时检查到底是否是nonblock方式打开。然后解析msg->i.nbytes来确定需要传递多少个数据,然后调用底层函数读取硬件数据,通过_IO_SET_READ_NBYTES (ctp, msg->i.nbytes);来告诉client可以返回的数据量。

        对于如何回复数据来说,QNX确实提供了不少简单的方法。可以使用returnENOMEM)返回一个错误;或者使用returnEOK)返回操作成功。如果想返回一定量数据的话,可以设置IOV数组返回,

比如通过设置IOV来返回一个或多个数组,比如:

        SETIOV (ctp->iov, buffer, nbytes);

        return (_RESMGR_NPARTS(1));

        或者直接调用宏返回一个完整的buffer

        return (_RESMGR_PTR(ctp, buffer, nbytes));

写数据的操作与读数据的操作类似,不再赘述。这样就完成了上层数据请求,下层数据读取并返回的过程,server重新回到receive blocked的状态。细心的朋友可能已经看出来了,既然是读写数据,那么地址是如何设置的呢?其实是通过devctl来设置的,其格式为

       int devctl( int fd, int dcmd, void *data, size_t nbytes, int * return_info);

其中最值得一提的就是int dcmd这个参数,这是一个自定义的命令,可以通过这个命令传递一个结构体指针,比如:

   Typedef struct{

       Uint32_t addr_t;

       Uint32_t status_r;

       } my_cfg_t;

     #define MYCMD_SET_ADDR  __DIOT(_DCMD_MISC, 0x01, my_cfg_t)

     client应用程序中定义my_cfg_t addr;通过命令

     Devctl(fd, MYCMD_SET_ADDR,& addr,sizeof(my_cfg_t),NULL);

完成设置。对于底层来说就比较简单了,主要分为获取数据指针,解析传来的命令获得数据就可以了。

你可能感兴趣的:(QNX驱动程序开发)