Chinaunix首页 | 论坛 | 博客
  • 博客访问: 544630
  • 博文数量: 104
  • 博客积分: 2089
  • 博客等级: 大尉
  • 技术积分: 1691
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-29 08:48
文章分类

全部博文(104)

文章存档

2015年(1)

2013年(13)

2012年(31)

2011年(59)

分类: LINUX

2011-05-13 18:44:48

***********************************************************
刨刨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.     
  8.     void __iomem *ioport_map(unsigned long port, unsigned int nr)
  9.     {
  10.             if (port > PIO_MASK)
  11.                     return NULL;
  12.             return (void __iomem *) (unsigned long) (port + PIO_OFFSET);
  13.     }
  14.     void ioport_unmap(void __iomem *addr)
  15.     {
  16.             /* Nothing to do */
  17.     }
  18.     
  19.     __iomem
  20.     -------------------------------------
  21.     include/linux/compiler.h
  22.     # define __iomem __attribute__((noderef, address_space(2)))
  23.     //对iomem地址进行检查

  24. -------------------------------------
  25. ioport_map ioport_unmap 小结
  26. -------------------------------------
  27.     从port的范围(0-0xffff) 可以看到,映射的地址是10000-0x1ffff, 即(64k) -> (128k-1)的空间。
  28.     还有一个是PIO_RESERVED 40000,是保留的空间。
  29.     在搜代码的时候,同时也会在include/asm-generic/io.h文件中出现。而其上方有 #ifndef CONFIG_GENERIC_IOMAP,个人理解是这文件处理的是没有iomap的功能情况。里面的函数大都是空。

  30. ==============================================================================

  31. ***********************************************************
  32.             ioread8() iowrite8()
  33. ***********************************************************

  34. lib/iomap.c
  35.     -------------------------------------
  36.     #define PIO_RESERVED 0x40000UL
  37.     #define PIO_OFFSET 0x10000UL
  38.     
  39.     unsigned int ioread8(void __iomem *addr)
  40.     {
  41.         IO_COND(addr, return inb(port), return readb(addr));
  42.         return 0xff;
  43.     }

  44.     void iowrite8(u8 val, void __iomem *addr)
  45.     {
  46.         IO_COND(addr, outb(val,port), writeb(val, addr));
  47.     }
  48.     
  49.     EXPORT_SYMBOL(ioread8);
  50.     EXPORT_SYMBOL(iowrite8);
  51.     
  52.     #define IO_COND(addr, is_pio, is_mmio) do { \
  53.             unsigned long port = (unsigned long __force)addr; \
  54.             if (port >= PIO_RESERVED) { \
  55.                     is_mmio; \
  56.             } else if (port > PIO_OFFSET) { \
  57.                     port &= PIO_MASK; \
  58.                     is_pio; \
  59.             } else \
  60.                     bad_io_access(port, #is_pio ); \
  61.     }     while (0)
  62.     
  63.     static void bad_io_access(unsigned long port, const char *access)
  64.     {
  65.         static int count = 10;
  66.         if (count) {
  67.             count--;
  68.             WARN(1, KERN_ERR "Bad IO access at port %#lx (%s)\n", port, access);
  69.         }
  70.     }
  71.     
  72.     WARN
  73.     -------------------------------------
  74.     ->include/asm-generic/bug.h
  75.     #define WARN(condition, format...) ({ \
  76.             int __ret_warn_on = !!(condition); \
  77.             unlikely(__ret_warn_on); \
  78.     })
  79.     
  80.     ioread8(addr)意思就是
  81.         if addr>=256K then readb(addr)
  82.         else if addr >64K then inb(addr - 64K)
  83.         else 打印错误
  84.     
  85.     继续追踪 inb 和 readb
  86.     =====================================

  87. include/asm-generic/io.h
  88.     -------------------------------------
  89.     #define readb __raw_readb
  90.     static inline u8 __raw_readb(const volatile void __iomem *addr)
  91.     {
  92.             return *(const volatile u8 __force *) addr;
  93.     }
  94.     
  95.     #define writeb __raw_writeb
  96.     static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
  97.     {
  98.             *(volatile u8 __force *) addr = b;
  99.     }
  100.     
  101.     -------------------------------------
  102.     static inline u8 inb(unsigned long addr)
  103.     {
  104.             return readb((volatile void __iomem *) addr);
  105.     }
  106.     static inline void outb(u8 b, unsigned long addr)
  107.     {
  108.             writeb(b, (volatile void __iomem *) addr);
  109.     }

  110. arch/x86/boot.c
  111. -------------------------------------
  112.     static inline u8 inb(u16 port)
  113.     {
  114.         u8 v;
  115.         asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
  116.         return v;
  117.     }
  118.     static inline void outb(u8 v, u16 port)
  119.     {
  120.         asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
  121.     }

-------------------------------------
小结
-------------------------------------
在这里,我做一下个人理解,在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只是用来记录申请的端口。
 
==============================================================================

今天先到这里,以后的再说,我猜测跟BSP有关,我对BSP不熟,等我考查了BSP再补全这个东西。
阅读(1039) | 评论(1) | 转发(0) |
0

上一篇:address_space 从哪里来

下一篇:BSP 和 BIOS

给主人留下些什么吧!~~