uio驱动编写 实例1

2023-05-16

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




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

uio驱动编写 实例1 的相关文章

  • 明白了一句话:“加速度信号对高频敏感,位移信号对低频敏感”

    以前听别人说这些 xff0c 然后记住了 但是一直不大理解 最近在调试IEPE传感器 xff0c 正好要算位移 速度 加速度 对于相同的速度 xff0c 频率越高 xff0c 加速度值就越大 因为从公式就能看出来 xff0c 对于固定频率的
  • ubuntu 16.04使用IntelRealSense D435i调用realsense ROS包时,报symbol lookup error和undefined symbol错误的解决办法

    在ubuntu 16 04使用IntelRealSense D435i调用realsense ROS包时 xff0c 运行 roscore roslaunch realsense2 camera rs rgbd launch 出现错误 xf
  • Android浪潮

    Google的Android手机就要席卷世界了 xff01 IT技术的发展常常太出人意料 xff0c 我也想不太清楚Google的Android平台究竟吸引人在哪里 xff0c 但我相信Android会很快改变手机平台的格局 新的形势会出人
  • 卡尔曼滤波相关介绍及优缺点

    1 卡尔曼滤波算法为什么会叫滤波算法 xff1f 以一维卡尔曼滤波为例 xff0c 如果我们单纯的相信测量的信号 xff0c 那么这个信号是包含噪声的 xff0c 是很毛糙的 xff0c 但是当我们运行卡尔曼滤波算法去做估计 xff0c 我
  • STM32单片机(五)-寄存器地址理解和控制LED闪烁

    芯片 xff1a stm32f103zet6 1 存储单元一般应具有存储数据和读写数据的功能 一般以8位二进制作为一个存储单元 也就是一个字节 每个单元有一个地址 是一个整数编码 可以表示为二进制整数 2 stm32是32位单片机 xff0
  • 跨平台构建 Docker 镜像新姿势,x86、arm 一把梭

    点击 34 阅读原文 34 可以获得更好的阅读体验 在工作和生活中 xff0c 我们可能经常需要将某个程序跑在不同的 CPU 架构上 xff0c 比如让某些不可描述的软件运行在树莓派或嵌入式路由器设备上 特别是 Docker 席卷全球之后
  • 正点原子STM32F4笔记

    使用寄存器操作 xff0c 不错的博客 xff1a https blog csdn net w471176877 article category 1230060 https blog csdn net w471176877 article
  • JAVA中this用法小结

    我知道很多朋友都和我一样 xff1a 在 JAVA 程序中似乎经常见到 this xff0c 自己也偶尔用到它 xff0c 但是到底 this 该怎么用 xff0c 却心中无数 xff01 很多人一提起它 xff0c 就说 当前对象 xff
  • Linux Platform总线+SPI总线分析

    2015 07 1 11 20 本文以MPC8308 powerpc架构 xff0c HX软件包为依据 xff0c 详细内容可参考源码 CPU e300c3MPC8308 400MHz BOARD Freescale MPC8308ERDB
  • ubuntu下SD卡分区与挂载

    本来只是想借SD卡来做一个OK6410的升级 但笔记本上只装了ubuntu xff0c 一开始是可以识别sd卡的 xff0c 但按照网上的教程不小心将 dev sdb1删除了 导致ubuntu不能识别sd卡了 记录一下解决过程 1 sd的设
  • 信号量与互斥锁的一些理解

    一直对信号量和互斥锁只有一个模糊的认识 xff0c 今天特别学习了 xff0c 总结一下 一 从作用上来讲 互斥锁是用在多线程多任务互斥的 信号量用于线程的同步 二 从原理上讲 线程互斥锁 pthread mutex t 的实现原理 xff
  • springboot2.x +kafka使用和源码分析九(KafkaListenerEndpointRegistry暂停启动容器)

    我们在运行中如果需要暂停启动容器时可以通过此类KafkaListenerEndpointRegistry来处理 KafkaListenerEndpointRegistry源码 只解释了核心代码 public class KafkaListe

随机推荐