写一个Linux UIO的示例代码
以下是一个Linux UIO的示例代码,包含内核模块和用户空间程序:
内核模块代码(my_uio_module.c
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <linux/module.h> #include <linux/uio_driver.h> #include <linux/ioport.h> #include <linux/io.h>
#define MEM_BASE 0x1000000 #define MEM_SIZE 0x1000
static struct uio_info my_uio_info = { .name = "my_uio_device", .version = "0.1", .irq = UIO_IRQ_NONE, };
static int __init my_uio_init(void) { if (!request_mem_region(MEM_BASE, MEM_SIZE, "my_uio")) { pr_err("Failed to request memory region\n"); return -EBUSY; }
my_uio_info.mem[0].name = "my_uio_region"; my_uio_info.mem[0].addr = MEM_BASE; my_uio_info.mem[0].size = MEM_SIZE; my_uio_info.mem[0].memtype = UIO_MEM_PHYS;
if (uio_register_device(NULL, &my_uio_info)) { pr_err("Failed to register UIO device\n"); release_mem_region(MEM_BASE, MEM_SIZE); return -ENODEV; }
pr_info("UIO device registered successfully\n"); return 0; }
static void __exit my_uio_exit(void) { uio_unregister_device(&my_uio_info); release_mem_region(MEM_BASE, MEM_SIZE); pr_info("UIO device unregistered\n"); }
module_init(my_uio_init); module_exit(my_uio_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name");
|
用户空间程序(uio_user.c
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <stdio.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h>
#define UIO_DEV "/dev/uio0" #define MAP_SIZE 0x1000
int main() { int uio_fd = open(UIO_DEV, O_RDWR); if (uio_fd < 0) { perror("Failed to open UIO device"); return 1; }
void *addr = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 0); if (addr == MAP_FAILED) { perror("mmap failed"); close(uio_fd); return 1; }
printf("Memory mapped at address: %p\n", addr);
volatile unsigned int *regs = (volatile unsigned int *)addr; printf("Read initial value: 0x%x\n", regs[0]); regs[0] = 0x12345678; printf("Wrote 0x12345678, read back: 0x%x\n", regs[0]);
munmap(addr, MAP_SIZE); close(uio_fd); return 0; }
|
编译与运行步骤
编译内核模块:
1 2
| obj-m += my_uio_module.o make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
|
插入内核模块(需要root权限):
1 2 3 4 5
| sudo insmod my_uio_module.o
dmesg | tail
ls /dev/uio*
|
编译用户空间程序:
1
| gcc uio_user.c -o uio_user
|
运行用户程序(需要root权限):
注意事项
物理地址调整:
示例中的MEM_BASE
(0x1000000
)是假设值,实际使用时需根据硬件手册调整。错误地址可能导致系统崩溃。
内存冲突:
使用request_mem_region
前,需确保目标地址未被其他驱动占用。可通过/proc/iomem
查看已注册的内存区域。
用户权限:
确保用户有权限访问/dev/uio*
设备节点(通常需要root权限)。
中断处理:
如需处理中断,需在my_uio_info
中设置.irq
和.handler
,并在用户空间通过read
等待中断。
动态内存分配:
更安全的方式是使用dma_alloc_coherent
动态分配物理内存,避免硬编码地址。
此示例演示了UIO的基本用法,实际开发中需结合具体硬件调整参数。