您的位置 首页 5G

[ARM笔记]设备IO端口和IO内存的拜访

设备通常会提供一组寄存器来用于控制设备、读写设备和获取设备状态,即控制寄存器、数据寄存器和状态寄存器。这些寄存器可能位于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() | /

  |______________________________|

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/5g/247912.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部