35、PCI设备驱动简介

简介: PCI(Peripheral Component Interconnect)总线标准是一种将系统外部设备连接起来的总线标准,速度可以达到133MB/s,它是PC中最重要的总线,其他总路线如ISA总线,USB总线等,都挂载在PCI总线上(通过桥接电路)。

PCI(Peripheral Component Interconnect)总线标准是一种将系统外部设备连接起来的总线标准,速度可以达到133MB/s,它是PC中最重要的总线,其他总路线如ISA总线,USB总线等,都挂载在PCI总线上(通过桥接电路)。由Intel推出的一种局部总线,为32位数据地址总线,可以扩展为64位,支持突发读写,及多组外围设备。

PCI系统中,Host/PCI称为北桥,连接主处理器总线到基础PCI局部总线;PCI-ISA桥称为南桥,连接基础PCI总线到ISA总线。其中南桥通常还含有中断控制器,IDE控制器,USB控制器和DMA控制器等设备。

wps_clip_image-27502

图示 P412

PCI有三个相互独立的物理地址空间:设备存储器地址空间,I/O地址空间和配置空间。由于PCI支持设备即插即用,所以PCI设备不占用固定的内存地址空间或I/O地址空间,而是可以由操作系统决定其映射的基址。

PCI总线规范定义的配置Hha总长度为256个字节,配置信息按一定的顺序和大小依次存放。根据读取PCI配置空间,可以得到PCI设备的所有资源。[1]中讲述了多种读取PCI配置空间的方法,包括通过最基本的I/O端口操作进行读取,通过DDK提供的函数HalGetBusData,HalSetBusDataNT式驱动中进行读取,在WDM驱动中的读取方法,等。

一般程序所看到的内存指针都是虚拟内存,如果想操作物理内存,必须使用DDK提供的内核函数WRITE_REGISTER_XX,READ_REGISTER_XX系列函数。

MmAllocateContiguousMemory分配连续的物理地址,MmGetPhysicalAddress得到连续的物理内存地址。

代码
 
   
#pragma PAGEDCODE
NTSTATUS InitMyPCI(IN PDEVICE_EXTENSION pdx,IN PCM_PARTIAL_RESOURCE_LIST list)
{
PDEVICE_OBJECT fdo
= pdx -> fdo;

ULONG vector;
KIRQL irql;
KINTERRUPT_MODE mode;
KAFFINITY affinity;
BOOLEAN irqshare;
BOOLEAN gotinterrupt
= FALSE;

PHYSICAL_ADDRESS portbase;
BOOLEAN gotport
= FALSE;

PCM_PARTIAL_RESOURCE_DESCRIPTOR resource
= & list -> PartialDescriptors[ 0 ];
ULONG nres
= list -> Count;
BOOLEAN IsMem0
= TRUE;
for (ULONG i = 0 ; i < nres; ++ i, ++ resource)
{
// for each resource
switch (resource -> Type)
{
// switch on resource type
case CmResourceTypePort:
portbase
= resource -> u.Port.Start;
pdx
-> nports = resource -> u.Port.Length;
pdx
-> mappedport = (resource -> Flags & CM_RESOURCE_PORT_IO) == 0 ;
gotport
= TRUE;
break ;

case CmResourceTypeMemory:
if (IsMem0)
{
pdx
-> MemBar0 = (PUCHAR)MmMapIoSpace(resource -> u.Memory.Start,
resource
-> u.Memory.Length,
MmNonCached);
pdx
-> nMem0 = resource -> u.Memory.Length;
IsMem0
= FALSE;
}
else
{
pdx
-> MemBar1 = (PUCHAR)MmMapIoSpace(resource -> u.Memory.Start,
resource
-> u.Memory.Length,
MmNonCached);
pdx
-> nMem1 = resource -> u.Memory.Length;
}

break ;

case CmResourceTypeInterrupt:
irql
= (KIRQL) resource -> u.Interrupt.Level;
vector
= resource -> u.Interrupt.Vector;
affinity
= resource -> u.Interrupt.Affinity;
mode
= (resource -> Flags == CM_RESOURCE_INTERRUPT_LATCHED)
? Latched : LevelSensitive;
irqshare
= resource -> ShareDisposition == CmResourceShareShared;
gotinterrupt
= TRUE;

break ;

default :
KdPrint((
" Unexpected I/O resource type %d\n " , resource -> Type));
break ;
}
// switch on resource type
} // for each resource

if ( ! (TRUE && gotport && gotinterrupt ))
{
KdPrint((
" Didn't get expected I/O resources\n " ));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}

if (pdx -> mappedport)
{
// map port address for RISC platform
pdx -> portbase = (PUCHAR) MmMapIoSpace(portbase, pdx -> nports, MmNonCached);
if ( ! pdx -> mappedport)
{
KdPrint((
" Unable to map port range %I64X, length %X\n " , portbase, pdx -> nports));
return STATUS_INSUFFICIENT_RESOURCES;
}
}
// map port address for RISC platform
else
pdx
-> portbase = (PUCHAR) portbase.QuadPart;

NTSTATUS status
= IoConnectInterrupt( & pdx -> InterruptObject, (PKSERVICE_ROUTINE) OnInterrupt,
(PVOID) pdx, NULL, vector, irql, irql, LevelSensitive, TRUE, affinity, FALSE);
if ( ! NT_SUCCESS(status))
{
KdPrint((
" IoConnectInterrupt failed - %X\n " , status));
if (pdx -> portbase && pdx -> mappedport)
MmUnmapIoSpace(pdx
-> portbase, pdx -> nports);
pdx
-> portbase = NULL;
return status;
}

#define IMAGE_LENGTH (640*480)
// 申请一段连续物理地址来读取图像
PHYSICAL_ADDRESS maxAddress;
maxAddress.u.LowPart
= 0xFFFFFFFF ;
maxAddress.u.HighPart
= 0 ;

pdx
-> MemForImage = MmAllocateContiguousMemory(IMAGE_LENGTH,maxAddress);

PHYSICAL_ADDRESS pycialAddressForImage
= MmGetPhysicalAddress(pdx -> MemForImage);

WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)pdx
-> MemBar0 + 0x10000 ,
(PUCHAR)
& pycialAddressForImage.u.LowPart, 4 );

return STATUS_SUCCESS;
}

 

示例代码 P428

参考

[1] Windows 驱动开发技术详解,张帆

目录
相关文章
|
传感器 数据采集 API
C语言与硬件编程:GPIO操作
C语言与硬件编程:GPIO操作
|
API Python
【Python】已解决:urllib.error.HTTPError: HTTP Error 403: Forbidden
【Python】已解决:urllib.error.HTTPError: HTTP Error 403: Forbidden
3543 2
|
JavaScript
Vue项目启动报错处理
Vue项目启动报错处理
443 1
|
前端开发 JavaScript 应用服务中间件
花十分钟将vue3前端项目一步一步自动化部署到linux的docker上
可以理解成镜像是 Docker 生命周期中的构建或者打包阶段,而容器则是启动或者执行阶段。
2626 0
|
机器学习/深度学习 人工智能 达摩院
如何打造真人化高表现力的语音合成系统
语音合成技术作为人机交互的重要环节,终极目标即达到媲美真人的合成效果。高表现力语音合成逐渐成为未来的趋势。高表现力语音有三个显著的特点:韵律自然、情感风格丰富和音质清澈。 需要认识到的是当下的技术水平在韵律自然表示、情感风格丰富度上和真人之间还存在着较大的、人耳容易分辨的差距。 因此,我们针对这三个特点,进行算法上的探索,形成达摩院第五代语音合成技术——基于韵律建模的 SAM-BERT、情感语音合成 Emotion TTS 和高清语音合成 HiFi-TTS 的 Expressive-TTS。
619 0
|
缓存 前端开发 NoSQL
基于springboot实现快递代取管理系统
本项目基于springboot框架开发而成,前端采用bootstrap和layer框架开发,系统功能完整,界面简洁大方,比较适合做毕业设计使用。 本项目主要实现了代取快递的信息管理功能,使用角色有三类:一是客户可以直接访问系统下单,输入代取快递的相关信息,并可以在系统中查询订单的完成进度,也可以对系统进行相应的反馈并查询反馈的回复情况。也可以直接在线支付代取费用。二是接单员,可以登陆系统进行接单,并根据自己的订单完成情况修改订单状态,查询自己的订单等。三是系统管理员,可以实现对人员和订单信息的管理,对反馈信息的回复等操作。
419 1
基于springboot实现快递代取管理系统
|
文字识别 搜索推荐 数据可视化
|
分布式计算 资源调度 Hadoop
在文件存储HDFS版上使用 Apache Flink
本文档主要介绍如何在挂载文件存储HDFS版的 Hadoop 集群上安装及使用 Flink。
613 0
|
移动开发 前端开发 JavaScript
AlloyImage:腾讯开源的 Web 图像处理库
这是一个来自腾讯 Web 前端 AlloyTeam的开源项目,是一个基于HTML5技术的专业图像处理库。
669 0
AlloyImage:腾讯开源的 Web 图像处理库
|
人工智能 编解码 监控
核桃编程:前端可观测性建设之路
随着核桃编程业务的快速增长,核心应用的系统规模和系统复杂度也在经历翻天覆地的变化。核桃技术团队不断通过新兴的技术手段维护整套系统架构的技术先进性。在3 年时间里,技术团队至少对整体系统架构进行了 6 次以上的重大重构,涉及微服务化、容器化、分布式数据库等重要的技术,并尝试通过 Serverless 技术提升系统的弹性伸缩能力。在疫情期间,当系统负荷呈现数倍突增的情况下,核桃编程的系统架构依然经受住了考验。
16473 0
核桃编程:前端可观测性建设之路