转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家提出意见,一起讨论!
需要源码的可以与我联系.
针对USB2.0 芯片CY7C68013A+FPGA实现的高速传输应用来写XP下的USB驱动程序。
其实在此芯片供应商CYPRESS的网站上已经可以获得针对它的XP下功能驱动的 .sys .inf 文件,(可以到这里下载http://www.cypress.com/?rID=34870)
下载后得到
安装后得到驱动安装文件:
由于供应商没有提供驱动源码,但为了让自己更明白驱动的开发过程,我们还是在这里自己开发功能驱动层,仅作为学习用。
真实的应用还是用供应商的驱动。
第4步我们给出了功能驱动的源码,假设我们已经得到了ezusbdrv.sys 文件。
接下来我们来测试它是否可用:
(1)编写inf文件。
由于是刚买回来的连接到CY7C8013的EEPROM里没有东西,这样CY7C8013里的增加型8051的代码不能从EEPROM中获得,于是CY7C8013只能从内核启动。
所以得到的PID与VID是默认设置的,即VID:04B4 PID:8613
这里告诉大家一个方法来知道连接到PC的USB设备的VID与PID:
在设备管理器中查看连接的USB设备,即使是没有加载驱动的设备,当你右击设备->属性时,会看到
这里看到的VID与PID是USB总线从CY7C中请求设备信息时得到的。
根据VID与PID我们写出ezusbdrv.inf文件:
; Installation INF for the Cypress Generic USB Driver for Windows XP
; Processor support for x86 based platforms.
;
; (c) Copyright 2011 Cypress Semiconductor Corporation
;
[Version]
Signature="$WINDOWS NT$"
Class=USB
ClassGUID={36FC9E60-C465-11CF-8056-444553540000}
provider=%EZUSBDRV_Provider%
CatalogFile=CYUSB.cat
DriverVer=10/17/2012,3.4.7.027
[SourceDisksNames]
1=%EZUSBDRV%,,,
[SourceDisksFiles]
ezusbdrv.sys = 1
[DestinationDirs]
CYUSB.Files.Ext = 10,System32\Drivers
[ControlFlags]
ExcludeFromSelect = *
[Manufacturer]
%EZUSBDRV_Provider%=Device,NT,NTx86,NTamd64
;for all platforms
[Device]
%VID_04B4&PID_8613.DeviceDesc%=CyUsb, USB\VID_04B4&PID_8613
;for windows 2000 non intel platforms
[Device.NT]
%VID_04B4&PID_8613.DeviceDesc%=CyUsb, USB\VID_04B4&PID_8613
;for x86 platforms
[Device.NTx86]
%VID_04B4&PID_8613.DeviceDesc%=CyUsb, USB\VID_04B4&PID_8613
;for x64 platforms
[Device.NTamd64]
%VID_04B4&PID_8613.DeviceDesc%=CyUsb, USB\VID_04B4&PID_8613
[CYUSB]
CopyFiles=CYUSB.Files.Ext
AddReg=CyUsb.AddReg
[CYUSB.HW]
AddReg=CYUSB.AddReg.Guid
[CYUSB.Services]
Addservice = CYUSB,2,CYUSB.AddService
[CYUSB.NT]
CopyFiles=CYUSB.Files.Ext
AddReg=CyUsb.AddReg
[CYUSB.NT.HW]
AddReg=CYUSB.AddReg.Guid
[CYUSB.NT.Services]
Addservice = CYUSB,2,CYUSB.AddService
[CYUSB.NTx86]
CopyFiles=CYUSB.Files.Ext
AddReg=CyUsb.AddReg
[CYUSB.NTx86.HW]
AddReg=CYUSB.AddReg.Guid
[CYUSB.NTx86.Services]
Addservice = CYUSB,2,CYUSB.AddService
[CYUSB.NTamd64]
CopyFiles=CYUSB.Files.Ext
AddReg=CyUsb.AddReg
[CYUSB.NTamd64.HW]
AddReg=CYUSB.AddReg.Guid
[CYUSB.NTamd64.Services]
Addservice = CYUSB,2,CYUSB.AddService
[CYUSB.AddReg]
; Deprecating - do not use in new apps to identify a CYUSB driver
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,ezusbdrv.sys
; You may optionally include a check for DriverBase in your application to check for a CYUSB driver
HKR,,DriverBase,,ezusbdrv.sys
HKR,"Parameters","MaximumTransferSize",0x10001,4096
HKR,"Parameters","DebugLevel",0x10001,2
HKR,,FriendlyName,,%EZUSBDRV_Description%
[CYUSB.AddService]
DisplayName = %EZUSBDRV_Description%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %10%\System32\Drivers\ezusbdrv.sys
AddReg = CYUSB.AddReg
LoadOrderGroup = Base
[CYUSB.Files.Ext]
ezusbdrv.sys
[CYUSB.AddReg.Guid]
HKR,,DriverGUID,,%EZUSBDRV.GUID%
HKR,,DriverEXECSCRIPT,,%EZUSBDRV.EXECSCRIPT%
[Strings]
EZUSBDRV_Provider = "EZUSBDRV"
CYUSB_Company = "Cypress Semiconductor Corporation"
EZUSBDRV_Description = "Cypress Generic USB Driver"
CYUSB_DisplayName = "Cypress USB Generic"
EZUSBDRV_Install = "Cypress CYUSB Driver Installation Disk"
VID_04B4&PID_8613.DeviceDesc="Cypress USB Generic Driver ezusbdrv(3.4.7.000)"
EZUSBDRV.GUID="{AE18AA60-7F6A-11d4-97DD-00010229B969}"
EZUSBDRV_Unused = "."
EZUSBDRV.EXECSCRIPT="\systemroot\system32\MyDevice\MyDevice.spt"
(2) 此时插入USB,由于没有驱动,会在其它设备下显示“USB device"。
右击“USB Device",更新驱动程序,选择“从列表或指定位置安装”
找到我们的ezusbdrv.sys 与 ezusbdrv.inf所在的文件夹。
i386下有ezusbdrv.inf和ezusbdrv.sys文件。
点下一步时,系统会到i386目录下找所有的.inf文件,并根据.inf里的VID、PID与自己获得的VID、PID比较,
如果发现一样,那么就按这个inf文件来安装驱动。
从上图大家可以看到,如果找到匹配的驱动,系统会把此驱动文件拷贝到C:\WINDOWS\system32\drivers下。
这样下次你再插入此设备时,会自动安装。
从下图中看出我们的驱动安装成功了:
(3) 解释.inf文件节点的在驱动安装中的真实意义
(3、1)在设备管理器中显示的名字
(3、2) 设备类型、制造商的对应
(4) 有时我们为了调试调动而要不断地去更新驱动
此时USB是连接上的,此时你按第二步去更新驱动程序,会发现如下提示:
这是由于在更新驱动时系统会去比较inf文件中的DriverVer字段,如果发现它比之前的版本一样或低,那么就不进行加载了。
所以我们的方法是把DriverVer字段的值改大一点就可以了。
采用WDM结构开发的。
编译环境可参考我 Window XP驱动开发 系列专栏里讲到的文章.
我的所有代码集中在一个文件ezusbsys.c中,现在把代码与大家共享。
由于此文件太长,CSDN上显示不了,我决定把它分为四部分显示,大家把它拼起来即可。
这样我们就得到了 ezusbdrv.sys 文件
(1)我们来看设备创建时IRP_MJ_CREATE对应的回调函数;
DriverObject->MajorFunction[IRP_MJ_CREATE] = Ezusb_Create;
它是当调用CreateFile时调用的。
Ezusb_Create做的事情很简单,主要是创建Link,然后结束IRP的请求(使用IoCompleteRequest),并让派遣函数返回成功;
(可参考我的文章: <<Window XP驱动开发(二十一)Window驱动的派遣函数>>)
(2)我们来看DriverObject->MajorFunction[IRP_MJ_PNP] = Ezusb_DispatchPnp;
它主要负责计算机中即插即用的处理:
(2、1)从栈中从Irp中获得信息; irpStack = IoGetCurrentIrpStackLocation (Irp);
(2、2)获得操作码; fcn = irpStack->MinorFunction;
(2、3)根据操作码对应相应的动作,重点。
动作有:
(2、3、1)IRP_MN_START_DEVICE
对应的回调函数是
NTSTATUS
Ezusb_HandleStartDevice(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
它主要做了以下三件事:
转发IRP_MN_START_DEVICE请求到底层;IoCopyCurrentIrpStackLocationToNext(Irp);
设置完成例程; IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete,(PVOID) &event, TRUE, TRUE, TRUE);
等待完成; KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
(2、3、2)RP_MN_STOP_DEVICE
首先把请求向下传给栈,再调用Ezusb_StopDevice;
Ezusb_DefaultPnpHandler(fdo,Irp);
ntStatus = Ezusb_StopDevice(fdo);
Ezusb_StopDevice主要完成的事情用一个空指针发送URB的配置,这样就关闭了配置并把设备放到了“未配置”状态。
(2、3、3)IRP_MN_REMOVE_DEVICE
NTSTATUS
Ezusb_HandleRemoveDevice(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
(2、3、4)IRP_MN_QUERY_CAPABILITIES;
(3)
第一部分:
#include
#include "stdarg.h"
#include "stdio.h"
//
// Include files needed for USB support
//
#include "usbdi.h"
#include "usbdlib.h"
//
// Include file for the Ezusb Device
//
#include "ezusbsys.h"
//
// incude file containing driver version
//
#include "version.h"
#ifdef DOWNLOAD_KEIL_MONITOR
extern INTEL_HEX_RECORD mon_ext_sio1_ezusb[];
extern INTEL_HEX_RECORD mon_ext_sio1_fx2[];
extern INTEL_HEX_RECORD loader[];
#endif // ifdef DOWNLOAD_KEIL_MONITOR
void
DumpBuffer(PVOID pvBuffer, ULONG length);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This is where the driver is called when the driver is being loaded
by the I/O system. This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
Ezusb_KdPrint (("entering (Ezusb) DriverEntry (Build: %s/%s\n",__DATE__,__TIME__));
//
// Create dispatch points for the various events handled by this
// driver. For example, device I/O control calls (e.g., when a Win32
// application calls the DeviceIoControl function) will be dispatched to
// routine specified below in the IRP_MJ_DEVICE_CONTROL case.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = Ezusb_Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ezusb_Close;
DriverObject->DriverUnload = Ezusb_Unload;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ezusb_ProcessIOCTL;
DriverObject->MajorFunction[IRP_MJ_PNP] = Ezusb_DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = Ezusb_DispatchPower;
DriverObject->DriverExtension->AddDevice = Ezusb_PnPAddDevice;
Ezusb_KdPrint (("exiting (Ezusb) DriverEntry (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_DefaultPnpHandler(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(pdx->StackDeviceObject, Irp);
}
///
// @func Handle completion of a request by a lower-level driver
// @parm Functional device object
// @parm I/O request which has completed
// @parm Context argument supplied to IoSetCompletionRoutine, namely address of
// KEVENT object on which ForwardAndWait is waiting
// @comm This is the completion routine used for requests forwarded by ForwardAndWait. It
// sets the event object and thereby awakens ForwardAndWait.
// @comm Note that it's *not* necessary for this particular completion routine to test
// the PendingReturned flag in the IRP and then call IoMarkIrpPending. You do that in many
// completion routines because the dispatch routine can't know soon enough that the
// lower layer has returned STATUS_PENDING. In our case, we're never going to pass a
// STATUS_PENDING back up the driver chain, so we don't need to worry about this.
NTSTATUS
OnRequestComplete(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp,
IN PKEVENT pev
)
/*++
Routine Description:
Handle completion of a request by a lower-level driver
Arguments:
DriverObject - Functional device object
Irp - I/O request which has completed
pev - Context argument supplied to IoSetCompletionRoutine, namely address of
KEVENT object on which ForwardAndWait is waiting
Return Value:
STATUS_MORE_PROCESSING_REQUIRED
--*/
{
KeSetEvent(pev, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
ForwardAndWait(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
Forward request to lower level and await completion
The only purpose of this routine in this particular driver is to pass down
IRP_MN_START_DEVICE requests and wait for the PDO to handle them.
The processor must be at PASSIVE IRQL because this function initializes
and waits for non-zero time on a kernel event object.
Arguments:
fdo - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
KEVENT event;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
NTSTATUS ntStatus;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Initialize a kernel event object to use in waiting for the lower-level
// driver to finish processing the object.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete,
(PVOID) &event, TRUE, TRUE, TRUE);
ntStatus = IoCallDriver(pdx->StackDeviceObject, Irp);
if (ntStatus == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
ntStatus = Irp->IoStatus.Status;
}
return ntStatus;
}
NTSTATUS
CompleteRequest(
IN PIRP Irp,
IN NTSTATUS status,
IN ULONG info
)
/*++
Routine Description:
Mark I/O request complete
Arguments:
Irp - I/O request in question
status - Standard status code
info Additional information related to status code
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Ezusb_DispatchPnp(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
Process Plug and Play IRPs sent to this device.
Arguments:
fdo - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
ULONG fcn;
NTSTATUS ntStatus;
Ezusb_KdPrint (("Enter Ezusb_DispatchPnp\n"));
if (!LockDevice(fdo))
return CompleteRequest(Irp, STATUS_DELETE_PENDING, 0);
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
fcn = irpStack->MinorFunction;
switch (fcn)
{
case IRP_MN_START_DEVICE:
Ezusb_KdPrint (("IRP_MN_START_DEVICE\n"));
ntStatus = Ezusb_HandleStartDevice(fdo,Irp);
if (ntStatus == STATUS_SUCCESS)
{
pdx->Started = TRUE;
}
break; //IRP_MN_START_DEVICE
case IRP_MN_STOP_DEVICE:
Ezusb_KdPrint (("IRP_MN_STOP_DEVICE\n"));
//
// first pass the request down the stack
//
Ezusb_DefaultPnpHandler(fdo,Irp);
ntStatus = Ezusb_StopDevice(fdo);
break; //IRP_MN_STOP_DEVICE
case IRP_MN_REMOVE_DEVICE:
Ezusb_KdPrint (("IRP_MN_REMOVE_DEVICE\n"))
ntStatus = Ezusb_HandleRemoveDevice(fdo,Irp);
break; //IRP_MN_REMOVE_DEVICE
case IRP_MN_QUERY_CAPABILITIES:
{
//
// This code swiped from Walter Oney. Please buy his book!!
//
PDEVICE_CAPABILITIES pdc = irpStack->Parameters.DeviceCapabilities.Capabilities;
Ezusb_KdPrint (("IRP_MN_QUERY_CAPABILITIES\n"))
// Check to be sure we know how to handle this version of the capabilities structure
if (pdc->Version < 1)
{
ntStatus = Ezusb_DefaultPnpHandler(fdo, Irp);
break;
}
ntStatus = ForwardAndWait(fdo, Irp);
if (NT_SUCCESS(ntStatus))
{ // IRP succeeded
pdc = irpStack->Parameters.DeviceCapabilities.Capabilities;
// setting this field prevents NT5 from notifying the user when the
// device is removed.
pdc->SurpriseRemovalOK = TRUE;
} // IRP succeeded
ntStatus = CompleteRequest(Irp, ntStatus, Irp->IoStatus.Information);
}
break; //IRP_MN_QUERY_CAPABILITIES
//
// All other PNP IRP's are just passed down the stack by the default handler
//
default:
Ezusb_KdPrint (("Passing down unhandled PnP IOCTL 0x%x\n", fcn));
ntStatus = Ezusb_DefaultPnpHandler(fdo, Irp);
} // switch MinorFunction
if (fcn != IRP_MN_REMOVE_DEVICE)
UnlockDevice(fdo);
Ezusb_KdPrint (("Exit Ezusb_DispatchPnp %x\n", ntStatus));
return ntStatus;
}//Ezusb_Dispatch
NTSTATUS
Ezusb_DispatchPower(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
fdo - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION irpStack, nextStack;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
NTSTATUS ntStatus;
Ezusb_KdPrint (("Enter Ezusb_DispatchPower\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
Ezusb_KdPrint (("IRP_MJ_POWER MIN=0x%x Type=0x%x State=0x%x\n",irpStack->MinorFunction,
irpStack->Parameters.Power.Type,
irpStack->Parameters.Power.State.DeviceState));
switch (irpStack->MinorFunction)
{
case IRP_MN_SET_POWER:
switch (irpStack->Parameters.Power.Type)
{
case SystemPowerState:
break; //SystemPowerState
case DevicePowerState:
switch (irpStack->Parameters.Power.State.DeviceState)
{
case PowerDeviceD3:
Ezusb_KdPrint (("IRP_MN_SET_D3\n"));
break;
case PowerDeviceD2:
Ezusb_KdPrint (("IRP_MN_SET_D2\n"));
break;
case PowerDeviceD1:
Ezusb_KdPrint (("IRP_MN_SET_D1\n"));
break;
case PowerDeviceD0:
Ezusb_KdPrint (("IRP_MN_SET_D0\n"));
break;
} // switch on Power.State.DeviceState
break; //DevicePowerState
}// switch on Power.Type
break; //IRP_MN_SET_POWER
case IRP_MN_QUERY_POWER:
// Look at what type of power query this is
switch (irpStack->Parameters.Power.Type)
{
case SystemPowerState:
break; //SystemPowerState
case DevicePowerState:
switch (irpStack->Parameters.Power.State.DeviceState)
{
case PowerDeviceD2:
Ezusb_KdPrint (("IRP_MN_QUERY_D2\n"));
break;
case PowerDeviceD1:
Ezusb_KdPrint (("IRP_MN_QUERY_D1\n"));
break;
case PowerDeviceD3:
Ezusb_KdPrint (("IRP_MN_QUERY_D3\n"));
break;
} //switch on Power.State.DeviceState
break; //DevicePowerState
}//switch on Power.Type
break; //IRP_MN_QUERY_POWER
default:
// A PnP Minor Function was not handled
Ezusb_KdPrint (("Power IOCTL not handled\n"));
} /* switch MinorFunction*/
nextStack = IoGetNextIrpStackLocation(Irp);
ASSERT(nextStack != NULL);
RtlCopyMemory(nextStack, irpStack, sizeof(IO_STACK_LOCATION));
//
// All PNP_POWER messages get passed to the StackDeviceObject that
// we were given in PnPAddDevice.
//
// This stack device object is managed by the USB software subsystem,
// and so this IRP must be propagated to the owning device driver for
// that stack device object, so that driver in turn can perform any
// device state management (e.g., remove its device object, etc.).
//
Ezusb_KdPrint (("Passing Power Irp down\n"));
//
// Notes on passing power IRPs down: Using IoCallDriver() to pass
// down power IRPs worked until Windows 2000. Using this method
// with Win2K causes a blue screen at system shutdown. Because of this,
// I am modifying the driver to use the more correct PoXXX() functions
// to handle power IRPs. Unfortunately, the PoXXX() calls weren't
// added until the kernel until after the release of Windows 95 OSR2.
// So, a driver using these calls will not load on a Windows 95 system.
// If you need to use this driver under Windows 95. then you must
// #define WIN95.
//
#ifdef WIN95
ntStatus = IoCallDriver(pdx->StackDeviceObject, Irp);
#else
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(pdx->StackDeviceObject,Irp);
#endif
//
// If lower layer driver marked the Irp as pending then reflect that by
// calling IoMarkIrpPending.
//
if (ntStatus == STATUS_PENDING)
{
IoMarkIrpPending(Irp);
Ezusb_KdPrint (("Power Irp came back with STATUS_PENDING (%x)\n", ntStatus));
}
else
{
Ezusb_KdPrint (("Power Irp came back, status = %x\n", ntStatus));
} // if ntStatus is PENDING
goto Ezusb_Dispatch_Done;
Ezusb_Dispatch_Done:
Ezusb_KdPrint (("Exit Ezusb_DispatchPower %x\n", ntStatus));
return ntStatus;
}//Ezusb_DispatchPower
VOID
Ezusb_Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
TODO: This is a placeholder for driver writer to add code on unload
Arguments:
DriverObject - pointer to a driver object
Return Value:
None
--*/
{
Ezusb_KdPrint (("enter Ezusb_Unload\n"));
/*
// TODO: Free any global resources allocated in DriverEntry
*/
Ezusb_KdPrint (("exit Ezusb_Unload\n"));
}
NTSTATUS
Ezusb_HandleRemoveDevice(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
ULONG i;
// set the removing flag to prevent any new I/O's
pdx->removing = TRUE;
// brute force - send an abort pipe message to all pipes to cancel any
// pending transfers. this should solve the problem of the driver blocking
// on a REMOVE message because there is a pending transfer.
for (i = 0; i < pdx->Interface->NumberOfPipes; i++)
{
Ezusb_AbortPipe(fdo,(USBD_PIPE_HANDLE) pdx->Interface->Pipes[i].PipeHandle);
}
UnlockDevice(fdo); // once for LockDevice at start of dispatch
UnlockDevice(fdo); // once for initialization during AddDevice
KeWaitForSingleObject(&pdx->evRemove, Executive, KernelMode, FALSE, NULL);
Ezusb_RemoveDevice(fdo);
ntStatus = Ezusb_DefaultPnpHandler(fdo, Irp);
return ntStatus; // lower-level completed IoStatus already
}
NTSTATUS
Ezusb_HandleStartDevice(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
{
NTSTATUS ntStatus;
//
// First let all lower-level drivers handle this request.
//
ntStatus = ForwardAndWait(fdo, Irp);
if (!NT_SUCCESS(ntStatus))
return CompleteRequest(Irp, ntStatus, Irp->IoStatus.Information);
//
// now do whatever we need to do to start the device
//
ntStatus = Ezusb_StartDevice(fdo);
return CompleteRequest(Irp, ntStatus, 0);
}
NTSTATUS
Ezusb_StartDevice(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Initializes a given instance of the Ezusb Device on the USB.
Arguments:
fdo - pointer to the device object for this instance of a
Ezusb Device
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb;
ULONG siz;
Ezusb_KdPrint (("enter Ezusb_StartDevice\n"));
pdx = fdo->DeviceExtension;
pdx->NeedCleanup = TRUE;
/*
// Get some memory from then non paged pool (fixed, locked system memory)
// for use by the USB Request Block (urb) for the specific USB Request we
// will be performing below (a USB device request).
*/
urb = ExAllocatePool( NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb) {
siz = sizeof(USB_DEVICE_DESCRIPTOR);
// Get some non paged memory for the device descriptor contents
deviceDescriptor = ExAllocatePool(NonPagedPool,
siz);
if (deviceDescriptor) {
// Use a macro in the standard USB header files to build the URB
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
siz,
NULL);
// Get the device descriptor
ntStatus = Ezusb_CallUSBD(fdo, urb);
// Dump out the descriptor info to the debugger
if (NT_SUCCESS(ntStatus)) {
Ezusb_KdPrint (("Device Descriptor = %x, len %x\n",
deviceDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
Ezusb_KdPrint (("Ezusb Device Descriptor:\n"));
Ezusb_KdPrint (("-------------------------\n"));
Ezusb_KdPrint (("bLength %d\n", deviceDescriptor->bLength));
Ezusb_KdPrint (("bDescriptorType 0x%x\n", deviceDescriptor->bDescriptorType));
Ezusb_KdPrint (("bcdUSB 0x%x\n", deviceDescriptor->bcdUSB));
Ezusb_KdPrint (("bDeviceClass 0x%x\n", deviceDescriptor->bDeviceClass));
Ezusb_KdPrint (("bDeviceSubClass 0x%x\n", deviceDescriptor->bDeviceSubClass));
Ezusb_KdPrint (("bDeviceProtocol 0x%x\n", deviceDescriptor->bDeviceProtocol));
Ezusb_KdPrint (("bMaxPacketSize0 0x%x\n", deviceDescriptor->bMaxPacketSize0));
Ezusb_KdPrint (("idVendor 0x%x\n", deviceDescriptor->idVendor));
Ezusb_KdPrint (("idProduct 0x%x\n", deviceDescriptor->idProduct));
Ezusb_KdPrint (("bcdDevice 0x%x\n", deviceDescriptor->bcdDevice));
Ezusb_KdPrint (("iManufacturer 0x%x\n", deviceDescriptor->iManufacturer));
Ezusb_KdPrint (("iProduct 0x%x\n", deviceDescriptor->iProduct));
Ezusb_KdPrint (("iSerialNumber 0x%x\n", deviceDescriptor->iSerialNumber));
Ezusb_KdPrint (("bNumConfigurations 0x%x\n", deviceDescriptor->bNumConfigurations));
}
} else {
ntStatus = STATUS_NO_MEMORY;
}
if (NT_SUCCESS(ntStatus)) {
/*
// Put a ptr to the device descriptor in the device extension for easy
// access (like a "cached" copy). We will free this memory when the
// device is removed. See the "Ezusb_RemoveDevice" code.
*/
pdx->DeviceDescriptor = deviceDescriptor;
pdx->Stopped = FALSE;
} else if (deviceDescriptor) {
/*
// If the bus transaction failed, then free up the memory created to hold
// the device descriptor, since the device is probably non-functional
*/
ExFreePool(deviceDescriptor);
pdx->DeviceDescriptor = NULL;
}
ExFreePool(urb);
} else {
// Failed getting memory for the Urb
ntStatus = STATUS_NO_MEMORY;
}
// If the Get_Descriptor call was successful, then configure the device.
if (NT_SUCCESS(ntStatus)) {
ntStatus = Ezusb_ConfigureDevice(fdo);
}
#ifdef DOWNLOAD_KEIL_MONITOR
//
// download the Keil monitor
//
//
// First download loader firmware. The loader firmware implements a vendor
// specific command that will allow us to anchor load to external ram
//
Ezusb_8051Reset(fdo,1);
Ezusb_DownloadIntelHex(fdo,loader);
Ezusb_8051Reset(fdo,0);
//
// Now download the Keil Monitor
//
if (IsFx2(fdo))
{
Ezusb_KdPrint (("**** Downloading FX2 monitor\n"));
Ezusb_DownloadIntelHex(fdo,mon_ext_sio1_fx2);
}
else
{
Ezusb_KdPrint (("**** Downloading EZ-USB monitor\n"));
Ezusb_DownloadIntelHex(fdo,mon_ext_sio1_ezusb);
}
Ezusb_8051Reset(fdo,1);
Ezusb_8051Reset(fdo,0);
#endif // if DOWNLOAD_KEIL_MONITOR
Ezusb_KdPrint (("exit Ezusb_StartDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_RemoveDevice(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Removes a given instance of a Ezusb Device device on the USB.
Arguments:
fdo - pointer to the device object for this instance of a Ezusb Device
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus = STATUS_SUCCESS;
Ezusb_KdPrint (("enter Ezusb_RemoveDevice\n"));
pdx = fdo->DeviceExtension;
if (pdx->DeviceDescriptor)
{
ExFreePool(pdx->DeviceDescriptor);
}
//
// Free up any interface structures in our device extension
//
if (pdx->Interface != NULL)
{
ExFreePool(pdx->Interface);
}
//
// remove the device object's symbolic link
//
if (pdx->NeedCleanup)
{
UNICODE_STRING deviceLinkUnicodeString;
pdx->NeedCleanup = FALSE;
RtlInitUnicodeString (&deviceLinkUnicodeString,
pdx->DeviceLinkNameBuffer);
IoDeleteSymbolicLink(&deviceLinkUnicodeString);
}
IoDetachDevice(pdx->StackDeviceObject);
IoDeleteDevice (fdo);
Ezusb_KdPrint (("exit Ezusb_RemoveDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_StopDevice(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Stops a given instance of a Ezusb Device device on USB.
Arguments:
fdo - pointer to the device object for this instance of a Ezusb Device
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
ULONG siz;
Ezusb_KdPrint (("enter Ezusb_StopDevice\n"));
pdx = fdo->DeviceExtension;
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle, this closes the configuration and puts the device in the 'unconfigured'
// state.
//
siz = sizeof(struct _URB_SELECT_CONFIGURATION);
urb = ExAllocatePool(NonPagedPool,
siz);
if (urb)
{
NTSTATUS status;
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
NULL);
status = Ezusb_CallUSBD(fdo, urb);
Ezusb_KdPrint (("Device Configuration Closed status = %x usb status = %x.\n",
status, urb->UrbHeader.Status));
ExFreePool(urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
Ezusb_KdPrint (("exit Ezusb_StopDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
This routine is called to create a new instance of the device
Arguments:
DriverObject - pointer to the driver object for this instance of Ezusb
PhysicalDeviceObject - pointer to a device object created by the bus
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION pdx;
int instance;
Ezusb_KdPrint(("enter Ezusb_PnPAddDevice\n"));
#define MAX_EZUSB_DEVICES 8
//
// create our functional device object (FDO). This driver supports multiple ezusb devices.
// This loop will look for an available instance number. Keep incrementing the instance
// until a call to Ezusb_CreateDeviceObject succeeds.
//
instance = 0;
do
{
ntStatus = Ezusb_CreateDeviceObject(DriverObject, &deviceObject, instance);
instance++;
} while (!NT_SUCCESS(ntStatus) && (instance < MAX_EZUSB_DEVICES));
if (NT_SUCCESS(ntStatus))
{
pdx = deviceObject->DeviceExtension;
//
// Non plug and play drivers usually create the device object in
// driver entry, and the I/O manager autimatically clears this flag.
// Since we are creating the device object ourselves in response to
// a PnP START_DEVICE IRP, we need to clear this flag ourselves.
//
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// This driver uses direct I/O for read/write requests
//
deviceObject->Flags |= DO_DIRECT_IO;
deviceObject->Flags |= DO_POWER_PAGABLE;
//
//
// store away the Physical device Object
//
pdx->PhysicalDeviceObject=PhysicalDeviceObject;
//
// Attach to the StackDeviceObject. This is the device object that what we
// use to send Irps and Urbs down the USB software stack
//
pdx->StackDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
ASSERT (pdx->StackDeviceObject != NULL);
pdx->LastFailedUrbStatus = 0;
pdx->usage = 1; // locked until RemoveDevice
KeInitializeEvent(&pdx->evRemove,
NotificationEvent,
FALSE); // set when use count drops to zero
}
Ezusb_KdPrint(("exit Ezusb_PnPAddDevice (%x)\n", ntStatus));
return ntStatus;
}
第二部分:
NTSTATUS
Ezusb_CreateDeviceObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT *DeviceObject,
LONG Instance
)
/*++
Routine Description:
Creates a Functional DeviceObject
Arguments:
DriverObject - pointer to the driver object for device
DeviceObject - pointer to DeviceObject pointer to return
created device object.
Instance - instnace of the device create.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
WCHAR deviceLinkBuffer[] = L"\\DosDevices\\Ezusb-0";
UNICODE_STRING deviceLinkUnicodeString;
WCHAR deviceNameBuffer[] = L"\\Device\\Ezusb-0";
UNICODE_STRING deviceNameUnicodeString;
PDEVICE_EXTENSION pdx;
STRING deviceName;
Ezusb_KdPrint(("enter Ezusb_CreateDeviceObject instance = %d\n", Instance));
//
// fix up device names based on Instance
//
deviceLinkBuffer[18] = (USHORT) ('0' + Instance);
deviceNameBuffer[14] = (USHORT) ('0' + Instance);
Ezusb_KdPrint(("Create Device name (%ws)\n", deviceNameBuffer));
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer);
//
//Print out the unicode string
//NOTE: We must first convert the string to Unicode due to a bug in the Debugger that does not allow
// Unicode Strings to be printed to the debug device.
//
deviceName.Buffer = NULL;
ntStatus = RtlUnicodeStringToAnsiString (&deviceName,
&deviceNameUnicodeString,
TRUE);
if (NT_SUCCESS(ntStatus))
{
Ezusb_KdPrint(("Create Device Name (%s)\n", deviceName.Buffer));
RtlFreeAnsiString (&deviceName);
}
else
{
Ezusb_KdPrint(("Unicode to Ansi str failed w/ ntStatus: 0x%x\n",ntStatus));
}
ntStatus = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
DeviceObject);
if (NT_SUCCESS(ntStatus))
{
// Initialize our device extension
pdx = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
RtlCopyMemory(pdx->DeviceLinkNameBuffer,
deviceLinkBuffer,
sizeof(deviceLinkBuffer));
pdx->OpenHandles = 0;
pdx->ConfigurationHandle = NULL;
pdx->DeviceDescriptor = NULL;
pdx->NeedCleanup = FALSE;
pdx->DataRingBuffer = NULL;
pdx->DescriptorRingBuffer = NULL;
pdx->Started = FALSE;
// Initialize our interface
pdx->Interface = NULL;
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer);
Ezusb_KdPrint(("Create DosDevice name (%ws)\n", deviceLinkBuffer));
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString);
}
Ezusb_KdPrint(("exit Ezusb_CreateDeviceObject (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_CallUSBD(
IN PDEVICE_OBJECT fdo,
IN PURB Urb
)
/*++
Routine Description:
Passes a Usb Request Block (URB) to the USB class driver (USBD)
Note that we create our own IRP here and use it to send the request to
the USB software subsystem. This means that this routine is essentially
independent of the IRP that caused this driver to be called in the first
place. The IRP for this transfer is created, used, and then destroyed
in this routine.
However, note that this routine uses the Usb Request Block (urb) passed
in by the caller as the request block for the USB software stack.
Implementation of this routine may be changed depending on the specific
requirements of your driver. For example, while this routine issues a
synchronous request to the USB stack, you may wish to implement this as an
asynchronous request in which you set an IoCompletionRoutine to be called
when the request is complete.
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
Urb - pointer to Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION pdx;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
Ezusb_KdPrint (("enter Ezusb_CallUSBD\n"));
pdx = fdo->DeviceExtension;
// issue a synchronous request (see notes above)
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
pdx->StackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
// Prepare for calling the USB driver stack
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
// Set up the URB ptr to pass to the USB driver stack
nextStack->Parameters.Others.Argument1 = Urb;
Ezusb_KdPrint (("Calling USB Driver Stack\n"));
//
// Call the USB class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
ntStatus = IoCallDriver(pdx->StackDeviceObject,
irp);
Ezusb_KdPrint (("return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING)
{
Ezusb_KdPrint (("Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
Ezusb_KdPrint (("Wait for single object, returned %x\n", status));
}
else
{
ioStatus.Status = ntStatus;
}
Ezusb_KdPrint (("URB status = %x status = %x irp status %x\n",
Urb->UrbHeader.Status, status, ioStatus.Status));
//
// USBD maps the error code for us. USBD uses error codes in its URB
// structure that are more insightful into USB behavior. In order to
// match the NT Status codes, USBD maps its error codes into more general NT
// error categories so higher level drivers can decipher the error codes
// based on standard NT error code definitions.
//
ntStatus = ioStatus.Status;
//
// If the URB status was not USBD_STATUS_SUCCESS, we save a copy of the
// URB status in the device extension. After a failure, another IOCTL,
// IOCTL_EZUSB_GET_LAST_ERROR can be used to retrieve the URB status
// for the most recently failed URB. Of course, this status gets
// overwritten by subsequent failures, but it's better than nothing.
//
if (!(USBD_SUCCESS(Urb->UrbHeader.Status)))
pdx->LastFailedUrbStatus = Urb->UrbHeader.Status;
//
// if ioStatus.Status indicates an error (ie. the IRP failed) then return that.
// If ioStatus.Status indicates success, it is still possible that what we were
// trying to do failed. For example, if the IRP is cancelled, the status returned
// by the I/O manager for the IRP will not indicate an error. In that case, we
// should check the URB status. If it indicates anything other than
// USBD_SUCCESS, then we should return STATUS_UNSUCCESSFUL.
//
if (NT_SUCCESS(ntStatus))
{
if (!(USBD_SUCCESS(Urb->UrbHeader.Status)))
ntStatus = STATUS_UNSUCCESSFUL;
}
Ezusb_KdPrint(("exit Ezusb_CallUSBD (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_ConfigureDevice(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Configures the USB device via USB-specific device requests and interaction
with the USB software subsystem.
Arguments:
fdo - pointer to the device object for this instance of the Ezusb Device
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus;
PURB urb = NULL;
ULONG siz;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
Ezusb_KdPrint (("enter Ezusb_ConfigureDevice\n"));
pdx = fdo->DeviceExtension;
//
// Get memory for the USB Request Block (urb).
//
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb != NULL)
{
//
// Set size of the data buffer. Note we add padding to cover hardware faults
// that may cause the device to go past the end of the data buffer
//
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 16;
// Get the nonpaged pool memory for the data buffer
configurationDescriptor = ExAllocatePool(NonPagedPool, siz);
if (configurationDescriptor != NULL) {
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
sizeof (USB_CONFIGURATION_DESCRIPTOR),/* Get only the configuration descriptor */
NULL);
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (NT_SUCCESS(ntStatus)) {
Ezusb_KdPrint (("Configuration Descriptor is at %x, bytes txferred: %d\n\
Configuration Descriptor Actual Length: %d\n",
configurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength,
configurationDescriptor->wTotalLength));
}//if
} else {
ntStatus = STATUS_NO_MEMORY;
goto Exit_EzusbConfigureDevice;
}//if-else
// Determine how much data is in the entire configuration descriptor
// and add extra room to protect against accidental overrun
siz = configurationDescriptor->wTotalLength + 16;
// Free up the data buffer memory just used
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
// Get nonpaged pool memory for the data buffer
configurationDescriptor = ExAllocatePool(NonPagedPool, siz);
// Now get the entire Configuration Descriptor
if (configurationDescriptor != NULL) {
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
siz, // Get all the descriptor data
NULL);
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (NT_SUCCESS(ntStatus)) {
Ezusb_KdPrint (("Entire Configuration Descriptor is at %x, bytes txferred: %d\n",
configurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
} else {
//Error in getting configuration descriptor
goto Exit_EzusbConfigureDevice;
}//else
} else {
// Failed getting data buffer (configurationDescriptor) memory
ntStatus = STATUS_NO_MEMORY;
goto Exit_EzusbConfigureDevice;
}//if-else
} else {
// failed getting urb memory
ntStatus = STATUS_NO_MEMORY;
goto Exit_EzusbConfigureDevice;
}//if-else
/*
// We have the configuration descriptor for the configuration
// we want.
//
// Now we issue the SelectConfiguration command to get
// the pipes associated with this configuration.
*/
if (configurationDescriptor) {
// Get our pipes
ntStatus = Ezusb_SelectInterfaces(fdo,
configurationDescriptor,
NULL // Device not yet configured
);
} //if
Exit_EzusbConfigureDevice:
// Clean up and exit this routine
if (urb != NULL) {
ExFreePool(urb); // Free urb memory
}//if
if (configurationDescriptor != NULL) {
ExFreePool(configurationDescriptor);// Free data buffer
}//if
Ezusb_KdPrint (("exit Ezusb_ConfigureDevice (%x)\n", ntStatus));
return ntStatus;
}//Ezusb_ConfigureDevice
NTSTATUS
Ezusb_SelectInterfaces(
IN PDEVICE_OBJECT fdo,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PUSBD_INTERFACE_INFORMATION Interface
)
/*++
Routine Description:
Initializes an Ezusb Device with multiple interfaces
Arguments:
fdo - pointer to the device object for this instance of the Ezusb Device
ConfigurationDescriptor - pointer to the USB configuration descriptor containing the interface and endpoint
descriptors.
Interface - pointer to a USBD Interface Information Object
- If this is NULL, then this driver must choose its interface based on driver-specific
criteria, and the driver must also CONFIGURE the device.
- If it is NOT NULL, then the driver has already been given an interface and
the device has already been configured by the parent of this device driver.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus;
PURB urb;
ULONG j;
UCHAR alternateSetting, MyInterfaceNumber;
PUSBD_INTERFACE_INFORMATION interfaceObject;
USBD_INTERFACE_LIST_ENTRY interfaceList[2];
Ezusb_KdPrint (("enter Ezusb_SelectInterfaces\n"));
pdx = fdo->DeviceExtension;
MyInterfaceNumber = SAMPLE_INTERFACE_NBR;
// Search the configuration descriptor for the first interface/alternate setting
interfaceList[0].InterfaceDescriptor =
USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
ConfigurationDescriptor,
-1, // Interface - don't care
-1, // Alternate Setting - don't care
-1, // Class - don't care
-1, // SubClass - don't care
-1); // Protocol - don't care
ASSERT(interfaceList[0].InterfaceDescriptor != NULL);
interfaceList[1].InterfaceDescriptor = NULL;
interfaceList[1].Interface = NULL;
urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor,&interfaceList[0]);
if (!urb)
{
Ezusb_KdPrint ((" USBD_CreateConfigurationRequestEx failed\n"));
}
DumpBuffer(urb, urb->UrbHeader.Length);
interfaceObject = (PUSBD_INTERFACE_INFORMATION) (&(urb->UrbSelectConfiguration.Interface));
/*
// We set up a default max transfer size for the endpoints. Your driver will
// need to change this to reflect the capabilities of your device's endpoints.
*/
for (j=0; jbNumEndpoints; j++)
interfaceObject->Pipes[j].MaximumTransferSize = (64 * 1024) - 1;
ntStatus = Ezusb_CallUSBD(fdo, urb);
DumpBuffer(urb, urb->UrbHeader.Length);
if (NT_SUCCESS(ntStatus) && USBD_SUCCESS(urb->UrbHeader.Status))
{
// Save the configuration handle for this device
pdx->ConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
pdx->Interface = ExAllocatePool(NonPagedPool,
interfaceObject->Length);
// save a copy of the interfaceObject information returned
RtlCopyMemory(pdx->Interface, interfaceObject, interfaceObject->Length);
// Dump the interfaceObject to the debugger
Ezusb_KdPrint (("---------\n"));
Ezusb_KdPrint (("NumberOfPipes 0x%x\n", pdx->Interface->NumberOfPipes));
Ezusb_KdPrint (("Length 0x%x\n", pdx->Interface->Length));
Ezusb_KdPrint (("Alt Setting 0x%x\n", pdx->Interface->AlternateSetting));
Ezusb_KdPrint (("Interface Number 0x%x\n", pdx->Interface->InterfaceNumber));
// Dump the pipe info
for (j=0; jNumberOfPipes; j++)
{
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &pdx->Interface->Pipes[j];
Ezusb_KdPrint (("---------\n"));
Ezusb_KdPrint (("PipeType 0x%x\n", pipeInformation->PipeType));
Ezusb_KdPrint (("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
Ezusb_KdPrint (("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
Ezusb_KdPrint (("Interval 0x%x\n", pipeInformation->Interval));
Ezusb_KdPrint (("Handle 0x%x\n", pipeInformation->PipeHandle));
Ezusb_KdPrint (("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
}
Ezusb_KdPrint (("---------\n"));
}
Ezusb_KdPrint (("exit Ezusb_SelectInterfaces (%x)\n", ntStatus));
return ntStatus;
}/* Ezusb_SelectInterfaces */
NTSTATUS
Ezusb_Read_Write(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code
STATUS_SUCCESS: Read was done successfully
STATUS_INVALID_PARAMETER_3: The Endpoint Index does not specify an IN pipe
STATUS_NO_MEMORY: Insufficient data memory was supplied to perform the READ
This routine fills the status code into the Irp
--*/
{
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PBULK_TRANSFER_CONTROL bulkControl =
(PBULK_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer;
ULONG bufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
PURB urb = NULL;
ULONG urbSize = 0;
ULONG transferFlags = 0;
PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL;
PUSBD_PIPE_INFORMATION pipeInfo = NULL;
USBD_PIPE_HANDLE pipeHandle = NULL;
Ezusb_KdPrint(("enter Ezusb_Read_Write()\n"));
//
// verify that the selected pipe is valid, and get a handle to it. If anything
// is wrong, return an error
//
interfaceInfo = pdx->Interface;
if (!interfaceInfo)
{
Ezusb_KdPrint(("Ezusb_Read_Write() no interface info - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (bulkControl->pipeNum > interfaceInfo->NumberOfPipes)
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeInfo = &(interfaceInfo->Pipes[bulkControl->pipeNum]);
if (!((pipeInfo->PipeType == UsbdPipeTypeBulk) ||
(pipeInfo->PipeType == UsbdPipeTypeInterrupt)))
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeHandle = pipeInfo->PipeHandle;
if (!pipeHandle)
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (bufferLength > pipeInfo->MaximumTransferSize)
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid transfer size - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
//
// allocate and fill in the Usb request (URB)
//
urbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
urb = ExAllocatePool(NonPagedPool,urbSize);
if (!urb)
{
Ezusb_KdPrint(("Ezusb_Read_Write() unable to alloc URB - Exiting\n"));
return STATUS_NO_MEMORY;
}
transferFlags = USBD_SHORT_TRANSFER_OK;
//
// get direction info from the endpoint address
//
if (USB_ENDPOINT_DIRECTION_IN(pipeInfo->EndpointAddress))
transferFlags |= USBD_TRANSFER_DIRECTION_IN;
UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb
(USHORT) urbSize, //size of urb
pipeHandle, //usbd pipe handle
NULL, //TransferBuffer
Irp->MdlAddress, //mdl
bufferLength, //bufferlength
transferFlags, //flags
NULL); //link
//
// Call the USB Stack.
//
ntStatus = Ezusb_CallUSBD(fdo, urb);
//
// If the transfer was successful, report the length of the transfer to the
// caller by setting IoStatus.Information
//
if (NT_SUCCESS(ntStatus))
{
Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
Ezusb_KdPrint(("Successfully transfered 0x%x bytes\n",Irp->IoStatus.Information));
}
//
// free the URB
//
ExFreePool(urb);
return ntStatus;
}
NTSTATUS
Ezusb_Create(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
This is the Entry point for CreateFile calls from user mode apps (apps may open "\\.\Ezusb-x\yyzz"
where yy is the interface number and zz is the endpoint address).
Here is where you would add code to create symbolic links between endpoints
(i.e., pipes in USB software terminology) and User Mode file names. You are
free to use any convention you wish to create these links, although the above
convention offers a way to identify resources on a device by familiar file and
directory structure nomenclature.
Arguments:
fdo - pointer to the device object for this instance of the Ezusb device
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION )fdo->DeviceExtension;
Ezusb_KdPrint(("Enter Ezusb_Create()\n"));
if (!pdx->Started)
{
return STATUS_UNSUCCESSFUL;
}
// increment the open handle counter
pdx->OpenHandles++;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
// Create all the symbolic links here
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
return ntStatus;
}//Ezusb_Create
NTSTATUS
Ezusb_Close(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
Entry point for CloseHandle calls from user mode apps to close handles they have opened
Arguments:
fdo - pointer to the device object for this instance of the Ezusb device
Irp - pointer to an irp
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION )fdo->DeviceExtension;
Ezusb_KdPrint(("Enter Ezusb_Close()\n"));
// decrement the open handle counter
pdx->OpenHandles--;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
return ntStatus;
}//Ezusb_Close
NTSTATUS
Ezusb_ProcessIOCTL(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
This where all the DeviceIoControl codes are handled. You can add more code
here to handle IOCTL codes that are specific to your device driver.
Arguments:
fdo - pointer to the device object for this instance of the Ezusb device.
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION )fdo->DeviceExtension;
ULONG ioControlCode;
NTSTATUS ntStatus;
ULONG length;
PUCHAR pch;
Ezusb_KdPrint (("IRP_MJ_DEVICE_CONTROL\n"));
if (!LockDevice(fdo))
return CompleteRequest(Irp, STATUS_DELETE_PENDING, 0);
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
//
// Handle Ioctls from User mode
//
switch (ioControlCode)
{
case IOCTL_Ezusb_VENDOR_REQUEST:
length = Ezusb_VendorRequest (fdo, (PVENDOR_REQUEST_IN) ioBuffer);
if (length)
{
Irp->IoStatus.Information = length;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
else
{
Irp->IoStatus.Status = STATUS_SUCCESS;
}
Ezusb_KdPrint(("Vendor Request returned %d bytes\n", length));
break;
case IOCTL_Ezusb_ANCHOR_DOWNLOAD:
{
#define CHUNKLENGTH 512
PURB urb = NULL;
int chunkcount;
int chunklength = 1024;
PVOID ioBufferPtr = NULL;
int i;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
Ezusb_KdPrint (("IOCTL_Ezusb_ANCHOR_DOWNLOAD\n"));
if (urb)
{
chunkcount = inputBufferLength / CHUNKLENGTH;
ioBufferPtr = ioBuffer;
for (i=0;iUrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
Ezusb_KdPrint (("ioBuffer: %x | inputBufferLength: %d | outputBufferLength: %d\n",
ioBuffer, inputBufferLength, outputBufferLength));
urb->UrbControlVendorClassRequest.TransferBufferLength = CHUNKLENGTH;
urb->UrbControlVendorClassRequest.TransferBuffer = ioBufferPtr;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = 0xA0;
urb->UrbControlVendorClassRequest.Value = (i * CHUNKLENGTH);
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
(char *) ioBufferPtr += CHUNKLENGTH;
}
ExFreePool(urb);
}
}
break;
case IOCTL_EZUSB_ANCHOR_DOWNLOAD:
{
PANCHOR_DOWNLOAD_CONTROL downloadControl = (PANCHOR_DOWNLOAD_CONTROL) ioBuffer;
Ezusb_KdPrint (("IOCTL_EZUSB_ANCHOR_DOWNLOAD\n"));
//
// check the arguments
//
if (inputBufferLength != sizeof(ANCHOR_DOWNLOAD_CONTROL) ||
outputBufferLength == 0)
{
Ezusb_KdPrint (("Error: Invalid Parameter\n"));
ntStatus = STATUS_INVALID_PARAMETER;
}
else
{
ntStatus = Ezusb_AnchorDownload(fdo,
downloadControl->Offset,
(PUCHAR) MmGetSystemAddressForMdl(Irp->MdlAddress),
outputBufferLength);
}
break;
}
case IOCTL_Ezusb_GET_CURRENT_CONFIG:
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IOCTL_EZUSB_GET_CURRENT_FRAME_NUMBER:
{
ULONG frameNumber = 0;
//
// make sure the output buffer is valid
//
if (outputBufferLength < sizeof(ULONG))
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
frameNumber = Ezusb_GetCurrentFrameNumber (fdo);
if (frameNumber)
{
*((PULONG)ioBuffer) = frameNumber;
Irp->IoStatus.Information = sizeof(ULONG);
Irp->IoStatus.Status = STATUS_SUCCESS;
}
else
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
break;
case IOCTL_Ezusb_RESETPIPE:
{
ULONG pipenum = *((PULONG) ioBuffer);
Irp->IoStatus.Status = Ezusb_ResetPipe(fdo,pipenum);
}
break;
case IOCTL_Ezusb_ABORTPIPE:
{
int pipenum = *((PULONG) ioBuffer);
Ezusb_AbortPipe(fdo,
(USBD_PIPE_HANDLE) pdx->Interface->Pipes[pipenum].PipeHandle);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_Ezusb_GET_PIPE_INFO:
//
// inputs - none
// outputs - we copy the interface information structure that we have
// stored in our device extension area to the output buffer which
// will be reflected to the user mode application by the IOS.
//
length = 0;
pch = (PUCHAR) ioBuffer;
if (pdx->Interface)
{
RtlCopyMemory(pch+length,
(PUCHAR) pdx->Interface,
pdx->Interface->Length);
length += pdx->Interface->Length;
}
Irp->IoStatus.Information = length;
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR:
//
// inputs - pointer to a buffer in which to place descriptor data
// outputs - we put the device descriptor data, if any is returned by the device
// in the system buffer and then we set the length inthe Information field
// in the Irp, which will then cause the system to copy the buffer back
// to the user's buffer
//
length = Ezusb_GetDeviceDescriptor (fdo, ioBuffer);
Ezusb_KdPrint(("Get Device Descriptor returned %d bytes\n", length));
Irp->IoStatus.Information = length;
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_Ezusb_GET_STRING_DESCRIPTOR:
{
PGET_STRING_DESCRIPTOR_IN Input = ioBuffer;
if ((inputBufferLength = sizeof(GET_STRING_DESCRIPTOR_IN)) &&
(outputBufferLength > 0))
{
length = Ezusb_GetStringDescriptor (fdo,
Input->Index,
Input->LanguageId,
ioBuffer,
outputBufferLength);
if (length)
{
Irp->IoStatus.Information = length;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
else
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
}
else
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_Ezusb_GET_CONFIGURATION_DESCRIPTOR:
//
// inputs - pointer to a buffer in which to place descriptor data
// outputs - we put the configuration descriptor data, if any is returned by the device
// in the system buffer and then we set the length in the Information field
// in the Irp, which will then cause the system to copy the buffer back
// to the user's buffer
//
length = Ezusb_GetConfigDescriptor (fdo, ioBuffer, outputBufferLength);
Ezusb_KdPrint(("Get Config Descriptor returned %d bytes\n", length));
Irp->IoStatus.Information = length;
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_Ezusb_SETINTERFACE:
{
PSET_INTERFACE_IN input = ioBuffer;
Irp->IoStatus.Status = SetInterface(fdo,
input->interfaceNum,
input->alternateSetting);
Irp->IoStatus.Status = 0;
}
break;
case IOCTL_Ezusb_RESET:
Ezusb_ResetParentPort(fdo);
break;
case IOCTL_EZUSB_BULK_WRITE:
case IOCTL_EZUSB_BULK_READ:
Irp->IoStatus.Status = Ezusb_Read_Write(fdo,Irp);
break;
case IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST:
Irp->IoStatus.Status = Ezusb_VendorRequest2(fdo,Irp);
break;
case IOCTL_EZUSB_GET_LAST_ERROR:
//
// make sure the output buffer is ok, and then copy the most recent
// URB status from the device extension to it
//
if (outputBufferLength >= sizeof(ULONG))
{
*((PULONG)ioBuffer) = pdx->LastFailedUrbStatus;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(ULONG);
}
else
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
break;
case IOCTL_EZUSB_ISO_READ:
case IOCTL_EZUSB_ISO_WRITE:
Irp->IoStatus.Status = Ezusb_StartIsoTransfer(fdo,Irp);
Irp->IoStatus.Information = 0;
break;
case IOCTL_EZUSB_START_ISO_STREAM:
Irp->IoStatus.Status = Ezusb_StartIsoStream(fdo,Irp);
Irp->IoStatus.Information = 0;
break;
case IOCTL_EZUSB_STOP_ISO_STREAM:
pdx->StopIsoStream = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IOCTL_EZUSB_READ_ISO_BUFFER:
{
ULONG dataBytesToRead;
ULONG descriptorBytesToRead;
ULONG dataBytesRead;
ULONG descriptorBytesRead;
PISO_TRANSFER_CONTROL isoControl =
(PISO_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer;
//
// verify the input and output params
//
if (inputBufferLength != sizeof(ISO_TRANSFER_CONTROL))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
if (outputBufferLength !=
isoControl->PacketCount * (isoControl->PacketSize + sizeof(USBD_ISO_PACKET_DESCRIPTOR)))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
//
// make sure the ring buffers exist
//
if (!(pdx->DataRingBuffer && pdx->DescriptorRingBuffer))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
break;
}
dataBytesToRead = isoControl->PacketCount * isoControl->PacketSize;
dataBytesRead = ReadRingBuffer(pdx->DataRingBuffer,
MmGetSystemAddressForMdl(Irp->MdlAddress),
dataBytesToRead);
Ezusb_KdPrint(("Copied %d bytes from the data ring buffer\n",dataBytesRead));
descriptorBytesToRead = (dataBytesRead / isoControl->PacketSize) * sizeof(USBD_ISO_PACKET_DESCRIPTOR);
descriptorBytesRead = ReadRingBuffer(pdx->DescriptorRingBuffer,
((PUCHAR) MmGetSystemAddressForMdl(Irp->MdlAddress)) + dataBytesRead,
descriptorBytesToRead);
Ezusb_KdPrint(("Copied %d bytes from the desc ring buffer\n",descriptorBytesRead));
Irp->IoStatus.Information = dataBytesRead + descriptorBytesRead;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_EZUSB_GET_DRIVER_VERSION:
{
PEZUSB_DRIVER_VERSION version = (PEZUSB_DRIVER_VERSION) ioBuffer;
if (outputBufferLength >= sizeof(EZUSB_DRIVER_VERSION))
{
version->MajorVersion = EZUSB_MAJOR_VERSION;
version->MinorVersion = EZUSB_MINOR_VERSION;
version->BuildVersion = EZUSB_BUILD_VERSION;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(EZUSB_DRIVER_VERSION);
}
else
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
}
break;
case IOCTL_EZUSB_SET_FEATURE:
{
//
// verify the input params
//
if (inputBufferLength != sizeof(SET_FEATURE_CONTROL))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
Ezusb_SetFeature(fdo,(PSET_FEATURE_CONTROL)Irp->AssociatedIrp.SystemBuffer);
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
}
UnlockDevice(fdo);
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return ntStatus;
}
第三部分:
ULONG
Ezusb_GetDescriptor(
IN PDEVICE_OBJECT fdo,
PVOID DescriptorBuffer,
ULONG BufferLength,
UCHAR DescriptorType
)
/*++
Routine Description:
Gets a device descriptor from the given device object
Arguments:
fdo - pointer to our device object
DescriptorBuffer - buffer to accept the descriptor table
BufferLength - size of the allocated Descriptor Buffer
DescriptorType - Descriptor Type (per USB spec)
Return Value:
Number of valid bytes in data buffer
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb = NULL;
ULONG length = 0;
PDEVICE_EXTENSION pdx = NULL;
Ezusb_KdPrint (("Enter Ezusb_GetDescriptor\n"));
pdx = fdo->DeviceExtension;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb)
{
if (DescriptorBuffer)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
DescriptorType, //descriptor type
0, //index
0, //language ID
DescriptorBuffer, //transfer buffer
NULL, //MDL
BufferLength, //buffer length
NULL); //link
ntStatus = Ezusb_CallUSBD(fdo, urb);
// If successful, get the length from the Urb
if (NT_SUCCESS(ntStatus))
{
length = urb->UrbControlDescriptorRequest.TransferBufferLength;
}
}
else
{
ntStatus = STATUS_INVALID_PARAMETER;
}
Ezusb_KdPrint (("%d bytes of descriptor received\n",length));
ExFreePool(urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
// If unsuccessful, set the length to 0
if (!(NT_SUCCESS(ntStatus)))
{
length = 0;
}
Ezusb_KdPrint (("Leaving Ezusb_GetDescriptor\n"));
return length;
}
ULONG
Ezusb_GetDeviceDescriptor(
IN PDEVICE_OBJECT fdo,
PVOID pvOutputBuffer
)
/*++
Routine Description:
Gets a device descriptor from the given device object
Arguments:
fdo - pointer to the sample device object
Return Value:
Number of valid bytes in data buffer
--*/
{
return (Ezusb_GetDescriptor(fdo,
pvOutputBuffer,
sizeof(USB_DEVICE_DESCRIPTOR),
USB_DEVICE_DESCRIPTOR_TYPE));
}
ULONG
Ezusb_GetConfigDescriptor(
IN PDEVICE_OBJECT fdo,
PVOID pvOutputBuffer,
ULONG ulLength
)
/*++
Routine Description:
Gets a configuration descriptor from the given device object
Arguments:
fdo - pointer to the sample device object
pvOutputBuffer - pointer to the buffer where the data is to be placed
ulLength - length of the buffer
Return Value:
Number of valid bytes in data buffer
--*/
{
return (Ezusb_GetDescriptor(fdo,
pvOutputBuffer,
ulLength,
USB_CONFIGURATION_DESCRIPTOR_TYPE));
}
ULONG
Ezusb_GetOtherSpeedConfigDescriptor(
IN PDEVICE_OBJECT fdo,
PVOID pvOutputBuffer,
ULONG ulLength
)
/*++
Routine Description:
Gets a configuration descriptor from the given device object
Arguments:
fdo - pointer to the sample device object
pvOutputBuffer - pointer to the buffer where the data is to be placed
ulLength - length of the buffer
Return Value:
Number of valid bytes in data buffer
--*/
{
return (Ezusb_GetDescriptor(fdo,
pvOutputBuffer,
ulLength,
7));
}
ULONG
Ezusb_GetStringDescriptor(
IN PDEVICE_OBJECT fdo,
UCHAR Index,
USHORT LanguageId,
PVOID pvOutputBuffer,
ULONG ulLength
)
/*++
Routine Description:
Gets the specified string descriptor from the given device object
Arguments:
fdo - pointer to the sample device object
Index - Index of the string descriptor
LanguageId - Language ID of the string descriptor
pvOutputBuffer - pointer to the buffer where the data is to be placed
ulLength - length of the buffer
Return Value:
Number of valid bytes in data buffer
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb = NULL;
ULONG length = 0;
Ezusb_KdPrint (("Enter Ezusb_GetStringDescriptor\n"));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb)
{
if (pvOutputBuffer)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_STRING_DESCRIPTOR_TYPE, //descriptor type
Index, //index
LanguageId, //language ID
pvOutputBuffer, //transfer buffer
NULL, //MDL
ulLength, //buffer length
NULL); //link
ntStatus = Ezusb_CallUSBD(fdo, urb);
}
else
{
ntStatus = STATUS_INVALID_PARAMETER;
}
// If successful, get the length from the Urb, otherwise set length to 0
if (NT_SUCCESS(ntStatus))
{
length = urb->UrbControlDescriptorRequest.TransferBufferLength;
}
else
length = 0;
Ezusb_KdPrint (("%d bytes of string descriptor received\n",length));
ExFreePool(urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
Ezusb_KdPrint (("Leaving Ezusb_GetStringDescriptor\n"));
return length;
}
NTSTATUS
Ezusb_VendorRequest2(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
{
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PVENDOR_OR_CLASS_REQUEST_CONTROL requestControl =
(PVENDOR_OR_CLASS_REQUEST_CONTROL) Irp->AssociatedIrp.SystemBuffer;
ULONG bufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
PURB urb = NULL;
ULONG urbSize = 0;
ULONG transferFlags = 0;
USHORT urbFunction = 0;
//
// verify that the input parameter is correct (or at least that it's
// the right size
//
if (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
sizeof(VENDOR_OR_CLASS_REQUEST_CONTROL))
{
ntStatus = STATUS_INVALID_PARAMETER;
return ntStatus;
}
//
// allocate and fill in the Usb request (URB)
//
urbSize = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb = ExAllocatePool(NonPagedPool,urbSize);
if (!urb)
{
return STATUS_NO_MEMORY;
}
RtlZeroMemory(urb,urbSize);
transferFlags = USBD_SHORT_TRANSFER_OK;
//
// get direction info from the input parms
//
if (requestControl->direction)
transferFlags |= USBD_TRANSFER_DIRECTION_IN;
//
// the type of request (class or vendor) and the recepient
// (device, interface, endpoint, other) combine to determine the
// URB function. The following ugly code transforms fields in
// the input param into an URB function
//
switch ((requestControl->requestType << 2) | requestControl->recepient)
{
case 0x04:
urbFunction = URB_FUNCTION_CLASS_DEVICE;
break;
case 0x05:
urbFunction = URB_FUNCTION_CLASS_INTERFACE;
break;
case 0x06:
urbFunction = URB_FUNCTION_CLASS_ENDPOINT;
break;
case 0x07:
urbFunction = URB_FUNCTION_CLASS_OTHER;
break;
case 0x08:
urbFunction = URB_FUNCTION_VENDOR_DEVICE;
break;
case 0x09:
urbFunction = URB_FUNCTION_VENDOR_INTERFACE;
break;
case 0x0A:
urbFunction = URB_FUNCTION_VENDOR_ENDPOINT;
break;
case 0x0B:
urbFunction = URB_FUNCTION_VENDOR_OTHER;
break;
default:
return STATUS_INVALID_PARAMETER;
}
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = urbFunction;
urb->UrbControlVendorClassRequest.TransferFlags = transferFlags;
urb->UrbControlVendorClassRequest.TransferBufferLength = bufferLength;
urb->UrbControlVendorClassRequest.TransferBufferMDL = Irp->MdlAddress;
urb->UrbControlVendorClassRequest.Request = requestControl->request;
urb->UrbControlVendorClassRequest.Value = requestControl->value;
urb->UrbControlVendorClassRequest.Index = requestControl->index;
//
// Call the USB Stack.
//
ntStatus = Ezusb_CallUSBD(fdo, urb);
//
// If the transfer was successful, report the length of the transfer to the
// caller by setting IoStatus.Information
//
if (NT_SUCCESS(ntStatus))
{
Irp->IoStatus.Information = urb->UrbControlVendorClassRequest.TransferBufferLength;
Ezusb_KdPrint(("Successfully transfered 0x%x bytes\n",Irp->IoStatus.Information));
}
if (urb)
ExFreePool(urb);
return ntStatus;
}
ULONG
Ezusb_VendorRequest(
IN PDEVICE_OBJECT fdo,
IN PVENDOR_REQUEST_IN pVendorRequest
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb = NULL;
ULONG length = 0;
PUCHAR buffer = NULL;
Ezusb_KdPrint (("Enter Ezusb_VendorRequest - yahoooo\n"));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// fill in the URB
//
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = pVendorRequest->wLength;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = pVendorRequest->bRequest;
urb->UrbControlVendorClassRequest.Value = pVendorRequest->wValue;
urb->UrbControlVendorClassRequest.Index = pVendorRequest->wIndex;
//
// very kludgey. The idea is: if its an IN then a buffer has been passed
// in from user mode. So, use the pointer to the system buffer as the transfer
// buffer. If the transfer is an out, then we need to allocate a transfer
// buffer. If the length of the transfer is 1, then put pVendorRequest->bData
// in the buffer. Otherwise, fill the buffer with an incrementing byte pattern.
// yuch
//
if (pVendorRequest->direction)
{
urb->UrbControlVendorClassRequest.TransferFlags |= USBD_TRANSFER_DIRECTION_IN;
urb->UrbControlVendorClassRequest.TransferBuffer = pVendorRequest;
}
else
{
urb->UrbControlVendorClassRequest.TransferFlags = 0;
buffer = ExAllocatePool(NonPagedPool, pVendorRequest->wLength);
urb->UrbControlVendorClassRequest.TransferBuffer = buffer;
if (pVendorRequest->wLength == 1)
{
buffer[0] = pVendorRequest->bData;
}
else
{
int i;
PUCHAR ptr = buffer;
for (i=0; i < pVendorRequest->wLength; i++)
{
*ptr = (UCHAR) i;
ptr++;
}
}
}
ntStatus = Ezusb_CallUSBD(fdo, urb);
//
// only return a length if this was an IN transaction
//
if (pVendorRequest->direction)
{
length = urb->UrbControlVendorClassRequest.TransferBufferLength;
}
else
{
length = 0;
}
ExFreePool(urb);
if (buffer)
ExFreePool(buffer);
}
return length;
}
NTSTATUS
Ezusb_ResetPipe(
IN PDEVICE_OBJECT fdo,
ULONG PipeNum
)
/*++
Routine Description:
Reset a given USB pipe.
NOTE: this will reset the data toggle on the host as well
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL;
USBD_PIPE_HANDLE pipeHandle = NULL;
PURB urb;
USBD_VERSION_INFORMATION VersionInformation;
Ezusb_KdPrint (("EZUSB.SYS: Reset Pipe \n"));
//
// verify that the selected pipe is valid, and get a handle to it. If anything
// is wrong, return an error
//
interfaceInfo = pdx->Interface;
if (!interfaceInfo)
{
Ezusb_KdPrint(("Ezusb_ResetPipe() no interface info - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (PipeNum > interfaceInfo->NumberOfPipes)
{
Ezusb_KdPrint(("Ezusb_ResetPipe() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeHandle = interfaceInfo->Pipes[PipeNum].PipeHandle;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST));
if (urb)
{
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle = pipeHandle;
//
// kludge. Win98 changed the size of the URB_PIPE_REQUEST.
// Check the USBDI version. If it is prior to win98 (0x101)
// make the structure smaller.
//
USBD_GetUSBDIVersion(&VersionInformation);
if (VersionInformation.USBDI_Version < 0x101)
{
Ezusb_KdPrint(("Ezusb_ResetPipe() Detected OSR2.1\n"));
urb->UrbHeader.Length -= sizeof(ULONG);
}
ntStatus = Ezusb_CallUSBD(fdo, urb);
ExFreePool(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
}
NTSTATUS
Ezusb_AbortPipe(
IN PDEVICE_OBJECT fdo,
IN USBD_PIPE_HANDLE PipeHandle
)
/*++
Routine Description:
cancel pending transfers for a pipe
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PURB urb;
USBD_VERSION_INFORMATION VersionInformation;
Ezusb_KdPrint (("'EZUSB.SYS: Reset Pipe \n"));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST));
if (urb)
{
RtlZeroMemory(urb,sizeof(struct _URB_PIPE_REQUEST));
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
urb->UrbPipeRequest.PipeHandle = PipeHandle;
//
// kludge. Win98 changed the size of the URB_PIPE_REQUEST.
// Check the USBDI version. If it is prior to win98 (0x101)
// make the structure smaller.
//
USBD_GetUSBDIVersion(&VersionInformation);
if (VersionInformation.USBDI_Version < 0x101)
{
Ezusb_KdPrint(("Ezusb_ResetPipe() Detected OSR2.1\n"));
urb->UrbHeader.Length -= sizeof(ULONG);
}
ntStatus = Ezusb_CallUSBD(fdo, urb);
ExFreePool(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
}
ULONG
Ezusb_GetCurrentFrameNumber(
IN PDEVICE_OBJECT fdo
)
{
PURB urb = NULL;
PDEVICE_EXTENSION pdx = NULL;
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG frameNumber = 0;
Ezusb_KdPrint (("Enter Ezusb_GetCurrentFrameNumber\n"));
pdx = fdo->DeviceExtension;
urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER));
if (urb == NULL)
return 0;
RtlZeroMemory(urb,sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER));
urb->UrbHeader.Length = sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER);
urb->UrbHeader.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (NT_SUCCESS(ntStatus))
{
frameNumber = urb->UrbGetCurrentFrameNumber.FrameNumber;
}
ExFreePool(urb);
return frameNumber;
}
NTSTATUS
Ezusb_ResetParentPort(
IN IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Reset the our parent port
Arguments:
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PDEVICE_EXTENSION pdx;
Ezusb_KdPrint (("EZUSB.SYS: enter Ezusb_ResetPort\n"));
pdx = fdo->DeviceExtension;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_RESET_PORT,
pdx->StackDeviceObject,
// pdx->TopOfStackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
Ezusb_KdPrint (("EZUSB.SYS: calling USBD enable port api\n"));
ntStatus = IoCallDriver(pdx->StackDeviceObject,
irp);
Ezusb_KdPrint (("EZUSB.SYS: return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
Ezusb_KdPrint (("EZUSB.SYS: Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
Ezusb_KdPrint (("EZUSB.SYS: Wait for single object, returned %x\n", status));
} else {
ioStatus.Status = ntStatus;
}
//
// USBD maps the error code for us
//
ntStatus = ioStatus.Status;
Ezusb_KdPrint (("EZUSB.SYS: Ezusb_ResetPort (%x)\n", ntStatus));
return ntStatus;
}
ULONG
Ezusb_DownloadTest(
IN PDEVICE_OBJECT fdo,
IN PVENDOR_REQUEST_IN pVendorRequest
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb = NULL;
ULONG length = 0;
ULONG i;
PUCHAR buffer1 = NULL;
PUCHAR buffer2 = NULL;
ULONG CompareCount = 0;
Ezusb_KdPrint (("Enter Ezusb_VendorRequest - yahoooo\n"));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
buffer1 = ExAllocatePool(NonPagedPool, CHUNKLENGTH);
buffer2 = ExAllocatePool(NonPagedPool, CHUNKLENGTH);
for (i=0; i < CHUNKLENGTH; i++)
{
buffer1[i] = (UCHAR) i;
}
if (urb)
{
for (i=0; i < 5120 / CHUNKLENGTH; i++)
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// fill in the URB
//
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = CHUNKLENGTH;
urb->UrbControlVendorClassRequest.TransferBuffer = buffer1;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = 0xA0;
urb->UrbControlVendorClassRequest.Value = (unsigned short) i * CHUNKLENGTH;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
}
for (i=0; i < 5120 / CHUNKLENGTH; i++)
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
RtlZeroMemory(buffer2, CHUNKLENGTH);
//
// fill in the URB
//
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = CHUNKLENGTH;
urb->UrbControlVendorClassRequest.TransferBuffer = buffer2;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = 0xA0;
urb->UrbControlVendorClassRequest.Value = (unsigned short) i * CHUNKLENGTH;
urb->UrbControlVendorClassRequest.Index = 0;
urb->UrbControlVendorClassRequest.TransferFlags |= USBD_TRANSFER_DIRECTION_IN;
ntStatus = Ezusb_CallUSBD(fdo, urb);
CompareCount = RtlCompareMemory(buffer1,buffer2,CHUNKLENGTH);
Ezusb_KdPrint (("%d matched\n",CompareCount))
if (CompareCount != CHUNKLENGTH)
{
Ezusb_KdPrint (("**** Compare Error *****************************************************\n"));
}
}
}
return length;
}
PUSB_CONFIGURATION_DESCRIPTOR
GetConfigDescriptor(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus;
PURB urb;
ULONG siz;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
Ezusb_KdPrint (("Ezusb.SYS: enter Ezusb_GetConfigDescriptor\n"));
pdx = fdo->DeviceExtension;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb) {
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR)+256;
get_config_descriptor_retry2:
configurationDescriptor = ExAllocatePool(NonPagedPool,
siz);
if (configurationDescriptor) {
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
siz,
NULL);
ntStatus = Ezusb_CallUSBD(fdo, urb);
Ezusb_KdPrint (("Ezusb.SYS: Configuration Descriptor = %x, len %x\n",
configurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus) &&
(urb->UrbControlDescriptorRequest.TransferBufferLength >=
sizeof(USB_CONFIGURATION_DESCRIPTOR)) &&
(configurationDescriptor->wTotalLength >=
sizeof(USB_CONFIGURATION_DESCRIPTOR)))
{
//
// The Get Config Descriptor request did not return an error
// AND at least enough data was transferred to fill a Config
// Descriptor AND the Config Descriptor wLength is at least the
// size of a Config Descriptor
//
if (configurationDescriptor->wTotalLength > siz)
{
//
// The request buffer is not big enough to hold the
// entire set of descriptors. Free the current buffer
// and retry with a buffer which should be big enough.
//
siz = configurationDescriptor->wTotalLength;
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
goto get_config_descriptor_retry2;
}
else if (configurationDescriptor->wTotalLength >
urb->UrbControlDescriptorRequest.TransferBufferLength)
{
//
// The request buffer is greater than or equal to the
// Config Descriptor wLength, but less data was transferred
// than wLength. Return NULL to indicate a device error.
//
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
}
//
// else everything is OK with the Config Descriptor, return it.
//
}
else
{
//
// The Get Config Descriptor request returned an error OR
// not enough data was transferred to fill a Config Descriptor
// OR the Config Descriptor wLength is less than the size of
// a Config Descriptor. Return NULL to indicate a device error.
//
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
}
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
Ezusb_KdPrint (("Ezusb.SYS: exit Ezusb_GetConfigDescriptor\n"));
return configurationDescriptor;
}
第四部分:
NTSTATUS
ConfigureDevice(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Configures the USB device via USB-specific device requests and interaction
with the USB software subsystem.
Arguments:
fdo - pointer to the device object for this instance of the Ezusb Device
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
NTSTATUS ntStatus;
PURB urb = NULL;
ULONG numberOfPipes;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
Ezusb_KdPrint (("enter ConfigureDevice\n"));
//
// Get the configuration Descriptor
//
configurationDescriptor = GetConfigDescriptor(fdo);
if (!configurationDescriptor)
{
Ezusb_KdPrint (("Get Configuration Descriptor Failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto CleanupConfigureDevice;
}
#define INTERFACENUMBER 0
#define ALTERNATESETTING 1
//
// Get the interface Descriptor for the interface we want
//
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
configurationDescriptor,
configurationDescriptor,
INTERFACENUMBER,
ALTERNATESETTING,
-1,
-1,
-1);
if (!interfaceDescriptor)
{
ntStatus = STATUS_UNSUCCESSFUL;
goto CleanupConfigureDevice;
}
numberOfPipes = interfaceDescriptor->bNumEndpoints;
//
// Configure the Device, but don't select any interfaces
//
urb = USBD_CreateConfigurationRequestEx(configurationDescriptor, NULL);
if (!urb)
{
Ezusb_KdPrint (("USBD_CreateConfigurationRequestEx Failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto CleanupConfigureDevice;
}
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (NT_SUCCESS(ntStatus))
{
pdx->ConfigurationHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
}
else
{
Ezusb_KdPrint (("Configuration Request Failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto CleanupConfigureDevice;
}
CleanupConfigureDevice:
// Clean up and exit this routine
if (urb != NULL)
{
ExFreePool(urb);
}
if (configurationDescriptor != NULL)
{
ExFreePool(configurationDescriptor);
}
Ezusb_KdPrint (("exit Ezusb_ConfigureDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
SetInterface(
IN PDEVICE_OBJECT fdo,
IN UCHAR InterfaceNumber,
IN UCHAR AlternateSetting
)
{
PUSBD_INTERFACE_INFORMATION interfaceInformation = NULL;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
PURB urb = NULL;
USHORT urbSize;
ULONG numberOfPipes;
ULONG i,j;
NTSTATUS ntStatus;
//
// Get the configuration Descriptor
//
configurationDescriptor = GetConfigDescriptor(fdo);
if (!configurationDescriptor)
{
Ezusb_KdPrint (("Get Configuration Descriptor Failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto CleanupSetInterface;
}
//
// Get the interface Descriptor for the interface we want
//
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
configurationDescriptor,
configurationDescriptor,
InterfaceNumber,
AlternateSetting,
-1,
-1,
-1);
if (!interfaceDescriptor)
{
ntStatus = STATUS_UNSUCCESSFUL;
goto CleanupSetInterface;
}
numberOfPipes = interfaceDescriptor->bNumEndpoints;
Ezusb_KdPrint (("numberOfPipes = %d\n", numberOfPipes));
urbSize = (USHORT)GET_SELECT_INTERFACE_REQUEST_SIZE(numberOfPipes);
Ezusb_KdPrint (("urbSize = %d\n", urbSize));
urb = ExAllocatePool(NonPagedPool,urbSize);
if (!urb)
{
ntStatus = STATUS_NO_MEMORY;
goto CleanupSetInterface;
}
RtlZeroMemory(urb,urbSize);
UsbBuildSelectInterfaceRequest(urb,
urbSize,
pdx->ConfigurationHandle,
InterfaceNumber,
AlternateSetting);
interfaceInformation = &(urb->UrbSelectInterface.Interface);
interfaceInformation->Length = (USHORT)GET_USBD_INTERFACE_SIZE(numberOfPipes);
for (i = 0 ;i < numberOfPipes ;i++ )
{
interfaceInformation->Pipes[i].MaximumTransferSize = (64*1024) -1;
}
ntStatus = Ezusb_CallUSBD(fdo, urb);
//
// If that succeeded, then update the Interface structure
// in the device extension.
//
if (NT_SUCCESS(ntStatus))
{
for (j=0; jNumberOfPipes; j++)
{
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &interfaceInformation->Pipes[j];
Ezusb_KdPrint (("---------\n"));
Ezusb_KdPrint (("PipeType 0x%x\n", pipeInformation->PipeType));
Ezusb_KdPrint (("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
Ezusb_KdPrint (("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
Ezusb_KdPrint (("Interval 0x%x\n", pipeInformation->Interval));
Ezusb_KdPrint (("Handle 0x%x\n", pipeInformation->PipeHandle));
Ezusb_KdPrint (("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
}
if (pdx->Interface)
{
ExFreePool(pdx->Interface);
}
pdx->Interface = NULL;
pdx->Interface = ExAllocatePool(NonPagedPool,interfaceInformation->Length);
if (!pdx->Interface)
{
ntStatus = STATUS_NO_MEMORY;
goto CleanupSetInterface;
}
RtlCopyMemory(pdx->Interface, interfaceInformation, interfaceInformation->Length);
}
CleanupSetInterface:
// Clean up and exit this routine
if (urb != NULL)
{
ExFreePool(urb);
}
if (configurationDescriptor != NULL)
{
ExFreePool(configurationDescriptor);
}
return(ntStatus);
}
#define BYTES_PER_LINE 0x10
void
DumpBuffer(PVOID pvBuffer, ULONG length)
{
int nItems = 0;
char temp[64] = "";
char temp2[64] = "";
ULONG i;
ULONG j;
PUCHAR ptr;
ptr = (PUCHAR) pvBuffer;
for (i = 0; i < ((length + BYTES_PER_LINE - 1) / BYTES_PER_LINE); i++)
{
sprintf(temp,"%04X ",(i*BYTES_PER_LINE));
for (j = 0; j < BYTES_PER_LINE; j++)
{
if (((i * BYTES_PER_LINE) + j) < length)
{
sprintf(temp2,"%02X ",*ptr++);
strcat(temp,temp2);
}
}
// SendMessage (hOutputBox, LB_ADDSTRING, 0, (LPARAM)temp);
Ezusb_KdPrint (("%s\n",temp));
}
}
///
// @func Lock a SIMPLE device object
// @parm Address of our device extension
// @rdesc TRUE if it was possible to lock the device, FALSE otherwise.
// @comm A FALSE return value indicates that we're in the process of deleting
// the device object, so all new requests should be failed
BOOLEAN LockDevice(
IN PDEVICE_OBJECT fdo
)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// Increment use count on our device object
LONG usage = InterlockedIncrement(&pdx->usage);
// AddDevice initialized the use count to 1, so it ought to be bigger than
// one now. HandleRemoveDevice sets the "removing" flag and decrements the
// use count, possibly to zero. So if we find a use count of "1" now, we
// should also find the "removing" flag set.
ASSERT(usage > 1 || pdx->removing);
// If device is about to be removed, restore the use count and return FALSE.
// If we're in a race with HandleRemoveDevice (maybe running on another CPU),
// the sequence we've followed is guaranteed to avoid a mistaken deletion of
// the device object. If we test "removing" after HandleRemoveDevice sets it,
// we'll restore the use count and return FALSE. In the meantime, if
// HandleRemoveDevice decremented the count to 0 before we did our increment,
// its thread will have set the remove event. Otherwise, we'll decrement to 0
// and set the event. Either way, HandleRemoveDevice will wake up to finish
// removing the device, and we'll return FALSE to our caller.
//
// If, on the other hand, we test "removing" before HandleRemoveDevice sets it,
// we'll have already incremented the use count past 1 and will return TRUE.
// Our caller will eventually call UnlockDevice, which will decrement the use
// count and might set the event HandleRemoveDevice is waiting on at that point.
if (pdx->removing)
{
if (InterlockedDecrement(&pdx->usage) == 0)
KeSetEvent(&pdx->evRemove, 0, FALSE);
return FALSE;
}
return TRUE;
}
///
// @func Unlock a SIMPLE device object
// @parm Address of our device extension
// @comm If the use count drops to zero, set the evRemove event because we're
// about to remove this device object.
void UnlockDevice(
PDEVICE_OBJECT fdo
)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
LONG usage = InterlockedDecrement(&pdx->usage);
ASSERT(usage >= 0);
if (usage == 0)
{ // removing device
ASSERT(pdx->removing); // HandleRemoveDevice should already have set this
KeSetEvent(&pdx->evRemove, 0, FALSE);
} // removing device
}
NTSTATUS IsoTransferComplete(
IN PDEVICE_OBJECT bunkfdo,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS ntStatus,status;
PISO_TRANSFER_OBJECT transferObject = (PISO_TRANSFER_OBJECT) Context;
PISO_STREAM_OBJECT streamObject = transferObject->StreamObject;
PDEVICE_OBJECT fdo = streamObject->DeviceObject;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
PIO_STACK_LOCATION nextStack;
PURB urb = transferObject->Urb;
USHORT urbSize = 0;
ULONG i;
Ezusb_KdPrint(("IsoTransferComplete Irp Status 0x%x\n",Irp->IoStatus.Status));
//
// copy the ISO transfer descriptors to the callers buffer. The user mode caller passed
// in a large buffer. That buffer holds both the data and also provides space for the ISO
// descriptors. This way, the caller can verify the status of each ISO packet transmitted
// or sent.
//
RtlCopyMemory((PUCHAR) streamObject->IsoDescriptorBuffer + (transferObject->Frame * sizeof(USBD_ISO_PACKET_DESCRIPTOR)),
urb->UrbIsochronousTransfer.IsoPacket,
(streamObject->FramesPerBuffer * sizeof(USBD_ISO_PACKET_DESCRIPTOR)));
for (i=0;iFramesPerBuffer; i++)
{
Ezusb_KdPrint (("Packet %d length = %d status = %d\n",i,
urb->UrbIsochronousTransfer.IsoPacket[i].Length,urb->UrbIsochronousTransfer.IsoPacket[i].Status));
}
transferObject->Frame += (streamObject->FramesPerBuffer * streamObject->BufferCount);
if (transferObject->Frame < streamObject->NumPackets)
{
Ezusb_KdPrint(("IsoTransferComplete setting up the next transfer at frame %d\n",transferObject->Frame));
//
// reinitialize the URB for the next transfer.
//
urbSize = (USHORT)GET_ISO_URB_SIZE(streamObject->FramesPerBuffer);
RtlZeroMemory(urb,urbSize);
urb->UrbHeader.Length = urbSize;
urb->UrbHeader.Function = URB_FUNCTION_ISOCH_TRANSFER;
urb->UrbIsochronousTransfer.PipeHandle = streamObject->PipeInfo->PipeHandle;
urb->UrbIsochronousTransfer.TransferFlags =
USB_ENDPOINT_DIRECTION_IN(streamObject->PipeInfo->EndpointAddress) ? USBD_TRANSFER_DIRECTION_IN : 0;
urb->UrbIsochronousTransfer.TransferFlags |=
USBD_START_ISO_TRANSFER_ASAP;
urb->UrbIsochronousTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
urb->UrbIsochronousTransfer.TransferBufferLength =
streamObject->PacketSize * streamObject->FramesPerBuffer;
urb->UrbIsochronousTransfer.TransferBuffer =
((PUCHAR) streamObject->TransferBuffer) + (transferObject->Frame * streamObject->PacketSize);
urb->UrbIsochronousTransfer.NumberOfPackets = streamObject->FramesPerBuffer;
for (i=0; iFramesPerBuffer; i++)
{
urb->UrbIsochronousTransfer.IsoPacket[i].Offset = i * streamObject->PacketSize;
urb->UrbIsochronousTransfer.IsoPacket[i].Length = streamObject->PacketSize;
}
//
// initialize the IRP for the next transfer
// cuz lynn says I hafta
//
IoInitializeIrp(Irp,
IoSizeOfIrp((pdx->StackDeviceObject->StackSize + 1)),
(CCHAR)(pdx->StackDeviceObject->StackSize + 1));
nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->Parameters.Others.Argument1 = transferObject->Urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
IoSetCompletionRoutine(Irp,
IsoTransferComplete,
transferObject,
TRUE,
TRUE,
TRUE);
//
// submit the request
//
status = IoCallDriver(pdx->StackDeviceObject,Irp);
Ezusb_KdPrint(("IsoTransferComplete Resubmit Irp Status 0x%x\n",status));
ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
}
else
{
Ezusb_KdPrint(("IsoTransferComplete All done, setting event\n"));
IoFreeIrp(Irp);
ExFreePool(urb);
KeSetEvent(&transferObject->Done,1,FALSE);
ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
}
return ntStatus;
}
NTSTATUS Ezusb_StartIsoTransfer(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
{
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PISO_TRANSFER_CONTROL isoControl =
(PISO_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer;
ULONG bufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG packetSize = 0;
PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL;
PUSBD_PIPE_INFORMATION pipeInfo = NULL;
USBD_PIPE_HANDLE pipeHandle = NULL;
PISO_STREAM_OBJECT streamObject;
ULONG i;
//
// verify that the selected pipe is valid, and get a handle to it. If anything
// is wrong, return an error
//
interfaceInfo = pdx->Interface;
if (!interfaceInfo)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() no interface info - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (isoControl->PipeNum > interfaceInfo->NumberOfPipes)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeInfo = &(interfaceInfo->Pipes[isoControl->PipeNum]);
if (!(pipeInfo->PipeType == UsbdPipeTypeIsochronous))
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeHandle = pipeInfo->PipeHandle;
if (!pipeHandle)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() invalid pipe - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
//
// verify that the FramesPerBuffer and BufferCount parameters are correct.
// A "feature" of this function is that PacketCount must
// be zero modulus (FramesPerBuffer * BufferCount).
//
if (isoControl->PacketCount % (isoControl->FramesPerBuffer * isoControl->BufferCount))
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() Invalid parameter - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
//
// verify that the caller has provided a buffer large enough for
// the requested transfer. The buffer must have room for all of
// the ISO data plus room for an array of ISO Packet Descriptor
// objects (1 for each packet transferred).
//
packetSize = isoControl->PacketSize;
if (bufferLength < (isoControl->PacketCount * (packetSize + sizeof(USBD_ISO_PACKET_DESCRIPTOR))))
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() OutputBuffer too small - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Allocate the streamObject
//
streamObject = ExAllocatePool(NonPagedPool, sizeof(ISO_STREAM_OBJECT));
if (!streamObject)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate stream object - Exiting\n"));
return STATUS_NO_MEMORY;
}
//
// FramesPerBuffer specifies how many frames of ISO data are transferred
// by a single URB. This field corresponds to the NumberOfPackets
// field in the ISO transfer URB (_URB_ISOCH_TRANSFER)
//
streamObject->FramesPerBuffer = isoControl->FramesPerBuffer;
//
// BufferCount specifies how many IRP's are queued to carry out an ISO transfer.
//
streamObject->BufferCount = isoControl->BufferCount;
streamObject->DeviceObject = fdo;
streamObject->PipeInfo = pipeInfo;
streamObject->PacketSize = packetSize;
streamObject->NumPackets = isoControl->PacketCount;
streamObject->TransferBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
streamObject->TransferBufferLength = streamObject->PacketSize * streamObject->NumPackets;
streamObject->IsoDescriptorBuffer = (PUCHAR) streamObject->TransferBuffer + streamObject->TransferBufferLength;
streamObject->TransferObject = ExAllocatePool(NonPagedPool,
sizeof(ISO_TRANSFER_OBJECT) * streamObject->BufferCount);
if (!streamObject->TransferObject)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate transfer object - Exiting\n"));
return STATUS_NO_MEMORY;
}
for (i=0; i < streamObject->BufferCount; i++)
{
InitTransferObject(streamObject,i);
}
for (i=0; i < streamObject->BufferCount; i++)
{
IoCallDriver(pdx->StackDeviceObject,
streamObject->TransferObject[i].Irp);
}
//
// wait for those guys to finish
//
for (i=0; i < streamObject->BufferCount; i++)
{
KeWaitForSingleObject(
&streamObject->TransferObject[i].Done,
Suspended,
KernelMode,
FALSE,
NULL);
}
//
// free the stream and transfer objects
//
ExFreePool(streamObject->TransferObject);
ExFreePool(streamObject);
return STATUS_SUCCESS;
}
NTSTATUS IsoStreamTransferComplete(
IN PDEVICE_OBJECT bunkfdo,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS ntStatus,status;
PISO_TRANSFER_OBJECT transferObject = (PISO_TRANSFER_OBJECT) Context;
PISO_STREAM_OBJECT streamObject = transferObject->StreamObject;
PDEVICE_OBJECT fdo = streamObject->DeviceObject;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
PIO_STACK_LOCATION nextStack;
PURB urb = transferObject->Urb;
USHORT urbSize = 0;
ULONG i;
PUSBD_PIPE_INFORMATION pipeInfo = streamObject->PipeInfo;
Ezusb_KdPrint(("IsoTransferComplete Irp Status 0x%x\n",Irp->IoStatus.Status));
for (i=0;iFramesPerBuffer; i++)
{
Ezusb_KdPrint (("Packet %d length = %d status = %d\n",i,
urb->UrbIsochronousTransfer.IsoPacket[i].Length,urb->UrbIsochronousTransfer.IsoPacket[i].Status));
}
//
// write the transfer descriptors to the descriptor ring buffer
//
WriteRingBuffer(streamObject->DescriptorRingBuffer,
(PUCHAR) &urb->UrbIsochronousTransfer.IsoPacket[0],
(streamObject->FramesPerBuffer * sizeof(USBD_ISO_PACKET_DESCRIPTOR)));
//
// write the transfer data to the data ring buffer
//
WriteRingBuffer(streamObject->DataRingBuffer,
urb->UrbIsochronousTransfer.TransferBuffer,
(streamObject->FramesPerBuffer * streamObject->PacketSize));
//
// If no errors occured, re-initialize and re-submit the IRP/URB
//
if (NT_SUCCESS(Irp->IoStatus.Status) && !pdx->StopIsoStream)
{
urbSize = (USHORT)GET_ISO_URB_SIZE(streamObject->FramesPerBuffer);
RtlZeroMemory(urb,urbSize);
urb->UrbHeader.Length = urbSize;
urb->UrbHeader.Function = URB_FUNCTION_ISOCH_TRANSFER;
urb->UrbIsochronousTransfer.PipeHandle = streamObject->PipeInfo->PipeHandle;
urb->UrbIsochronousTransfer.TransferFlags =
USB_ENDPOINT_DIRECTION_IN(streamObject->PipeInfo->EndpointAddress) ? USBD_TRANSFER_DIRECTION_IN : 0;
urb->UrbIsochronousTransfer.TransferFlags |=
USBD_START_ISO_TRANSFER_ASAP;
urb->UrbIsochronousTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
urb->UrbIsochronousTransfer.TransferBufferLength =
streamObject->PacketSize * streamObject->FramesPerBuffer;
urb->UrbIsochronousTransfer.TransferBuffer =
((PUCHAR) streamObject->TransferBuffer) + (transferObject->Frame * streamObject->PacketSize);
urb->UrbIsochronousTransfer.NumberOfPackets = streamObject->FramesPerBuffer;
for (i=0; iFramesPerBuffer; i++)
{
urb->UrbIsochronousTransfer.IsoPacket[i].Offset = i * streamObject->PacketSize;
urb->UrbIsochronousTransfer.IsoPacket[i].Length = streamObject->PacketSize;
}
//
// initialize the IRP for the next transfer
// cuz lynn says I hafta
//
IoInitializeIrp(Irp,
IoSizeOfIrp((pdx->StackDeviceObject->StackSize + 1)),
(CCHAR)(pdx->StackDeviceObject->StackSize + 1));
nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->Parameters.Others.Argument1 = transferObject->Urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
IoSetCompletionRoutine(Irp,
IsoStreamTransferComplete,
transferObject,
TRUE,
TRUE,
TRUE);
//
// submit the request
//
status = IoCallDriver(pdx->StackDeviceObject,Irp);
//Ezusb_KdPrint(("IsoTransferComplete Resubmit Irp Status 0x%x\n",status));
ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
}
else
{
Ezusb_KdPrint(("IsoTransferComplete All done, setting event\n"));
IoFreeIrp(Irp);
ExFreePool(urb);
streamObject->PendingTransfers--;
if (streamObject->PendingTransfers == 0)
{
ExFreePool(streamObject->TransferBuffer);
ExFreePool(streamObject->TransferObject);
FreeRingBuffer(streamObject->DataRingBuffer);
pdx->DataRingBuffer = NULL;
FreeRingBuffer(streamObject->DescriptorRingBuffer);
pdx->DescriptorRingBuffer = NULL;
ExFreePool(streamObject);
}
ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
}
return ntStatus;
}
NTSTATUS Ezusb_StartIsoStream(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
{
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PISO_TRANSFER_CONTROL isoControl =
(PISO_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer;
PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL;
PUSBD_PIPE_INFORMATION pipeInfo = NULL;
USBD_PIPE_HANDLE pipeHandle = NULL;
PISO_STREAM_OBJECT streamObject;
ULONG i;
//
// verify that the selected pipe is valid, and get a handle to it. If anything
// is wrong, return an error
//
interfaceInfo = pdx->Interface;
if (!interfaceInfo)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() no interface info - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (isoControl->PipeNum > interfaceInfo->NumberOfPipes)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeInfo = &(interfaceInfo->Pipes[isoControl->PipeNum]);
if (!(pipeInfo->PipeType == UsbdPipeTypeIsochronous))
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeHandle = pipeInfo->PipeHandle;
if (!pipeHandle)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() invalid pipe - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Allocate the streamObject
//
streamObject = ExAllocatePool(NonPagedPool, sizeof(ISO_STREAM_OBJECT));
if (!streamObject)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate stream object - Exiting\n"));
return STATUS_NO_MEMORY;
}
//
// FramesPerBuffer specifies how many frames of ISO data are transferred
// by a single URB. This field corresponds to the NumberOfPackets
// field in the ISO transfer URB (_URB_ISOCH_TRANSFER)
//
// MDNISO streamObject->PendingTransfers =
streamObject->FramesPerBuffer = isoControl->FramesPerBuffer;
//
// BufferCount specifies how many IRP's are queued to carry out an ISO transfer.
//
streamObject->PendingTransfers =
streamObject->BufferCount = isoControl->BufferCount;
streamObject->DeviceObject = fdo;
streamObject->PipeInfo = pipeInfo;
streamObject->PacketSize = isoControl->PacketSize;
streamObject->TransferBufferLength = streamObject->PacketSize * streamObject->FramesPerBuffer * streamObject->BufferCount;
streamObject->TransferBuffer = ExAllocatePool(NonPagedPool, streamObject->TransferBufferLength);
if (!streamObject->TransferBuffer)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate transfer buffer - Exiting\n"));
return STATUS_NO_MEMORY;
}
streamObject->DataRingBuffer = AllocRingBuffer(isoControl->PacketCount * isoControl->PacketSize);
if (!streamObject->DataRingBuffer)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate data ring buffer - Exiting\n"));
return STATUS_NO_MEMORY;
}
pdx->DataRingBuffer = streamObject->DataRingBuffer;
streamObject->DescriptorRingBuffer =
AllocRingBuffer(isoControl->PacketCount * sizeof(USBD_ISO_PACKET_DESCRIPTOR));
if (!streamObject->DescriptorRingBuffer)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate descriptor ring buffer - Exiting\n"));
return STATUS_NO_MEMORY;
}
pdx->DescriptorRingBuffer = streamObject->DescriptorRingBuffer;
streamObject->TransferObject = ExAllocatePool(NonPagedPool,
sizeof(ISO_TRANSFER_OBJECT) * streamObject->BufferCount);
if (!streamObject->TransferObject)
{
Ezusb_KdPrint(("Ezusb_StartIsoTransfer() unable to allocate transfer object - Exiting\n"));
return STATUS_NO_MEMORY;
}
for (i=0; i < streamObject->BufferCount; i++)
{
InitTransferObject(streamObject,i);
//
// override the completion routine that InitTransferObject registered
//
IoSetCompletionRoutine(streamObject->TransferObject[i].Irp,
IsoStreamTransferComplete,
&streamObject->TransferObject[i],
TRUE,
TRUE,
TRUE);
}
pdx->StopIsoStream = FALSE;
for (i=0; i < streamObject->BufferCount; i++)
{
IoCallDriver(pdx->StackDeviceObject,
streamObject->TransferObject[i].Irp);
}
return STATUS_SUCCESS;
}
NTSTATUS InitTransferObject(
IN OUT PISO_STREAM_OBJECT streamObject,
IN ULONG index
)
{
PISO_TRANSFER_OBJECT transferObject = &streamObject->TransferObject[index];
PUSBD_PIPE_INFORMATION pipeInfo = streamObject->PipeInfo;
USHORT urbSize = 0;
CCHAR stackSize;
PIO_STACK_LOCATION nextStack = NULL;
PURB urb = NULL;
PIRP irp = NULL;
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) streamObject->DeviceObject->DeviceExtension;
ULONG i;
//
// allocate and prepare the URB
//
urbSize = (USHORT)GET_ISO_URB_SIZE(streamObject->FramesPerBuffer);
urb = ExAllocatePool(NonPagedPool, urbSize);
RtlZeroMemory(urb,urbSize);
urb->UrbHeader.Length = urbSize;
urb->UrbHeader.Function = URB_FUNCTION_ISOCH_TRANSFER;
urb->UrbIsochronousTransfer.PipeHandle = pipeInfo->PipeHandle;
urb->UrbIsochronousTransfer.TransferFlags =
USB_ENDPOINT_DIRECTION_IN(pipeInfo->EndpointAddress) ? USBD_TRANSFER_DIRECTION_IN : 0;
urb->UrbIsochronousTransfer.TransferFlags |=
USBD_START_ISO_TRANSFER_ASAP;
urb->UrbIsochronousTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
urb->UrbIsochronousTransfer.TransferBufferLength =
streamObject->PacketSize * streamObject->FramesPerBuffer;
urb->UrbIsochronousTransfer.TransferBuffer =
((PUCHAR) streamObject->TransferBuffer) + (index * streamObject->PacketSize * streamObject->FramesPerBuffer);
urb->UrbIsochronousTransfer.NumberOfPackets = streamObject->FramesPerBuffer;
//
// setup the ISO packet descriptors
//
for (i=0; iFramesPerBuffer; i++)
{
urb->UrbIsochronousTransfer.IsoPacket[i].Offset = i * streamObject->PacketSize;
urb->UrbIsochronousTransfer.IsoPacket[i].Length = streamObject->PacketSize;
}
stackSize = (CCHAR) (pdx->StackDeviceObject->StackSize + 1);
//
// allocate and prepare the IRP
//
irp = IoAllocateIrp(stackSize, FALSE);
IoInitializeIrp(irp, irp->Size, stackSize);
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
IoSetCompletionRoutine(irp,
IsoTransferComplete,
transferObject,
TRUE,
TRUE,
TRUE);
transferObject->Frame = index * streamObject->FramesPerBuffer;
transferObject->Urb = urb;
transferObject->Irp = irp;
transferObject->StreamObject = streamObject;
KeInitializeEvent(&transferObject->Done, NotificationEvent, FALSE);
return STATUS_SUCCESS;
}
NTSTATUS Ezusb_8051Reset(
PDEVICE_OBJECT fdo,
UCHAR resetBit
)
/*++
Routine Description:
Uses the ANCHOR LOAD vendor specific command to either set or release the
8051 reset bit in the EZ-USB chip.
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
resetBit - 1 sets the 8051 reset bit (holds the 8051 in reset)
0 clears the 8051 reset bit (8051 starts running)
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PURB urb = NULL;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
// toggle the EZ-USB reset bit (harmless on FX2)
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = 1;
urb->UrbControlVendorClassRequest.TransferBuffer = &resetBit;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = CPUCS_REG_EZUSB;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
// toggle the FX2 reset bit (harmless on EZ-USB)
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = 1;
urb->UrbControlVendorClassRequest.TransferBuffer = &resetBit;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = CPUCS_REG_FX2;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
if (urb)
ExFreePool(urb);
return ntStatus;
}
//
// this is the number of bytes of firmware to download per setup transfer.
//
#define CHUNK_SIZE 64
NTSTATUS Ezusb_AnchorDownload(
PDEVICE_OBJECT fdo,
WORD offset,
PUCHAR downloadBuffer,
ULONG downloadSize
)
/*++
Routine Description:
Uses the ANCHOR LOAD vendor specific command to download code to the EZ-USB
device. The actual code is stored as data within the driver binary in the
global 'firmware' which is an EZUSB_FIRMWARE struct included in the file
firmware.c.
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
downloadBuffer - pointer to the firmware image
downloadSize - total size (bytes) of the firmware image to download
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PURB urb = NULL;
int i;
int chunkCount;
PUCHAR ptr = downloadBuffer;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
chunkCount = ((downloadSize + CHUNK_SIZE - 1) / CHUNK_SIZE);
//
// The download will be split into CHUNK_SIZE pieces and
// downloaded with multiple setup transfers. For the Rev B parts
// CHUNK_SIZE should not exceed 64 bytes, as larger transfers can
// result in data corruption when other USB devices are present.
//
for (i = 0; i < chunkCount; i++)
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength =
((i == (chunkCount - 1)) && (downloadSize % CHUNK_SIZE)) ?
(downloadSize % CHUNK_SIZE) :
CHUNK_SIZE;
urb->UrbControlVendorClassRequest.TransferBuffer = ptr;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = (i * CHUNK_SIZE) + offset;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (!NT_SUCCESS(ntStatus))
break;
ptr += CHUNK_SIZE;
}
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
if (urb)
ExFreePool(urb);
return ntStatus;
}
NTSTATUS Ezusb_DownloadIntelHex(
PDEVICE_OBJECT fdo,
PINTEL_HEX_RECORD hexRecord
)
/*++
Routine Description:
This function downloads Intel Hex Records to the EZ-USB device. If any of the hex records
are destined for external RAM, then the caller must have previously downloaded firmware
to the device that knows how to download to external RAM (ie. firmware that implements
the ANCHOR_LOAD_EXTERNAL vendor specific command).
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
hexRecord - pointer to an array of INTEL_HEX_RECORD structures. This array
is terminated by an Intel Hex End record (Type = 1).
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PURB urb = NULL;
PINTEL_HEX_RECORD ptr = hexRecord;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
//
// The download must be performed in two passes. The first pass loads all of the
// external addresses, and the 2nd pass loads to all of the internal addresses.
// why? because downloading to the internal addresses will probably wipe out the firmware
// running on the device that knows how to receive external ram downloads.
//
//
// First download all the records that go in external ram
//
while (ptr->Type == 0)
{
if (!INTERNAL_RAM(ptr->Address))
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = ptr->Length;
urb->UrbControlVendorClassRequest.TransferBuffer = ptr->Data;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_EXTERNAL;
urb->UrbControlVendorClassRequest.Value = ptr->Address;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (!NT_SUCCESS(ntStatus))
break;
}
ptr++;
}
//
// Now download all of the records that are in internal RAM. Before starting
// the download, stop the 8051.
//
Ezusb_8051Reset(fdo,1);
ptr = hexRecord;
while (ptr->Type == 0)
{
if (INTERNAL_RAM(ptr->Address))
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = ptr->Length;
urb->UrbControlVendorClassRequest.TransferBuffer = ptr->Data;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = ptr->Address;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (!NT_SUCCESS(ntStatus))
break;
}
ptr++;
}
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
if (urb)
ExFreePool(urb);
return ntStatus;
}
PRING_BUFFER
AllocRingBuffer(
ULONG Size
)
{
PRING_BUFFER ringBuffer = NULL;
ringBuffer = ExAllocatePool(NonPagedPool, sizeof(RING_BUFFER));
if (!ringBuffer)
return NULL;
ringBuffer->buffer = ExAllocatePool(NonPagedPool, Size);
if (!ringBuffer->buffer)
{
ExFreePool(ringBuffer);
return NULL;
}
ringBuffer->inPtr = ringBuffer->buffer;
ringBuffer->outPtr = ringBuffer->buffer;
ringBuffer->totalSize = Size;
ringBuffer->currentSize = 0;
KeInitializeSpinLock(&ringBuffer->spinLock);
return ringBuffer;
}
VOID
FreeRingBuffer(
PRING_BUFFER ringBuffer
)
{
ExFreePool(ringBuffer->buffer);
ExFreePool(ringBuffer);
}
ULONG
ReadRingBuffer(
PRING_BUFFER ringBuffer,
PUCHAR readBuffer,
ULONG numberOfBytesToRead
)
/*
Routine Description:
This routine reads data from a ring buffer.
Arguments:
ringBuffer - pointer to a ring buffer structure
readBuffer - pointer to a user supplied buffer to transfer data into
numberOfBytesToRead - number of bytes to read from the ring buffer
Return Value:
ULONG - number of bytes read. May be smaller than requested number of bytes.
*/
{
ULONG byteCount;
KIRQL oldIrql;
Ezusb_KdPrint(( "ReadRingBuffer() enter\n"));
if (numberOfBytesToRead > ringBuffer->totalSize)
return 0;
if (ringBuffer->currentSize == 0)
return 0;
if ( numberOfBytesToRead > ringBuffer->currentSize )
byteCount = ringBuffer->currentSize;
else
byteCount = numberOfBytesToRead;
//
// two cases. Read either wraps or it doesn't.
// Handle the non-wrapped case first
//
if ((ringBuffer->outPtr + byteCount - 1) <
(ringBuffer->buffer + ringBuffer->totalSize))
{
Ezusb_KdPrint(( "ReadRingBuffer() about to copy a\n"));
RtlCopyMemory(readBuffer, ringBuffer->outPtr, byteCount);
ringBuffer->outPtr += byteCount;
if (ringBuffer->outPtr == ringBuffer->buffer + ringBuffer->totalSize)
ringBuffer->outPtr = ringBuffer->buffer;
}
// now handle the wrapped case
else
{
ULONG fragSize;
Ezusb_KdPrint(( "ReadRingBuffer() about to copy b\n"));
// get the first half of the read
fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->outPtr;
RtlCopyMemory(readBuffer, ringBuffer->outPtr, fragSize);
// now get the rest
RtlCopyMemory(readBuffer + fragSize, ringBuffer->buffer, byteCount - fragSize);
ringBuffer->outPtr = ringBuffer->buffer + byteCount - fragSize;
}
//
// update the current size of the ring buffer. Use spinlock to insure
// atomic operation.
//
KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
ringBuffer->currentSize -= byteCount;
KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);
Ezusb_KdPrint(( "ReadRingBuffer() exit\n"));
return byteCount;
}
ULONG
WriteRingBuffer(
PRING_BUFFER ringBuffer,
PUCHAR writeBuffer,
ULONG numberOfBytesToWrite
)
/*
Routine Description:
This routine writes data to a ring buffer. If the requested write size exceeds
available space in the ring buffer, then the write is rejected.
Arguments:
ringBuffer - pointer to a ring buffer structure
readBuffer - pointer to a user supplied buffer of data to copy to the ring buffer
numberOfBytesToRead - number of bytes to write to the ring buffer
Return Value:
ULONG - number of bytes written.
*/
{
ULONG byteCount;
KIRQL oldIrql;
if ( numberOfBytesToWrite >
(ringBuffer->totalSize - ringBuffer->currentSize) )
{
Ezusb_KdPrint(( "WriteRingBuffer() OVERFLOW\n"));
return 0;
}
byteCount = numberOfBytesToWrite;
//
// two cases. Write either wraps or it doesn't.
// Handle the non-wrapped case first
//
if ((ringBuffer->inPtr + byteCount - 1) <
(ringBuffer->buffer + ringBuffer->totalSize))
{
RtlCopyMemory(ringBuffer->inPtr, writeBuffer, byteCount);
ringBuffer->inPtr += byteCount;
if (ringBuffer->inPtr == ringBuffer->buffer + ringBuffer->totalSize)
ringBuffer->inPtr = ringBuffer->buffer;
}
// now handle the wrapped case
else
{
ULONG fragSize;
// write the first fragment
fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->inPtr;
RtlCopyMemory(ringBuffer->inPtr, writeBuffer, fragSize);
// now write the rest
RtlCopyMemory(ringBuffer->buffer, writeBuffer + fragSize, byteCount - fragSize);
ringBuffer->inPtr = ringBuffer->buffer + byteCount - fragSize;
}
//
// update the current size of the ring buffer. Use spinlock to insure
// atomic operation.
//
KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql);
ringBuffer->currentSize += byteCount;
KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql);
return byteCount;
}
BOOLEAN IsFx2(
IN PDEVICE_OBJECT fdo
)
/*
Routine Description:
This routine queries the device via a SETUP command to determine if it is
an FX2 chip. In order for this to work, the device must implement the vendor
specific IN SETUP command 0xAC, which returns 1 if the chip is FX2 and 0
otherwise.
Arguments:
fdo - our device object
Return Value:
BOOL - TRUE if FX2, FALSE otherwise
*/
{
NTSTATUS ntStatus;
PURB urb = NULL;
UCHAR transferBuffer[64];
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferFlags = USBD_TRANSFER_DIRECTION_IN ;
urb->UrbControlVendorClassRequest.TransferBufferLength = 1;
urb->UrbControlVendorClassRequest.TransferBuffer = transferBuffer;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = ANCHOR_ISFX2;
urb->UrbControlVendorClassRequest.Value = 0;
urb->UrbControlVendorClassRequest.Index = 0;
Ezusb_KdPrint (("**** About to query ISFX2\n"));
ntStatus = Ezusb_CallUSBD(fdo, urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
if (urb)
ExFreePool(urb);
if (transferBuffer[0] == 1)
{
return TRUE;
}
else
{
return FALSE;
}
}
NTSTATUS Ezusb_SetFeature(
IN PDEVICE_OBJECT fdo,
IN PSET_FEATURE_CONTROL setFeatureControl
)
/*
Routine Description:
This routine performs a Set Feature control transfer
Arguments:
fdo - our device object
setFeatureControl - a data structure that contains the arguments for the
set featire command
Return Value:
NTSTATUS
*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb = NULL;
ULONG length = 0;
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
Ezusb_KdPrint (("Enter Ezusb_SetFeature\n"));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
if (urb)
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_FEATURE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_DEVICE;
urb->UrbControlFeatureRequest.FeatureSelector = setFeatureControl->FeatureSelector;
urb->UrbControlFeatureRequest.Index = setFeatureControl->Index;
ntStatus = Ezusb_CallUSBD(fdo, urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
Ezusb_KdPrint (("Leaving Ezusb_SetFeature\n"));
return ntStatus;
}
在代码中有涉到内存分配的有以下几个方面:
1、URB块
2、传送Buffer
3、获得接口Interface
4、获得配置描述符Descriptor
5、Vender请求
6、ISO_STREAM_OBJECT传送对象
我们都是采用ExAllocatePool来分配内存,关于驱动中内存分配的方法不止这几种,
大家可以参考我的另一篇文章:<<Window XP驱动开发(十九)Window驱动的内存管理>>