Dell 7080mff 黑苹果 小记(独显篇)

Dell 7080mff 黑苹果 小记(独显篇),第1张

主机:dell 7080mff pcie独显版

显卡:rx640

驱动独显的正确姿势:

DeviceProperties添加

Pice位置 PciRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)

原理:Rx640显卡为Rx550的马甲卡,也就是Rx460 Lexa的马甲,Lexa核心的显卡并不免驱,甚至网上很多大佬说mac下并不能驱动Lexa核心的显卡。上面的信息fake了蓝宝石Rx550的信息,总所周知Rx550里只有蓝宝石是Polaris核心,其余都是Lexa核心。仿冒Polaris核心让Mac识别也能成功驱动。上面的信息同样适用其他Lexa核心的Rx550和Rx460的显卡。

参考链接: https://www.tonymacx86.com/threads/guide-catalina-on-optiplex-9020-sff-w-rx550.276296/

内核流(Kernel Streaming)驱动模型在多媒体方面应用的比较多,支持内核流模型的驱动能够

向系统报告它的性能,以及能够将数据高效,通用的传递。通俗的说,就是可以将摄像头的数据直接传递到显卡中显示,而不需要通过应用层.它可以避免数据在应用层和内核层之间的传递,但是这对于上层来说是透明的;并且采用WDM 内核流模型还可以实现设备无关性,使得程序有很好的移植性和通用性。一般来说,QQ摄像头就是使用基于WDM内核流的组件来实现的。所以可以在打开摄像头的时候轻易的更换为给对方播放影音文件(在上层使用相同的组件和流程,仅仅更换了source filter)。在这里需要指明的是,minidriver一般是可以和硬件设备相关,但是也不一样会和硬件设备相关,它在内核层同样可以调用其他的组件,例如可以实现虚拟摄像头之类的应用。

一般来说,硬件设备会提供一个KsProxy组件,这个组件能够完成一些相应的扩展功能,同时,也可以将数据进行不同类别的传送。上层应用程序能够控制底层数据的流向,而不是将数据拷贝到应用层,然后再传递给内核层处理(这个和DirectX的处理有相似的地方,因为DirectShow曾经也是DirectX的一员)。

虽然现在微软对于流内核结构进行了调整,新的流类型采用的是AVStream(下一次在叙述AVStream框架)。但是从目前来看,很多情况下仍然采用目前的方式来处理数据。

下面通过源代码和数据类型的形式来讲解一下这个驱动程序的框架结构。会尽量屏蔽代码中关于具体设备的细节,专注于描述stream class的流程和结构:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1. 驱动程序的入口点:

NTSTATUS DriverEntry(__in PDRIVER_OBJECT DriverObject, __in PUNICODE_STRING

RegistryPath)

{

HW_INITIALIZATION_DATA HwInitData

RtlZeroMemory( &HwInitData, sizeof(HW_INITIALIZATION_DATA) )

HwInitData.HwInitializationDataSize = sizeof(HwInitData)// 结构大小

HwInitData.HwInterrupt = NULL// 硬件回调

HwInitData.HwReceivePacket = MyReceivePacket// 控制回调

HwInitData.HwCancelPacket = MyCancelOnePacket// 取消回调

HwInitData.HwRequestTimeoutHandler = MyTimeoutHandler// 超时回调

HwInitData.DeviceExtensionSize = sizeof(MY_EXTENSION)// 设备扩展

HwInitData.PerStreamExtensionSize = sizeof(STREAMEX)// 流扩展

HwInitData.PerRequestExtensionSize = sizeof(IRB)// SRB大小

HwInitData.FilterInstanceExtensionSize = 0// 安装大小

HwInitData.BusMasterDMA = FALSE// 总线DMA

HwInitData.Dma24BitAddresses = FALSE// DMA地址

HwInitData.BufferAlignment = sizeof(ULONG) - 1//

HwInitData.TurnOffSynchronization = TRUE

HwInitData.DmaBufferSize = 0

// 注册流端口驱动和回调函数

return (StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData))

}

这里可以看得出,驱动入口点基本上只是向stream class注册回调函数和信息。此处的设备

扩展和流扩展需要我们自己定义。

超时回调函数和取消回调函数本身并没有做太过于特殊的事情,关键在于控制命令回调函数,它是接收上层,也就是stream class 发送的控制包,下面会详细的讲解控制命令回调函数:

2. MyReceivePacket函数:

VOID

MyReceivePacket(IN PHW_STREAM_REQUEST_BLOCK pSrb)

{

PIO_STACK_LOCATION IrpStack

PMY_EXTENSION pDevExt = (PMY_EXTENSION) pSrb->HwDeviceExtension

PAGED_CODE()

pSrb->Status = STATUS_SUCCESS

switch (pSrb->Command) {

case SRB_INITIALIZE_DEVICE: // 初始化设备

break

case SRB_INITIALIZATION_COMPLETE: // 初始化设备完成

break

case SRB_GET_STREAM_INFO:// 获取设备信息

break

case SRB_OPEN_STREAM: // 打开流

break

case SRB_CLOSE_STREAM: // 关闭流

break

case SRB_SURPRISE_REMOVAL: // 移除设备

break

case SRB_UNKNOWN_DEVICE_COMMAND: // 未知的命令

break

case SRB_UNINITIALIZE_DEVICE: // 卸载设备

break

case SRB_GET_DATA_INTERSECTION: // 获取格式和范围

break

case SRB_CHANGE_POWER_STATE: // 改变电源状态

break

case SRB_GET_DEVICE_PROPERTY: // 获取设备属性

break

case SRB_SET_DEVICE_PROPERTY: // 设置设备属性

break

case SRB_PAGING_OUT_DRIVER: // ?

break

default:

pSrb->Status = STATUS_NOT_IMPLEMENTED

break

}

StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension,

pSrb)

}

可以看出来的是,上层会通过向这个函数发送命令包,来控制设备的行为。这个端口驱动需要

自己决定从什么拷贝来数据,或者怎么向上层回复。

这里stream class的命令中,需要关注地方并不多,由于设备可能会是USB设备/1394设备/网络

组件/图像采集卡,所以很难统一的给出一份具体的代码.但是通过下面的几个命令的讲解,大家

应该很容易的构建出具体设备的代码来:

2.1 初始化命令: 在设备的初始化阶段,stream class 会依次发送下面的命令

SRB_INITIALIZE_DEVICE->SRB_GET_STREAM_INFO->SRB_INITIALIZATION_COMPLETE

一般来说,SRB_INITIALIZE_DEVICE命令主要是初始化设备扩展和属性结构的初始化,

SRB_GET_STREAM_INFO命令则是向注册表写入自己的属性,并提供相应的另一组回调函数给

Stream class,便于接受更微观的控制SRB_INITIALIZATION_COMPLETE命令一般是一个完成回调

的方式。

下面的代码会揭示在SRB_GET_STREAM_INFO命令时候,一般会进行的处理:

typedef struct _HW_STREAM_HEADER {

ULONG NumberOfStreams// 支持的流的数目

ULONG SizeOfHwStreamInformation// 结构大小

ULONG NumDevPropArrayEntries// 支持的属性数组大小

PKSPROPERTY_SET DevicePropertiesArray// 属性数组

ULONG NumDevEventArrayEntries// 支持的事件数组大小

PKSEVENT_SET DeviceEventsArray// 事件数组

PKSTOPOLOGY Topology//

PHW_EVENT_ROUTINE DeviceEventRoutine// 超时时间

ULONG Reserved[2]// 保留

} HW_STREAM_HEADER, *PHW_STREAM_HEADER

typedef struct _HW_STREAM_INFORMATION {

ULONG NumberOfPossibleInstances// 设备支持的流的数量

KSPIN_DATAFLOW DataFlow// 数据流的方向

BOOLEAN DataAccessible// 数据释放是否能够被看到

ULONG NumberOfFormatArrayEntries// 支持的属性信息

PKSDATARANGE* StreamFormatsArray// 属性信息数组

PVOID ClassReserved[4]

ULONG NumStreamPropArrayEntries// 流媒体的支持属性数组的下标

PKSPROPERTY_SET StreamPropertiesArray// 属性数组

ULONG NumStreamEventArrayEntries

PKSEVENT_SET StreamEventsArray

GUID* Category// Pin范围

GUID* Name// Pin的名字

ULONG MediumsCount

const KSPIN_MEDIUM* Mediums// 媒体类型

BOOLEAN BridgeStream// 允许流进行桥接?

ULONG Reserved[2]

} HW_STREAM_INFORMATION, *PHW_STREAM_INFORMATION

VOID MyGetStreamInfo(IN PHW_STREAM_REQUEST_BLOCK Srb)

{

PHW_STREAM_HEADER StreamHeader = &(Srb->CommandData.StreamBuffer->StreamHeader)

PMY_EXTENSION pDevExt = (PMY_EXTENSION) Srb->HwDeviceExtension

PHW_STREAM_INFORMATION StreamInfo = &(Srb->CommandData.StreamBuffer->StreamInfo)

PAGED_CODE()

ASSERT (Srb->NumberOfBytesToTransfer >=

sizeof (HW_STREAM_HEADER) +

sizeof (HW_STREAM_INFORMATION))

RtlZeroMemory(StreamHeader,

sizeof (HW_STREAM_HEADER) +

sizeof (HW_STREAM_INFORMATION))

StreamHeader->NumberOfStreams = 1

StreamHeader->SizeOfHwStreamInformation = sizeof(HW_STREAM_INFORMATION)

StreamHeader->NumDevPropArrayEntries = pDevExt->ulPropSetSupported

StreamHeader->DevicePropertiesArray = &pDevExt->VideoProcAmpSet

StreamInfo->NumberOfPossibleInstances = 1

StreamInfo->DataFlow = KSPIN_DATAFLOW_OUT

StreamInfo->DataAccessible = TRUE

StreamInfo->NumberOfFormatArrayEntries = pDevExt->ModeSupported

StreamInfo->StreamFormatsArray = &pDevExt->MyStrmModes[0]

StreamInfo->NumStreamPropArrayEntries = NUMBER_VIDEO_STREAM_PROPERTIES

StreamInfo->StreamPropertiesArray = (PKSPROPERTY_SET) VideoStreamProperties

StreamInfo->Name = (GUID *) &PINNAME_VIDEO_CAPTURE

StreamInfo->Category = (GUID *) &PINNAME_VIDEO_CAPTURE

Srb->CommandData.StreamBuffer->StreamHeader.Topology = &Topology

Srb->Status = STATUS_SUCCESS

}

2.2 打开和关闭流: SRB_OPEN_STREAM/SRB_CLOSE_STREAM 命令,此处需要注意的就是一个协商的

过程了,因为此处上层和下层需要来协商进行哪种数据类型的传递。

下面的代码片段屏蔽了硬件的具体相关细节,主要描述和stream class相关的部分:

VOID MyOpenStream(IN PHW_STREAM_REQUEST_BLOCK pSrb)

{

PIRB Irb

ULONG nSize

PMY_EXTENSION pDevExt

PSTREAMEX pStrmEx

PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormat =

(PKS_DATAFORMAT_VIDEOINFOHEADER) pSrb->CommandData.OpenFormat

PKS_VIDEOINFOHEADER pVideoInfoHdrRequested =

&pKSDataFormat->VideoInfoHeader

PAGED_CODE()

Irb = (PIRB) pSrb->SRBExtension

pDevExt = (PMY_EXTENSION) pSrb->HwDeviceExtension

pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension

// 缓存流扩展

pDevExt->pStrmEx = pStrmEx

pSrb->Status = STATUS_SUCCESS

// 确定哪些编号流被打开了。这些编号表明在流信息结构的偏移数组中被调用的

// 流信息适配器

//

// So:

// 0 - Video data from camera

//

// 0 - 从硬件出来的视频数据

switch (pSrb->StreamObject->StreamNumber) {

case 0:

// 检查设备是否在使用

// 找出格式,他们正试图打开第一格式,此处一般采用的是循环对比的方式

// 来找到合适的媒体类型。

if (!AdapterVerifyFormat (pDevExt->ModeSupported, pDevExt->MyStrmModes, pKSDataFormat, pSrb->StreamObject->StreamNumber)) {

pDevExt->pStrmEx = NULL

pSrb->Status = STATUS_INVALID_PARAMETER

return

}

// 初始化流扩展

InitializeStreamExtension(pDevExt, pSrb->StreamObject, pStrmEx)

// 使用我们的安全版本

if (!NT_SUCCESS(RTL_SAFE_KS_SIZE_VIDEOHEADER(pVideoInfoHdrRequested, &nSize))) {

pSrb->Status = STATUS_INTEGER_OVERFLOW

return

}

pStrmEx->pVideoInfoHeader = ExAllocatePoolWithTag(NonPagedPool, nSize, 'macd')

if (pStrmEx->pVideoInfoHeader == NULL) {

ASSERT(pStrmEx->pVideoInfoHeader != NULL)

pDevExt->pStrmEx = NULL

pSrb->Status = STATUS_INSUFFICIENT_RESOURCES

return

}

// 拷贝媒体信息头

RtlCopyMemory(

pStrmEx->pVideoInfoHeader,

pVideoInfoHdrRequested,

nSize)

// 分配硬件需要的资源

pSrb->Status = MyAllocateIsochResource(pDevExt, pSrb->SRBExtension, TRUE)

if (pSrb->Status) {

ExFreePool(pStrmEx->pVideoInfoHeader)

pStrmEx->pVideoInfoHeader = NULL

pDevExt->pStrmEx = NULL

pSrb->Status = STATUS_INSUFFICIENT_RESOURCES

return

}

// 提交控制回调/数据回调函数

pSrb->StreamObject->ReceiveDataPacket = (PHW_RECEIVE_STREAM_DATA_SRB) MyReceiveDataPacket

pSrb->StreamObject->ReceiveControlPacket = (PHW_RECEIVE_STREAM_CONTROL_SRB) MyReceiveCtrlPacket

if(pDevExt->bDevRemoved || pDevExt->bStopIsochCallback) {

pDevExt->bStopIsochCallback = FALSE

pDevExt->bDevRemoved = FALSE

}

// 初始化流扩展句柄信息

break

default:

ASSERT(FALSE)

pDevExt->pStrmEx = NULL

pSrb->Status = STATUS_INVALID_PARAMETER

return

}

pSrb->StreamObject->HwClockObject.ClockSupportFlags = 0

// 我们不使用DMA方式

pSrb->StreamObject->Dma = FALSE

pSrb->StreamObject->StreamHeaderMediaSpecific = sizeof(KS_FRAME_INFO)

// PIO 必须设置为mini驱动缓冲区使用逻辑寻址,我们不打算控制这部分缓冲区

pSrb->StreamObject->Pio = FALSE

// 将最后保存配置

SetCurrentDevicePropertyValues(pDevExt, (PIRB) pSrb->SRBExtension)

ASSERT(pSrb->Status == STATUS_SUCCESS)

}

VOID MyCloseStream(IN PHW_STREAM_REQUEST_BLOCK pSrb)

{

PMY_EXTENSION pDevExt

PSTREAMEX pStrmEx

PIRB pIrb

PAGED_CODE()

pSrb->Status = STATUS_SUCCESS

pDevExt = (PMY_EXTENSION) pSrb->HwDeviceExtension

ASSERT(pDevExt)

// 等待所有的未决工作完成

KeWaitForSingleObject( &pDevExt->PendingWorkItemEvent, Executive, KernelMode, FALSE, NULL )

pStrmEx = (PSTREAMEX)pDevExt->pStrmEx

ASSERT(pStrmEx)

if(!pStrmEx ) {

StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb)

return

}

// pDevExt->Irb可能被释放了,在HwUninitialize()中

// 由于某个原因,所以必须使用下面的

pIrb = (PIRB) pSrb->SRBExtension

// 保存设备扩展信息

MySetPropertyValuesToRegistry(pDevExt)

// 释放硬件资源

MyFreeIsochResource (pDevExt, pIrb, TRUE)

if(pStrmEx->pVideoInfoHeader) {

ExFreePool(pStrmEx->pVideoInfoHeader)

pStrmEx->pVideoInfoHeader = NULL

}

pStrmEx->hMasterClock = 0

// 如果输入读,那么取消掉它们

if(pDevExt->PendingReadCount >0) {

if( InterlockedExchange((PLONG)&pStrmEx->CancelToken, 1 ) == 0 ) {

MyCancelAllPackets(

pDevExt,

&pDevExt->PendingReadCount

)

}

}

pDevExt->pStrmEx = 0

StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb)

}

2.3 属性设置: 属性设置这一部分实际上都是通过特定的属性表来实现的,它和硬件的相关性很大,一般采用DEFINE_KSPROPERTY_TABLE宏来实现对于属性的封装,这一部分可以查阅相应的资料即可实现。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/11295915.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-15
下一篇 2023-05-15

发表评论

登录后才能评论

评论列表(0条)

保存