用户空间代码:
#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"
#define UIO_ADDR1 "/sys/class/uio/uio0/maps/map1/addr"
#define UIO_SIZE1 "/sys/class/uio/uio0/maps/map1/size"
#define LED_ON 1 //LED亮状态
#define LED_OFF 0 //LED灭状态
static char uio_addr_buf[16], uio_size_buf[16];
int main(int argc, char **argv)
{
int uio_fd, addr_fd, size_fd, addr_fd_1, size_fd_1;
int uio_size, uio_size_1;
void *uio_addr, *uio_addr_1, *access_address, *access_address_1;
volatile unsigned long virt, virt_1;
volatile unsigned long *GPBCON, *GPBDAT, *GPBUP, *RETVAL;
unsigned long pagesz;
int turn, index;
uio_fd = open(UIO_DEV,O_RDWR);
addr_fd = open(UIO_ADDR, O_RDONLY);
size_fd = open(UIO_SIZE, O_RDONLY);
addr_fd_1 = open(UIO_ADDR1, O_RDONLY);
size_fd_1 = open(UIO_SIZE1, O_RDONLY);
if(addr_fd < 0 || size_fd < 0 || uio_fd < 0 || addr_fd_1 < 0 || size_fd_1 < 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);
read(addr_fd_1, uio_addr_buf, sizeof(uio_addr_buf));
read(size_fd_1, uio_size_buf, sizeof(uio_size_buf));
uio_addr_1 = (void*)strtoul(uio_addr_buf, NULL, 0);
uio_size_1 = (int)strtol(uio_size_buf, NULL, 0);
access_address = mmap(NULL, uio_size, PROT_READ | PROT_WRITE,
MAP_SHARED, uio_fd, 0);
access_address_1 = mmap(NULL, uio_size_1, PROT_READ | PROT_WRITE,
MAP_SHARED, uio_fd, getpagesize());
if (access_address == (void*) -1 || access_address_1 == (void*) -1) {
fprintf(stderr, "mmap: %s\n", strerror(errno));
exit(-1);
}
printf("The device address %p (lenth %d)\ncan be accessed over\nlogical address %p\n\n", uio_addr, uio_size, access_address);
pagesz = getpagesize();
virt = (unsigned long)uio_addr;
virt = ((unsigned long)access_address + (virt & (pagesz - 1)));
virt_1 = (unsigned long)uio_addr_1;
virt_1 = ((unsigned long)access_address_1 + (virt_1 & (pagesz - 1)));
GPBCON = (unsigned long *)(virt + 0x00);
GPBDAT = (unsigned long *)(virt + 0x04);
GPBUP = (unsigned long *)(virt + 0x08);
RETVAL = (unsigned long *)virt_1;
int retval = (int)(*RETVAL);
printf("GPBCON %p \n"
"GPBDAT %p \n"
"GPBUP %p \n\n", GPBCON, GPBDAT, GPBUP);
printf("retval ==============> %d \n", retval);
// GPBCON
if(*GPBCON != 0x154FD)
*GPBCON = 0x154FD;
// GPBDAT close all leds
*GPBDAT = 0x1E0;
// open all leds
//*GPBDAT = 0x00;
// GPBUP
if(*GPBUP != 0x7FF)
*GPBUP = 0x7FF;
fd_set rd_fds, tmp_fds;
/***************************
while (1) {
// 清空文件描述符集合
FD_ZERO(&rd_fds);
FD_SET(uio_fd, &rd_fds);
tmp_fds = rd_fds;
// 以阻塞的方式等待 tmp_fds(此处为读取数据文件描述集合)中读取数据事件的发生
// 此方法会清除掉没有事件发生的相文件应描述符位
// ret 待处理事件总数
int ret = select(uio_fd+1, &tmp_fds, NULL, NULL, NULL);
if (ret > 0) {
// 检测读管道文件描述符是否存储在tmp_fds中
// 检测此文件描述符中是否有事件发生
if (FD_ISSET(uio_fd, &tmp_fds)) {
int c;
read(uio_fd, &c, sizeof(int));
retval = (int)(*RETVAL);
printf("current event count is: %d \n", c);
printf("current return value is: %d \n", retval);
}
}
if(retval == 10)
break;
}
**********************************/
close(uio_fd);
return 0;
}
内核空间代码:
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uio_driver.h>
#include <asm/io.h>
#include <linux/slab.h> /* kmalloc, kfree */
#include <linux/irq.h> /* IRQ_TYPE_EDGE_BOTH */
static irqreturn_t my_interrupt(int irq, void *dev_id)
{
struct uio_info *info = (struct uio_info *)dev_id;
unsigned long *ret_val_add = (unsigned long *)(info->mem[1].addr);
*ret_val_add = 10;
printk("----------------------------------------------------%d \n" ,(int)(*ret_val_add));
return IRQ_RETVAL(IRQ_HANDLED);
}
struct uio_info kpart_info = {
.name = "kpart",
.version = "0.1",
.irq = IRQ_EINT19,
.handler = my_interrupt,
.irq_flags = IRQ_TYPE_EDGE_RISING,
};
struct button_irq_desc {
int irq;
int num;
char *name;
};
static struct button_irq_desc button_irqs [] = {
{IRQ_EINT8 , 1, "KEY0"},
{IRQ_EINT11, 2, "KEY1"},
{IRQ_EINT13, 3, "KEY2"},
{IRQ_EINT14, 4, "KEY3"},
{IRQ_EINT15, 5, "KEY4"},
};
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 irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
unsigned long *ret_val_add = (unsigned long *)(kpart_info.mem[1].addr);
*ret_val_add = button_irqs->num;
printk("%s is being pressed ..... \n", button_irqs->name);
uio_event_notify(&kpart_info);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int drv_kpart_probe(struct device *dev)
{
printk("drv_kpart_probe(%p)\n", dev);
unsigned long phys = 0x56000010; // 0x56000010 = GPBCON
kpart_info.mem[0].addr = phys;
kpart_info.mem[0].memtype = UIO_MEM_PHYS;
kpart_info.mem[0].size = 12;
kpart_info.mem[1].addr = (unsigned long)kmalloc(4,GFP_KERNEL);;
if(kpart_info.mem[1].addr == 0)
return -ENOMEM;
kpart_info.mem[1].memtype = UIO_MEM_LOGICAL;
kpart_info.mem[1].size = 4;
unsigned long *ret_val_add = (unsigned long *)(kpart_info.mem[1].addr);
*ret_val_add = 999;
if(uio_register_device(dev, &kpart_info)){
kfree((void *)kpart_info.mem[1].addr);
return -ENODEV;
}
int i = 0 ,err = 0;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING,
button_irqs[i].name, (void *)&button_irqs[i]);
if (err)
break;
}
return 0;
}
static int drv_kpart_remove(struct device *dev)
{
kfree((void *)kpart_info.mem[1].addr);
uio_unregister_device(&kpart_info);
return 0;
}
static struct platform_device * uio_dummy_device;
static int __init uio_kpart_init(void)
{
printk("Hello, Mini2440 module is installed !\n");
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");