免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1344 | 回复: 0
打印 上一主题 下一主题

UIO-用户空间驱动的新发展 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-23 11:21 |只看该作者 |倒序浏览
               
                尚观科技原创文章

并非所有的设备驱动程序都要在内核编写,有些情况下,在用户空间编写驱动程序能够更好地解决遇到的问题。是否应鼓励人们开发用户态的驱动一直是一个有争议的话题,反对者认为,用户态驱动常常是不开放源代码的,这和linux的开源精神背道而驰,另外,用户态驱动的性能也常常受到质疑;而支持者认为,在内核中引入对用户态驱动的支持是现实的需要,这种方式能更好地应对复杂的或者是比较特殊的硬件,尤其是在嵌入式领域中,更值得推广。
本文无意于讨论这两种观点孰优孰劣,只是帮助大家了解一下这种驱动编写方式的优点和缺点,然后再来看看linux最新版内核中如何支持这一概念。
用户空间驱动程序的优点:
*可以和整个C库链接
驱动程序不用借助外部程序(对于复杂的外设,常常需要和驱动一起发行用户提供策略的应用程序)就可以完成许多非常规的任务。
*在驱动中可以使用浮点数
在某些特殊的硬件中,可能需要使用浮点数,而linux内核并不提供浮点数的支持。如果能在用户态实现驱动,就可以轻松解决这一问题
*驱动的问题不会导致整个系统挂起
有过驱动开发经验的人一定会对调试深有感触,一些错误常常导致整个系统挂起。而用户态的驱动在调试上就要方便很多。
*用户内存可以换出
*设计良好的驱动仍然可以支持对设备的并发访问
*可以给出封闭源码的驱动程序,不必采用GPL
*更为灵活
用户空间驱动的最常见例子是X-server,很多USB设备的驱动也可以放到用户空间。目前,很多人尝试在用户态为PCI设备提供驱动
用户空间驱动的缺点:
*中断在用户空间不可用
最新的UIO接口已经解决了这一问题
*响应时间较慢
*只能支持字符设备,无法支持块设备和网络设备
*可靠性较低,很多驱动都是闭源的,我们没法通过阅读代码解决问题
*有些硬件厂商只提供和某些linux开发版(常常早就过时了)相匹配的用户空间驱动
尽管对用户空间驱动存在争议,但内核还是选择对其进行支持。最新的接口称为UIO(以前的内核也有,但新版本做了很多修改),是在2.6.22版本的一个补丁中出现的,并且在2.6.23中正式合并到了内核的代码树中。和以前相比,该接口有了一些改变。
和以前的版本一样,UIO并没有完全取消内核空间代码。在内核中有一个很小的模块用于建立连接到PCI总线的设备(device)或者接口(interface),并提供中断处理程序。这一点(中断处理程序)很重要,尽管有更多的事情可以在用户空间完成,但还是需要有一个内核中的中断处理程序来通知设备停止发送中断。
该内核模块需要包括。如果他是一个PCI设备的驱动,需要按照统一设备模型的要求注册PCI驱动。当需要连接设备的时候(可能在PCI的probe()函数中),该驱动需要填写一个uio_info结构体:
struct uio_info {
  char *name;
  char  *version;
  struct uio_mem  mem[MAX_UIO_MAPS];
  long irq;
  unsigned long irq_flags;
  void  *priv;
  irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
  int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
  int (*open)(struct uio_info *info, struct inode *inode);
  int (*release)(struct uio_info *info, struct inode *inode);
/* Internal stuff omitted */
    };
上面结构体中,name是设备的名字;version是驱动的版本号(将显示在sysfs中);irp是设备所使用的IRQ号;irq_flags是中断调用标志,将传递给request_irq();handler()是中断处理程序,除了负责应答硬件中断,一般不再做别的工作;mmap()/open()/release()由file_operations中的对应成员调用
结构体中的mem数组用于描述任何可以被映射到用户空间的内存区域。uio_mem结构体的主要成员如下:
struct uio_mem {
  unsigned long addr;
  unsigned long size;
  int memtype;
  void __iomem *internal_addr;
  /* ... */
};
对于每个可以映射的区域,addr是该区域的地址(物理地址);size是该区域的大小;internal_addr是由ioremap()返回的该区域地址(虚拟地址)。
memtype用于描述该区域的属性,包括:
*UIO_MEM_PHYS
表明addr是一个物理地址,通常用于I/O内存区
*UIO_MEM_LOGICAL
该区域处于内核的逻辑地址空间,例如那些通过kmalloc()获得的空间
*UIO_MEM_VIRTUAL
该区域处于内核的虚拟地址空间,这些区域由vmalloc_user()使用
一旦uio_info结构体填写完毕,驱动会将其传给如下函数:
  int uio_register_device(struct device *parent, struct uio_info *info);
parent指针告诉内核该UIO设备是和哪个"real"的设备相关联,如果驱动是针对PCI设备,则parent指向pci_dev->dev。
内核空间的UIO基本上就这些API了,当设备被拔除,驱动需要调用:
  void uio_unregister_device(struct uio_info *info);
最后一个和通知(note)相关的函数是:
  void uio_event_notify(struct uio_info *info);
该函数的目的是通知UIO核心,发生了一个事件(典型情况是一个中断)。当真正的中断发生时,stub驱动不必调用uio_event_notify(),但这个函数可以在其他的情况下模拟中断。
在用户空间,第一个UIO处理的设备将显示为/dev/uio0(假设udev已启动)。用户空间的驱动将会打开该设备。对该设备的读操作返回一个int值,该值保存了事件计数(发生了多少次中断)。如果从上次读设备以来还没有产生中断,则读操作会阻塞直到一个中断发生(当然,支持非阻塞的操作)。文件描述符可以被发送给poll()。
在内核空间驱动中所描述的内存区域可以通过mmap()调用映射到用户空间中。传递给mmap()的参数有一些奇怪,内核的第N个区域,其offset参数的值将是当前页大小的第N倍。也就是说,如果当前系统的页大小是4096个字节,映射第一个内存区的offset值为0,而第二个内存区就是4096,第三个就是8192,以此类推。
当然了,使用UIO会受到一些限制。首先,UIO驱动是字符型的驱动,目前没有提供创建用户空间块设备或网络设备驱动的接口。另外,在用户空间也不可能建立DMA操作。但是,对于那些只包括I/O内存访问以及简单的中断处理程序的驱动,UIO接口完全可以胜任。
在UIO接口的patch中,除了UIO核心程序,还有一个示例程序。根据作者ThomasGleixner的实验,如果采用完全装入内核的方式实现驱动,则需要实现68个不同的ioctl()命令,整个驱动的长度超过5000行,对应的用户空间代码超过3000行;而如果采用UIO模式的驱动,内核代码只有156行,而用户空间代码也下降到3000行以内。
不过,linux内核的重要维护者Andrew Morton也对UIO的使用表达了一些保留意见:
“我对UIO的整个想法有一些不确定,我感觉我们应该更鼓励人们在GPL许可证下开发内核驱动,而不是鼓励他们开发不公开源代码的用户空间驱动。这些驱动往往更慢,缺乏可靠性,并且无法跨平台使用。”
在2.6.23中,和UIO相关的主要有以下文件:
(1)/drivers/uio/uio.c
uio子系统的核心文件
(2)/drivers/uio/uio_cif.c
Hilscher CIF DeviceNet以及Profibus card的驱动。
这是一个示例驱动,说明了如何实现用户空间驱动的内核部分。驱动在用户空间的部分以及用于测试的应用程序可以从
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93926/showart_1874141.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP