Files
bds.mr.devmgr/src.devmgr/drv/usb/mr.drv.usb.winusb.pas
T
2026-01-08 19:04:51 +01:00

643 lines
25 KiB
ObjectPascal

unit mr.drv.usb.winusb;
interface
uses
Windows,
mr.drv.usb.types,
mr.drv.usb;
type
TWinUsbInterfaceHandle = THandle;
TWinUsbDriver = class( TUsbDriver)
public
class procedure Scan( ScanCallback: TScanCallback); override;
protected
fWinUsbHandle : TWinUsbInterfaceHandle;
public
procedure Open; override;
procedure Close; override;
function GetDescriptor( DescriptorType : byte;
Index : byte;
LanguageID : word;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal) : boolean; override;
function GetAssociatedInterface
(
InterfaceIndex : byte;
var InterfaceHandle
): boolean; override;
function QueryInterfaceSettings
(
AlternateSettingNumber : byte;
var AlternateSettingDescriptor : TUsbAlternateSettingDescriptor
): boolean; override;
function QueryPipe
(
AlternateInterfaceNumber : byte;
PipeIndex : byte;
var PipeInformation : TusbPipeInformation
): boolean; override;
function ControlTransfer
(
SetupPacket : TUsbSetupPacket;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped = nil
): boolean; override;
function AbortPipe( PipeID : byte): boolean; override;
function FlushPipe( PipeID : byte): boolean; override;
function ResetPipe( PipeID : byte): boolean; override;
function ReadPipe
(
PipeID : byte;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped = nil
): boolean; override;
function WritePipe
(
PipeID : byte;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped = nil
): boolean; override;
function GetOverlappedResult
(
Overlapped : POverlapped;
var Transferred : cardinal;
Wait : boolean
): boolean; override;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
end;
implementation
uses
System.SysUtils,
System.StrUtils,
System.Win.ComObj,
WinApi.ActiveX,
WinApi.PropSys,
WinApi.FunctionDiscovery,
mr.dev.manager;
type
TWinUsb_Initialze =
function( DeviceHandle : THandle;
var WinUsbHandle : TWinUsbInterfaceHandle) : BOOL cdecl stdcall;
TWinUsb_Free =
function( WinUsbHandle : TWinUsbInterfaceHandle) : BOOL cdecl stdcall;
TWinUsb_QueryDeviceInformation =
function( WinUsbHandle : TWinUsbInterfaceHandle;
InformationType : cardinal;
var BufferLength : cardinal;
var Buffer) : bool cdecl stdcall;
TWinUsb_GetDescriptor =
function( InterfaceHandle : TWinUsbInterfaceHandle;
DescriptorType : byte;
Index : byte;
LanguageID : word;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal) : bool cdecl stdcall;
TWinUsb_GetAssociatedInterface =
function( WinUsbHandle : TWinUsbInterfaceHandle;
InterfaceIndex : byte;
var InterfaceHandle : TWinUsbInterfaceHandle): bool cdecl stdcall;
TWinUsb_QueryInterfaceSettings =
function( InterfaceHandle : TWinUsbInterfaceHandle;
AlternateSettingNumber : byte;
var AlternateSettingDescriptor : TUsbAlternateSettingDescriptor): bool cdecl stdcall;
TWinUsb_QueryPipe =
function( InterfaceHandle : TWinUsbInterfaceHandle;
AlternateInterfaceNumber : byte;
PipeIndex : byte;
var PipeInformation : TusbPipeInformation): bool; cdecl stdcall;
TWinUsb_GetCurrentAlternateSetting =
function( InterfaceHandle : TWinUsbInterfaceHandle;
var SettingNumber : byte): bool cdecl stdcall;
TWinUsb_SetCurrentAlternateSetting =
function( InterfaceHandle : TWinUsbInterfaceHandle;
SettingNumber : byte): bool cdecl stdcall;
TWinUsb_ControlTransfer =
function( InterfaceHandle : TWinUsbInterfaceHandle;
SetupPacket : TUsbSetupPacket;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped): bool cdecl stdcall;
TWinUsb_ResetPipe =
function( InterfaceHandle : TWinUsbInterfaceHandle;
PipeId : byte): bool cdecl stdcall;
TWinUsb_AbortPipe =
function( InterfaceHandle : TWinUsbInterfaceHandle;
PipeId : byte): bool cdecl stdcall;
TWinUsb_FlushPipe =
function( InterfaceHandle : TWinUsbInterfaceHandle;
PipeId : byte): bool cdecl stdcall;
TWinUsb_ReadPipe =
function( InterfaceHandle : TWinUsbInterfaceHandle;
PipeID : byte;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped): bool cdecl stdcall;
TWinUsb_WritePipe =
function( InterfaceHandle : TWinUsbInterfaceHandle;
PipeID : byte;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped): bool cdecl stdcall;
TWinUsb_GetOverlappedResult =
function( InterfaceHandle : TWinUsbInterfaceHandle;
Overlapped : POverlapped;
var Transferred : cardinal;
Wait : bool): bool cdecl stdcall;
var
hWinUsb : HMODULE = 0;
WinUsb_Initialize : TWinUsb_Initialze = nil;
WinUsb_Free : TWinUsb_Free = nil;
WinUsb_QueryDeviceInformation : TWinUsb_QueryDeviceInformation = nil;
WinUsb_GetDescriptor : TWinUsb_GetDescriptor = nil;
WinUsb_GetAssociatedInterface : TWinUsb_GetAssociatedInterface = nil;
WinUsb_QueryInterfaceSettings : TWinUsb_QueryInterfaceSettings = nil;
WinUsb_GetCurrentAlternateSetting : TWinUsb_GetCurrentAlternateSetting = nil;
WinUsb_SetCurrentAlternateSetting : TWinUsb_SetCurrentAlternateSetting = nil;
WinUsb_ControlTransfer : TWinUsb_ControlTransfer = nil;
WinUsb_QueryPipe : TWinUsb_QueryPipe = nil;
WinUsb_ResetPipe : TWinUsb_ResetPipe = nil;
WinUsb_AbortPipe : TWinUsb_AbortPipe = nil;
WinUsb_FlushPipe : TWinUsb_FlushPipe = nil;
WinUsb_ReadPipe : TWinUsb_ReadPipe = nil;
WinUsb_WritePipe : TWinUsb_WritePipe = nil;
WinUsb_GetOverlappedResult : TWinUsb_GetOverlappedResult = nil;
{ TWinUsbDriver }
// ================================================================================================
// After Construction
// ================================================================================================
procedure TWinUsbDriver.AfterConstruction;
begin
inherited;
fWinUsbHandle := INVALID_HANDLE_VALUE;
fDeviceHandle := INVALID_HANDLE_VALUE;
end;
// ================================================================================================
// Before Destrruction
// ================================================================================================
procedure TWinUsbDriver.BeforeDestruction;
begin
Close;
fWinUsbHandle := INVALID_HANDLE_VALUE;
fDeviceHandle := INVALID_HANDLE_VALUE;
inherited;
end;
// ================================================================================================
// Open
//
// DevicePath must be in the form of:
// \\?\USB#VID_04B4&PID_8613#6&26c545a4&0&1#{CDDE880F-898A-4DAB-B0EA-51FBA32C1D82}
// ================================================================================================
procedure TWinUsbDriver.Open;
var
path : WideString;
len : cardinal;
buf : byte;
i : integer;
begin
path := WideString(fDevicePath);
// ---------------------------------------------------------------
// Prepare device path
// ---------------------------------------------------------------
// strip device description
{ i := Pos('#', path);
if i > 0 then
path := Copy( path, 1, i-1);
path := ReplaceStr(path,'\','#');
path := '\\?\'+path+'#'+fInterfaceGuid;
}
// ---------------------------------------------------------------
// open
// ---------------------------------------------------------------
if fDeviceHandle = INVALID_HANDLE_VALUE then
begin
fWinUsbHandle := 0;
fDeviceHandle := CreateFile( PWideChar(path),
GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_READ + FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,
0);
if fDeviceHandle <> INVALID_HANDLE_VALUE then
begin
// -------------------------------------------------------------------
// Initialize WinUSB
// -------------------------------------------------------------------
WinUsb_Initialize( fDeviceHandle, fWinUsbHandle);
// -------------------------------------------------------------------
// Determine bus speed
// -------------------------------------------------------------------
len := 1;
if WinUsb_QueryDeviceInformation( fWinUsbHandle, 1, len, buf) then
case buf of
1: fDeviceSpeed := LowSpeed;
2: fDeviceSpeed := FullSpeed;
3: fDeviceSpeed := HighSpeed;
end;
// -------------------------------------------------------------------
// Get device descriptor
// -------------------------------------------------------------------
WinUsb_GetDescriptor( fWinUsbHandle,
DSCR_DEVICE,
0, // index (not used)
0, // language id (not used)
@fDeviceDescriptor,
sizeof(TUsbDeviceDescriptor),
len);
end;
{
b :=
i := 0;
while WinUsb_QueryInterfaceSettings( fWinUsbHandle, i, sss) do
INC(i);
b := WinUsb_GetCurrentAlternateSetting( fWinUsbHandle, setting);
b := WinUsb_SetCurrentAlternateSetting( fWinUsbHandle, setting);
}
end
end;
// ================================================================================================
// Close
// ================================================================================================
procedure TWinUsbDriver.Close;
begin
if fWinUsbHandle <> INVALID_HANDLE_VALUE then
begin
WinUsb_Free( fWinUsbHandle);
fWinUsbHandle := INVALID_HANDLE_VALUE;
end;
if fDeviceHandle <> INVALID_HANDLE_VALUE then
begin
CloseHandle( fDeviceHandle);
fDeviceHandle := INVALID_HANDLE_VALUE;
end
end;
// ================================================================================================
// Get Descriptor
// ================================================================================================
function TWinUsbDriver.GetDescriptor( DescriptorType : byte;
Index : byte;
LanguageID : word;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal) : boolean;
begin
result := false;
if Assigned( WinUsb_GetDescriptor) then
result := WinUsb_GetDescriptor( fWinUsbHandle,
DescriptorType,
Index,
LanguageID,
Buffer,
BufferLength,
Transferred);
end;
// ================================================================================================
// Get Associated Interface
// ================================================================================================
function TWinUsbDriver.GetAssociatedInterface( InterfaceIndex: byte;
var InterfaceHandle): boolean;
begin
result := false
end;
// ================================================================================================
// QueryInterfaceSettings
// ================================================================================================
function TWinUsbDriver.QueryInterfaceSettings( AlternateSettingNumber : byte;
var AlternateSettingDescriptor: TUsbAlternateSettingDescriptor): boolean;
begin
result := false;
if Assigned( WinUsb_QueryInterfaceSettings) then
result := WinUsb_QueryInterfaceSettings( fWinUsbHandle,
AlternateSettingNumber,
AlternateSettingDescriptor);
end;
// ================================================================================================
// Query Pipe
// ================================================================================================
function TWinUsbDriver.QueryPipe( AlternateInterfaceNumber: byte;
PipeIndex : byte;
var PipeInformation : TusbPipeInformation): boolean;
begin
result := false;
if Assigned( WinUsb_QueryPipe) then
result := WinUsb_QueryPipe( fWinUsbHandle,
AlternateInterfaceNumber,
PipeIndex,
PipeInformation);
end;
// ================================================================================================
// Abort Pipe
// ================================================================================================
function TWinUsbDriver.AbortPipe( PipeID: byte): boolean;
begin
if Assigned( WinUsb_AbortPipe)
then result := WinUsb_AbortPipe( fWinUsbHandle, PipeID)
else result := false
end;
// ================================================================================================
// Flush Pipe
// ================================================================================================
function TWinUsbDriver.FlushPipe( PipeID: byte): boolean;
begin
if Assigned( WinUsb_FlushPipe)
then result := WinUsb_FlushPipe( fWinUsbHandle, PipeID)
else result := false
end;
// ================================================================================================
// Reset Pipe
// ================================================================================================
function TWinUsbDriver.ResetPipe( PipeID: byte): boolean;
begin
if Assigned( WinUsb_ResetPipe)
then result := WinUsb_ResetPipe( fWinUsbHandle, PipeID)
else result := false
end;
// ================================================================================================
// Read Pipe
// ================================================================================================
function TWinUsbDriver.ReadPipe( PipeID : byte;
Buffer : pointer;
BufferLength: cardinal;
var Transferred : cardinal;
Overlapped : POverlapped): boolean;
begin
result := false;
if Assigned( WinUsb_ReadPipe) then
result := WinUsb_ReadPipe( fWinUsbHandle,
PipeID,
Buffer,
BufferLength,
Transferred,
Overlapped)
end;
// ================================================================================================
// Write Pipe
// ================================================================================================
function TWinUsbDriver.WritePipe( PipeID : byte;
Buffer : pointer;
BufferLength: cardinal;
var Transferred : cardinal;
Overlapped : POverlapped): boolean;
begin
result := false;
if Assigned( WinUsb_WritePipe) then
result := WinUsb_WritePipe( fWinUsbHandle,
PipeID,
Buffer,
BufferLength,
Transferred,
Overlapped)
end;
// ================================================================================================
// Control Transfer
// ================================================================================================
function TWinUsbDriver.ControlTransfer( SetupPacket : TUsbSetupPacket;
Buffer : pointer;
BufferLength : cardinal;
var Transferred : cardinal;
Overlapped : POverlapped): boolean;
begin
result := false;
if Assigned( WinUsb_ControlTransfer) then
result := WinUsb_ControlTransfer( fWinUsbHandle,
SetupPacket,
Buffer,
BufferLength,
Transferred,
Overlapped)
end;
// ================================================================================================
// Get Overlapped Result
// ================================================================================================
function TWinUsbDriver.GetOverlappedResult( Overlapped : POverlapped;
var Transferred : cardinal;
Wait : boolean): boolean;
begin
result := false;
if Assigned( WinUsb_GetOverlappedResult) then
result := WinUsb_GetOverlappedResult( fWinUsbHandle, Overlapped, Transferred, Wait)
end;
// ================================================================================================
// scan
// ================================================================================================
class procedure TWinUsbDriver.Scan( ScanCallback: TScanCallback);
var
dsc : IFunctionDiscovery;
fcts : IFunctionInstanceCollection;
fct : IFunctionInstance;
props : IPropertyStore;
propv : TPropVariant;
hr : HResult;
cat : PWChar;
cnt : DWORD;
i : integer;
s : string;
begin
try
dsc := CreateComObject( CLSID_FunctionDiscovery) as IFunctionDiscovery;
cat := FCTN_CATEGORY_PNP;
hr := dsc.GetInstanceCollection(cat, nil, true, fcts);
if Succeeded(hr) and Succeeded(fcts.GetCount(cnt)) then
for i := 0 to cnt -1 do
if Succeeded( fcts.Item(i,fct)) then
begin
fct.OpenPropertyStore( STGM_READ, props);
if Succeeded( props.GetValue(PKEY_Device_Service, propv)) then
begin
if 'WinUSB' = propv.pwszVal then
begin
// \\?\USB#VID_04B4&PID_8613#6&26c545a4&0&1#{CDDE880F-898A-4DAB-B0EA-51FBA32C1D82}
props.GetValue( PKEY_Device_InstanceId, propv);
s := StringReplace( propv.pwszVal, '\', '#', [rfReplaceAll]);
s := Uppercase('\\?\' +s +'#' +fInterfaceGuid);
ScanCallback( s)
end
end
end
finally
end
end;
// @@@: Initialization / finalization +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Initialization / finalization
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
var
x: pointer = nil;
initialization
CoInitialize(x);
hWinUsb := LoadLibrary('WinUsb.dll');
if hWinUsb <> 0 then
begin
@WinUsb_Initialize := GetProcAddress( hWinUsb, 'WinUsb_Initialize');
@WinUsb_Free := GetprocAddress( hWinUsb, 'WinUsb_Free');
@WinUsb_QueryDeviceInformation := GetProcAddress( hWinUsb, 'WinUsb_QueryDeviceInformation');
@WinUsb_GetDescriptor := GetProcAddress( hWinUsb, 'WinUsb_GetDescriptor');
@WinUsb_GetCurrentAlternateSetting := GetProcAddress( hWinUsb, 'WinUsb_GetCurrentAlternateSetting');
@WinUsb_SetCurrentAlternateSetting := GetProcAddress( hWinUsb, 'WinUsb_SetCurrentAlternateSetting');
@WinUsb_GetAssociatedInterface := GetProcAddress( hWinUsb, 'WinUsb_GetAssociatedInterface');
@WinUsb_QueryInterfaceSettings := GetProcAddress( hWinUsb, 'WinUsb_QueryInterfaceSettings');
@WinUsb_ControlTransfer := GetProcAddress( hWinUsb, 'WinUsb_ControlTransfer');
@WinUsb_QueryPipe := GetProcAddress( hWinUsb, 'WinUsb_QueryPipe');
@WinUsb_ResetPipe := GetProcAddress( hWinUsb, 'WinUsb_ResetPipe');
@WinUsb_AbortPipe := GetProcAddress( hWinUsb, 'WinUsb_AbortPipe');
@WinUsb_FlushPipe := GetProcAddress( hWinUsb, 'WinUsb_FlushPipe');
@WinUsb_ReadPipe := GetProcAddress( hWinUsb, 'WinUsb_ReadPipe');
@WinUsb_WritePipe := GetProcAddress( hWinUsb, 'WinUsb_WritePipe');
@WinUsb_GetOverlappedResult := GetProcAddress( hWinUsb, 'WinUsb_GetOverlappedResult');
// --------------------------------------------------------------------------------
// from driver 'inf' file
// [Dev_AddReg]
// HKR,,DeviceInterfaceGUIDs,0x10000,"{CDDE880F-898A-4DAB-B0EA-51FBA32C1D82}"
//
// This guid needed in 'CreateFile' function to open the device !!!
//
// The device path must look like this:
// \\?\USB#VID_04B4&PID_8613#6&26c545a4&0&1#Cypress-FX2
// --------------------------------------------------------------------------------
// TWinUsbDriver.fDriverID := StringToGuid('{CDDE880F-898A-4DAB-B0EA-51FBA32C1D82}');
// RegisterDriver( TWinUsbDriver);
end;
finalization
if hWinUsb <> 0 then
FreeLibrary( hWinUsb);
CoUninitialize;
end.