-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfs-ide.adb
240 lines (208 loc) · 9.28 KB
/
fs-ide.adb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
-------------------------------------------------------------------------
-- --
-- RTEMS FILE-SYSTEM SUPPORT --
-- --
-- F S . I D E --
-- --
-- B o d y --
-- --
-- $ Revision: 1.0 $ --
-- --
-- Alejandro Villanueva Uribarri (Universidad de Zaragoza) --
-- --
-------------------------------------------------------------------------
-------------------------------------------------------------------------
-- This package provides the IDE_Driver. You can basically perform two --
-- operations with it: --
-- (*) IDE_Driver.Init will reset the driver. This function is called --
-- when the package is withed. --
-- (*) IDE_Driver.DEV_IO will read or write any sector into a variable --
-- of type Data_Block. --
-- --
-- Please note that only the Read operation is currently implemented. --
-- Writing operation is not needed, so I won't implement it. Anyhow it --
-- is simple to implement in case you need to. --
-- --
-- For this driver to work properly you should configure your disk in --
-- CHS mode in the BIOS parameter table. If configured in LBA mode it --
-- won't work. --
-------------------------------------------------------------------------
with System.Storage_Elements, Port_IO, Ada.Text_IO;
use System.Storage_Elements, Port_IO, Ada.Text_IO;
package body fs.ide is
---[ On or Off ]------------------------------------------------------
type On_or_Off is (Off, On);
for On_or_Off use (Off => 0, On => 1);
for On_or_Off'Size use 1;
---[ Interrupt Vector ]-----------------------------------------------
type Interrupt_Vector is
record
Segment: Word;
Offset: Word;
end record;
for Interrupt_Vector use
record
Segment at 2 range 0 .. 15;
Offset at 0 range 0 .. 15;
end record;
Int_41h_Vector: Interrupt_Vector;
for Int_41h_Vector'Address use To_Address (16#41# * 4);
---[ Drive Info ]-----------------------------------------------------
type Drive_Info is
record
Cylinders: Word;
Heads: Byte;
Sectors: Byte;
end record;
for Drive_Info use
record
Cylinders at 0 range 0 .. 15;
Heads at 2 range 0 .. 7;
Sectors at 14 range 0 .. 7;
end record;
Info_hd0: Drive_Info;
for Info_hd0'Address use To_Address
(Integer_Address
(Integer (Int_41h_Vector.Segment) * 16 +
Integer (Int_41h_Vector.Offset) ) );
---[ I/O Ports ]------------------------------------------------------
Reg_Data: constant := 16#1F0#;
Reg_Error: constant := 16#1F1#;
Reg_Sec_Cnt: constant := 16#1F2#;
Reg_Sec_Num: constant := 16#1F3#;
Reg_Cyl_LSB: constant := 16#1F4#;
Reg_Cyl_MSB: constant := 16#1F5#;
Reg_Drv_Head: constant := 16#1F6#;
Reg_Status: constant := 16#1F7#;
Reg_Command: constant := 16#1F7#;
---[ Status Register ]------------------------------------------------
BSY: constant := 7;
DRQ: constant := 3;
ERR: constant := 0;
---[ Error Register ]-------------------------------------------------
ABT: constant := 2;
---[IDE Driver ]------------------------------------------------------
protected body IDE_Driver is
function Byte_Status (The_Byte: in Port_IO.Byte;
The_Bit: in Byte_Range;
Check_For: in On_or_Off)
return Boolean is
Working_Byte: Port_IO.Byte := The_Byte;
Remainder: Port_IO.Byte;
begin
for I in 0 .. The_Bit loop
Remainder := Working_Byte rem 2;
Working_Byte := Working_Byte / 2;
end loop;
return (Remainder = On_or_Off'Pos (Check_For));
end Byte_Status;
procedure Recalibrate is
Status: Port_IO.Byte;
begin
loop
Inport_Byte (Reg_Status, Status);
exit when Byte_Status (Status, BSY, Off);
end loop;
Outport_Byte (Reg_Drv_Head, 16#A0#);
Outport_Byte (Reg_Command, 16#10#);
loop
Inport_Byte (Reg_Status, Status);
exit when Byte_Status (Status, BSY, Off);
end loop;
end Recalibrate;
entry Init when not Initialized is
package Byte_IO is new Integer_IO (Byte);
package Word_IO is new Integer_IO (Word);
use Byte_IO, Word_IO;
begin
Put ("Hard Disk (hd0): ");
Put (Info_hd0.Cylinders, Width => 0);
Put (" cylinders, ");
Put (Info_hd0.Heads, Width => 0);
Put (" heads, ");
Put (Info_hd0.Sectors, Width => 0);
Put (" sectors");
New_Line;
Recalibrate;
Initialized := True;
end Init;
entry Dev_IO (rw_flag: in Read_or_Write;
Pos: in DWord;
Data: out Data_Block)
when Initialized is
Ok: Boolean := False;
Error_Cnt: Byte := 0;
Max_Errors: constant Byte := 3;
Cylinder, Remainder: DWord;
Cyl_LSB, Cyl_MSB, Head, Sector: Port_IO.Byte;
Command, Status, Error: Port_IO.Byte;
Data_Mini_Block: Port_IO.Word;
begin
-- get CHS format from Pos parameter
Cylinder :=
Pos / DWord (Info_hd0.Sectors * Info_hd0.Heads);
Remainder :=
Pos rem DWord (Info_hd0.Sectors * Info_hd0.Heads);
Cyl_MSB :=
Port_IO.Byte (Cylinder / 256);
Cyl_LSB :=
Port_IO.Byte (Cylinder rem 256);
Head :=
Port_IO.Byte (Remainder /
DWord (Info_hd0.Sectors));
Sector :=
Port_IO.Byte (Remainder rem
DWord (Info_hd0.Sectors)) + 1;
if rw_flag = Read then
Command := 16#20#;
else
Command := 16#30#;
end if;
while not Ok and Error_Cnt < Max_Errors loop
-- wait until not BSY
loop
Inport_Byte (Reg_Status, Status);
exit when Byte_Status (Status, BSY, Off);
end loop;
-- issue command
Outport_Byte (Reg_Sec_Cnt, 1 );
Outport_Byte (Reg_Sec_Num, Sector );
Outport_Byte (Reg_Cyl_LSB, Cyl_LSB );
Outport_Byte (Reg_Cyl_MSB, Cyl_MSB );
Outport_Byte (Reg_Drv_Head, 16#A0# + Head);
Outport_Byte (Reg_Command, Command );
-- wait for data to be ready
loop
Inport_Byte (Reg_Status, Status);
exit when
Byte_Status (Status, BSY, Off) and
Byte_Status (Status, DRQ, On);
end loop;
-- transfer data to main memory
for I in 0 .. Sector_Size / 2 - 1 loop
Inport_Word (Reg_Data, Data_Mini_Block);
Data (I * 2 + 0) := Byte (Data_Mini_Block rem 256);
Data (I * 2 + 1) := Byte (Data_Mini_Block / 256);
end loop;
-- check for errors
Inport_Byte (Reg_Status, Status);
Inport_Byte (Reg_Error, Error );
if Byte_Status (Status, ERR, On )
and Byte_Status (Status, BSY, Off)
and Byte_Status (Error, ABT, On ) then
-- we've got a command abortion here!
Recalibrate;
Ok := False;
Error_Cnt := Error_Cnt + 1;
else
Ok := True;
end if;
end loop;
If Error_Cnt = Max_Errors then
raise Disk_Error;
end if;
end Dev_IO;
end IDE_Driver;
begin
IDE_Driver.Init;
end fs.ide;