Linux内核驱动--硬件访问I/O【原创】

寄存器与内存

        寄存器与内存的区别在哪里呢?

寄存器和RAM的主要不同在于寄存器操作有副作用(side effect或边际效果):

读取某个地址时可能导致该地址内容发生变化,比如很多设备的中断状态寄存器只要一读取,便自动清零。

内存与IO

在X86处理器中存在IO空间的概念,IO空间是相对内存空间而言的,他们是彼此独立的地址空间,在32位的x86系统中,IO空间大小只有64K,内存却有4G

 

X86          支持内存空间、IO空间

ARM                 只支持内存空间

MIPS        只支持内存空间

PowerPC  只支持内存空间

IO端口:

当一个寄存器或内存位于IO空间时,称其为IO端口。

IO内存:

当一个寄存器或内存位于内存空间时,称其为IO内存。

 

操作I/O端口

对I/O端口的操作需按如下步骤完成:

1、  申请

2、  访问

3、  释放

 

申请I/O端口

内核提供了一套函数来允许驱动申请他需要的I/O端口,其中核心的函数是:

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

这个函数告诉内核,你要使用从first开始的n个端口,name参数是设备的名字。如果申请成功,返回非NULL,如果申请失败,返回NULL.

系统中端口的分配情况记录在/proc/ioports中. cat  /proc/ioports,如果不能分配需要的端口,可以来这里看看谁在使用。

 

访问I/O端口

I/O端口可分为8位,16,32位端口,Linux内核头文件(体系依赖的头文件<asm/io.h>)定义了下列内联函数来访问I/O端口:

unsigned inb(unsigned port)           读字节端口(8位宽)

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 outl(unsigned long word, unsigned port)       存取32位端口

 

释放I/O端口

当用完一组I/O端口(通常在驱动卸载的时候),用如下函数把它们返还给系统:

void release_region(unsigned long start, unsigned long n)

 

操作I/O内存

步骤:

1、  申请

2、  映射

3、  访问

4、  释放

 

申请I/O内存

核心函数为:

Struct resource *request_mem_region(unsigned long start, unsigned long len, char *name)

这个函数申请一个从start开始, 长度为len 字节的内存区。如果成功,返回非NULL,

否则返回NULL, 所有已经在使用的I/O内存在 /proc/iomem中列出

 

映射I/O内存

在访问IO内存之前,必须进行物理地址到虚拟地址的映射,

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

 

访问IO内存

从IO内存读:

unsigned ioread8(void *addr)

unsigned ioread16(void *addr)

unsigned ioread32(void *addr)

 

写IO内存

void iowrite8(u8 value, void *addr)

void iowrite16(u16 value, void *addr)

void iowrite32(u32 value, void *addr)

 

老版本的I/O内存访问函数:

从I/O内存读,

unsigned readb(address)

unsigned readw(address)

unsigned readl(address)

 

写IO内存

unsigned writeb(unsigned value, address)

unsigned writew(unsigned value, address)

unsigned writel(unsigned value, address)

 

释放IO内存

IO内存不再需要使用时应当释放,步骤:

1、  void iounmap(void *addr)

2、  void release_mem_region(unsigned long start, unsigned long len)

 

欢迎交流

如有转载请注明出处

新浪博客:http://blog.sina.com.cn/u/2049150530
博客园:http://www.cnblogs.com/sky-heaven/
知乎:http://www.zhihu.com/people/zhang-bing-hua

时间: 2024-10-27 15:07:42

Linux内核驱动--硬件访问I/O【原创】的相关文章

Linux内核驱动--mmap设备方法【原创】

mmap系统调用(功能) void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) 内存映射函数mmap , 负责把文件内容映射到进程的虚拟内存空间,通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read, write等操作.   addr:        指定映射的起始地址,通常设为NULL, 由系统指定. len:          映射到内存的文件长度 prot:    

Linux内核驱动fsync机制实现图解

  在Linux内核中的IO模型基本分为4类: 1.同步阻塞I/O 2.同步非阻塞I/O 3.异步阻塞I/O 4.异步非阻塞I/O 同步:应用显式地通过函数访问数据,在此函数返回时就会得到结果(成功或失败). 异步:应用会显示地通过函数提出访问或关注申请.数据到达时,硬件和驱动会通知应用,此时代码一般不在读写访问函数中,而是得到通知了再去有目的的访问数据. 阻塞:在等待数据的过程中会休眠在此处,而非阻塞即函数不休眠立即返回,可执行接下来的代码. 对于这4种机制,在<深入Linux设备驱动程序内核

linux内核驱动-内核初涉

  一.为什么要学习内核? 有些人要学习内核,而有些人则可以不学习它.你如果以后要从事系统研发或驱动开发的话,就要学习内核. 刚刚接触内核,主要学习内核的接口函数.不要深入的去读内核,因为你读也读不懂,内核代码庞大如野兽一般不可驾驭. 学习内核主要掌握层次学习法,即从头开始学习,一环紧扣一环. 内核学习的四步学习法:1.核心理论学习-概念与函数原型2.范例程序分析3.思维导图设计4.亲自编写代码 二.linux内核简介 1.linux体系结构 分为两部分:用户空间和内核空间 2.linux为什么

linux内核驱动中对字符串的操作【转】

转自:http://www.360doc.com/content/12/1224/10/3478092_255969530.shtml Linux内核中关于字符串的相关操作,首先包含头文件: [cpp] view plaincopyprint? #include <linux/string.h>   可用函数包括如下:lib/string.c  [cpp] view plaincopyprint? int strnicmp(const char *s1, const char *s2, siz

Linux内核驱动之GPIO子系统(一)GPIO的使用【转】

  转自:http://blog.csdn.net/tommy_wxie/article/details/9427047 一 概述   Linux内核中gpio是最简单,最常用的资源(和 interrupt ,dma,timer一样)驱动程序,应用程序都能够通过相应的接口使用gpio,gpio使用0-MAX_INT之间的整数标识,不能使用负数,gpio与硬件体系密切相关的,不过linux有一个框架处理gpio,能够使用统一的接口来操作gpio.在讲gpio核心(gpiolib.c)之前先来看看g

谈谈 Linux 内核驱动的编码风格

最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的coding style要求还是差很多.当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周.不过, 在不遵守规则的程序员队 伍里,我并不是孤独的.如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的coding style,而且在很多驱动程序的TODO文件里,都会把"checkpatch.pl fixes"作为自

谈谈Linux内核驱动的编码风格

最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的coding style要求还是差很多.当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周.不过, 在不遵守规则的程序员队 伍里,我并不是孤独的.如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的coding style,而且在很多驱动程序的TODO文件里,都会把"checkpatch.pl fixes"作为自

Linux内核驱动中对文件的读写

有时候需要在Linux kernel–大多是在需要调试的驱动程序–中读写文件数据.在kernel中操作文件没有标准库可用,需要利用kernel的一些函数,这些函数主 要有: filp_open() filp_close(), vfs_read() vfs_write(),set_fs(),get_fs()等,这些函数在linux/fs.h和asm/uaccess.h头文件中声明.下面介绍主要步骤 1. 打开文件 filp_open()在kernel中可以打开文件,其原形如下: strcut fi

Linux 内核驱动--多点触摸接口【转】

转自:http://blog.csdn.net/joard_yang/article/details/6225937 译自:linux-2.6.31.14/Documentation/input/multi-touch-protocol.txt 简介 为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指触摸数据.这个文档所描述的多点触控协议可以让内核驱动程序向用户层上报任意多指的数据信息. 使用说明 单点触摸信息是以ABS承载并按一定顺序发送,如BTN_TOUCH.ABS_