Android深度探索:HAL与驱动开发学习笔记--内存管理(学习重点)
来源:互联网 发布:微信视频强制分享源码 编辑:程序博客网 时间:2024/05/16 09:27
Linux内存管理机制没有用过,以前在vxworks系统下做过内存管理的模块,这里就先介绍些重点学习内容,以后需要查找一些实例,结合来学习!
1、分页机制等等
2、内存分配函数
3、slab
4、内存池
5、I/O端口及I/O内存
1、 访问I/O内存的流程是:
request_mem_region()-> ioremap() -> ioread8()/iowrite8() -> iounmap()->release_mem_region() 。
前面说过,IO内存是统一编址下的概念,对于统一编址,IO地址空间是物理主存的一部分,对于编程而言,我们只能操作虚拟内存,所以,访问的第一步就是要把设备所处的物理地址映射到虚拟地址,Linux2.6下用ioremap():
void *ioremap(unsigned long offset, unsigned long size);
然后,我们可以直接通过指针来访问这些地址,但是也可以用Linux内核的一组函数来读写:
ioread8(),iowrite16(), ioread8_rep(), iowrite8_rep()......
2、 访问I/O端口
访问IO端口有2种途径:I/O映射方式(I/O-mapped)、内存映射方式(Memory-mapped)。前一种途径不映射到内存空间,直接使用 intb()/outb()之类的函数来读写IO端口;后一种MMIO是先把IO端口映射到IO内存(“内存空间”),再使用访问IO内存的函数来访问 IO端口。
void ioport_map(unsigned long port, unsigned int count);
通过这个函数,可以把port开始的count个连续的IO端口映射为一段“内存空间”,然后就可以在其返回的地址是像访问IO内存一样访问这些IO端口。
request_region()函数用于申请IO端口,
request_mem_region用于申请IO内存(一般为控制寄存器)。
这两个函数申请之后还要通过ioremap函数去映射到内核虚拟地址。
voidrequest_region(unsigned long from, unsigned long num, const char *name)
这个函数用来申请一块输入输出区域。
如果这段I/O端口没有被占用,在我们的驱动程序中就可以使用它。在使用之前,必须向系统登记,以防止被其他程序占用。登记后,在/proc/ioports文件中可以看到你登记的io口。
参数1:io端口的基地址。
参数2:io端口占用的范围。
参数3:使用这段io地址的设备名。
在对I/O口登记后,就可以放心地用inb(), outb()之类的函来访问了。********************************************************************************************
request_region()用于内核为驱动“分配”端口,这里分配的意思是,记录该端口已经被某个进程使用,要是其它进程试图访问它,就会产生“忙”错误。所以目的在于实现资源的互斥访问。
反之, 如果一个资源只被一个进程访问,不会导致资源的争用,这时request_region()是可选的。
Linux下的IO端口和IO内存
CPU对外设端口物理地址的编址方式有两种:一种是IO映射方式,另一种是内存映射方式。
Linux将基于IO映射方式的和内存映射方式的IO端口统称为IO区域(IO region)。
IO region仍然是一种IO资源,因此它仍然可以用resource结构类型来描述。
Linux管理IO region:
1) request_region()
把一个给定区间的IO端口分配给一个IO设备。
2) check_region()
检查一个给定区间的IO端口是否空闲,或者其中一些是否已经分配给某个IO设备。
3) release_region()
释放以前分配给一个IO设备的给定区间的IO端口。
Linux中可以通过以下辅助函数来访问IO端口:
inb(),inw(),inl(),outb(),outw(),outl()
“b”“w”“l”分别代表8位,16位,32位。
实例:
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gameport.h>
#define L4_PORT 0x201
#define L4_SELECT_ANALOG 0xa4
#define L4_SELECT_DIGITAL 0xa5
#define L4_SELECT_SECONDARY 0xa6
#define L4_CMD_ID 0x80
#define L4_CMD_GETCAL 0x92
#define L4_CMD_SETCAL 0x93
#define L4_ID 0x04
#define L4_BUSY 0x01
#define L4_TIMEOUT 80 /* 80 us*/
MODULE_AUTHOR("Vojtech Pavlik<vojtech@ucw.cz>");
MODULE_DESCRIPTION("PDPI Lightning 4gamecard driver");
MODULE_LICENSE("GPL");
struct l4 {
structgameport *gameport;
unsignedchar port;
};
static struct l4 l4_ports[8];
/*
*l4_wait_ready() waits for the L4 to become ready.
*/
static int l4_wait_ready(void)
{
unsignedint t = L4_TIMEOUT;
while((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
return-(t <= 0);
}
/*
*l4_cooked_read() reads data from the Lightning 4.
*/
static int l4_cooked_read(struct gameport*gameport, int *axes, int *buttons)
{
structl4 *l4 = gameport->port_data;
unsignedchar status;
inti, result = -1;
outb(L4_SELECT_ANALOG,L4_PORT);
outb(L4_SELECT_DIGITAL+ (l4->port >> 2), L4_PORT);
if(inb(L4_PORT) & L4_BUSY) goto fail;
outb(l4->port& 3, L4_PORT);
if(l4_wait_ready()) goto fail;
status= inb(L4_PORT);
for(i = 0; i < 4; i++)
if(status & (1 << i)) {
if(l4_wait_ready()) goto fail;
axes[i]= inb(L4_PORT);
if(axes[i] > 252) axes[i] = -1;
}
if(status & 0x10) {
if(l4_wait_ready()) goto fail;
*buttons= inb(L4_PORT) & 0x0f;
}
result= 0;
fail: outb(L4_SELECT_ANALOG,L4_PORT);
returnresult;
}
static int l4_open(struct gameport*gameport, int mode)
{
structl4 *l4 = gameport->port_data;
if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
return-1;
outb(L4_SELECT_ANALOG,L4_PORT);
return0;
}
/*
*l4_getcal() reads the L4 with calibration values.
*/
static int l4_getcal(int port, int *cal)
{
inti, result = -1;
outb(L4_SELECT_ANALOG,L4_PORT);
outb(L4_SELECT_DIGITAL+ (port >> 2), L4_PORT);
if(inb(L4_PORT) & L4_BUSY)
gotoout;
outb(L4_CMD_GETCAL,L4_PORT);
if(l4_wait_ready())
gotoout;
if(inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
gotoout;
if(l4_wait_ready())
gotoout;
outb(port & 3, L4_PORT);
for(i = 0; i < 4; i++) {
if(l4_wait_ready())
gotoout;
cal[i]= inb(L4_PORT);
}
result= 0;
out: outb(L4_SELECT_ANALOG,L4_PORT);
returnresult;
}
/*
*l4_setcal() programs the L4 with calibration values.
*/
static int l4_setcal(int port, int *cal)
{
inti, result = -1;
outb(L4_SELECT_ANALOG,L4_PORT);
outb(L4_SELECT_DIGITAL+ (port >> 2), L4_PORT);
if(inb(L4_PORT) & L4_BUSY)
gotoout;
outb(L4_CMD_SETCAL,L4_PORT);
if(l4_wait_ready())
gotoout;
if(inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
gotoout;
if(l4_wait_ready())
gotoout;
outb(port & 3, L4_PORT);
for(i = 0; i < 4; i++) {
if(l4_wait_ready())
gotoout;
outb(cal[i],L4_PORT);
}
result= 0;
out: outb(L4_SELECT_ANALOG,L4_PORT);
returnresult;
}
/*
*l4_calibrate() calibrates the L4 for the attached device, so
*that the device's resistance fits into the L4's 8-bit range.
*/
static int l4_calibrate(struct gameport*gameport, int *axes, int *max)
{
inti, t;
intcal[4];
structl4 *l4 = gameport->port_data;
if(l4_getcal(l4->port, cal))
return-1;
for(i = 0; i < 4; i++) {
t= (max[i] * cal[i]) / 200;
t= (t < 1) ? 1 : ((t > 255) ? 255 : t);
axes[i]= (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
axes[i]= (axes[i] > 252) ? 252 : axes[i];
cal[i]= t;
}
if(l4_setcal(l4->port, cal))
return-1;
return0;
}
static int __init l4_create_ports(intcard_no)
{
structl4 *l4;
structgameport *port;
inti, idx;
for(i = 0; i < 4; i++) {
idx= card_no * 4 + i;
l4= &l4_ports[idx];
if(!(l4->gameport = port = gameport_allocate_port())) {
printk(KERN_ERR"lightning: Memory allocation failed\n");
while(--i >= 0) {
gameport_free_port(l4->gameport);
l4->gameport= NULL;
}
return-ENOMEM;
}
l4->port= idx;
port->port_data= l4;
port->open= l4_open;
port->cooked_read= l4_cooked_read;
port->calibrate= l4_calibrate;
gameport_set_name(port,"PDPI Lightning 4");
gameport_set_phys(port,"isa%04x/gameport%d", L4_PORT, idx);
if(idx == 0)
port->io= L4_PORT;
}
return0;
}
static int __init l4_add_card(int card_no)
{
intcal[4] = { 255, 255, 255, 255 };
inti, rev, result;
structl4 *l4;
outb(L4_SELECT_ANALOG,L4_PORT);
outb(L4_SELECT_DIGITAL+ card_no, L4_PORT);
if(inb(L4_PORT) & L4_BUSY)
return-1;
outb(L4_CMD_ID,L4_PORT);
if(l4_wait_ready())
return-1;
if(inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
return-1;
if(l4_wait_ready())
return-1;
if(inb(L4_PORT) != L4_ID)
return-1;
if(l4_wait_ready())
return-1;
rev= inb(L4_PORT);
if(!rev)
return-1;
result= l4_create_ports(card_no);
if(result)
returnresult;
printk(KERN_INFO"gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
card_no? "secondary" : "primary", rev >> 4, rev, L4_PORT);
for(i = 0; i < 4; i++) {
l4= &l4_ports[card_no * 4 + i];
if(rev > 0x28) /* on 2.9+ thesetcal command works correctly */
l4_setcal(l4->port,cal);
gameport_register_port(l4->gameport);
}
return0;
}
static int __init l4_init(void)
{
inti, cards = 0;
if(!request_region(L4_PORT, 1, "lightning"))
return-EBUSY;
for(i = 0; i < 2; i++)
if(l4_add_card(i) == 0)
cards++;
outb(L4_SELECT_ANALOG,L4_PORT);
if(!cards) {
release_region(L4_PORT,1);
return-ENODEV;
}
return0;
}
static void __exit l4_exit(void)
{
inti;
intcal[4] = { 59, 59, 59, 59 };
for(i = 0; i < 8; i++)
if(l4_ports[i].gameport) {
l4_setcal(l4_ports[i].port,cal);
gameport_unregister_port(l4_ports[i].gameport);
}
outb(L4_SELECT_ANALOG,L4_PORT);
release_region(L4_PORT,1);
}
module_init(l4_init);
module_exit(l4_exit);
对IO内存资源的访问
1) request_mem_region()
请求分配指定的IO内存资源。
2) check_mem_region()
检查指定的IO内存资源是否已被占用。
3) release_mem_region()
释放指定的IO内存资源。
其中传给函数的start address参数是内存区的物理地址(以上函数参数表已省略)。
驱动开发人员可以将内存映射方式的IO端口和外设内存统一看作是IO内存资源。
ioremap()用来将IO资源的物理地址映射到内核虚地址空间(3GB - 4GB)中,参数addr是指向内核虚地址的指针。
- Android深度探索:HAL与驱动开发学习笔记--内存管理(学习重点)
- Android深度探索:HAL与驱动开发学习笔记--中断
- Android深度探索:HAL与驱动开发学习笔记--时间管理
- Android深度探索:HAL与驱动开发学习笔记(一)
- Android深度探索:HAL与驱动开发学习笔记(二)
- Android深度探索:HAL与驱动开发学习笔记(三)
- Android深度探索:HAL与驱动开发学习笔记--并发控制之原子操作
- Android深度探索:HAL与驱动开发学习笔记--并发控制之互斥锁
- Android深度探索:HAL与驱动开发学习笔记--并发控制之自旋锁
- Android深度探索:HAL与驱动开发学习笔记--并发控制之顺序锁
- Android深度探索:HAL与驱动开发学习笔记--并发控制之信号量&完成量
- Android深度探索:HAL与驱动开发学习笔记--并发控制总结
- Android深度探索:HAL与驱动开发学习笔记--等待队列
- Android深度探索:HAL与驱动开发学习笔记--工作队列
- 【读书笔记】深度探索 HAL与驱动开发
- 《Android深度探索(卷1):HAL与驱动开发》新书发布
- Android底层HAL驱动开发学习笔记
- 《Android深度探索(卷1):HAL与驱动开发》实验环境配置与实验资源下载
- 《Learning RabbitMQ》阅读笔记(1.简介)
- Linux的SOCKET编程详解
- android 开源数据层框架。解放数据吧
- SPFA算法总结
- 阿里巴巴Java规范开发手册
- Android深度探索:HAL与驱动开发学习笔记--内存管理(学习重点)
- 下一代数据可视化分析系统的七个特征(二)
- 序列化和反序列化二叉树
- MediaPlayer实现金额的语音播报功能
- linux上printf出带颜色字体
- 洋河梦之蓝M9政府专供 是真是假?
- C++笔记之抽象类与接口类
- yii2的文件土拍你上传类UploadedFile的使用
- MySQL高可用数据库内核深度优化的四重定制