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;
}
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;
}
相关文章推荐
- uio驱动编写 实例2 //增加了中断部分
- 实例:中断的下半部分之-软中断
- ARM 微处理器部分指令实例整理(持续增加...)
- 编写一个类,增加一个实例方法 打印字符串 用反射
- 编写一个类,增加一个实例方法用于打印一条字符串。
- 在系统中增加一个可唤醒中断--简单实例
- 在系统中增加一个可唤醒中断--简单实例
- Awk 实例,第 2 部分
- sed 实例,第 3 部分
- Awk 实例,第 3 部分
- 串口中断应用实例
- sed 实例,第 1 部分
- 如何利用C#编写在Windows右下角增加图标的程序?
- Awk 实例,第 1 部分
- sed 实例,第 1 部分
- [转]smarty实例教程 ---模板设计部分
- 程序安装,升级及卸载核心部分(java编写)
- Eclipse界面编写实例(1)--扩展TitleAreaDialog
- Eclipse界面编写实例(2)--理解布局2
- Bash 实例,第 3 部分