1、介绍性材料
#include<linux/mm.h>
#include<asm/page.h>
和内存管理相关的大部分函数和结构,原型和定义在这些头文件.
void*__va(unsignedlongphysaddr);
unsignedlong__pa(void*kaddr);
在内核逻辑地址和物理地址之间转换的宏定义.
PAGE_SIZE
PAGE_SHIFT
常量,给出底层硬件的页的大小(字节)和一个页面号必须被移位来转变为一个物理地址的位
数.
structpage
在系统内存映射中表示一个硬件页的结构.
structpage*virt_to_page(void*kaddr);
void*page_address(structpage*page);
structpage*pfn_to_page(intpfn);
宏定义,在内核逻辑地址和它们相关的内存映射入口之间转换的.page_address只用在低地址
页或者已被明确映射的高地址页.pfn_to_page转换一个页面号到它的相关的structpage指针.
unsignedlongkmap(structpage*page);
voidkunmap(structpage*page);
kmap返回一个内核虚拟地址,被映射到给定页,如果需要并创建映射.kunmap为给定页删除
映射.
#include<linux/highmem.h>
#include<asm/kmap_types.h>
void*kmap_atomic(structpage*page,enumkm_typetype);
voidkunmap_atomic(void*addr,enumkm_typetype);
kmap的高性能版本;结果的映射只能被原子代码持有.对于驱动,type应当是KM_USER1,
KM_USER1,KM_IRQ0,或者KM_IRQ1.
structvm_area_struct;
描述一个VMA的结构.
2、实现mmap
intremap_pfn_range(structvm_area_struct*vma,unsignedlongvirt_add,unsignedlongpfn,unsignedlong
size,pgprot_tprot);
intio_remap_page_range(structvm_area_struct*vma,unsignedlongvirt_add,unsignedlongphys_add,
unsignedlongsize,pgprot_tprot);
位于mmap核心的函数.它们映射size字节的物理地址,从pfn指出的页号开始到虚拟地址
virt_add.和虚拟空间相关联的保护位在prot里指定.io_remap_page_range应当在目标地址在
I/O内存空间里时被使用.
structpage*vmalloc_to_page(void*vmaddr);
转换一个由vmalloc获得的内核虚拟地址到它的对应的structpage指针.
3、实现直接I/O
intget_user_pages(structtask_struct*tsk,structmm_struct*mm,unsignedlongstart,intlen,intwrite,int
force,structpage**pages,structvm_area_struct**vmas);
函数,加锁一个用户空间缓冲到内存并且返回对应的structpage指针.调用者必须持有mm-
>mmap_sem.
SetPageDirty(structpage*page);
宏定义,标识给定的页为"脏"(被修改)并且需要写到它的后备存储,在它被释放前.
voidpage_cache_release(structpage*page);
释放给定的页从页缓存中.
intis_sync_kiocb(structkiocb*iocb);
宏定义,返回非零如果给定的IOCB需要同步执行.
intaio_complete(structkiocb*iocb,longres,longres2);
函数,指示一个异步I/O操作完成.
4、直接内存存取
#include<asm/io.h>
unsignedlongvirt_to_bus(volatilevoid*address);
void*bus_to_virt(unsignedlongaddress);
过时的不好的函数,在内核,虚拟,和总线地址之间转换.总线地址必须用来和外设通讯.
#include<linux/dma-mapping.h>
需要来定义通用DMA函数的头文件.
intdma_set_mask(structdevice*dev,u64mask);
对于无法寻址整个32-位范围的外设,这个函数通知内核可寻址的地址范围并且如果可进行
DMA返回非零.
void*dma_alloc_coherent(structdevice*dev,size_tsize,dma_addr_t*bus_addr,intflag);
voiddma_free_coherent(structdevice*dev,size_tsize,void*cpuaddr,dma_handle_tbus_addr);
分配和释放一致DMA映射,对一个将持续在驱动的生命周期中的缓冲.
#include<linux/dmapool.h>
structdma_pool*dma_pool_create(constchar*name,structdevice*dev,size_tsize,size_talign,size_t
allocation);
voiddma_pool_destroy(structdma_pool*pool);
void*dma_pool_alloc(structdma_pool*pool,intmem_flags,dma_addr_t*handle);
voiddma_pool_free(structdma_pool*pool,void*vaddr,dma_addr_thandle);
创建,销毁,和使用DMA池来管理小DMA区的函数.
enumdma_data_direction;
DMA_TO_DEVICE
DMA_FROM_DEVICE
DMA_BIDIRECTIONAL
DMA_NONE
符号,用来告知流映射函数在什么方向数据移入或出缓冲.
dma_addr_tdma_map_single(structdevice*dev,void*buffer,size_tsize,enumdma_data_direction
direction);
voiddma_unmap_single(structdevice*dev,dma_addr_tbus_addr,size_tsize,enumdma_data_direction
direction);
创建和销毁一个单使用,流DMA映射.
voiddma_sync_single_for_cpu(structdevice*dev,dma_handle_tbus_addr,size_tsize,enum
dma_data_directiondirection);
voiddma_sync_single_for_device(structdevice*dev,dma_handle_tbus_addr,size_tsize,enumdma_data_directiondirection);
同步一个由一个流映射的缓冲.必须使用这些函数,如果处理器必须存取一个缓冲当使用流
映射时.(即,当设备拥有缓冲时).
#include<asm/scatterlist.h>
structscatterlist{/*...*/};
dma_addr_tsg_dma_address(structscatterlist*sg);
unsignedintsg_dma_len(structscatterlist*sg);
这个散布表结构描述一个涉及不止一个缓冲的I/O操作.宏sg_dma_addresshesg_dma_len可
用来抽取总线地址和缓冲长度来传递给设备,当实现发散/汇聚操作时.
dma_map_sg(structdevice*dev,structscatterlist*list,intnents,enumdma_data_directiondirection);
dma_unmap_sg(structdevice*dev,structscatterlist*list,intnents,enumdma_data_directiondirection);
voiddma_sync_sg_for_cpu(structdevice*dev,structscatterlist*sg,intnents,enumdma_data_direction
direction);
voiddma_sync_sg_for_device(structdevice*dev,structscatterlist*sg,intnents,enumdma_data_direction
direction);
dma_map_sg映射一个发散/汇聚操作,并且dma_unmap_sg恢复这些映射.如果在这个映射
被激活时缓冲必须被存取,dma_sync_sg_*可用来同步.
/proc/dma
包含在DMA控制器中的被分配的通道的文本快照的文件.基于PCI的DMA不显示,因为每
个板独立工作,不需要分配一个通道在DMA控制器中.
#include<asm/dma.h>
定义或者原型化所有和DMA相关的函数和宏定义.它必须被包含来使用任何下面符号.
intrequest_dma(unsignedintchannel,constchar*name);
voidfree_dma(unsignedintchannel);
存取DMA注册.注册必须在使用ISADMA通道之前进行.
unsignedlongclaim_dma_lock();
voidrelease_dma_lock(unsignedlongflags);
获取和释放DMA自旋锁,它必须被持有,在调用其他的在这个列表中描述的ISADMA函数
之前.它们在本地处理器上也关闭和重新使能中断
voidset_dma_mode(unsignedintchannel,charmode);
voidset_dma_addr(unsignedintchannel,unsignedintaddr);
voidset_dma_count(unsignedintchannel,unsignedintcount);
编程DMA信息在DMA控制器中.addr是一个总线地址.
voiddisable_dma(unsignedintchannel);
voidenable_dma(unsignedintchannel);
一个DMA通道必须被关闭在配置期间.这些函数改变DMA通道的状态.
intget_dma_residue(unsignedintchannel);
如果这驱动需要知道一个DMA传送在进行,它可调用这个函数,返回尚未完成的数据传输
的数目.在成功的DMA完成后,这个函数返回0;值是不可预测的当数据仍然在传送时.
voidclear_dma_ff(unsignedintchannel);
DMAflip-flop被控制器用来传送16-位值,通过2个8位操作.它必须被清除,在发送任何数
据给处理器之前.