1 //********************************************************************
2 // ATA LOW LEVEL I/O DRIVER -- ATAIOTMR.C
4 // by Hale Landis (www.ata-atapi.com)
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.
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.
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.
20 // Compile with one of the Borland C or C++ compilers.
22 // This C source file contains functions to access the BIOS
23 // Time of Day information and to set and check the command
25 //********************************************************************
31 //**************************************************************
33 long tmr_time_out = 20L; // max command execution time in seconds
35 long tmr_cmd_start_time; // command start time - see the
36 // tmr_set_timeout() and
37 // tmr_chk_timeout() functions.
39 long tmr_1s_count; // number of I/O port reads required
41 long tmr_1ms_count; // number of I/O port reads required
43 long tmr_1us_count; // number of I/O port reads required
45 long tmr_500ns_count; // number of I/O port reads required
48 //**************************************************************
50 // tmr_read_bios_timer() - function to read the BIOS timer
52 //**************************************************************
54 long tmr_read_bios_timer_old( void )
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 );
64 // loop so we get a valid value without
65 // turning interrupts off and on again
69 } while ( curTime != * todPtr );
73 unsigned long long timer_getbiostimer();
74 long tmr_read_bios_timer( void )
76 return timer_getbiostimer();
79 //**************************************************************
81 // tmr_set_timeout() - get the command start time
83 //**************************************************************
85 void tmr_set_timeout( void )
89 // get the command start time
90 tmr_cmd_start_time = tmr_read_bios_timer();
93 //**************************************************************
95 // tmr_chk_timeout() - check for command timeout.
97 // Gives non-zero return if command has timed out.
99 //**************************************************************
101 int tmr_chk_timeout( void )
107 curTime = tmr_read_bios_timer();
109 // if we have passed midnight, restart
110 if ( curTime < tmr_cmd_start_time )
112 tmr_cmd_start_time = curTime;
117 if ( curTime >= ( tmr_cmd_start_time + ( tmr_time_out * 18L ) ) )
124 //**************************************************************
126 // tmr_get_delay_counts - compute the number calls to
127 // tmr_waste_time() required for 1s, 1ms, 1us and 500ns delays.
129 //**************************************************************
131 // our 'waste time' function (do some 32-bit multiply/divide)
133 static long tmr_waste_time( long p );
135 static long tmr_waste_time( long p )
138 volatile long lc = 100;
139 for(int i = 0; i < 100; i++){
140 volatile long k = ( lc * lc ) / ( ( p * p ) + 1 );
143 return ( lc * lc ) / ( ( p * p ) + 1 );
146 // get the delay counts
148 void tmr_get_delay_counts( void )
152 long curTime, startTime, endTime;
160 // outside loop to handle crossing midnight
165 // wait until the timer ticks
166 startTime = tmr_read_bios_timer();
169 curTime = tmr_read_bios_timer();
170 if ( curTime != startTime )
173 // waste time for 1 second
174 endTime = curTime + 18L;
177 for ( loop = 0; loop < 100; loop ++ )
181 curTime = tmr_read_bios_timer();
183 if ( curTime < startTime )
185 count = 0; // yes, zero count
189 if ( curTime >= endTime )
191 retry = 0; // yes, we have a 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;
206 // make sure 1us count is at least 2
207 if ( tmr_1us_count < 2L )
209 // make sure 500ns count is at least 1
210 if ( tmr_500ns_count < 1L )
211 tmr_500ns_count = 1L;
214 //**************************************************************
216 // tmr_delay_1ms - delay approximately 'count' milliseconds
218 //**************************************************************
220 void tmr_delay_1ms( long count )
223 long loopcnt = tmr_1ms_count * count;
225 while ( loopcnt > 0 )
232 //**************************************************************
234 // tmr_delay_1us - delay approximately 'count' microseconds
236 //**************************************************************
238 void tmr_delay_1us( long count )
241 long loopcnt = tmr_1us_count * count;
243 while ( loopcnt > 0 )
250 //**************************************************************
252 // tmr_ata_delay - delay approximately 500 nanoseconds
254 //**************************************************************
256 void tmr_delay_ata( void )
259 long loopcnt = tmr_500ns_count;
261 while ( loopcnt > 0 )
268 //**************************************************************
270 // tmr_atapi_delay() - delay for ~80ms so that poorly designed
271 // atapi device have time to updated their
274 //**************************************************************
276 void tmr_delay_atapi( int dev )
280 if ( reg_config_info[dev] == REG_CONFIG_TYPE_ATA )
282 if ( ! reg_atapi_delay_flag )
284 trc_llt( 0, 0, TRC_LLT_DELAY1 );
285 tmr_delay_1ms( 80L );
288 //**************************************************************
290 // tmr_xfer_delay() - random delay until the bios timer ticks
293 //**************************************************************
295 void tmr_delay_xfer( void )
300 trc_llt( 0, 0, TRC_LLT_DELAY2 );
301 lw = tmr_read_bios_timer();
302 while ( lw == tmr_read_bios_timer() )