日期:2014-05-16  浏览次数:20600 次

Linux驱动之与硬件通信

1 IO端口和IO内存区别

像x86系列处理器有两种地址空间:一种是内存地址空间,一种是端口地址空间,访问端口有单独的指令,例如in/out指令,而像ARM这类处理器则使用单一的地址空间,没有端口地址空间的概念。在硬件层,IO端口和IO内存并无本质区别,都是通过向地址总线和控制总线发送地址和控制信号,再通过数据总线读写数据。


2 使用IO端口

2.1 IO端口分配

IO端口分配使用request_region函数,该函数用于取得该IO端口的独占访问,头文件在linux/ioport.h中,函数原型如下:

struct resourse *request_region(unsigned long first, unsigned long n, const char *name);

first表示起始端口号,n表示端口数量。

如果分配成功,返回非NULL值,如果request_region返回NULL,表示不能使用这些IO端口(有可能被其它程序占用了)。


2.2 IO端口释放

如果不在使用该IO端口,则调用release_region函数释放该IO端口的控制,函数原型如下:

void release_region(unsigned long start, unsigned long n);


2.3 检查IO端口是否可用

int check_region(unsigned long first, unsigned long n);

如果该端口不可用,则返回错误码。Linux中并不赞成使用这个函数,因为该函数只是对IO端口做检查,并不对IO端口进行锁定,这样有可能其它程序也能使用这组IO端口,这是一个比较老的函数。


2.4 操作IO端口

这组函数与具体的体系架构有关,所以头文件在asm/io.h中

unsigned inb(unsigned port);

void outb(unsigned char byte, unsigned port);

8位(字节)读写函数。


unsigned inw(unsigned port);

void outw(unsigned short word, unsigned port);

16位读写函数。


unsigned inl(unsigned port);

void out(unsinged long word, unsinged port);

32位读写函数。


3 使用IO内存

3.1 IO内存分配

在使用之前,必须首先分配IO内存,需要包含头文件linux/ioport.h,函数原型如下:

struct resourse *request_mem_region(unsigned long start, unsigned long len, char *name);

表示从start开始分配len字节的内存区域,如果成功,返回非NULL指针,否则返回NULL,所有的IO内存分配情况可以从/proc/iomem中看到。


3.2 IO内存释放

不再使用这段内存时,需要调用release_mem_region释放,函数原型如下:

void release_mem_region(unsigned long start, unsigned long len);


同样也提供了一个比较老的函数,用来检查IO内存是否可用

int check_mem_region(unsigned long start, unsigned long len);

同check_region一样,它也是不安全的,应该避免使用。


3.3 IO内存映射和释放

通常,是不能直接访问IO内存的,需要对IO内存进行映射,映射是将物理地址映射成虚拟地址,函数原型如下:

void *ioremap(unsigned long phys_addr, unsinged long size);

void iounmap(void *addr);

要使用这些函数需要包含头文件asm/io.h