与硬件通信(第九章 )

来源:互联网 发布:回溯算法与n皇后问题 编辑:程序博客网 时间:2024/06/06 16:33
1、I/O端口和I/O内存
     I/O寄存器和常规内存
     Linux提供了4个宏来解决由编译器和硬件重新排序引起的问题:
     #include <linux/kernel.h>
     void barrier(void);
     #include <asm/system.h>
     void rmb(void);
     void read_barrier_depends(void);
     void wmb(void);
     void mb(void);
     针对smp系统的,仅在内核针对smp系统时有效,在单处理器系统上,会被扩展为简单的调用:
     void smp_rmb(void);
     void smp_read_depends(void);
     void smp_wmb(void);
     void smp_mb(void);
     某些体系架构上,允许把赋值语句和内存屏障进行结合以提高效率。内核提供了执行这种合并的宏,默认情况下,这些宏的定义如下:
     #define set_mb(var, value) do {var = value; mb()}   while  0
     #define set_wmb(var, value) do {var = value; wmb()}   while  0
     #define set_rmb(var, value) do {var = value; rmb()}   while  0
2、使用I/O端口:
(1)I/O端口分配:
     #include <linux/ioport.h>
     struct resource *request_region(unsigned long first, unsigned long n, const char *name);
     将端口返还给系统:
     void release_region(unsigned long start, unsigned long n);
     检查给定的I/O端口是否可用:
     int check_region(unsigned long first, unsigned long n);
(2)操作I/O端口:
     定义在<asm/io.h>中的一些访问I/O的内联函数:
     unsigned inb(unsigned port);
     void outb(unsigned char byte, unsigned port);
     unsigned inw(unsigned port);
     void outw(unsigned short word, unsigned port);
     unsigned inl(unsigned port);
     void outl(unsigned long word, unsigned port);
(3)串操作
     串I/O函数的原型如下:
     1)从内存地址addr开始连续读/写count数目的字节,只对单一端口port读取或写入数据。
     void insb(unsigned port, void *addr, unsigned long count);
     void outsb(unsigned port, void *addr, unsigned long count);
     2)对一个16位的端口读写数据:
     void insw(unsigned port, void *addr, unsigned long count);
     void outsw(unsigned port, void *addr, unsigned long count);
     3)对一个32位的端口读写数据:0
     void insl(unsigned port, void *addr, unsigned long count);
     void outsl(unsigned port, void *addr, unsigned long count);
3、I/O内存分配和映射
(1)分配内存区域函数接口:
     struct resource *request_mem_region(unsigned long start, unsigned long len, char * name);
(2)释放已分配的内存区域:
     void release_mem_region(unsigned long start, unsigned long len);
(3)检查给定的区域是否可用:
     int check_mem_region(unsigned long start, unsigned long len);//老函数,不安全,不建议使用
分配完内存后我们必须首先建立映射,映射的建立由ioremap函数来完成。
     #include <asm/io.h>
     void *ioremap(unsigned long phys_addr, unsigned long size);
     void *ioremap_nocache(unsigned long phys_addr, unsigned long size);
     void iounmap(void *addr);
4、访问I/O内存
(1)要从I/O内存中读取数据,使用下面的函数之一:
     unsigned int ioread8(void *addr);
     unsigned int ioread16(void *addr);
     unsigned int ioread32(void *addr);
注:addr是从ioremap获得的地址。
(2)用于写入I/O内存的函数:
     void iowrite8(u8 value, void *addr);
     void iowrite16(u16 value, void *addr);
     void iowrite32(u32 value, void *addr);
(3)如果在给定的I/O内存地址处读/写一系列的值,则可以使用上述函数的重复版本:
     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);
     void iowrite8_rep(void *addr, const void *buf, unsigned long count);
     void iowrite16_rep(void *addr, const void *buf, unsigned long count);
     void iowrite32_rep(void *addr, const void *buf, unsigned long count);
(4)上面给出的函数均在给定的addr处执行所有的I/O操作,如果我们在一块I/O内存上执行则使用下面的函数之一:
     void memset_io(void *addr, u8 value, unsigned int count);
     void memcpy_fromio(void *dest, void *source, unsigned int count);
     void memcpy_toio(void *dest, void *source, unsigned int count);
5、像I/O内存一样使用端口
     将端口映射到内存上:
     void *ioport_map(unsigned long port, unsigned int count);
     当不需要要这种映射时,可调用下面的函数来撤销:
     void ioport_unmap(void *addr);


原创粉丝点击