资讯详情

将 KMDF 外设驱动程序连接到串行端口

将 KMDF 外部驱动程序连接到串行端口

04/20/2017

本文内容

SerCx2 串行端口管理的外围设备 KMDF 驱动程序需要一些硬件资源来运行设备。 这些资源包括驱动程序打开串行端口逻辑连接所需的信息。 其他资源可能包括中断和一个或多个 GPIO 输入或输出插针。

该驱动程序实现了一组即插即用和电源管理事件回调函数。 如果要注册这些函数 KMDF,驱动程序的 EvtDriverDeviceAdd 调用事件回调函数 WdfDeviceInitSetPnpPowerEventCallbacks 方法。 该框架调用电源管理事件的回调功能,通知驱动程序电源设备电源状态的变化。 包括这些函数 EvtDevicePrepareHardware 该函数执行使设备能够访问驱动程序所需的任何操作。

串行连接的外围设备进入未初始化 D0 驱动程序框架调用设备电源状态后 EvtDevicePrepareHardware 告知外围设备驱动程序准备设备使用函数。 在此调用期间,驱动程序收到两个硬件资源列表作为输入参数。 ResourcesRaw 参数是 原始资源列表 WDFCMRESLIST 对象句柄, ResourcesTranslated 参数是已 转换资源列表 WDFCMRESLIST 对象句柄。 已翻译的资源包括与外围设备建立驱动程序逻辑连接所需的资源 连接 ID 。

下面的代码示例演示 EvtDevicePrepareHardware 函数如何从 ResourcesTranslated 连接参数 ID。

BOOLEAN fConnectionIdFound = FALSE;

LARGE_INTEGER connectionId = 0;

ULONG resourceCount;

NTSTATUS status = STATUS_SUCCESS;

resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);

// Loop through the resources and save the relevant ones.

for (ULONG ix = 0; ix < resourceCount; ix )

{

PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;

pDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, ix);

if (pDescriptor == NULL)

{

status = E_POINTER;

break;

}

// Determine the resource type.

switch (pDescriptor->Type)

{

case CmResourceTypeConnection:

{

// Check against the expected connection types.

UCHAR Class = pDescriptor->u.Connection.Class;

UCHAR Type = pDescriptor->u.Connection.Type;

if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL)

{

if (Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_UART)

{

if (fConnectionIdFound == FALSE)

{

// Save the connection ID.

connectionId.LowPart = pDescriptor->u.Connection.IdLowPart;

connectionId.HighPart = pDescriptor->u.Connection.IdHighPart;

fConnectionIdFound = TRUE;

}

}

}

if (Class == CM_RESOURCE_CONNECTION_CLASS_GPIO)

{

// Check for GPIO pin resource.

...

}

}

break;

case CmResourceTypeInterrupt:

{

// Check for interrupt resource.

...

}

break;

default:

// Don't care about other resource descriptors.

break;

}

}

前面的代码示例将串行连接外围设备 ID 在名称的变量中复制 connectionId 。

如何连接以下代码示例? ID 将其合并到设备路径名称中,可用于打开外围设备的逻辑连接。 该设备的路径名称将资源中心识别为系统组件,以获问外围设备所需的参数。

// Use the connection ID to create the full device path name.

DECLARE_UNICODE_STRING_SIZE(szDeviceName, RESOURCE_HUB_PATH_SIZE);

status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&szDeviceName,

connectionId.LowPart,

connectionId.HighPart);

if (!NT_SUCCESS(status))

{

// Error handling

...

}

在上述代码示例中, 声明 _ unicode _ 字符串 _ 大小 宏创建了一个已初始化的名字 UNICODE _ 字符串 变量的声明 szDeviceName ,该变量的缓冲区足以包含资源中心使用的格式的设备路径名称。 此宏在 Ntdef 在头文件中定义。 资源 _ 中心 _ 路径 _ 大小 常量指定设备路径名中的字节数。 资源 _ 中心 " _ _ _ 从 _ ID 创建路径" 宏从连接 ID 生成设备路径名。 资源 _在 Reshub 在头文件中定义集线器 _ 路径 _ 大小 和 资源 _ 中心 _ _ _ 从 _ ID 创建路径 。

下面的代码示例用设备路径名打开一个文件句柄 (SerialIoTarget) 连接到串行连接的外围设备。

// Open the peripheral device on the serial port as a remote I/O target.

WDF_IO_TARGET_OPEN_PARAMS openParams;

WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&openParams,

&szDeviceName,

(GENERIC_READ | GENERIC_WRITE));

openParams.ShareAccess = 0;

openParams.CreateDisposition = FILE_OPEN;

openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL;

status = WdfIoTargetOpen(SerialIoTarget, &openParams);

if (!NT_SUCCESS(status))

{

// Error handling

...

}

在上述代码示例中, _ _ _ _ _ _ _ 通过 _ NAME 函数打开的 wdf io target open params INIT 初始化 wdf _ io _ target _ open _ params 结构使驱动程序能够打开连接到串行连接外围设备的逻辑连接。 SerialIoTarget变量是框架 i/o 目标对象的 WDFIOTARGET 句柄。 这句柄是从前对的 WdfIoTargetCreate 通过调用方法获得的方法未在示例中显示。 如果对 WdfIoTargetOpen 如果方法调用成功,可以使用驱动程序 SerialIoTarget 句柄将 i/o 请求将其发送到外围设备。

在 EvtDriverDeviceAdd 在事件回调函数中,可以调用外围设备驱动程序 WdfRequestCreate 该方法将框架请求对象分配给驱动程序。 驱动程序将来不再需要对象时调用 WdfObjectDelete 删除对象的方法。 从 WdfRequestCreate 调用获得的框架请求对象,将 i/o 请求将其发送到外围设备。 读取、写入或同步发送 IOCTL 请求将调用驱动程序 WdfIoTargeSendReadSynchronously、 WdfIoTargetSendWriteSynchronously或 WdfIoTargetSendIoctlSynchronously 方法。

在下面的代码示例中,驱动程序调用 WdfIoTargetSendWriteSynchronously 以将 IRP _ MJ _ 写入 请求同步发送到外围设备。 在此示例的开头, pBuffer 变量指向包含要写入外围设备的数据的非分页缓冲区, dataSize 变量指定此数据的大小(以字节为单位)。

ULONG_PTR bytesWritten;

NTSTATUS status;

// Describe the input buffer.

WDF_MEMORY_DESCRIPTOR memoryDescriptor;

WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, pBuffer, dataSize);

// Configure the write request to time out after 2 seconds.

WDF_REQUEST_SEND_OPTIONS requestOptions;

WDF_REQUEST_SEND_OPTIONS_INIT(&requestOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT);

requestOptions.Timeout = WDF_REL_TIMEOUT_IN_SEC(2);

// Send the write request synchronously.

status = WdfIoTargetSendWriteSynchronously(SerialIoTarget,

SerialRequest,

&memoryDescriptor,

NULL,

&requestOptions,

&bytesWritten);

if (!NT_SUCCESS(status))

{

// Error handling

...

}

前面的代码示例执行以下操作:

Wdf _ 内存 _ 说明符 _ INIT _ BUFFER函数调用初始化 memoryDescriptor 变量,该变量是描述输入缓冲区的 WDF _ 内存 _ 说明符结构。 以前,驱动程序调用了例程(如 ExAllocatePoolWithTag ),以便从非分页池分配缓冲区,并将写入数据复制到此缓冲区。

Wdf _ 请求 _ 发送 _ 选项 _ INIT函数调用初始化 requestOptions 变量,该变量是一个 WDF _ 请求 _ 发送 _ 选项结构,其中包含写入请求的可选设置。 在此示例中,结构将请求配置为在两秒钟后未完成时超时。

对 WdfIoTargetSendWriteSynchronously 方法的调用会将写入请求发送到外围设备。 在写操作完成或超时后,方法会同步返回。如有必要,另一个驱动程序线程可以调用 WdfRequestCancelSentRequest 来取消请求。

在 WdfIoTargetSendWriteSynchronously 调用中,驱动程序提供名为的变量 SerialRequest ,该变量是驱动程序之前创建的框架请求对象的句柄。 WdfIoTargetSendWriteSynchronously 调用之后,驱动程序通常应调用 WdfRequestReuse方法来准备要再次使用的 framework 请求对象。

标签: 插针连接器组件

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台