You are on page 1of 9

23/4/2016

Usb4pas.zipUSB.PAS

www.pudn.com>Usb4pas.zip>USB.PAS,change:19990125,size:22635b

Searchcodes

{$A+,B,D+,E+,F,G+,I+,L+,N,O,P,Q,R,S+,T,V+,X+,Y+}

{************************************************************************}
{USB.PAS:SBBASICRoutinesbyDieterR.Pawelczak<dieterp@bigfoot.de>}
{========================================================================}
{}
{UnittoinitializeandaddresstheUSBHostController}
{}
{(c)1998byDieterPawelczak,<dieterp@bigfoot.de>}
{ThisispublicdomainSoftwaresellingthissoftwareisprohibeted!}
{}
{functionDetectVirtualRealMode(..)detectsvirtualrealmode
{functionUSBdetect(..);detectsanPCIUSBControllerdonebyINIT
{functionUSBEnableenablesUSBControllerPCIBUSMaster
{functionUSBGetDeviceIOSpace(..)readsI/Oportaddress
{functionUSBSetDeviceIOSpace(..)setsI/Oportaddress
{functionUSBReadCommandRegreadaccessIOCommandRegister
{procedureUSBWriteCommandRegwriteaccessIOCommandRegister
{
{InitializationshouldfirstchecktheUSBdevice(testUSBdetected),
{readtheI/Oaddressspaceandifzerosetanunusedportaddressspace
{(32byte),nowPICBUSMasterControlcanbeenabledbyUSBenable
{}
{************************************************************************}

{$defineDEBUG}{EnablesDEBUGOutput}

unitusb;

interface

{$IFDEFDEBUG}
usesPCI,dutils;
{$ELSE}
usesPCI;
{$ENDIF}

const{USBCommandRegiser}

MAXP=$80;
CF=$40;
SWDBG=$20;
FGR=$10;
EGSM=$08;
GRESET=$04;
HCRESET=$02;
RS=$01;

typeFrameListPointer=longint;{32bitaddress+Q&Tflag}
typeFrameListPointerArray=Array[0..1023]ofFrameListPointer;
typeFrameList=^FrameListPointerArray;

typeLinkPointer=longint;{32bitaddress+Vf&Q&Tflag}
typeBufferPointer=longint;{32bitaddressofthedatabuffer}

typeTransferDescriptor=record
next:LinkPointer;{pointstonextT/QdescriptororindicatesterminationbyTflag}
ActLen:word;{presentstheactuallength(11bit)=and2047}
Status:byte;{presentstheStatus}
Flags:Byte;{FlagsSPD(5),C_ERR(4,3),LS(2),ISO(1),IOC(0)}
Token:longint;{MaxLen/R/R/EndPt/DeviceAddr/PIDtobesent}
BufferPtr:BufferPointer;{BufferPointerforData}
res:array[0..3]oflongint;
end;
typetransmitstatusptr=^byte;
typeQueueHeadLinkPointer=longint;{32bitaddress+Q&Tflag}
typeQueueHeadElementPointer=longint;{32bitaddress+Q&Tflag,bit2isundefined(writeas0)}

typeQueueHead=record
next:QueueHeadLinkPointer;{pointstonextT/QdescriptororindicatesterminationbyTflag}
Element:QueueHeadElementPointer;{pointstonextQueueOperationorindicatesterminationbyTflag}
end;

typePortState=(port_disabled,port_newAttached,port_enabled,port_configured);

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

1/9

23/4/2016

Usb4pas.zipUSB.PAS

typeUSBRequest=record
bmRequestType:Byte;
bRequest:byte;
wValue:word;
wIndex:word;
wLength:word;
end;

constGetDeviceDescriptor:USBRequest=
(bmRequestType:$80;bRequest:$06;wValue:$0001;wIndex:$0000;wLength:$0012);
constSetAddress:USBRequest=
(bmRequestType:$00;bRequest:$05;wValue:$0001;wIndex:$0000;wLength:$0000);

varUSBDeviceID,USBVendorID:word;{PCIIdentificationUSBController}
USBBusNumber,USBFunctionNumber:Byte;
USBDescription:string;{TextDescription}
USBIOSpace:word;{I/Oaddressspaceset/read}
USBdetected:boolean;{FlagsetbyINIT}

varISADeviceID,ISAVendorID:word;{PCIIdentificationPCIISAController}
ISABusNumber,ISAFunctionNumber:Byte;{neededbyUSBSetInt}
ISADescription:string;{TextDescription}
ISAdetected:boolean;{FlagsetbyINIT}

varFrameListPtr:FrameList;{pointertotheframelist}
FrameListBase:longint;{framelist32bitbaseaddress}
FrameListHandle:pointer;{TPmemoryhandle}

{LOWLEVEL:USBHostControllerandPCIfunctions}
functionUSBdetect(VarDeviceID,VendorID:word;VARBusNumber,FunctionNumber:Byte;varDescription:string):boolean;
functionUSBEnable:boolean;
functionUSBDisable:boolean;
functionUSBGetDeviceIOSpace(varIOSpace:word):boolean;
functionUSBSetDeviceIOSpace(IOSpace:word):boolean;
functionUSBReadCommandReg:word;
functionUSBReadStatusReg:word;
functionUSBReadPort0Reg:word;
functionUSBReadPort1Reg:word;
functionUSBReadInterruptReg:word;
functionUSBReadFrameBaseReg:longint;
functionUSBReadFrameNumberReg:word;
procedureUSBWriteCommandReg(value:word);
procedureUSBWriteStatusReg(value:word);
procedureUSBWriteInterruptReg(value:word);
procedureUSBWriteFrameNumberReg(value:word);
procedureUSBWritePort0Reg(value:word);
procedureUSBWritePort1Reg(value:word);
functionUSBSetInterruptNumber(IntNo:word;active:boolean):boolean;
functionUSBGetInterruptNumber(VarIntNo:word;Varactive:boolean):boolean;
functionUSBAllocateFrameList(VarFList:FrameList;VARFLBase:FrameListPointer):boolean;
procedureUSBCommandRun;
procedureUSBCommandStop;
procedureUSBDone;
procedureusbclearframelist;

{GeneralUSBFunctions}

functionAllocateTransferDescriptor:pointer;{ReturnspointertoTDornil}
procedureFreeTransferDescriptor(p:pointer);
functionCreateTransferDescriptor(Terminate,Queue,Depth:boolean;Link:linkpointer;
Actln:word;State:word;IOC,IOS,LS:Boolean;C_error:byte;SPD:boolean;
PID,DeviceAddress,EndPt:Byte;DataToggle:boolean;MaxLen:word;
BPtr:BufferPointer):pointer;{AllocatesandconfiguresTDReturnspointertoTDornil}
procedureAlterTransferDescriptor(p:pointer;Actln:word;State:word;IOC,IOS,LS:Boolean;C_error:byte;SPD:boolean);

procedureInsertQueueDescriptorInFrameList(Number:word;p:pointer);
procedureInsertTransferDescriptorInFrameList(Number:word;p:pointer);
functionGetLinkPointerFromTransferDescriptor(p:pointer):LinkPointer;
functionGetLinkPointerFromFrameList(number:word):LinkPointer;
functionGetTransferDescriptorFromFrameList(number:word):pointer;
functionGetTransferDescriptorFromLinkPointer(l:linkpointer):pointer;
{Helpers}

functionDetectVirtualRealMode:boolean;
functionGetPtrBase(p:pointer):longint;
functionGetBasePtr(b:longint):pointer;

{$IFDEFDEBUG}
procedureUSBprintTD(P:pointer);
procedureUSBprintFrameList;
{$ENDIF}

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

2/9

23/4/2016

Usb4pas.zipUSB.PAS

implementation

functionUSBdetect(VarDeviceID,VendorID:word;VARBusNumber,FunctionNumber:Byte;varDescription:string):boolean;
vari:byte;
error,found:boolean;
begin
BusNumber:=0;FunctionNumber:=0;
USBdetect:=false;
i:=0;
error:=false;
found:=false;
repeat{checkdifferentpossibleUSBPCIdevices...}
caseiof
0:begindeviceId:=$7020;vendorId:=$8086;description:='Intel82371SBUSBcontroller';end;
1:begindeviceId:=$7112;vendorId:=$8086;description:='IntelPIIX4USBcontroller';end;
2:begindeviceId:=$0571;vendorId:=$1106;description:='VIAAMD645USBcontroller';end;
3:begindeviceId:=$A0F8;vendorID:=$1045;description:='Opti82C750(Vendetta)USBcontroller';end;
4:begindeviceId:=$C861;vendorID:=$1045;description:='Opti82C861/871(Firelink/FireBlast)USBcontroller';end;
end;
inc(i);
found:=detectPCIdevice(deviceId,vendorId,BusNumber,FunctionNumber);
error:=i>4;
untilerrororfound;
USBdetect:=found;
end;

functionISAdetect(VarDeviceID,VendorID:word;VARBusNumber,FunctionNumber:Byte;varDescription:string):boolean;
vari:byte;
error,found:boolean;
begin
BusNumber:=0;FunctionNumber:=0;
ISAdetect:=false;
i:=0;
error:=false;
found:=false;
repeat{checkdifferentpossibleISAPCIdevices...}
caseiof
0:begindeviceId:=$7000;vendorId:=$8086;description:='Intel82371SBISAPCIcontroller';end;
1:begindeviceId:=$7110;vendorId:=$8086;description:='IntelPIIX4ISAPCIcontroller';end;
{2:begindeviceId:=$0571;vendorId:=$1106;description:='VIAAMD645USBcontroller';end;
3:begindeviceId:=$A0F8;vendorID:=$1045;description:='Opti82C750(Vendetta)USBcontroller';end;
4:begindeviceId:=$C861;vendorID:=$1045;description:='Opti82C861/871(Firelink/FireBlast)USBcontroller';end;}
end;
inc(i);
found:=detectPCIdevice(deviceId,vendorId,BusNumber,FunctionNumber);
error:=i>2;
untilerrororfound;
ISAdetect:=found;
end;

functionUSBGetDeviceIOSpace(varIOSpace:word):boolean;
varokay:boolean;
result:word;
setiospace:word;
begin
okay:=false;
ifreadPCIRegisterWord($20,USBBusNumber,USBFunctionNumber,result)then
begin
okay:=true;
IOSpace:=resultand$FFFE;
USBIOSpace:=IOSpace;
end;
USBGetDeviceIOSpace:=okay;
end;

functionUSBSetDeviceIOSpace(IOSpace:word):boolean;
varokay:boolean;
result:word;
setiospace:word;
begin
okay:=false;
IOSpace:=IOSpace;
ifwritePCIRegisterWord($20,USBBusNumber,USBFunctionNumber,IOSpace)then
begin
okay:=true;
USBIOSpace:=IOSpace;
end;
USBSetDeviceIOSpace:=okay;
end;

functionUSBReadCommandReg:word;
begin
USBReadCommandReg:=portw[USBIOSpace];
end;

functionUSBReadStatusReg:word;
begin

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

3/9

23/4/2016

Usb4pas.zipUSB.PAS

USBReadStatusReg:=portw[USBIOSpace+2];
end;

functionUSBReadInterruptReg:word;
begin
USBReadInterruptReg:=portw[USBIOSpace+4];
end;

functionUSBReadPort0Reg:word;
begin
USBReadPort0Reg:=portw[USBIOSpace+16];
end;

procedureUSBWritePort0Reg(value:word);
begin
portw[USBIOSpace+16]:=value;
end;

functionUSBReadPort1Reg:word;
begin
USBReadPort1Reg:=portw[USBIOSpace+18];
end;

procedureUSBWritePort1Reg(value:word);
begin
portw[USBIOSpace+18]:=value;
end;

procedureUSBWriteInterruptReg(value:word);
begin
portw[USBIOSpace+4]:=value;
end;

procedureUSBWriteStatusReg(value:word);
begin
portw[USBIOSpace+2]:=value;
end;

procedureUSBWriteCommandReg(value:word);
begin
portw[USBIOSpace]:=value;
end;

procedureUSBWriteFrameNumberReg(value:word);
begin
portw[USBIOSpace+6]:=value;
end;

functionUSBReadFrameNumberReg:word;
begin
USBReadFrameNumberReg:=portw[USBIOSpace+6];
end;

functionUSBReadFrameBaseReg:longint;
begin
asm
movdx,USBIOSpace
adddx,08h
db66h;inax,dx{indx,eax}
db66h;movwordptrFrameListBase,ax{mov..,eax}
end;
USBReadFrameBaseReg:=FrameListBase;
end;

functionUSBEnable:boolean;
varokay:boolean;
command:word;
begin
okay:=false;
ifusbdetectedand(USBIOspace<>0)then
ifreadPCIRegisterWord($4,USBBusNumber,USBFunctionNumber,command)then
begin
okay:=commandand5=5;
command:=commandor5;
ifwritePCIRegisterWord($4,USBBusNumber,USBFunctionNumber,command)then
okay:=true;
end;
USBenable:=okay;
end;

functionUSBGetInterruptNumber(VarIntNo:word;Varactive:boolean):boolean;
varokay:boolean;
command:longint;
command2:longint;
begin
okay:=false;
active:=false;

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

4/9

23/4/2016

Usb4pas.zipUSB.PAS

ifisadetectedthen
ifreadPCIRegisterDWord($60,ISABusNumber,ISAFunctionNumber,command)then
begin
intno:=commandshr24;
active:=intnoand128=0;
intno:=intnoand15;
okay:=true;
end;
USBGetInterruptNumber:=okay;
end;

functionUSBSetInterruptNumber(IntNo:word;active:boolean):boolean;
varokay:boolean;
command:byte;
command2:word;
dummy:word;
begin
okay:=false;
asm
cli
end;
ifisadetectedthen
ifreadPCIRegisterByte($63,ISABusNumber,ISAFunctionNumber,command)then
begin
{RedirectIRQD=Register63htoISABUSIRQ}
command:=IntNo+ord(notactive)*128;{SetinterruptNumbertoMSB}
command2:=1shlintno;
ifcommand2>255then
begin
dummy:=port[$4d1]and(not(command2shr8));
port[$4d1]:=port[$4d1]and(not(command2shr8));
endelse
begin
dummy:=port[$4d0]and(not(command2shr8));
port[$4d0]:=port[$4d0]and(not(command2));
end;
dummy:=port[$21];
ifwritePCIRegisterByte($63,ISABusNumber,ISAFunctionNumber,command)then
begin
dummy:=port[$21];
{SetInterruptSensitiveMode}
okay:=true;
end;
ifintno>7then
begin
asm
inal,0a1h
movcl,byteptrintno
subcl,8
movdl,1
shldl,cl
notdl
andal,dl
out0a1h,al
inal,021h
movdl,2
notdl
andal,dl
out021h,al
end;
endelse
begin
asm
inal,021h
movcl,byteptrintno
movdl,1
shldl,cl
notdl
andal,dl
out021h,al
end;
end;

end;
asm
sti
end;
USBSetInterruptNumber:=okay;
end;

functionUSBDisable:boolean;
varokay:boolean;
begin
okay:=false;
ifusbdetectedand(USBIOspace<>0)then
ifWritePCIRegisterWord($4,USBBusNumber,USBFunctionNumber,0)then
begin

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

5/9

23/4/2016

Usb4pas.zipUSB.PAS

okay:=true;
end;
USBDisable:=okay;
end;

procedureusbclearframelist;
vari:word;
begin
fori:=0to1023do
FrameListPtr^[i]:=1;{SetTerminate}
end;

functionUSBAllocateFrameList(VarFList:FrameList;VARFLBase:FrameListPointer):boolean;
varokay:boolean;
i:word;
begin
ifmemavail>8192then
begin
getmem(FrameListHandle,8192);
FrameListBase:=longint(seg(FrameListHandle^))shl4+longint(ofs(FrameListHandle^));
{4Kalignment}
FrameListBase:=longint(FrameListbase+4096)and$fffff000;
FrameListPtr:=getbaseptr(FrameListBase);
FList:=FrameListPtr;
FLBase:=FrameListBase;
USBWriteFrameNumberReg(0);
fori:=0to1023do
FrameListPtr^[i]:=1;{SetTerminate}
asm
movdx,USBIOSpace
adddx,08h
db66h;movax,wordptrFrameListBase{moveax,...}
db66h;outdx,ax{outdx,eax}
end;
USBWriteFrameNumberReg(0);
okay:=true;
end;
USBAllocateFrameList:=okay;
end;

procedureInsertTransferDescriptorInFrameList(Number:word;p:pointer);
begin
FrameListPtr^[Number]:=getPtrBase(p)and$fffffffc;
end;

functionGetLinkPointerFromFrameList(number:word):LinkPointer;
begin
GetLinkPointerFromFrameList:=FrameListPtr^[Number]and$fffffffc;
end;

procedureInsertQueueDescriptorInFrameList(Number:word;p:pointer);
begin
FrameListPtr^[Number]:=getPtrBase(p)and$fffffffc+2;
end;

procedureUSBCommandRun;
varvalue:word;
begin
value:=USBReadCommandReg;
value:=valueor1;
USBWriteCommandReg(value);
end;

procedureUSBCommandStop;
varvalue:word;
begin
value:=USBReadCommandReg;
value:=valueand$fe;
USBWriteCommandReg(value);
end;

functionDetectVirtualRealMode:boolean;assembler;
asm
smswax
andax,1
end;

functionGetPtrBase(p:pointer):longint;
begin
GetPtrBase:=longint(seg(p^))shl4+longint(ofs(p^));
end;

functionGetBasePtr(b:longint):pointer;
varh1,h2:longint;

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

6/9

23/4/2016

Usb4pas.zipUSB.PAS

begin
h1:=bshr4;
h2:=band$f;
GetbasePtr:=Ptr(h1,h2);
end;

functionAllocateTransferDescriptor:pointer;
vari,j,k:word;
p1:^transferdescriptor;
PA:array[1..1000]ofpointer;
begin
p1:=nil;
getmem(p1,32);
ifofs(p1^)and$f<>0then
begin
j:=0;
repeat
inc(j);
freemem(p1,32);p1:=NIL;
getmem(pa[j],1);
getmem(p1,32);
until(j=1000)or(ofs(p1^)=0);
ifj=1000then
begin
writeln('Fatal:AllocatingTDmemoryerror...');
halt(3);
end;
fork:=1tojdoFreemem(pa[k],1);
end;
ifp1<>NILthen
withp1^do
begin
next:=0;
ActLen:=0;
Status:=0;
Flags:=0;
token:=0;
BufferPtr:=0;
end;
AllocateTransferDescriptor:=p1;
end;

procedureFreeTransferDescriptor(p:pointer);
vartd:^TransferDescriptor;
begin
freemem(p,32);
end;

functionGetLinkPointerFromTransferDescriptor(p:pointer):LinkPointer;
begin
GetLinkPointerFromTransferDescriptor:=getptrbase(p);
end;

functionGetTransferDescriptorFromLinkPointer(l:linkpointer):pointer;
begin
GetTransferDescriptorFromLinkPointer:=getbaseptr(land$fffffffc);
end;

functionGetTransferDescriptorFromFrameList(number:word):pointer;
begin
GetTransferDescriptorFromFrameList:=getbaseptr(FrameListPtr^[Number]and$fffffffc);
end;

procedureAlterTransferDescriptor(p:pointer;Actln:word;State:word;IOC,IOS,LS:Boolean;C_error:byte;SPD:boolean);
vartd:^TransferDescriptor;
begin
td:=p;
iftd<>nilthenwithtd^do
begin
Actlen:=Actln;
flags:=ord(IOC)+ord(IOS)shl1+ord(ls)shl2+(c_errorand3)shl3+ord(spd)shl5;
Status:=state;
end;
end;

functionCreateTransferDescriptor(Terminate,Queue,Depth:boolean;Link:linkpointer;
Actln:word;State:word;IOC,IOS,LS:Boolean;C_error:byte;SPD:boolean;
PID,DeviceAddress,EndPt:Byte;DataToggle:boolean;MaxLen:word;
BPtr:BufferPointer):pointer;{AllocatesandconfiguresTDReturnspointertoTDornil}
vartd:^TransferDescriptor;
begin
td:=AllocateTransferDescriptor;
iftd<>nilthenwithtd^do
begin
next:=linkand$fffffff0+ord(Terminate)+ord(Queue)shl1+ord(Depth)shl2;
Actlen:=Actln;
Status:=state;

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

7/9

23/4/2016

Usb4pas.zipUSB.PAS

flags:=ord(IOC)+ord(IOS)shl1+ord(ls)shl2+(c_errorand3)shl3+ord(spd)shl5;
token:=pid+longint(DeviceAddress)shl8+longint(EndPt)shl15+longint(ord(DataToggle))shl19+longint(maxlen)shl21;
bufferPtr:=Bptr;

end;
CreateTransferDescriptor:=td;
end;

{$IFDEFDEBUG}
procedureUSBprintLinkPtr(L:LinkPointer);
varh:longint;
i:word;
begin
h:=land$fffffff0;
write('LinkPtr:');
ifh=0thenwrite('EMPTY[');
write('[',hexs(h));
ifland4=4thenwrite(']Vf')elsewrite(']');
ifland2=2thenwrite('Q')elsewrite('');
ifland1=1thenwrite('T')elsewrite('');
writeln;
end;

procedureUSBprintFrameList;
vari,j:word;
l:longint;
begin
write('FrameList[',hexs(FrameListBase),']');
fori:=0to1023do
begin
ifimod6=0thenwriteln;
l:=FrameListPtr^[i];
write('[',hexs(l),']');
ifland2=2thenwrite('Q')elsewrite('');
ifland1=1thenwrite('T')elsewrite('');
write('');
end;
writeln;
writeLn('');
end;

procedureUSBprintTD(P:pointer);
vartd:^TransferDescriptor;
i:word;
h:longint;
hp:^byte;
begin
td:=p;
withtd^do
begin
writeLn('TransferDescriptor[',hexs(GetPtrBase(p)),']');
USBprintLinkPtr(next);
write('Control:');
ifflagsand32=32thenwrite('SP')elsewrite('');
write('C_ERROR:',chr(48+ord(flagsand16=16)),chr(48+ord(flagsand8=8)));
ifflagsand4=4thenwrite('LS')elsewrite('');
ifflagsand2=2thenwrite('ISO')elsewrite('');
ifflagsand1=1thenwrite('ICO')elsewrite('');
write('Status:',bins8(status));
writeln('Len:',Actlen);
write('Token:MaxLen:',Tokenshr21and$7ff);
write('Toggle:',(Tokenshr19)and1);
WRite('EndPt:',hexs8((Tokenshr15)and$f));
WRite('DevAddr:',hexs8((Tokenshr8)and$7f));
WRite('PID:',hexs8((Token)and$ff));
writeln;
write('BufferPtr:',hexs(bufferptr));
ifbufferptr<>0then
begin
write('');
hp:=getBasePtr(bufferptr);
fori:=1to8do
begin
write(hexs8(hp^),'');
inc(hp);
end;
end;
writeln;

writeLn('');
end;
end;

{$ENDIF}

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

8/9

23/4/2016

Usb4pas.zipUSB.PAS

varoldmasterintmask:byte;
oldslaveintmask:byte;
old_port4d0:byte;
old_port4d1:byte;
old_pirqd:byte;

procedureUSBDone;
begin
port[$4d0]:=old_port4d0;
port[$4d1]:=old_port4d1;
WritePCIRegisterByte($63,ISABusNumber,ISAFunctionNumber,old_pirqd);
asm
moval,oldslaveintmask
out0a1h,al
moval,oldmasterintmask
out021h,al
end;
end;

begin
USBdetected:=false;
ifdetectPCIbiosthen
begin
USBdetected:=USBdetect(USBDeviceId,USBVendorId,USBBusNumber,USBFunctionNumber,USBdescription);
ISAdetected:=ISAdetect(ISADeviceId,ISAVendorId,ISABusNumber,ISAFunctionNumber,ISAdescription);
old_port4d0:=port[$4d0];
old_port4d1:=port[$4d1];
readPCIRegisterByte($63,ISABusNumber,ISAFunctionNumber,old_pirqd);
asm
inal,0a1h
movoldslaveIntMask,al
inal,021h
movoldmasterIntMask,al
end;
end;
end.

http://read.pudn.com/downloads56/sourcecode/others/197778/USB.PAS__.htm

9/9

You might also like