📄 drvpnp.c
字号:
#include "zjHMCFUsb.h"
#include "DrvIoCode.h"
/************************************************************************************************
* Function Type : private
* Parameter : fdo - pointer to the device object for this instance
* of the device.
* ConfigurationDescriptor - pointer to the USB configuration
* descriptor containing the interface and endpoint
* descriptors.
* Return Value : NT status code
* Description : 从配置描述符里取得接点和端点信息
*************************************************************************************************/
NTSTATUS hwSelectInterface
(
IN PDEVICE_OBJECT fdo,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
{
PDEVICE_EXTENSION dx;
NTSTATUS ntStatus;
PURB urb = NULL;
ULONG i;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
PUSBD_INTERFACE_INFORMATION Interface = NULL;
USHORT siz;
hwDbgPrint(" -->>>>>> hwSelectInterface()\n");
hwDbgPrint ( "fdo = 0x%x\n",fdo );
hwDbgPrint ( "ConfigurationDescriptor = 0x%x\n",ConfigurationDescriptor );
dx = fdo->DeviceExtension;
//------------------------------------------------------------------
// BulkUsb驱动只支持一个接点,我们必须解析这个
// 接点的配置描述符并记下管道信息
//------------------------------------------------------------------
urb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &siz);
if (urb)
{
//------------------------------------------------------------------
// USBD_ParseConfigurationDescriptorEx()搜索一个给定的配置描述符
// 并且返回一个匹配指定搜索标准的接点描述符
// 这个设备我们只支持一个接点
//------------------------------------------------------------------
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
ConfigurationDescriptor,
ConfigurationDescriptor, //search from start of config descriptro
-1, // interface number not a criteria; we only support one interface
-1, // not interested in alternate setting here either
-1, // interface class not a criteria
-1, // interface subclass not a criteria
-1); // interface protocol not a criteria
if ( !interfaceDescriptor )
{
hwDbgPrint("ParseConfigurationDescriptorEx() failed, Returning STATUS_INSUFFICIENT_RESOURCES\n");
FreeIfAllocated(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
Interface = &urb->UrbSelectConfiguration.Interface;
// 为管道信息结构体申请空间
dx->PipeState = (PzjHMCFUsb_PIPESTATE)ExAllocatePool ( NonPagedPool,
Interface->NumberOfPipes * sizeof ( zjHMCFUsb_PIPESTATE ));
if ( !dx->PipeState )
{
FreeIfAllocated(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory ( dx->PipeState,
Interface->NumberOfPipes * sizeof ( zjHMCFUsb_PIPESTATE ) );
//------------------------------------------------------------------
// 在此执行所有管道的初始化工作
// 我们将设置最大传输大小和任何被使用的管道
//------------------------------------------------------------------
for (i=0; i< Interface->NumberOfPipes; i++)
{
Interface->Pipes[i].MaximumTransferSize = dx->MaximumTransferSize;
dx->PipeState[i].fPipeOpened = FALSE;
}
UsbBuildSelectConfigurationRequest ( urb,
(USHORT) siz,
ConfigurationDescriptor);
ntStatus = hwCallUSBD(fdo, urb);
}
else
{
hwDbgPrint("USBD_CreateConfigurationRequest() failed, returning STATUS_INSUFFICIENT_RESOURCES\n");
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus))
{
// Save the configuration handle for this device
dx->UsbConfigurationHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
dx->UsbInterface = ExAllocatePool ( NonPagedPool,
Interface->Length);
if (dx->UsbInterface)
{
ULONG j;
// save a copy of the interface information returned
RtlCopyMemory(dx->UsbInterface, Interface, Interface->Length);
// Dump the interface to the debugger
hwDbgPrint("/**************** Interface information ****************/\n");
hwDbgPrint("NumberOfPipes %d\n", dx->UsbInterface->NumberOfPipes);
hwDbgPrint("Length %d\n", dx->UsbInterface->Length);
hwDbgPrint("Alt Setting 0x%x\n", dx->UsbInterface->AlternateSetting);
hwDbgPrint("Interface Number %d\n", dx->UsbInterface->InterfaceNumber);
hwDbgPrint("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
dx->UsbInterface->Class,
dx->UsbInterface->SubClass,
dx->UsbInterface->Protocol);
// Dump the pipe info
for (j=0; j<Interface->NumberOfPipes; j++)
{
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &dx->UsbInterface->Pipes[j];
hwDbgPrint("---------\n");
hwDbgPrint("PipeType 0x%x\n", pipeInformation->PipeType);
hwDbgPrint("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress);
hwDbgPrint("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize);
hwDbgPrint("Interval 0x%x\n", pipeInformation->Interval);
hwDbgPrint("Handle 0x%x\n", pipeInformation->PipeHandle);
hwDbgPrint("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize);
}
hwDbgPrint("/****************************************************/\n");
}
}
if (urb)
{
FreeIfAllocated(urb);
}
hwDbgPrint("hwSelectInterface(), ntStatus 0x%x-->>>>>>\n",ntStatus);
return ntStatus;
}
/************************************************************************************************
* Function Type : private
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* Return Value : NT status code
* Description : 初始化一个指定的USB设备实例,并且选择和保存这个配置
*************************************************************************************************/
NTSTATUS hwConfigureDevice(IN PDEVICE_OBJECT fdo)
{
PDEVICE_EXTENSION dx;
NTSTATUS ntStatus;
PURB urb;
ULONG siz;
hwDbgPrint(" -->>>>>> hwConfigureDevice(fdo=0x%x)\n",fdo);
dx = fdo->DeviceExtension;
hwASSERT( dx->UsbConfigurationDescriptor == NULL );
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if ( !urb )
return STATUS_INSUFFICIENT_RESOURCES;
//------------------------------------------------------------------
// 指定DescriptorType为USB_CONFIGURATION_DESCRIPTOR_TYPE来调用
// UsbBuildGetDescriptorRequest()获取所有的接点、端点、厂商
// 等信息,配置信息也将被获得。
// 调用者必须申请足够大的缓冲来保存这些信息,否则
// 数据将被切割而不报任何错误。
// 因此先猜想一个合适的"siz"大小,调用UsbBuildGetDescriptorRequest()
// 后获取实际需要的"siz"大小,然后以实际的"siz"大小
// 重新调用UsbBuildGetDescriptorRequest()
//------------------------------------------------------------------
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512;
// 当dx->UsbConfigurationDescriptor有足够大的缓冲以至于
// 数据不被切割时我们将退出这个循环
while( 1 )
{
dx->UsbConfigurationDescriptor = ExAllocatePool(NonPagedPool, siz);
if ( !dx->UsbConfigurationDescriptor )
{
FreeIfAllocated(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
UsbBuildGetDescriptorRequest
(
urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
dx->UsbConfigurationDescriptor,
NULL,
siz,
NULL
);
ntStatus = hwCallUSBD(fdo, urb);
hwDbgPrint("hwCallUSBD() Configuration Descriptor = 0x%x, len %d\n",
dx->UsbConfigurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength);
// if we got some data see if it was enough.
// NOTE: we may get an error in URB because of buffer overrun
if (urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&
dx->UsbConfigurationDescriptor->wTotalLength > siz)
{
siz = dx->UsbConfigurationDescriptor->wTotalLength;
FreeIfAllocated(dx->UsbConfigurationDescriptor);
}
else
{
break; // 我们已经获取了配置描述符
}
} // end, while (retry loop )
FreeIfAllocated(urb);
hwASSERT( dx->UsbConfigurationDescriptor );
//------------------------------------------------------------------
// 我们已经获得了配置描述符
// 现在我们要选择配置命令来获取配置相关联的
// 管道信息
//------------------------------------------------------------------
ntStatus = hwSelectInterface(fdo, dx->UsbConfigurationDescriptor);
hwDbgPrint("hwConfigureDevice (%x)-->>>>>>\n", ntStatus);
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* Return Value : NT status code
* Description : 这个例程是处理IRP_MJ_PNP,初始化一个给定USB设备的实例
* USB客户驱动像我们一样设置好URBs(USB请求包)发送请求
* 到主控制驱动(HCD)。URB结构定义了一个包含所有可能
* 的命令发送给USB设备。这里,我们请求驱动的描述符并
* 保存它,并且配制我们的设备
* Note : 1、先让下层驱动处理这个irp
* 2、分配URB非分页内存
* 3、构建一个获取描述符的URB请求
* 4、调用hwCallUSBD()函数递交这个URB
* 5、释放URB所占的非分页内存空间
* 6、调用hwConfigureDevice()获取设备配置信息
*************************************************************************************************/
NTSTATUS hwStartDevice( IN PDEVICE_OBJECT fdo, IN PIRP Irp, IN PNTSTATUS p_ntStatus)
{
PDEVICE_EXTENSION dx;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb;
ULONG siz;
NTSTATUS waitStatus;
KEVENT startDeviceEvent;
hwDbgPrint(" -->>>>>> hwStartDevice(fdo = 0x%x)\n",fdo);
dx = fdo->DeviceExtension;
(*p_ntStatus) = STATUS_SUCCESS;
//------------------------------------------------------------------
//这个IPR是在分配资源之后发送的,这个设备最近被
//枚举并第一次启动,或者是在停止后重新启动将会
// 收到这个IRP
// 先让FDO处理这个IRP
//------------------------------------------------------------------
KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine ( Irp,
hwIRPCompletionRoutine,
&startDeviceEvent, // pass the event to the completion routine as the Context
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation
(*p_ntStatus) = IoCallDriver(dx->LowerDeviceObject,Irp);
if ((*p_ntStatus) == STATUS_PENDING)
{
waitStatus = KeWaitForSingleObject(
&startDeviceEvent,
Suspended,
KernelMode,
FALSE,
NULL);
(*p_ntStatus) = Irp->IoStatus.Status;
}
if (!NT_SUCCESS((*p_ntStatus)))
{
goto done;
}
//现在我们准备启动我们的设备
urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb)
{
siz = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = ExAllocatePool(NonPagedPool,siz);
hwDbgPrint("ExAllocatePool() for deviceDescriptor %s\n",
deviceDescriptor?"SUCCESS":"FAILED");
if ( !deviceDescriptor )
{
// 分配deviceDescriptor内存失败
(*p_ntStatus) = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
UsbBuildGetDescriptorRequest
(
urb, //Points to an URB to be formatted for a get descriptor request to the HCD. The caller must allocate nonpaged pool for this URB.
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -