您的位置:首页 > 产品设计 > UI/UE

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

2017-07-07 15:38 591 查看
http://blog.csdn.net/ganggexiongqi/article/details/6794215

AUTHOR: Joseph Yang (杨红刚) <ganggexiongqi@gmail.com>

CONTENT: uio驱动编写 实例2

NOTE:
Linux-3.0

LAST MODIFIED:09-20-2011

-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)

===============================================================


[b]第一个例子: uio驱动编写
实例
1 [/b]

原理简述:

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

每当中断发生时,uio_event_notify 将被调用,用来对设备的中断事件计数器()增一,并通知各读进程,

有数据可读。所以,我们通过内核定时器,来周期性的产生中断,而在定时器的处理程序中

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

如下,是内核部分 simple1.c

[cpp]
view plain
copy
print?

/** 
*  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“提示。

[cpp]
view plain
copy
print?

#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;  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: