📄 stick.pas
字号:
Program stick (output);
{This sample reads a sector from a USB memory stick using the "bulk
only" protocol. Adapted from 'stick.bas' by Joe da Silva, to suit
various real-mode compilers, such as Turbo Pascal 5.5 (available
for free download from "http://bdn.borland.com/museum"). However,
for TP/BP 7.0, be sure to use a non-Borland version of the CRT unit
(or not at all), else you may encounter the infamous "RTE 200" bug.}
Uses
dos, {provides the "registers" type & "intr" routine}
crt; {provides the "clrscr" & "gotoxy" routines}
Const
DosUsbInt = $65; {interrupt used by DosUSB/DosUHCI driver}
control_token = $2D; {transaction_token values ...}
in_token = $69;
out_token = $E1;
command_token = $FF;
devadd = 2; {1} {device address assigned by DosUSB/DosUHCI}
in_endpoint = 1; {was 2}
out_endpoint = 2; {was 1}
CR = ^M;
LF = ^J;
Type
dword = longint;
URB_type =
packed record
transaction_token : byte; {see token values above}
chain_end_flag : byte; {1 = another URB follows this one in memory}
dev_add : byte;
end_point : byte;
error_code : byte;
status : byte; {returned by dosuhci}
transaction_flags : word; {reserved}
buffer_off : word; {for in/out}
buffer_seg : word; {for in/out}
buffer_length : word; {for in/out}
actual_length : word; {for in/out}
setup_buffer_off : word; {for control}
setup_buffer_seg : word; {for control}
start_frame : word; {reserved}
nr_of_packets : word; {reserved - iso}
int_interval : byte; {reserved}
error_count : byte; {reserved}
timeout : word; {reserved}
next_urb_off : word; {reserved}
next_urb_seg : word; {reserved}
end; {record, 32 bytes long}
setup_type =
packed record
bmRequestType : byte;
bRequest : byte;
wValue : word;
wIndex : word;
wLength : word;
end; {record}
read_command =
packed record
{first cbw fields 15 bytes}
signature : dword;
tag : dword;
tlength : dword;
flags : byte;
cbwlun : byte;
clength : byte;
{now command fields 16 bytes}
operation_code : byte;
lun : byte;
lba : dword;
reserved : byte;
blocks : word;
controls : byte;
padding1 : word;
padding2 : word;
padding3 : word;
end; {record, 31 bytes long}
hexstring = string[8];
buffer_type = packed array [1..64] of char;
Var
urb : URB_type;
device_request : setup_type;
read_command_request : read_command;
{inquiry_command_request : read_command;}
buffer : buffer_type;
sbuffer : packed array [1..1256] of char;
ecode : integer;
lba : dword;
(***************************************************************)
Function swap4endian (number : dword) : dword;
type
dual_word =
packed record
first, second : word;
end; {record}
var
temp : dual_word;
begin {swap_endian}
temp.first := swap(dual_word(number).second);
temp.second := swap(dual_word(number).first);
swap4endian := dword(temp);
end; {swap_endian}
Procedure writechars (var first : char; len : word; ln : boolean);
type
bigstring = packed array [1..32000] of char;
var
charptr : ^bigstring;
i : integer;
begin {writechars}
charptr := addr(first);
for i := 1 to len do
write(charptr^[i]);
if ln
then
writeln;
end; {writechars}
Function hex2char (nibble : byte) : char;
{Form hex character from nibble value}
begin {hex2char}
if nibble < 10
then
hex2char := chr(ord('0')+nibble)
else
hex2char := chr(ord('A')+nibble-10)
end; {hex2char}
Function hexstr (num : dword; digits : word) : hexstring;
var
st : array [1..8] of char;
i : word;
begin {hexstr}
for i := digits downto 1 do
begin {for}
st[i] := hex2char(num mod 16);
num := num div 16
end; {for}
hexstr := copy(st,1,digits);
end; {hexstr}
Procedure DosUHCI (var urb : URB_type; cmd_code : word);
{Call DosUHCI/DosUSB driver API. Note, 'cmd_code' only
applies when 'transaction_token' = command_token ($FF).}
var
regs : registers;
begin {DosUHCI}
urb.error_code := 0;
regs.AX := cmd_code;
regs.DS := seg(urb);
regs.DX := ofs(urb);
intr(DosUsbInt, regs);
case urb.error_code of
0 : {no error};
1 : writeln('Error, invalid device address.');
2 : writeln('Error, internal error.');
3 : writeln('Error, invalid transaction_type.');
4 : writeln('Error, invalid buffer length.')
else
writeln('Error, code = ',urb.error_code);
end; {case}
end; {DosUHCI}
Function DosUHCIpresent : boolean;
const
check_presence = 6;
confirmation = $47;
var
urb : URB_type;
vector : pointer;
begin {DosUHCIpresent}
{prepare for DosUHCI call, also initializes return code}
urb.transaction_token := command_token;
urb.dev_add := 0; {driver-sensitive item, empirically determined}
urb.buffer_length := 0; {driver-sensitive item, empirically determined}
{call API, but first ensure int. vector is plausible}
GetIntVec(DosUsbInt,vector);
if seg(vector^) > $100
then
DosUHCI(urb,check_presence);
DosUHCIpresent := (urb.transaction_token = confirmation);
end; {DosUHCIpresent}
Procedure EnableDebug (dev_addr : byte);
const
enable_debug = 2;
var
urb : URB_type;
begin {EnableDebug}
urb.transaction_token := command_token;
urb.dev_add := dev_addr;
DosUHCI(urb,enable_debug);
end; {EnableDebug}
Procedure DisableDebug (dev_addr : byte);
const
disable_debug = 3;
var
urb : URB_type;
begin {DisableDebug}
urb.transaction_token := command_token;
urb.dev_add := dev_addr;
DosUHCI(urb,disable_debug);
end; {DisableDebug}
Procedure InRequest (dev_id: byte; var urb: URB_type; var buf: buffer_type);
begin {InRequest}
{set up In request}
urb.transaction_token := in_token;
urb.chain_end_flag := 0;
urb.dev_add := dev_id;
urb.end_point := in_endpoint;
urb.error_code := 0;
urb.status := 0;
urb.transaction_flags := 0;
urb.buffer_off := ofs(buf);
urb.buffer_seg := seg(buf);
urb.buffer_length := 64;
urb.actual_length := 64;
urb.setup_buffer_off := 0;
urb.setup_buffer_seg := 0;
urb.start_frame := 0;
urb.nr_of_packets := 0;
urb.int_interval := 0;
urb.error_count := 0;
urb.timeout := 0;
urb.next_urb_off := 0;
urb.next_urb_seg := 0;
{now call DosUHCI/DosUSB}
DosUHCI(urb,0);
end; {InRequest}
Procedure OutRequest (dev_id: byte; var urb: URB_type; var buf: buffer_type);
begin {OutRequest}
{set up Out request}
urb.transaction_token := out_token;
urb.chain_end_flag := 0;
urb.dev_add := dev_id;
urb.end_point := out_endpoint;
urb.error_code := 0;
urb.status := 0;
urb.transaction_flags := 0;
urb.buffer_off := ofs(buf);
urb.buffer_seg := seg(buf);
urb.buffer_length := 31;
urb.actual_length := 64;
urb.setup_buffer_off := 0;
urb.setup_buffer_seg := 0;
urb.start_frame := 0;
urb.nr_of_packets := 0;
urb.int_interval := 0;
urb.error_count := 0;
urb.timeout := 0;
urb.next_urb_off := 0;
urb.next_urb_seg := 0;
{now call DosUHCI/DosUSB}
DosUHCI(urb,0);
end; {OutRequest}
Procedure CommandRequest (dev_id: byte; var urb: URB_type;
var buf: buffer_type; var dev_req : setup_type);
begin {CommandRequest}
{set up Command request}
urb.transaction_token := control_token;
urb.chain_end_flag := 0;
urb.dev_add := dev_id;
urb.end_point := 0;
urb.error_code := 0;
urb.status := 0;
urb.transaction_flags := 0;
urb.buffer_off := ofs(buf);
urb.buffer_seg := seg(buf);
urb.buffer_length := 1;
urb.actual_length := 8;
urb.setup_buffer_off := ofs(dev_req);
urb.setup_buffer_seg := seg(dev_req);
urb.start_frame := 0;
urb.nr_of_packets := 0;
urb.int_interval := 0;
urb.error_count := 0;
urb.timeout := 0;
urb.next_urb_off := 0;
urb.next_urb_seg := 0;
{now call DosUHCI/DosUSB}
DosUHCI(urb,0);
end; {CommandRequest}
Procedure do_read (lbanumber : dword);
var
i : integer;
midpos : integer;
begin {do_read}
{set up bulk read command incl. cbw}
read_command_request.signature := $43425355;
read_command_request.tag := $82A36008;
read_command_request.tlength := $200; {512 bytes}
read_command_request.flags := $80;
read_command_request.cbwlun := 0; {1}
read_command_request.clength := $0A;
{now command fields}
read_command_request.operation_code := $28;
read_command_request.lun := 0; {32} {1}
read_command_request.lba := swap4endian(lbanumber); {0} {big endian}
{write('LBA:', hexstr(read_command_request.lba,8), ' ');}
read_command_request.reserved := 0;
read_command_request.blocks := swap($01); {00} {big endian}
{writeln('Blocks:', hexstr(read_command_request.blocks,4));}
read_command_request.controls := 0;
read_command_request.padding1 := 0;
read_command_request.padding2 := 0;
read_command_request.padding3 := 0;
move(read_command_request,buffer[1],64);
OutRequest(devadd, urb, buffer);
fillchar(buffer,64,chr(0)); {return data here}
i := 0;
while i < 8 {leave if 8 ( 8*64=512 )} do
begin {while}
InRequest(devadd, urb, buffer);
if urb.status = 0
then
begin {then}
inc(i);
midpos := 1+(i-1)*64;
move(buffer,sbuffer[midpos],sizeof(buffer));
end {then}
else
if urb.status <> 88
then
exit; {do not incr. if 88}
end; {while}
end; {do_read}
(***************************************************************)
Begin {stick}
{revert console I/O from CRT to standard}
assign(input,'');
reset(input);
assign(output,'');
rewrite(output);
{initialization start}
if not DosUHCIpresent
then
begin {then}
writeln(CR,LF,'Error : DosUHCI/DosUSB driver isn''t loaded.');
halt(1);
end; {then}
{EnableDebug(devadd);}
{DisableDebug(devadd);}
ClrScr;
fillchar(buffer,64,chr(0)); {return data here}
fillchar(sbuffer,1256,chr(0)); {return data here}
val(ParamStr(1), lba, ecode);
if ecode <> 0
then
lba := 0; {543}
writeln('LBA = ', lba, ' (Assumptions: USB device = ', devadd,
', In endpoint = ', in_endpoint,
', Out endpoint = ', out_endpoint, ')');
{initialization end}
(* optional code ...
{get max lun}
device_request.bmRequestType := $A1;
device_request.bRequest := $FE;
device_request.wValue := $0000;
device_request.wIndex := $0000;
device_request.wLength := $0001;
CommandRequest(devadd, urb, buffer, device_request);
{transaction error?}
if urb.status > 1
then
begin {then}
ClrScr;
gotoxy(14,23);
writeln('Device does not respond');
end; {then}
write(CR,LF,'Logical units:');
writechars(buffer[1],urb.actual_length,true);
... optional code *)
{set up inquiry command incl. cbw}
read_command_request.signature := $43425355;
read_command_request.tag := $82A36008;
read_command_request.tlength := $24;
read_command_request.flags := $80;
read_command_request.cbwlun := 0; {1}
read_command_request.clength := $06;
{now command fields}
read_command_request.operation_code := $12;
read_command_request.lun := 0; {32} {1}
read_command_request.lba := $240000;
read_command_request.reserved := 0;
read_command_request.blocks := 0;
read_command_request.controls := 0;
read_command_request.padding1 := 0;
read_command_request.padding2 := 0;
read_command_request.padding3 := 0;
move(read_command_request,buffer,sizeof(read_command_request));
OutRequest(devadd, urb, buffer);
(* stick.bas: buffer=repeat$(100,chr$(0)) 'return data here
!!! buffer is only 64 bytes, so 100 seems a bug ... *)
fillchar(buffer,64,chr(0));
InRequest(devadd, urb, buffer);
write(CR,LF,'Inquiry:');
writechars(buffer[1],urb.actual_length,true);
{In request - to read CSW}
InRequest(devadd, urb, buffer);
write(CR,LF,'CSW:');
writechars(buffer[1],urb.actual_length,true);
do_read(lba);
if urb.error_code > 0
then
begin
ClrScr;
gotoxy(14,23);
writeln('Buffer length exceeded');
end;
writeln(CR,LF,'Sector (LBA): ',lba);
writechars(sbuffer[1],512,true);
{In request - to read CSW}
InRequest(devadd, urb, buffer);
write(CR,LF,'CSW:');
writechars(buffer[1],urb.actual_length,true);
End. {stick}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -