开辟sys节点用户层直接操作物理地址(比/dev/mem方便)
在调试驱动程序时, 经常要设置主控器寄存器参数或者运行时读取寄存器值debug问题, 每次修改驱动读取寄存器值都要编译一次驱动再insmod, 十分不方便, 哪怕驱动提供一个节点
如dev/mem给应用程序读取, 还要编写应用程序open(), mmap(), read(), write() 听着都头大, 我在/sys开辟vedic目录, 里面放着各种方便debug的节点, 其中就有个可以直接操作物理地址的节点“mem”,
在用户空间直接echo操作物理地址, 包括寄存器和内存地址, 非常方便:
/* 读取0x87800000 物理地址值 */ / # echo R 0x87800000 0x4 > /sys/vedic/mem [0x87800000] = 0x12341234 /* 写0x87800000 物理地址 */ / # echo w 0x87800000 0x55555555 > /sys/vedic/mem [0x87800000] = 0x55555555 错误会提示要求格式: / # echo R 0x87800000 > /sys/vedic/mem Usage: echo [R - Read/W - write] [Physical Address] [Value(Write)/Count(Read)] > /sys/vedic/mem Eg: echo R 0x8008000 0x10 > /sys/vedic/mem echo w 0x8008000 0x12345678 > /sys/vedic/mem
具体代码如下:
#include <linux/init.h> #include <linux/module.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/io.h> #include <linux/sysfs.h> #include <linux/delay.h> struct kobject *vedic_kobj = NULL; static ssize_t mem_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { unsigned int addr, val, count=0, loop; void __iomem *vaddr; char rw; if(sscanf(buf, "%c %x %x", &rw, &addr, &val) == 3) { vaddr = ioremap(addr, PAGE_SIZE); if(rw == 'W' || rw == 'w') { writel(val, vaddr); count = 4; } else if(rw == 'R' || rw == 'r') { count = (val+3) & ~3; } count = count > PAGE_SIZE ? PAGE_SIZE : count; printk("\n"); for(loop=0; loop<count; loop+=4) { val = readl(vaddr + loop); printk("[0x%08x] = 0x%08x\n", addr + loop, val); } iounmap(vaddr); } else { printk("\nUsage: echo [R - Read/W - write] [Physical Address] " " [Value(Write)/Count(Read)] > /sys/vedic/mem\n" "Eg: echo R 0x8008000 0x10 > /sys/vedic/mem\n" " echo w 0x8008000 0x12345678 > /sys/vedic/mem\n"); n = -EINVAL; } return n; } static DEVICE_ATTR(mem, 0644, NULL, mem_store); static struct attribute *vedic_attrs[] = { &dev_attr_mem.attr, NULL, }; static struct attribute_group vedic_attr_group = { .attrs = vedic_attrs, }; static int __init sys_vedic_init(void) { vedic_kobj = kobject_create_and_add("vedic", NULL); if (!vedic_kobj) return -ENOMEM; return sysfs_create_group(vedic_kobj, &vedic_attr_group); } static void __exit sys_vedic__exit(void) { if (vedic_kobj) sysfs_remove_group(vedic_kobj, &vedic_attr_group); } module_init(sys_vedic_init); module_exit(sys_vedic__exit); MODULE_AUTHOR("Vedic <FZKmxcz@163.com>"); MODULE_LICENSE("GPL");