天天看点

PCI设备内存操作函数总结

1.  exallocatepool()

函数说明:

exallocatepool allocates pool memory of the specified type and returns a pointer to the allocated

block.

函数定义:

pvoid exallocatepool(

                            __in  pool_type pooltype,

                            __in  size_t numberofbytes

);

代码中用来分配设备描述dma adepter设备的特性(device_description),作为参数传递给iogetdmaadapter()函数。在调用iogetdmaadapter()函数之前就要对pdevice_description结构进行指定各种特性。

         实际中这样使用:

                   pdevice_description devicedescription = (pdevice_description) exallocatepool

(pagedpool, sizeof(device_description));

2. rtlzeromemory()

         函数说明:

the rtlzeromemory routine fills a block of memory with zeros, given a pointer to the block and the length, in bytes, to be filled.

         函数定义:

                  void rtlzeromemory(

                         __in  void unaligned *destination,

                         __in  size_t length

3. iogetdmaadapter()

the iogetdmaadapter routine returns a pointer to the dma adapter structure for a physical device object.

struct _dma_adapter* iogetdmaadapter(

  __in_opt  pdevice_object physicaldeviceobject,

  __in      struct _device_description *devicedescription,

  __out     pulong numberofmapregisters

实际代码中这样使用:

ulong  numberofmapregisters=100;

pdx->dmaadapter=iogetdmaadapter(pdx->nextstackdevice,devicedescription,&numberofmapregisters);// nextstackdevice在adddevice函数中已经attach了。

4. allocatecommonbuffer()

the allocatecommonbuffer routine allocates memory and maps it so that it is simultaneously accessible from both the processor and a device for dma operations。

pvoid allocatecommonbuffer(

  __in   pdma_adapter dmaadapter,

  __in   ulong length,

  __out  pphysical_address logicaladdress,

  __in   boolean cacheenabled

注:第一个参数是iogetdmaadapter()返回的,第三个参数是自己顶一顶一个物理地址类型,用来接收分配得到的物理地址首址。

返回值:返回值为虚拟地址,供上层使用

pdx->descaddress=pdx->allocatecommonbuffer(pdx->dmaadapter,(ulong)desc_address*port_num,&pdx->desclogicaladdress,false);

附:使用该函数必不可少的会使用下面的函数

pdx->dmaadapter=iogetdmaadapter(pdx->nextstackdevice,devicedescription,&numberofmapregisters);

//创建一个dma适配器

pdx->allocatecommonbuffer=*pdx->dmaadapter->dmaoperations->allocatecommonbuffer; 

//分配连续的物理内存dma函数

pdx->freecommonbuffer = *pdx->dmaadapter->dmaoperations->freecommonbuffer;

//释放连续的物理内存dma函数

pdx->putdmaadapter=*pdx->dmaadapter->dmaoperations->putdmaadapter;      

//释放dma adapter对象

当通过allocatecommonbuffer()分配得到地址之后需要把这个地址分成两部分来处理,与硬件打交道的需要用logicaddress 与 应用程序打交道需用 virtual address.

最好将allocatecommonbuffer()函数取得的这两个地址保存到设备扩展中特定的变量中(根据内存块的用处),便于以后操作。可以这样做:

pdx->rxdescvirbase=(pchar)pdx->descaddress;

pdx->rxdescphybase=(ulong)(pdx->desclogicaladdress.lowpart); //物理地址

write_register_ulong( (pulong)&pdx->phbaregs->rxaddr_des_0,pdx->rx_fc_des

c_buf_phy[0]+16);

write_register_ulong( (pulong)&pdx->phbaregs->rxaddr_des_addr0_ptr,pdx->r

x_fc_desc_buf_phy[0]+4);

                   注意前面的 +16 和 +4 实际分别代表美一块内存的的偏移位置,由于我们定义了这块内存的结构,并在里面布局,+16 其实代表了struct rx_fc_ctl_tab 结构中的 struct rx_fc_desc_entity entity[rx_fc_desc_num] 域,这里又是一个结构,也就是我们最终会用到的“描述符”。注意:我们这里的操作是将一个地址写到一个寄存器,这个地址必须是物理地址,也就是前面说的logicaddress。这里phbaregs是通过pdx->phbaregs=(phba_regs)pdx->regsbase;    

获得的,也就是在cmresourcetypememory传过来时解析,代表硬件提供的dma寄存器首址。

对于硬件的初始化就是通过write_register_ulong()函数来完成,针对设备的起始地址来进行偏移,自己定义结构来匹配各个寄存器的内容,注意这个自己定义的结构一定要严格跟硬件寄存器相同,一bit都不能差。