linux驱动中读写IO地址空间的值

linux驱动中读写IO地址空间的值

引言

说一下起因:最近调试DDR驱动,想读一下某些控制器的寄存器值,由于不能进入到用户空间,无法使用/dev/mem的应用程序读写IO空间的地址,所以只能在内核中打印.

第一次尝试

在内核中直接编写读函数是不行的,因为有虚拟地址映射.开始也试了一下,确实引发crash.所以需要使用IOREMAP,先将IO空间的物理地址映射到虚拟地址上来.

从内核其他使用到ioremap的地方查看别人是怎么用的.发现他们都会首先从device端获取到一个resource,然后再映射.
但是我想做的是放到任意地方使用,不用去管device的那些写死的基地址.
我最终想要的是从数据手册上查看一个寄存器地址就能很快知道它的值.

为保险起见,在别人使用resource的地方打印查看了一下,resource的start成员,确定ioremap传入的第一个参数就是物理地址.

然后编写了如下程序:

	static void __iomem *base;

	base = ioremap(0x20E0000, 0x478);
	printk("read 20e0000+478=0x%x\n", __raw_readw(base + 0x478));
	
	iounmap(base);
	base = NULL;

这段程序一跑,同样crash.后来发现 ioremap的第二个参数有问题.

第二次尝试

修改为如下:

	static void __iomem *base;

	base = ioremap(0x20E0000, SZ_4K);
	printk("read 20e0000+478=0x%x\n", __raw_readw(base + 0x478));
	
	iounmap(base);
	base = NULL;

去跑同样有问题.
之后这里找了我好久,可能花了一个钟,主要是感觉读的话已经是虚拟地址了,可以读取任意长度的值,没想到却是不行,__raw_readw是读16位,数据手册上查看一个寄存器占了32位.

最终代码

最后测试没问题.

	u32 val = 0;

	static void __iomem *base;

	base = ioremap(0x20E0000, SZ_4K);
	printk("base = %p \n",base);
	
	val = __raw_readl(base);
	printk("data= %x\n", val);
	val = __raw_readl(base + 0x478);
	printk("data= %x\n", val);
	printk("read 20e0000+478=0x%x\n", __raw_readl(base + 0x478));
	
	iounmap(base);
	base = NULL;
	return count;

总结

不知道这个读多少长度是硬件外设不让读还是内核软件代码决定的,
我想多半是前者的原因,因为上面也说了映射出来的只是一块内存,读少了,应该硬件不会给你.
也有可能是读这个函数是按32位去取的?那要读8位,读16的函数干嘛,具体要纠结的话,得看更加底层的代码了.
不过我所要的已经满足了,也可以不用管了.
有明确知道的小伙伴,可以留言讨论.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值