• io端口


    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) ", 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只是用来记录申请的端口

  • 相关阅读:
    cgic: CGI的C函数库
    linux下的webserver BOA及CGIC库的使用指南(转帖)
    UDP 收/发 广播包
    winsock 收发广播包
    Linux系统下UDP发送和接收广播消息小例子
    uboot里读sd卡内容
    uboot从SD卡烧写内核和文件系统
    intellij 创建一个文件自动就add到git了,这个怎么取消
    内部类和外部类之间的相互调用
    JDK8的新特性——Lambda表达式
  • 原文地址:https://www.cnblogs.com/timssd/p/4781094.html
Copyright © 2020-2023  润新知