驱动程序_硬件访问

本文详细介绍了驱动程序如何访问硬件,包括寄存器与内存的区别、内存与I/O空间的特性、IO端口与IO内存的操作流程,如申请、访问和释放。还提及了内核函数在驱动程序中的应用,如申请I/O端口和内存、映射和释放等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

寄存器与内存

  寄存器与内存的区别在哪里呢?寄存器和RAM的主要不同在于寄存器操作有副作用(side effect或边际效果):读取某个地址时可能导致该地址内容发生变化,比如很多设备的中断状态寄存器只要一读取,便自动清零。

内存与I/O

  在X86处理器中存在I/O空间的概念,I/O空间是相对内存空间而言的,它们是彼此独立的地址空间,在32位的x86系统中,I/O空间大小为64K,内存空间大小为4G
在这里插入图片描述

  • X86:支持内存空间、IO空间。
  • ARM:只支持内存空间。
  • MIPS:只支持内存空间。
  • PowerPC:只支持内存空间。

IO端口与IO内存

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

操作I/O端口

  对I/O端口的操作需按如下步骤完成:申请、访问和释放。

申请I/O端口

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

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

这个函数告诉内核,你要使用从first开始的n个端口,name参数是设备的名字。如果申请成功,返回非NULL;申请失败,返回NULL
  系统中端口的分配情况记录在/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 ); /* 读字节端口(16位宽) */
void outw ( unsigned short word, unsigned port ); /* 写字节端口(16位宽) */
unsigned inl ( unsigned port ); /* 读字节端口(32位宽) */
void outl ( unsigned longword, unsigned port ); /* 写字节端口(32位宽) */

释放I/O端口

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

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

操作I/O内存

  对I/O内存的操作需按如下步骤完成:申请、映射、访问和释放。

申请I/O内存

  内核提供了一套函数来允许驱动申请它需要的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内存

  在访问I/O内存之前,必须进行物理地址到虚拟地址的映射,ioremap函数具有此功能:

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

访问I/O内存

  访问I/O内存的正确方法是通过一系列内核提供的函数:
  1. 从I/O内存读,使用下列之一:

unsigned ioread8 ( void *addr );
unsigned ioread16 ( void *addr );
unsigned ioread32 ( void *addr );

  2. 写I/O内存,使用下列之一:

void iowrite8 ( u8 value, void *addr );
void iowrite16 ( u16 value, void *addr );
void iowrite32 ( u32 value, void *addr );

  3. 老版本的I/O内存访问函数:从I/O内存读,使用下列之一:

unsigned readb ( address );
unsigned readw ( address );
unsigned readl ( address );

  写I/O内存,使用下列之一:

unsigned writeb ( unsigned value, address );
unsigned writew ( unsigned value, address );
unsigned writel ( unsigned value, address );

释放I/O内存

  I/O内存不再需要使用时应当释放,步骤如下:

void iounmap ( void *addr );
void release_mem_region ( unsigned long start, unsigned long len );
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值