【Linux开发】linux设备驱动归纳总结(五):3.操作硬件——IO静态映射
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
有时候会觉得,每次访问硬件都要先通过ioremap来获取虚拟地址,其实有没有一种一劳永逸的方法,只要一次的操作,以后就能通过这个地址来访问硬件。答案是“有”,这就是接下来要介绍的IO内存静态映射。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
一、静态IO是怎么建立的
Io静态映射发生在内核启动的时候,接下来通过内核源代码来分析,如果你的开发板是mini2440或者时候mini2440的内核配置文件,可以跟着我同样修改。注意:我的开发板只是使用mini2440的配置文件,外围电路跟mini2440不一样。
注:以下代码在内核目录linux-2.6.29/arch/arm/mach-s3c2440/mach-mini2440.c。
静态映射的建立方法,是在内核启动的时候,读取struct map_desc结构体里面的成员:
/*arch/arm/include/asm/mach/map.h*/
14 struct map_desc {
15 unsigned long virtual; //存放以后需要操作的虚拟地址,由自己定义
16 unsigned long pfn; //需要操作的硬件的物理地址对应的页帧号,即物理地址右移12
17 unsigned long length; //需要映射的大小
18 unsigned int type; //类型
19 };
这里要说明两个成员:
1)物理地址的页帧号pfn:如果你了解linux的页式管理,那你应该知道,一个页的大小是4096B(2
<< 12),所以一个地址的31-12位是用来表示一个地址对应的页帧号。对应的,一个物理地址,只要右移12位就能得到对应的页帧号,也可以使用函数:
#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT) //其实也是右移12位
2)类型type:有下面这些类型定义:
/*include/asm/mach/map.h*/
21 /* types 0-3 are defined in asm/io.h */
22 #define MT_UNCACHED
4
23 #define MT_CACHECLEAN 5
24 #define MT_MINICLEAN 6
25 #define MT_LOW_VECTORS 7
26 #define MT_HIGH_VECTORS 8
27 #define MT_MEMORY 9
28 #define MT_ROM 10
其中,MT_UNCACHED是我们常用的,表示该地址不放在缓冲区cached中。要知道,为了方便内存的访问,内核会将一些经常使用的内存数据放在cached中,但是这样在访问寄存器时就不行了,如果寄存器改变了,内核读取数据是从cached中读取数据,而不在寄存器读取,这样的做法是不合理的。
首先,我们需要往这个结构体中填充我们需要访问的地址。
本来这个结构体是空的。
/*arch/arm/mach-s3c2440/mach-mini2440.c*/
45 static struct map_desc mini2440_iodesc[] __initdata = {
46 };
修改成:
45 static struct map_desc mini2440_iodesc[] __initdata = {
46 {
47 .virtual = 0xeeee0000,
48 .pfn = __phys_to_pfn(0x56000000), //0x56000
49 .length = SZ_4K, //这里我直接映射一页
50 .type = MT_UNCACHED
51 },
52 };
填充结构体后,我们再看看启动时通过调用什么函数:
/*linux-2.6.29/arch/arm/mach-s3c2440/mach-mini2440.c*/
264 static void __init mini2440_map_io(void)
265 { //就是这个函数,将我刚才修改的结构体的成员进行静态映射
266 s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
267 s3c24xx_init_clocks(12000000);
268 s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
269 }
这个函数里面有一个重要的函数——iotable_init(),其实大部分的工作都由这个函数来完成,实现静态映射。
既然修改了内核,就需要重新编译内核:
make bzImage
通过上面这几步,我们就实现了这样的一个操作,可以通过虚拟地址0xeeee0000来访问一页的物理地址。既然知道了虚拟地址和物理地址之间的关系,就不需要再用ioremap了。
为了更好的规范,我们使用一个头文件来定义寄存器的访问地址,方便编程时使用:
/*5th_mm_3/1st/test_map_io.h*/
1 #ifndef _TEST_H
2 #define _TEST_H
3
4 typedef volatile unsigned long * s3c_reg_t;
5
6 #define S3C2440_VA 0xeeee0000 //我们已经知道静态映射的虚拟地址
7
8 #define S3C2440_BASE(x) (S3C2440_VA + (x))
9 #define S3C2440_GPEBASE S3C2440_BASE(0x40)
10 #define S3C2440_GPECON S3C2440_BASE(0x40) //这就是我们要操作的寄存器
11 #define S3C2440_GPEDAT S3C2440_BASE(0x44)
12 #define S3C2440_GPEUP S3C2440_BASE(0x48)
13
14
15 #endif /* _TEST_H */
然后再修改一下前一节的2nd函数,去掉ioremap部分:
1 #include
2 #include
3
4 #include
5 #include "test_map_io.h"
6
7 s3c_reg_t *GPECON,
*GPEDAT, *GPEUP;
8 unsigned long reg;
9
10 void led_device_init(void)
11 {
12 GPECON = (s3c_reg_t
*)S3C2440_GPECON;
13 GPEDAT = (s3c_reg_t
*)S3C2440_GPEDAT;
14 GPEUP = (s3c_reg_t
*)S3C2440_GPEUP;
15 }
16
17 void led_configure(void)
18 {
19 reg = ioread32(GPECON);
20 reg &= ~(3 << 24);
21 reg |= (1 << 24);
22 iowrite32(reg, GPECON);
23
24 reg = ioread32(GPEUP);
25 reg &= ~(3 << 12);
26 iowrite32(reg, GPEUP);
27 }
28
29 void led_on(void)
30 {
31 reg = ioread32(GPEDAT);
32 reg &= ~(1 << 12);
33 iowrite32(reg, GPEDAT);
34 }
35
36 void led_off(void)
37 {
38 reg = ioread32(GPEDAT);
39 reg |= (1 << 12);
40 iowrite32(reg, GPEDAT);
41 }
42
43 static int __init test_init(void) //模块初始化函数
44 {
45 led_device_init();
46 led_configure();
47 led_on();
48 printk("hello led!\n");
49 return 0;
50 }
51
52 static void __exit test_exit(void) //模块卸载函数
53 {
54 led_off();
55 printk("bye\n");
56 }
57
58 module_init(test_init);
59 module_exit(test_exit);
60
61 MODULE_LICENSE("GPL");
62 MODULE_AUTHOR("xoao bai");
63 MODULE_VERSION("v0.1");
除了红笔部分,和删除的ioremap相关函数,其他部分都没有改动,效果还是一样,加载灯亮,卸载灯灭。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
二、总结
这节介绍的内容确实是少:
1)内核中使用什么数据结构来管理静态映射IO。
2)内核时候什么函数在启动过程实现静态IO映射。
3)如何编写驱动函数来使用静态映射IO。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
源代码: 5th_mm_3.rar
【Linux开发】linux设备驱动归纳总结(五):3.操作硬件——IO静态映射的更多相关文章
- linux设备驱动归纳总结(五):3.操作硬件——IO静态映射【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-83299.html linux设备驱动归纳总结(五):3.操作硬件——IO静态映射 xxxxxxxxx ...
- linux设备驱动归纳总结
前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...
- 【Linux】linux设备驱动归纳总结
前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...
- 【Linux开发】linux设备驱动归纳总结(五):1.在内核空间分配内存
linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(五):2.操作硬件——IO内存
linux设备驱动归纳总结(五):2.操作硬件--IO内存 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(五):4.写个简单的LED驱动
linux设备驱动归纳总结(五):4.写个简单的LED驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- linux设备驱动归纳总结(五):1.在内核空间分配内存【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-79134.html linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(六):1.中断的实现
linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(六):2.分享中断号
linux设备驱动归纳总结(六):2.分享中断号 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
随机推荐
- C++中虚函数继承类的内存占用大小计算
计算一个类对象的大小时的规律: 1.空类.单一继承的空类.多重继承的空类所占空间大小为:1(字节,下同): 2.一个类中,虚函数本身.成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空 ...
- 基于LVM 测试磁盘写性能.md
准备工作 /dev/sdb 创建一个卷组,基于卷组创建5个逻辑卷,各100G 在10.10.88.214 新建5台虚拟机,每台虚拟机用到lvm建的逻辑卷 dd 压测 在每台虚拟机上执行dd 命令: d ...
- Django后台获取不到前端axios-post请求提交的参数的解决方法
解决方法 用 URLSearchParams 传递参数 let param = new URLSearchParams() param.append('username', 'admin') para ...
- python Print 输出
print 默认输出是换行的,如果要实现不换行需要在变量末尾加上逗号 , #!/usr/bin/python # -*- coding: UTF-8 -*- x="a" y=&qu ...
- HZOJ 20190727 T2 单(树上dp+乱搞?+乱推式子?+dfs?)
考试T2,考试时想到了40pts解法,即对于求b数组,随便瞎搞一下就oxxk,求a的话,很明显的高斯消元,但考试时不会打+没开double挂成10pts(我真sb),感觉考试策略还是不够成熟,而且感觉 ...
- POI2012 BEZ-Minimalist Security | noi.ac #537 Graph
题目链接:戳我 首先注意这张图有可能不连通!! 然后我们考虑对于每一个联通块,首先任意确定一个点,给它设最终值为x,然后进行搜索.(因为对于一个联通块而言,我们知道一个点的最终值,那么整个联通块上面点 ...
- ZAP-Queries【luogu3455】
题目大意 有不超过\(50000\)个询问,每次询问有多少正整数对\(x\),\(y\),满足\(x\leqslant a\),\(y \leqslant b\),并且\(gcd(x,y)=c\).其 ...
- JavaWeb_(Hibernate框架)Hibernate中事务
Hibernate中事务 事务的性质 事物的隔离级别 配置事务的隔离级别 事务的性质 原子性:原子,不可再分,一个操作不能分为更小的操作,要么全都执行,要么全不执行. 一致性:事务在完成时,必须使得所 ...
- [CSP-S模拟测试]:地理课(并查集+线段树分治)
题目传送门(内部题146) 输入格式 从$geography.in$读入数据. 第一行两个数$n,m$,表示有$n$个点,$m$个时刻.接下来$m$行每行三个数,要么是$1\ u\ v$,要么是$2\ ...
- Ubuntu——关于以root权限操作和启用root账户的讨论
概括性的说,在Ubuntu下面,推荐用户加入到sudo之后,使用命令: sudo -i 来以管理员权限进行操作. 而不推荐用户直接登录root用户. 具体内参考:https://help.ubuntu ...