io端口

***********************************************************

io端口设备访问流程为

-----------------------------------------------------------

1 request_region() 1 request_region()

2 ioport_map() 2 in() outb()

3 ioread8() iowrite8() ... 3 release_region()

4 ioport_unmap()

5 release_region()

****************** ******************

映射到内存空间 不映射到内存空间

-----------------------------------------------------------

先看 request_region

例子

惠普的一个设备

drivers/input/serio/hp_sdc.c

-------------------------------------

if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))

goto err0;

如果request_region 分配端口成功,返回非空指针。

  1. drivers/input/serio/hp_sdc.c
  2. -------------------------------------
  3. if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
  4. goto err0;
  5. 如果request_region 分配端口成功,返回非空指针。
  6. request_region
  7. -------------------------------------
  8. ->./include/linux/ioport.h:
  9. #define request_region(start,n,name) \
  10. __request_region(&ioport_resource, (start), (n), (name), 0)
  11. =====================================
  12. ioport_resource
  13. -------------------------------------
  14. -->kernel/resource.c
  15. struct resource ioport_resource = {
  16. .name = "PCI IO",
  17. .start = 0,
  18. .end = IO_SPACE_LIMIT,
  19. .flags = IORESOURCE_IO,
  20. };
  21. EXPORT_SYMBOL(ioport_resource);
  22. __request_region
  23. -------------------------------------
  24. -->kernel/resource.c
  25. struct resource * __request_region(struct resource *parent,
  26. resource_size_t start, resource_size_t n,
  27. const char *name, int flags)
  28. {
  29. struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
  30. if (!res)return NULL;
  31. res->name = name;
  32. res->start = start;
  33. res->end = start + n - 1;
  34. res->flags = IORESOURCE_BUSY;
  35. res->flags |= flags;
  36. write_lock(&resource_lock);
  37. for (;;) {
  38. struct resource *conflict;
  39. conflict = __request_resource(parent, res);
  40. if (!conflict) break; //申请成功
  41. if (conflict != parent) {
  42. parent = conflict;
  43. if (!(conflict->flags & IORESOURCE_BUSY))
  44. continue;
  45. }
  46. /* Uhhuh, that didn‘t work out.. */
  47. kfree(res);
  48. res = NULL;
  49. break;
  50. }
  51. write_unlock(&resource_lock);
  52. return res;
  53. }
  54. EXPORT_SYMBOL(__request_region);
  55. =====================================
  56. kzalloc
  57. -------------------------------------
  58. --->include/linux/slab.h
  59. static inline void *kzalloc(size_t size, gfp_t flags)
  60. {
  61. return kmalloc(size, flags | __GFP_ZERO);
  62. }
  63. __request_resource
  64. -------------------------------------
  65. --->kernel/resource.c
  66. static struct resource *
  67. __request_resource(struct resource *root,
  68. struct resource *new)
  69. {
  70. resource_size_t start = new->start;
  71. resource_size_t end = new->end;
  72. struct resource *tmp, **p;
  73. if (end < start) return root;
  74. if (start < root->start) return root;
  75. if (end > root->end) return root;
  76. p = &root->child;
  77. for (;;) {
  78. tmp = *p;
  79. if (!tmp || tmp->start > end) {
  80. new->sibling = tmp;
  81. *p = new;
  82. new->parent = root;
  83. return NULL; //成功
  84. }
  85. p = &tmp->sibling;
  86. if (tmp->end < start) continue;
  87. return tmp;
  88. }
  89. }
  90. =====================================

-------------------------------------

ioport_resource 小结

-------------------------------------

这是一个只有两层的树,第二层横向是个链

下面的图就是这个结构

% child指针

单线 parent指针

== sibling 指针

可以很容易得出如下特点

父节点会把子节点的范围包含

1 S :申请的io口的数量  S(i) > 0

2 s :申请的io的起始地址 0

3 s(i+j) > s(i)

4 j,i=1,2,3, ...

ioport_resource

-------------------------------------

ioport_resource (0,0xffff)

% ↑          ↑          ↑

% /            |            \

↓ /              |             \

(s1,s1+S1)==>   (s2,s2+S2)==>   (s3,s3+S3)==>

到此我们可以判断端口号的范围是 0-0xffff, 那么他和物理地址以及虚拟地址的关系呢?

如果有关系,从申请内存的kzalloc(sizeof(*res), GFP_KERNEL)句考察应该是个好入口。

接下来就是看 kmalloc(size, GFP_KERNEL | __GFP_ZERO)了

个人感觉没有多大关系。因为申请的关键性标志为 GFP_KERNEL,这表示申请的是内核常规内存。具体有没有关系,如果有,有什么样的关系,等看了kmalloc再说。

接着应该看

==============================================================================

***********************************************************

ioport_map ioport_unmap

***********************************************************

  1. lib/iomap.c
  2. -------------------------------------
  3. #define PIO_OFFSET 0x10000UL //64k
  4. #define PIO_MASK 0x0ffffUL
  5. #define PIO_RESERVED 0x40000UL //256K
  6. #endif
  7. void __iomem *ioport_map(unsigned long port, unsigned int nr)
  8. {
  9. if (port > PIO_MASK)
  10. return NULL;
  11. return (void __iomem *) (unsigned long) (port + PIO_OFFSET);
  12. }
  13. void ioport_unmap(void __iomem *addr)
  14. {
  15. /* Nothing to do */
  16. }
  17. __iomem
  18. -------------------------------------
  19. include/linux/compiler.h
  20. # define __iomem __attribute__((noderef, address_space(2)))
  21. //对iomem地址进行检查
  22. -------------------------------------
  23. ioport_map ioport_unmap 小结
  24. -------------------------------------
  25. 从port的范围(0-0xffff) 可以看到,映射的地址是10000-0x1ffff, 即(64k) -> (128k-1)的空间。
  26. 还有一个是PIO_RESERVED 40000,是保留的空间。
  27. 在搜代码的时候,同时也会在include/asm-generic/io.h文件中出现。而其上方有 #ifndef CONFIG_GENERIC_IOMAP,个人理解是这文件处理的是没有iomap的功能情况。里面的函数大都是空。
  28. ==============================================================================
  29. ***********************************************************
  30. ioread8() iowrite8()
  31. ***********************************************************
  32. lib/iomap.c
  33. -------------------------------------
  34. #define PIO_RESERVED 0x40000UL
  35. #define PIO_OFFSET 0x10000UL
  36. unsigned int ioread8(void __iomem *addr)
  37. {
  38. IO_COND(addr, return inb(port), return readb(addr));
  39. return 0xff;
  40. }
  41. void iowrite8(u8 val, void __iomem *addr)
  42. {
  43. IO_COND(addr, outb(val,port), writeb(val, addr));
  44. }
  45. EXPORT_SYMBOL(ioread8);
  46. EXPORT_SYMBOL(iowrite8);
  47. #define IO_COND(addr, is_pio, is_mmio) do { \
  48. unsigned long port = (unsigned long __force)addr; \
  49. if (port >= PIO_RESERVED) { \
  50. is_mmio; \
  51. } else if (port > PIO_OFFSET) { \
  52. port &= PIO_MASK; \
  53. is_pio; \
  54. } else \
  55. bad_io_access(port, #is_pio ); \
  56. }     while (0)
  57. static void bad_io_access(unsigned long port, const char *access)
  58. {
  59. static int count = 10;
  60. if (count) {
  61. count--;
  62. WARN(1, KERN_ERR "Bad IO access at port %#lx (%s)\n", port, access);
  63. }
  64. }
  65. WARN
  66. -------------------------------------
  67. ->include/asm-generic/bug.h
  68. #define WARN(condition, format...) ({ \
  69. int __ret_warn_on = !!(condition); \
  70. unlikely(__ret_warn_on); \
  71. })
  72. ioread8(addr)意思就是
  73. if addr>=256K then readb(addr)
  74. else if addr >64K then inb(addr - 64K)
  75. else 打印错误
  76. 继续追踪 inb 和 readb
  77. =====================================
  78. include/asm-generic/io.h
  79. -------------------------------------
  80. #define readb __raw_readb
  81. static inline u8 __raw_readb(const volatile void __iomem *addr)
  82. {
  83. return *(const volatile u8 __force *) addr;
  84. }
  85. #define writeb __raw_writeb
  86. static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
  87. {
  88. *(volatile u8 __force *) addr = b;
  89. }
  90. -------------------------------------
  91. static inline u8 inb(unsigned long addr)
  92. {
  93. return readb((volatile void __iomem *) addr);
  94. }
  95. static inline void outb(u8 b, unsigned long addr)
  96. {
  97. writeb(b, (volatile void __iomem *) addr);
  98. }
  99. arch/x86/boot.c
  100. -------------------------------------
  101. static inline u8 inb(u16 port)
  102. {
  103. u8 v;
  104. asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
  105. return v;
  106. }
  107. static inline void outb(u8 v, u16 port)
  108. {
  109. asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
  110. }

-------------------------------------

小结

-------------------------------------

在这里,我做一下个人理解,在io映射过以后,使用的是io.h中的函数,包括inb,outb。

如果没有映射,使用的是boot.c中的函数

inb或outb在不同情况下的值比较

boot.c的port值 小于 64k,

io.h中的port值 介于 64K 和 128k

从boot.c中的inb、outb可以看出,端口号一定和在主板的位置(或者是总线地址有关),有什么关系呢?

是不是和BSP有关,怎么有关的?

到这里,不能算完,待深入?

不过应该确认的是,端口和申请的resource地址无关,resource只是用来记录申请的端口

时间: 2024-10-09 09:59:30

io端口的相关文章

linux 系统对IO端口和IO内存的管理

一.I/O端口       端口(port)是接口电路中能被CPU直接访问的寄存器的地址.几乎每一种外设都是通过读写设备上的寄存器来进行的.CPU通过这些地址即端口向接口电路中的寄存器发送命令,读取状态和传送数据.外设寄存器也称为“I/O端口”,通常包括:控制寄存器.状态寄存器和数据寄存器三大类,而且一个外设的寄存器通常被连续地编址. 二.IO内存        例如,在PC上可以插上一块图形卡,有2MB的存储空间,甚至可能还带有ROM,其中装有可执行代码. 三.IO端口和IO内存的区分及联系 

20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动)

20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动) 2015-02-22 李海沿 刚刚我们实现了linux系统内存的分配,读写,释放功能,下面,我们一鼓作气将IO端口映射及IO内存映射搞定,加油! (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存.BIOS等).在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址

驱动笔记 - IO端口和IO内存

访问IO端口 (#include <asm/io.h>) 设备资源struct resource{ resource_size_t start; //资源起始物理地址 resource_size_t end; //资源结束物理地址 const char *name; unsigned long flags; //资源类型,如IORESOURCE_MEM,IORESOURCE_IO,IORESOURCE_IRQ struct resource *parent, *sibling, *child;

[转]io端口和io内存

(一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上 (如显存.BIOS等).在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址线上.        物理地址空间,一部分给物理RAM(内存)用,一部分给总线用,这是由硬件设计来决定的,因此在32 bits地址线的x86处理器中,物理地址空间是2的32次方,即4GB,但物理RAM一般不能上到4GB,因为还

ATMEGA16 IO端口相关总结

ATMEGA16 IO端口相关的寄存器总共有三个DDRX.PORTX和PINX.如果要对IO操作基本上就是对这三个寄存器进行相关的操纵.DDRX也称为数据方向寄存器.PORTX称为数据寄存器.PINX称为端口输入引脚. DDRX的作用: 当DDRX = 0时,表示的是某端口的引脚为输入:当DDRX = 0xff时表示某端口的引脚为输出. 引脚的状态:输入或者输出是根据什么定义的呢? 是根据高低电平是输入单片机还是从单片机输出.输入是指:不属于单片机的外部的电平输入到单片机:输出是指:单片机的电平

Linux 下IO端口编程访问

以前写的一篇笔记,偶尔翻出来了,放在这里做个纪念 Linux 下IO端口编程访问 这里记录的方法是在用户态访问IO端口,不涉及驱动程序的编写. 首先要包含头文件 /usr/include/asm/io.h ioperm() 在 unistd.h 中声明.用来打开对IO端口的访问权限,要求程序执行时必须有root 权限.只可以打开0x00到0x3ff 这一地址段的IO端口. ioperm( from, num, turn_on) 比如: #include<asm/io.h> #include&l

IO端口和IO内存的区别 转

目录(?)[-] Linux系统对IO端口和IO内存的管理 一.I/O端口 二.IO内存 三.IO端口和IO内存的区分及联系 四.外设IO端口物理地址的编址方式 统一编址 独立编址 优缺点 五.Linux下访问IO端口 I/O映射方式 内存映射方式 六.Linux下访问IO内存 六.ioremap和ioport_map 七.总结 IO端口和IO内存的区别及分别使用的函数接口  每个外设都是通过读写其寄存器来控制的.外设寄存器也称为I/O端口,通常包括:控制寄存器.状态寄存器和数据寄存器三大类.根

IO端口和IO内存的区别及分别使用的函数接口

每个外设都是通过读写其寄存器来控制的.外设寄存器也称为I/O端口,通常包括:控制寄存器.状态寄存器和数据寄存器三大类.根据访问外设寄存器的不同方式,可以把CPU分成两大类.一类CPU(如M68K,Power PC等)把这些寄存器看作内存的一部分,寄存器参与内存统一编址,访问寄存器就通过访问一般的内存指令进行,所以,这种CPU没有专门用于设备I/O的指令.这就是所谓的"I/O内存"方式.另一类CPU(典型的如X86),将外设的寄存器看成一个独立的地址空间,所以访问内存的指令不能用来访问这

&lt;摘录&gt;io端口和io内存

linux中的 IO端口映射和IO内存映射 (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义.物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上 (如显存.BIOS等).在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址线上.        物理地址空间,一部分给物理RAM(内存)用,一部分给总线用,这是由硬件设计来决定的,因此在32 bits地址线的x86处理器中,物理地址空间是2的32次方,即4