首页
登录 | 注册

uio驱动编写 实例1

怎么编写uio驱动详解======================
为了用最简单的例子说明问题,我们在我们uio驱动的内核部分只映射了一块1024字节的逻辑内存。没有申请中断。
这样加载上我们的驱动后,将会在/sys/class/uio/uio0/maps/map0中看到
 addr name offset size。他们分别是映射内存的起始地址, 映射内存的名字,起始地址的页内偏移,
 映射内存 的大小。 在uio驱动的用户空间部分,我们将打开addr, size以便使用映射好的内存。
   ---------- simple.c -------------
[plain] view plaincopy
  1. /**  
  2. *  This is a simple demon of uio driver.  
  3. *  Last modified by   
  4.         09-05-2011   Joseph Yang(Yang Honggang)  
  5. *  
  6. * Compile:    
  7. *   Save this file name it simple.c  
  8. *   # echo "obj-m := simple.o" > Makefile  
  9. *   # make -Wall -C /lib/modules/`uname -r`/build M=`pwd` modules  
  10. * Load the module:  
  11. *   #modprobe uio  
  12. *   #insmod simple.ko  
  13. */  
  14.   
  15. #include   
  16. #include   
  17. #include   
  18. #include  /* kmalloc, kfree */  
  19. struct uio_info kpart_info = {  
  20.         .name = "kpart",  
  21.         .version = "0.1",  
  22.         .irq = UIO_IRQ_NONE,  
  23. };  
  24.   
  25. static int drv_kpart_probe(struct device *dev);  
  26. static int drv_kpart_remove(struct device *dev);  
  27. static struct device_driver uio_dummy_driver = {  
  28.         .name = "kpart",  
  29.         .bus = &platform_bus_type,  
  30.         .probe = drv_kpart_probe,  
  31.         .remove = drv_kpart_remove,  
  32. };  
  33.   
  34. static int drv_kpart_probe(struct device *dev)  
  35. {  
  36.         printk("drv_kpart_probe( %p)\n", dev);  
  37.         kpart_info.mem[0].addr = (unsigned long)kmalloc(1024,GFP_KERNEL);  
  38.   
  39.         if(kpart_info.mem[0].addr == 0)  
  40.                 return -ENOMEM;  
  41.         kpart_info.mem[0].memtype = UIO_MEM_LOGICAL;  
  42.         kpart_info.mem[0].size = 1024;  
  43.   
  44.         if( uio_register_device(dev, &kpart_info))  
  45.                 return -ENODEV;  
  46.         return 0;  
  47. }  
  48.   
  49. static int drv_kpart_remove(struct device *dev)  
  50. {  
  51.     uio_unregister_device(&kpart_info);  
  52.   
  53.     return 0;  
  54. }  
  55.   
  56. static struct platform_device * uio_dummy_device;  
  57.   
  58. static int __init uio_kpart_init(void)  
  59. {  
  60.         uio_dummy_device = platform_device_register_simple("kpart", -1,  
  61.                         NULL, 0);  
  62.   
  63.         return driver_register(&uio_dummy_driver);  
  64. }  
  65.   
  66. static void __exit uio_kpart_exit(void)  
  67. {  
  68.         platform_device_unregister(uio_dummy_device);  
  69.         driver_unregister(&uio_dummy_driver);  
  70. }  
  71.   
  72. module_init(uio_kpart_init);  
  73. module_exit(uio_kpart_exit);  
  74.   
  75. MODULE_LICENSE("GPL");  
  76. MODULE_AUTHOR("Benedikt Spranger");  
  77. MODULE_DESCRIPTION("UIO dummy driver");  



 
 这个文件是我们uio驱动的内核部分。下面做下简要解释。
 一个uio驱动的注册过程简单点说有两个步骤:
   1. 初始化设备相关的 uio_info结构。
   2. 调用uio_register_device 分配并注册一个uio设备。
    
 uio驱动必须要提供并初始化的结构 uio_info, 它包含了您要注册的uio_device的重要特性。
 struct uio_info kpart_info = { 
        .name = "kpart",
        .version = "0.1",
        .irq = UIO_IRQ_NONE,//我们没有使用中断,所以初始为UIO_IRQ_NONE
};
当你没有实际的硬件设备,但是,还想产生中断的话,就可以把irq设置为UIO_IRQ_CUSTOM,
并初始化uio_info的handler字段,那么在产生中断时,你注册的中断处理函数将会被调用。
如果有实际的硬件设备,那么irq应该是您的硬件设备实际使用的中断号。

然后,在drv_kpart_probe函数(先不要管为什么在这个函数中进行这些操作)中,完成了
kpart_info.mem[0].addr, kpart_info.mem[0].memtype,
  kpart_info.mem[0].size字段的初始化。这是内存映射必须要设置的。
  其中,  kpart_info.mem[0].memtype可以是 UIO_MEM_PHYS,那么被映射到用户空间的是你
  设备的物理内存。也可以是UIO_MEM_LOGICAL,那么被映射到用户空间的是逻辑内存
  (比如使用 kmalloc分配的内存)。还可以是UIO_MEM_VIRTUAL,那么被映射到用户空间的是
  虚拟内存(比如用vmalloc分配的内存).这样就完成了uio_info结构的初始化。
  下一步,还是在drv_kpart_probe中,调用uio_register_device完成了uio设备向uio core的注册。
  
  下面讲一下,为什么我们的设备跟platform之类的东东扯上了关系?
  我们的驱动不存在真正的物理设备与之对应。而 Platform  驱动“自动探测“,这个特性是
  我们在没有实际硬件的情况下需要的。
  
  先从uio_kpart_init开始分析。
  platform_device_register_simple的调用创建了一个简单的platform设备。
  注册device_driver类型的uio_dummy_driver变量到bus。
  这里需要注意一个问题,就是 device_driver结构中的name为“kpart", 我们创建的platform设备
  名称也是"kpart"。而且先创建platform设备,后注册驱动。这是因为,创建好设备后,注册驱动时,
  驱动依靠name来匹配设备。
  之后 drv_kpart_probe就完成了uio_info的初始化和uio设备的注册。

--------------- user_part.c ----------------------
这个是uio驱动的用户空间部分。
[plain] view plaincopy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7.   
  8. #define UIO_DEV "/dev/uio0"  
  9. #define UIO_ADDR "/sys/class/uio/uio0/maps/map0/addr"  
  10. #define UIO_SIZE "/sys/class/uio/uio0/maps/map0/size"  
  11.   
  12. static char uio_addr_buf[16], uio_size_buf[16];  
  13.   
  14. int main(void)  
  15. {  
  16.   int uio_fd, addr_fd, size_fd;  
  17.   int uio_size;  
  18.   void* uio_addr, *access_address;  
  19.    
  20.   uio_fd = open(UIO_DEV, /*O_RDONLY*/O_RDWR);  
  21.   addr_fd = open(UIO_ADDR, O_RDONLY);  
  22.   size_fd = open(UIO_SIZE, O_RDONLY);  
  23.   if( addr_fd < 0 || size_fd < 0 || uio_fd < 0) {  
  24.        fprintf(stderr, "mmap: %s\n", strerror(errno));  
  25.        exit(-1);  
  26.   }  
  27.   read(addr_fd, uio_addr_buf, sizeof(uio_addr_buf));  
  28.   read(size_fd, uio_size_buf, sizeof(uio_size_buf));  
  29.   uio_addr = (void*)strtoul(uio_addr_buf, NULL, 0);  
  30.   uio_size = (int)strtol(uio_size_buf, NULL, 0);  
  31.   
  32.   access_address = mmap(NULL, uio_size, PROT_READ | PROT_WRITE,  
  33.                      MAP_SHARED, uio_fd, 0);  
  34.   if ( access_address == (void*) -1) {  
  35.       fprintf(stderr, "mmap: %s\n", strerror(errno));  
  36.       exit(-1);  
  37.   }  
  38.   printf("The device address %p (lenth %d)\n"  
  39.          "can be accessed over\n"  
  40.          "logical address %p\n", uio_addr, uio_size, access_address);  
  41.  //读写操作  
  42. /*  
  43.  access_address = (void*)mremap(access_address, getpagesize(), uio_size + getpagesize() + 11111, MAP_SHARED);  
  44.   
  45.   if ( access_address == (void*) -1) {  
  46.       fprintf(stderr, "mremmap: %s\n", strerror(errno));  
  47.       exit(-1);  
  48.   }   
  49.   printf(">>>AFTER REMAP:"  
  50.          "logical address %p\n", access_address);  
  51. */  
  52.   return 0;  
  53. }  





-------------------------------------------------------
加载uio模块
#modprobe uio

加载simple.ko
#insmod simple.ko
# ls /dev/ | grep uio0
   uio0
# ls /sys/class/uio/uio0 
   ...
如果相应的文件都存在,那么加载用户空间驱动部分。
#./user_part
The device address 0xee244400 (lenth 1024)
can be accessed over
logical address 0xb78d4000
======================================================================

可能有用的链接:

UIO 子系统结构介绍 :http://blog.csdn.net/ganggexiongqi/article/details/6748103


uio.c 分析:http://blog.csdn.net/ganggexiongqi/article/details/6737647


platform_device与platform_driver: http://blog.csdn.net/ganggexiongqi/article/details/6750097


相关文章

  • 1.安装C++版驱动之前,先安装C版的驱动,过程如下: 我的安装平台:ubuntu14.04     64位,其他平台可参考:http://api.mongodb.org/c/current/installing.html#installi ...
  • dpdk net_virtio前端驱动实现分析
    dpdk net_virtio前端驱动实现分析 --lvyilong316 和kernel中的vhost-net对应,net_virtio是dpdk中实现的网络virtio的前端.相对于kernel dpdk的net_virtio实现要简单 ...
  • GSC3280的ADC子系统驱动模型(一)
    一.芯片和驱动架构总体介绍 1.1.芯片介绍         本文使用的芯片为GSC3280,根据芯片手册的介绍,ADC 与触摸屏控制器通过 SPI 接口挂在GSC3280的SPI0总 线上,支持4线电阻式触摸屏或当ADC输入使用.GSC3 ...
  • GSC3280的ADC子系统驱动模型(二)
    一.ADC子系统--创建设备文件         本部分包括创建设备节点和在应用层通过操作/dev目录下的设备节点来控制设备. 1.1.创建设备节点         在第一篇文章中的ADC子系统核心的注册函数中,调用了adc_dev_ini ...
  • 以下的文章主要是向大家描述的是.net连接MySQL数据库的实际操作方法与其实例的演示.net连接MySQL数据库的实际操作方案我们主要是将其分成三部分,以下的文章就有其详细内容的描述. http://dev.csdn.net/develo ...
  • 在ffmpeg的源代码中,有新旧版本的编解码接口调用示例,但是demux.mux然后decode.encode的联动起来的接口调用实例并没有,在使用旧版本的编解码接口在编译时会报接口弃用告警信息,所以最好尽快把原有的调用方式切换到新的编解码 ...

2020 unjeep.com webmaster#unjeep.com
12 q. 0.013 s.
京ICP备10005923号