在調試驅動程序時, 常常要設置主控器寄存器參數或者運行時讀取寄存器值debug問題, 每次修改驅動讀取寄存器值都要編譯一次驅動再insmod, 十分不方便, 哪怕驅動提供一個節點linux
如dev/mem給應用程序讀取, 還要編寫應用程序open(), mmap(), read(), write() 聽着都頭大, 我在/sys開闢vedic目錄, 裏面放着各類方便debug的節點, 其中就有個能夠直接操做物理地址的節點「mem」,oop
在用戶空間直接echo操做物理地址, 包括寄存器和內存地址, 很是方便:spa
/* 讀取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
具體代碼以下:debug
#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");