当前位置:首页 > 单片机 > 单片机
[导读]设备通常会提供一组寄存器来用于控制设备、读写设备和获取设备状态,即控制寄存器、数据寄存器和状态寄存器。这些寄存器可能位于IO空间,也可能位于内存空间。当位于IO空间时,通常被称为IO端口,位于内存空间时,对

设备通常会提供一组寄存器来用于控制设备、读写设备和获取设备状态,即控制寄存器、数据寄存器和状态寄存器。这些寄存器可能位于IO空间,也可能位于内存空间。当位于IO空间时,通常被称为IO端口,位于内存空间时,对应的内存空间成为IO内存。

1. Linux IO端口和IO内存访问接口
1.1 IO端口
在Linux设备驱动中,应使用Linux内核提供的函数来访问定位于IO空间的端口,这些函数包括如下几种:
(1)读写字节端口(8位宽)
unsigned inb(unsigned port);
void outb(unsigned char byte , unsigned port);

(2)读写字端口(16位宽)
unsigned inw(unsigned port);
void outw(unsigned char byte , unsigned port);

(3)读写长字端口(32位宽)
unsigned inl(unsigned port);
void outl(unsigned char byte , unsigned port);

(4)读写一串字
void insw(unsigned port , void *addr , unsigned long count);
void outsw(unsigned port , void *addr , unsigned long count);

(5)读写一串长字
void insl(unsigned port , void *addr , unsigned long count);
void outsl(unsigned port , void *addr , unsigned long count);
上述各函数中IO端口号port的类型高度依赖于具体的硬件平台,因此,只是写出了unsigned。

1.2 IO内存
在内核中访问IO内存之前,需首先使用ioremap()函数将设备所处的物理地址映射到虚拟地址。ioremap的原型如下:
void *ioremap(unsigned long offset , unsigned long size);
ioremap()与vmalloc()类似,也需要建立新的页表,但是它并不进行vmalloc()中所执行的内存分配行为。ioremap()返回一个特殊的虚拟地址,该地址可用来存取特定的物理地址范围。通过ioremap()获得的虚拟地址应该被iounmap()函数释放,其原型为:
void iounmap(void *addr);
在设备的物理地址被映射到虚拟地址之后,尽管可以直接通过指针访问这些地址,但是可以使用Linux内核的如下一组函数来完成设备内存映射的虚拟地址的读写,这些函数如下所示。
(1)读IO内存
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
与上述函数对应的较早版本的函数为(这些函数在Linux2.6中仍然被支持):
unsigned readb(address);
unsigned readw(address);
unsigned readl(address);

(2)写IO内存
void iowrite8(u8 value , void *addr);
void iowrite16(u16 value , void *addr);
void iowrite32(u32 value , void *addr);
与上述函数对应的较早版本的函数为(这些函数在Linux2.6中仍然被支持):
unsigned writeb(address);
unsigned writew(address);
unsigned writel(address);

(3)读一串IO内存
void ioread8_rep(void *addr , void *buf , unsigned long count);
void ioread16_rep(void *addr , void *buf , unsigned long count);
void ioread32_rep(void *addr , void *buf , unsigned long count);

(4)写一串IO内存
void iowrite8_rep(void *addr , void *buf , unsigned long count);
void iowrite16_rep(void *addr , void *buf , unsigned long count);
void iowrite32_rep(void *addr , void *buf , unsigned long count);

(5)复制IO内存
void memcpy_fromio(void *dest , void *source , unsigned int count);
void memcpy_toio(void *dest , void *source , unsigned int count);

(6)设置IO内存
void memset_io(void *addr , u8 value , unsigned int count);

1.3 把IO端口映射到内存空间
void *ioport_map(unsigned long port , unsigned int count);
通过这个函数,可以把port开始的count个连续的IO端口重映射为一段“内存空间”。然后就可以在其返回的地址上像访问IO内存一样访问这些IO端口。当不再需要这种映射时,需要调用下面的函数来撤销。
void ioport_unmap(void *addr);
实际上,分析ioport_map()的源代码可发现,映射到内存空间行为实际上是给开发人员制造的一个“假象”,并没有映射到内核虚拟地址,仅仅是为了让工程师可使用统一的IO内存访问接口访问IO端口。

2. 申请与释放设备IO端口和IO内存
2.1 IO端口申请
Linux内核提供了一组函数用于申请和释放IO端口。
struct resource *request_region(resource_size_t start, resource_size_t n, const char *name);
这个函数向内核申请了n个端口,这些端口从first开始,name参数为设备的名称。如果分配成功返回非NULL,失败,则返回NULL。
当用request_region()申请的IO端口使用完成后,应当使用release_region()函数将它们还给系统,这个函数的原型如下:
void release_region(resource_size_t start , resource_size_t n);

2.2 IO内存申请
Linux内核提供了一组函数用于申请和释放IO内存的范围。
struct resource *request_mem_region(resource_size_t start, resource_size_t n, const char *name, const char *name);
这个函数向内核申请n个内存地址,这些地址从first开始,name参数为设备的名称。如果分配成功返回值是非NULL,如果失败,返回NULL。
当用request_mem_region()申请的IO内存使用完成后,应当使用release_region()函数将它们还给系统,这个函数的原型如下:
void release_region(resource_size_t start , resource_size_t n);
上述request_region()和release_mem_region()都不是必须的,但建议使用。其任务是检查申请的资源是否可用,如果可用则申请成功,并标志为已经使用,其他驱动想再次申请该资源就会失败。
查看内核源码可知,request_region()和request_mem_region()调用的函数是一样的,只是传入参数的不同。
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))

3. 设备IO端口和IO内存访问流程
IO端口访问的一种途径是直接使用IO端口操作函数:在设备打开或驱动模块被加载时申请IO端口区域,之后使用inb()、outb()等进行端口访问,最后,在设备关闭或驱动被卸载时释放IO端口范围。
___________________________
||
| request_region() | 在设备驱动模块加载或open()函数中进行
|__________________________|
|
___________________________
| |
| inb()、outb()等 | 在设备驱动初始化、write()、read()、iotcl()等函数中进行
|__________________________ |
|
___________________________
| |
| release_region()等 | 在设备驱动模块卸载或release()函数中进行
|__________________________ |
IO端口的访问流程(不映射到内存空间)

IO端口访问的另一种途径是将IO端口映射为内存进行访问:在设备打开或驱动模块被加载时,申请IO端口区域并使用ioport_map()映射到内存,之后使用IO内存的函数进行端口访问,最后,在设备关闭或驱动被卸载时释放IO端口并释放映射。整个流程如下图所示:
___________________________
| |
| request_region()等 |
|__________________________ |
| 在设备驱动模块加载或open()函数中进行
___________________________ /
| | /
| ioport_map()等 |
|__________________________ |
|
___________________________
| |
| ioread8、ioread16、 | 在设备驱动初始化、write()、read()、ioctl等函数中调用
| ioread32、iowrite8等|
|__________________________ |
|
___________________________
| |
| ioport_unmap()|
|__________________________ |
|
___________________________ /在设备驱动卸载或release()函数中调用
| | /
| release_region()| /
|__________________________ |
IO端口的访问流程(映射到内存空间)

___________________________________
| |
| request_mem_region()等|
|__________________________________ |
| 在设备驱动模块加载或open()函数中进行
__________________________________ /
| | /
| ioremap()等 |/
|__________________________________|
|
___________________________
| |
| ioread8、ioread16、 | 在设备驱动初始化、write()、read()、ioctl等函数中调用
| ioread32、iowrite8等 |
|__________________________ |
|
______________________________
| |
| iounmap() |
|_____________________________ |
|
______________________________ /在设备驱动卸载或release()函数中调用
| | /
| release_mem_region() | /
|______________________________|

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭