OSDN Git Service

first commit
[winexe-harib/winexe-harib.git] / haribote / ata / ATAIOTMR.C
1 //********************************************************************
2 // ATA LOW LEVEL I/O DRIVER -- ATAIOTMR.C
3 //
4 // by Hale Landis (www.ata-atapi.com)
5 //
6 // There is no copyright and there are no restrictions on the use
7 // of this ATA Low Level I/O Driver code.  It is distributed to
8 // help other programmers understand how the ATA device interface
9 // works and it is distributed without any warranty.  Use this
10 // code at your own risk.
11 //
12 // This code is based on the ATA-2, ATA-3 and ATA-4 standards and
13 // on interviews with various ATA controller and drive designers.
14 //
15 // This code has been run on many ATA (IDE) drives and
16 // MFM/RLL controllers.  This code may be a little
17 // more picky about the status it sees at various times.  A real
18 // BIOS probably would not check the status as carefully.
19 //
20 // Compile with one of the Borland C or C++ compilers.
21 //
22 // This C source file contains functions to access the BIOS
23 // Time of Day information and to set and check the command
24 // time out period.
25 //********************************************************************
26
27 #include <dos.h>
28
29 #include "ataio.h"
30
31 //**************************************************************
32
33 long tmr_time_out = 20L;      // max command execution time in seconds
34
35 long tmr_cmd_start_time;      // command start time - see the
36                               // tmr_set_timeout() and
37                               // tmr_chk_timeout() functions.
38
39 long tmr_1s_count;            // number of I/O port reads required
40                               //    for a 1s delay
41 long tmr_1ms_count;           // number of I/O port reads required
42                               //    for a 1ms delay
43 long tmr_1us_count;           // number of I/O port reads required
44                               //    for a 1us delay
45 long tmr_500ns_count;         // number of I/O port reads required
46                               //    for a 500ns delay
47
48 //**************************************************************
49 //
50 // tmr_read_bios_timer() - function to read the BIOS timer
51 //
52 //**************************************************************
53
54 long tmr_read_bios_timer_old( void )
55
56 {
57    long curTime;
58
59    // Pointer to the low order word
60    // of the BIOS time of day counter at
61    // location 40:6C in the BIOS data area.
62    static volatile long far * todPtr = (long *)MK_FP( 0x40, 0x6c );
63
64    // loop so we get a valid value without
65    // turning interrupts off and on again
66    do
67    {
68       curTime = * todPtr;
69    } while ( curTime != * todPtr );
70    return curTime;
71 }
72
73 unsigned long long timer_getbiostimer();
74 long tmr_read_bios_timer( void )
75 {
76         return timer_getbiostimer();
77 }
78
79 //**************************************************************
80 //
81 // tmr_set_timeout() - get the command start time
82 //
83 //**************************************************************
84
85 void tmr_set_timeout( void )
86
87 {
88
89    // get the command start time
90    tmr_cmd_start_time = tmr_read_bios_timer();
91 }
92
93 //**************************************************************
94 //
95 // tmr_chk_timeout() - check for command timeout.
96 //
97 // Gives non-zero return if command has timed out.
98 //
99 //**************************************************************
100
101 int tmr_chk_timeout( void )
102
103 {
104    long curTime;
105
106    // get current time
107    curTime = tmr_read_bios_timer();
108
109    // if we have passed midnight, restart
110    if ( curTime < tmr_cmd_start_time )
111    {
112       tmr_cmd_start_time = curTime;
113       return 0;
114    }
115
116    // timed out yet ?
117    if ( curTime >= ( tmr_cmd_start_time + ( tmr_time_out * 18L ) ) )
118       return 1;      // yes
119
120    // no timeout yet
121    return 0;
122 }
123
124 //**************************************************************
125 //
126 // tmr_get_delay_counts - compute the number calls to
127 //    tmr_waste_time() required for 1s, 1ms, 1us and 500ns delays.
128 //
129 //**************************************************************
130
131 // our 'waste time' function (do some 32-bit multiply/divide)
132
133 static long tmr_waste_time( long p );
134
135 static long tmr_waste_time( long p )
136
137 {
138    volatile long lc = 100;
139    for(int i = 0; i < 100; i++){
140         volatile long k = ( lc * lc ) / ( ( p * p ) + 1 );
141    }
142
143    return ( lc * lc ) / ( ( p * p ) + 1 );
144 }
145
146 // get the delay counts
147
148 void tmr_get_delay_counts( void )
149
150 {
151    long count;
152    long curTime, startTime, endTime;
153    int loop;
154    int retry;
155
156    // do only once
157    if ( tmr_1s_count )
158       return;
159
160    // outside loop to handle crossing midnight
161    count = 0;
162    retry = 1;
163    while ( retry )
164    {
165       // wait until the timer ticks
166       startTime = tmr_read_bios_timer();
167       while ( 1 )
168       {
169          curTime = tmr_read_bios_timer();
170          if ( curTime != startTime )
171             break;
172       }
173       // waste time for 1 second
174       endTime = curTime + 18L;
175       while ( 1 )
176       {
177          for ( loop = 0; loop < 100; loop ++ )
178             tmr_waste_time( 7 );
179          count += 100 ;
180          // check timer
181          curTime = tmr_read_bios_timer();
182          // pass midnight?
183          if ( curTime < startTime )
184          {
185             count = 0;  // yes, zero count
186             break;      // do again
187          }
188          // one second yet?
189          if ( curTime >= endTime )
190          {
191             retry = 0;  // yes, we have a count
192             break;      // done
193          }
194       }
195    }
196
197    // save the 1s count
198    tmr_1s_count = count;
199    // divide by 1000 and save 1ms count
200    tmr_1ms_count = count = count / 1000L;
201    // divide by 1000 and save 1us count
202    tmr_1us_count = count = count / 1000L;
203    // divide by 2 and save 500ns count
204    tmr_500ns_count = count / 2;
205
206    // make sure 1us count is at least 2
207    if ( tmr_1us_count < 2L )
208       tmr_1us_count = 2L;
209    // make sure 500ns count is at least 1
210    if ( tmr_500ns_count < 1L )
211       tmr_500ns_count = 1L;
212 }
213
214 //**************************************************************
215 //
216 // tmr_delay_1ms - delay approximately 'count' milliseconds
217 //
218 //**************************************************************
219
220 void tmr_delay_1ms( long count )
221
222 {
223    long loopcnt = tmr_1ms_count * count;
224
225    while ( loopcnt > 0 )
226    {
227       tmr_waste_time( 7 );
228       loopcnt -- ;
229    }
230 }
231
232 //**************************************************************
233 //
234 // tmr_delay_1us - delay approximately 'count' microseconds
235 //
236 //**************************************************************
237
238 void tmr_delay_1us( long count )
239
240 {
241    long loopcnt = tmr_1us_count * count;
242
243    while ( loopcnt > 0 )
244    {
245       tmr_waste_time( 7 );
246       loopcnt -- ;
247    }
248 }
249
250 //**************************************************************
251 //
252 // tmr_ata_delay - delay approximately 500 nanoseconds
253 //
254 //**************************************************************
255
256 void tmr_delay_ata( void )
257
258 {
259    long loopcnt = tmr_500ns_count;
260
261    while ( loopcnt > 0 )
262    {
263       tmr_waste_time( 7 );
264       loopcnt -- ;
265    }
266 }
267
268 //**************************************************************
269 //
270 // tmr_atapi_delay() - delay for ~80ms so that poorly designed
271 //                     atapi device have time to updated their
272 //                     status.
273 //
274 //**************************************************************
275
276 void tmr_delay_atapi( int dev )
277
278 {
279
280    if ( reg_config_info[dev] == REG_CONFIG_TYPE_ATA )
281       return;
282    if ( ! reg_atapi_delay_flag )
283       return;
284    trc_llt( 0, 0, TRC_LLT_DELAY1 );
285    tmr_delay_1ms( 80L );
286 }
287
288 //**************************************************************
289 //
290 // tmr_xfer_delay() - random delay until the bios timer ticks
291 //                    (from 0 to 55ms).
292 //
293 //**************************************************************
294
295 void tmr_delay_xfer( void )
296
297 {
298    long lw;
299
300    trc_llt( 0, 0, TRC_LLT_DELAY2 );
301    lw = tmr_read_bios_timer();
302    while ( lw == tmr_read_bios_timer() )
303       /* do nothing */ ;
304 }
305
306 // end ataiotmr.c