uio驱动编写 实例2 //增加了中断部分

AUTHOR: Joseph Yang (杨红刚) <ganggexiongqi@gmail.com>
CONTENT: uio驱动编写 实例2
NOTE: linux-3.0
LAST MODIFIED:09-20-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)
===============================================================

第一个例子: uio驱动编写 实例


原理简述:

在第一个例子的基础上,增加了中断部分。但是,我们没有实际产生中断的硬件。但是我们可以”模拟“硬件中断。

每当中断发生时,uio_event_notify 将被调用,用来对设备的中断事件计数器()增一,并通知各读进程,
有数据可读。所以,我们通过内核定时器,来周期性的产生中断,而在定时器的处理程序中

调用uio_event_notify,从而产生的效果和有硬件是相同。


如下,是内核部分 simple1.c

/**
*  This is a simple demon of uio driver.
*  Last modified by 
        09-20-2011   Joseph Yang(Yang Honggang)<ganggexiongqi@gmail.com>
*
* Compile:  
*   Save this file name it simple.c
*   # echo "obj-m := simpleX.o" > Makefile
*   # make -Wall -C /lib/modules/`uname -r`/build M=`pwd` modules
* Load the module:
*   #modprobe uio
*   #insmod simpleX.ko
*/

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uio_driver.h>
#include <linux/slab.h> /* kmalloc, kfree */
#include <linux/device.h> /* class_create */
#include <linux/kobject.h> /* kobject_uevent */
#define FREQ HZ	

static long freq = FREQ;
static long my_event_count = 0;

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 struct timer_list poll_timer;// generate interruption 

static void drv_kpart_timer(unsigned long data)
{
		struct uio_info *info = (struct uio_info *)data;
		unsigned long *addr = (unsigned long *)info->mem[0].addr;
         unsigned long swap = 0;
 
		if (my_event_count == 0) {
				printk(KERN_EMERG"first timer interrupt \n");
				*addr = my_event_count;
		} else if (my_event_count == 10){
				printk(KERN_EMERG"timer interrupt happened 10 times\n"
								"it works well\n");
		}
		swap = *addr;
        if ( swap != my_event_count){
				printk(KERN_EMERG"counter reset\n");
				my_event_count = swap;
		} else {
		       my_event_count++;
			   *addr = my_event_count;
//			   printk(KERN_EMERG"update counter \n");
		}
//		*addr = my_event_count;
		uio_event_notify(&kpart_info); // gernerate a interrupt here
		mod_timer(&poll_timer, jiffies + freq); // reset the timer
}

static int drv_kpart_probe(struct device *dev)
{

		printk(KERN_EMERG"----->  /// 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;
		// for the timer interruption
        kpart_info.irq_flags = UIO_IRQ_CUSTOM; 

		if( uio_register_device(dev, &kpart_info)){
				kfree((void *)kpart_info.mem[0].addr);
				return -ENODEV;
		}
        //initiate and add the timer
		init_timer(&poll_timer);
		poll_timer.data = (unsigned long)&kpart_info;
		poll_timer.function = drv_kpart_timer;
		mod_timer(&poll_timer, jiffies + freq);//set timer

        return 0;
}

static int drv_kpart_remove(struct device *dev)
{
	uio_unregister_device(&kpart_info);
    
	//delet the timer
	del_timer_sync(&poll_timer);

	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);
		printk("&platform_device->dev = (%p)\n", &uio_dummy_device->dev);
		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");

这是用户空间的测试部分。

我们通过mmap返回的地址addr跟驱动的内核部分进行交互。在用户空间写入addr的值0,可以重新设置驱动内核部分的

内部变量my_event_count。从而驱动程序会打印出”update counter“提示。

#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, "open: %s\n", strerror(errno));
       exit(-1);
  }
  read(addr_fd, uio_addr_buf, sizeof(uio_addr_buf));
  close(addr_fd);
  read(size_fd, uio_size_buf, sizeof(uio_size_buf));
  close(size_fd);
  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);

  printf("*access_address = %u\n",*((unsigned long*) access_address));
  
  unsigned long * addr = (unsigned long*) access_address;

  printf("1: read addr:%u\n", *addr);
  printf("1: write 0 to access_address\n");
 //读写操作
  *addr = 0;
//  sleep(10);
//  printf("2: read addr:%u\n", *addr);
 // read out the timer interuption times  
/*  unsigned long counter = 0;
  int ret;
  while ((ret = read(uio_fd, &counter, sizeof(counter)))
				  == sizeof(counter)) {
		  printf("Interrupt number is %d\n",
						  counter);
  }
  
  if(ret < 0) 
		  fprintf(stderr, "read error: %s\n", strerror(errno));
  printf("exit: counter is %d\n", counter);
*/
  munmap(access_address, uio_size);
  close(uio_fd);
  return 0;
}


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于PetaLinux开发UIO驱动,我可以给你一些基本的指导。 首先,UIO是一种通用的用户空间I/O框架,它允许用户空间的应用程序访问设备驱动程序。在PetaLinux中,你可以使用UIO驱动程序来访问PL中的IP核。下面是一些基本的步骤: 1.首先,在PetaLinux中启用UIO支持。你可以使用petalinux-config命令来打开配置菜单,选择Kernel菜单,然后选择Device Drivers -> Userspace I/O driver support -> Userspace I/O platform driver with generic IRQ handling支持。 2.然后,编写你的UIO驱动程序。你需要创建一个新的内核模块,实现UIO驱动程序的基本功能。你需要实现的主要函数是probe和remove,它们分别在设备被识别和移除时调用。在probe函数中,你需要初始化设备并注册UIO设备,然后将设备映射到用户空间。在remove函数中,你需要取消设备的映射和UIO设备的注册。 3.编译并加载你的UIO驱动程序。在PetaLinux中,你可以使用petalinux-build命令来编译内核模块,并使用petalinux-module命令将其加载到系统中。 4.在用户空间中使用UIO设备。一旦你的UIO驱动程序加载到系统中,你就可以在用户空间中使用它了。你需要使用mmap函数将UIO设备映射到用户空间,并使用read和write函数访问设备。 希望这些基本的指导对你有所帮助。如果你需要更详细的指导,可以参考PetaLinux文档或者一些UIO驱动程序的示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值