编写Linux用户空间驱动程序

设备驱动程序大概可分为两种:

内核驱动程序及用户空间驱动程序。

内核驱动程序

是内核空间实现的驱动程序,它使用内核资源,内核栈。它包括可加载的内核驱动模块。在这里我想主要说说用户空间驱动程序的编写。

用户空间驱动程序

就是指在用户空间实现的驱动程序。可以认为,它跟普通的用户程序没有什么两样,它使用用户进程空间和栈。这里说下,我不是讨论接到串口,并口上什么设备!

大家不要以为在用户空间写驱动程序不过瘾!其实,作为设备驱动程序,其主要做的事就是配置设备寄存器(一家之言)。所以也不用把驱动程序看得那么神秘。当然,有些设备是不合适在用户空间实现驱动的。个人认为,使用中断的设备不宜在用户空间驱动,除此外,都有办法在用户空间来驱动。

在用户空间实现驱动的一个好处就是,方便用GDB调试。

怎么写

上面说到,驱动程序主要做的事情就是配置设备寄存器。那么,只要在用户空间,我能获得到寄存器地址(或是映像地址)那就可以驱动这个设备了。

PCI设备为例,假设你的PCI设备主芯片的配置寄存器在PCI配置头的0x14位置:

首先:通过/proc文件系统的pci文件,及/proc/bus/pci目录下的文件,可以获取到你的设备PCI配置头的信息,当然,也可以读出0x14偏移的值。假设其值为0xE0080000;这个就是你的PCI设备主芯片的配置寄存器的物理地址。在有MMU的处理器里,直接使用这个地址是不允许的。我们都知道,在用户进程空间寻址一个物理地址,首先要把这个物理地址映射到进程空间内。

怎么映射呢?

我们知道,在Linux/dev目录下,有一个mem的设备。我们简单认为它就是管理0x00000000-0xFFFFFFFF(32位处理器)物理地址的一个设备(不单指物理内存,它的空间也含盖了PCI地址空间)。将PCI配置寄存器空间映射到进程空间的逻辑如下:

 

fd = open("/dev/mem",O_RDWR);

reg_addr = mmapNULL,0x100,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0xE0080000);

 

之后,你就可以使用reg_addr这个地址,在0x100大小空间范围内配置你的PCI设备了。

就这么完了吗

在用户空间实现的驱动程序,不用为设备建立设备文件。当然,在多个进程使用时,要使用IPC机制来实现设备临界区的保护等。如果你真的感觉写用户空间的设备驱动程序没什么水平,那你可以用它来调试好你的设备(也是就知道怎么设置寄存器)后,再花一点时间把它移到内核去,加上文件系统接口,使用内核同步机制进行同步,再实现初始化函数,就可以变成内核驱动了。

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