uio驱动编写 实例1
来源:互联网 发布:淘宝达人申请认证理由 编辑:程序博客网 时间:2024/05/18 17:26
AUTHOR: Joseph Yang (杨红刚) <eagle.rtlinux@gmail.com>
CONTENT: uio驱动编写 实例1
NOTE: linux-3.0
LAST MODIFIED:09-06-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)
===============================================================
怎么编写uio驱动详解
======================为了用最简单的例子说明问题,我们在我们uio驱动的内核部分只映射了一块1024字节的
逻辑内存。没有申请中断。
这样加载上我们的驱动后,将会在/sys/class/uio/uio0/maps/map0中看到
addr name offset size。他们分别是映射内存的起始地址, 映射内存的名字,起始地址的页内偏移,
映射内存 的大小。 在uio驱动的用户空间部分,我们将打开addr, size以便使用映射好的内存。
---------- simple.c -------------
/*** This is a simple demon of uio driver.* Last modified by 09-05-2011 Joseph Yang(Yang Honggang)<ganggexiongqi@gmail.com>** Compile: * Save this file name it simple.c* # echo "obj-m := simple.o" > Makefile* # make -Wall -C /lib/modules/`uname -r`/build M=`pwd` modules* Load the module:* #modprobe uio* #insmod simple.ko*/#include <linux/module.h>#include <linux/platform_device.h>#include <linux/uio_driver.h>#include <linux/slab.h> /* kmalloc, kfree */struct uio_info kpart_info = {.name = "kpart",.version = "0.1",.irq = UIO_IRQ_NONE,};static int drv_kpart_probe(struct device *dev);static int drv_kpart_remove(struct device *dev);static struct device_driver uio_dummy_driver = {.name = "kpart",.bus = &platform_bus_type,.probe = drv_kpart_probe,.remove = drv_kpart_remove,};static int drv_kpart_probe(struct device *dev){printk("drv_kpart_probe( %p)\n", dev);kpart_info.mem[0].addr = (unsigned long)kmalloc(1024,GFP_KERNEL);if(kpart_info.mem[0].addr == 0)return -ENOMEM;kpart_info.mem[0].memtype = UIO_MEM_LOGICAL;kpart_info.mem[0].size = 1024;if( uio_register_device(dev, &kpart_info))return -ENODEV;return 0;}static int drv_kpart_remove(struct device *dev){uio_unregister_device(&kpart_info);return 0;}static struct platform_device * uio_dummy_device;static int __init uio_kpart_init(void){uio_dummy_device = platform_device_register_simple("kpart", -1,NULL, 0);return driver_register(&uio_dummy_driver);}static void __exit uio_kpart_exit(void){platform_device_unregister(uio_dummy_device);driver_unregister(&uio_dummy_driver);}module_init(uio_kpart_init);module_exit(uio_kpart_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Benedikt Spranger");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驱动的用户空间部分。
#include <stdio.h>#include <fcntl.h>#include <stdlib.h>#include <unistd.h>#include <sys/mman.h>#include <errno.h>#define UIO_DEV "/dev/uio0"#define UIO_ADDR "/sys/class/uio/uio0/maps/map0/addr"#define UIO_SIZE "/sys/class/uio/uio0/maps/map0/size"static char uio_addr_buf[16], uio_size_buf[16];int main(void){ int uio_fd, addr_fd, size_fd; int uio_size; void* uio_addr, *access_address; uio_fd = open(UIO_DEV, /*O_RDONLY*/O_RDWR); addr_fd = open(UIO_ADDR, O_RDONLY); size_fd = open(UIO_SIZE, O_RDONLY); if( addr_fd < 0 || size_fd < 0 || uio_fd < 0) { fprintf(stderr, "mmap: %s\n", strerror(errno)); exit(-1); } read(addr_fd, uio_addr_buf, sizeof(uio_addr_buf)); read(size_fd, uio_size_buf, sizeof(uio_size_buf)); uio_addr = (void*)strtoul(uio_addr_buf, NULL, 0); uio_size = (int)strtol(uio_size_buf, NULL, 0); access_address = mmap(NULL, uio_size, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 0); if ( access_address == (void*) -1) { fprintf(stderr, "mmap: %s\n", strerror(errno)); exit(-1); } printf("The device address %p (lenth %d)\n" "can be accessed over\n" "logical address %p\n", uio_addr, uio_size, access_address); //读写操作/* access_address = (void*)mremap(access_address, getpagesize(), uio_size + getpagesize() + 11111, MAP_SHARED); if ( access_address == (void*) -1) { fprintf(stderr, "mremmap: %s\n", strerror(errno)); exit(-1); } printf(">>>AFTER REMAP:" "logical address %p\n", access_address);*/ return 0;}
-------------------------------------------------------
加载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
- uio驱动编写 实例1
- uio驱动编写 实例1
- (用户态驱动)uio驱动编写 实例1 UIO 子系统结构介绍
- uio驱动编写 实例2 //增加了中断部分
- uio驱动编写 实例2 //增加了中断部分
- Linux UIO 驱动模型
- DPDK-UIO 驱动认识
- UIO 用户空间设备驱动
- Linux 设备驱动之 UIO 机制(测试 UIO 机制)
- Linux 设备驱动之 UIO 机制(测试 UIO 机制)
- 用户态驱动--UIO机制的实现
- UIO-用户空间驱动的新发展
- UIO-用户空间驱动的新发展
- 用户态驱动--UIO机制的实现
- Linux 设备驱动之 UIO 用户态驱动优缺点分析
- Linux 设备驱动之 UIO 用户态驱动优缺点分析
- Android平台驱动模块编写实例
- xenomai 实时linux驱动编写实例
- HDOJ 畅通工程
- 开始学习QNX
- thinkphp 文件下载 文件下载php
- HDOJ 继续畅通工程
- Effective c++ 学习笔记——条款04:确定对象被使用前已先被初始化
- uio驱动编写 实例1
- Noip2003p4 麦森数
- 对QNX的初步了解
- HDOJ 还是畅通工程
- 聚类算法
- QNX的英文资料
- HDOJ Eddy's picture
- CSV processing in Ruby
- Ubuntu下安装LAMP及phpmyadmin