针对io端口单独编址的情况(x86),可以使用专用道指令in\out\ins\outs指令访问,针对这样的情况内核会用一些数据结构如resource 管理这些端口。
使用
struct resource {
const char *name; //资源拥有者名称
unsigned long start, end; //资源范围的起止地址
unsigned long flags;//各种标志
struct resource *parent, *sibling, *child; //指向资源树的父、兄、子的指针
};
此节点的孩子都被链在一个链表内,首元素被child指向
1、request_resource函数检查资源范围是否冲突,不冲突则将指定的资源挂入资源树
a、加锁resource_lock
b、调用__request_resource申请资源,如果发现了范围冲突则返回冲突的节点
c、释放锁,检查冲突节点,如果没有冲突节点则__request_resource会将指定的资源挂入资源树,如果有直接返回-EBUSY错误
2、int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
unsigned long align,
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data)
a、加锁resource_lock
b、调用find_resource函数查找
c、调用__request_resource申请资源
d、释放锁
e、成功返回0或者失败返回-EBUSY
3、int release_resource(struct resource *old) 释放io资源
a、加锁resource_lock
b、调用__release_resource函数去从资源树上取下需要释放的资源节点
c、释放resource_lock,成功返回0,失败返回-EBUSY
针对非统一编址则需要将io地址空间映射为内存地址里的一部分
主要通过ioremap函数来进行映射
void __iomem *
__ioremap(unsigned long phys_addr, size_t size, unsigned long flags,
unsigned long align)
a、计算出映射的最后地址范围,进行页面对齐
b、调用get_vm_area函数获取vmalloc一块符合大小的虚拟内存
c、调用remap_area_pages将虚拟地址与物理端口地址进行映射绑定
d、出错了则释放c步骤申请的虚拟地址
e、返回申请的虚拟地址与页面对齐返回的offset