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"
#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");

 

转载于:https://my.oschina.net/hanshubo/blog/796838

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值