1 |
30 |
unneback |
/*-------------------------------------------------------------------------+
|
2 |
|
|
| ckinit.c v1.1 - PC386 BSP - 1997/08/07
|
3 |
|
|
+--------------------------------------------------------------------------+
|
4 |
|
|
| This file contains the PC386 clock package.
|
5 |
|
|
+--------------------------------------------------------------------------+
|
6 |
|
|
| (C) Copyright 1997 -
|
7 |
|
|
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
8 |
|
|
|
|
9 |
|
|
| http://pandora.ist.utl.pt
|
10 |
|
|
|
|
11 |
|
|
| Instituto Superior Tecnico * Lisboa * PORTUGAL
|
12 |
|
|
+--------------------------------------------------------------------------+
|
13 |
|
|
| Disclaimer:
|
14 |
|
|
|
|
15 |
|
|
| This file is provided "AS IS" without warranty of any kind, either
|
16 |
|
|
| expressed or implied.
|
17 |
|
|
+--------------------------------------------------------------------------+
|
18 |
|
|
| This code is based on:
|
19 |
|
|
| ckinit.c,v 1.4 1995/12/19 20:07:13 joel Exp - go32 BSP
|
20 |
|
|
| With the following copyright notice:
|
21 |
|
|
| **************************************************************************
|
22 |
|
|
| * COPYRIGHT (c) 1989-1999.
|
23 |
|
|
| * On-Line Applications Research Corporation (OAR).
|
24 |
|
|
| *
|
25 |
|
|
| * The license and distribution terms for this file may be
|
26 |
|
|
| * found in found in the file LICENSE in this distribution or at
|
27 |
|
|
| * http://www.OARcorp.com/rtems/license.html.
|
28 |
|
|
| **************************************************************************
|
29 |
|
|
|
|
30 |
|
|
| $Id: ckinit.c,v 1.2 2001-09-27 11:59:47 chris Exp $
|
31 |
|
|
+--------------------------------------------------------------------------*/
|
32 |
|
|
|
33 |
|
|
|
34 |
|
|
#include <stdlib.h>
|
35 |
|
|
|
36 |
|
|
#include <bsp.h>
|
37 |
|
|
#include <irq.h>
|
38 |
|
|
#include <rtems/libio.h>
|
39 |
|
|
|
40 |
|
|
/*-------------------------------------------------------------------------+
|
41 |
|
|
| Macros
|
42 |
|
|
+--------------------------------------------------------------------------*/
|
43 |
|
|
#if 0
|
44 |
|
|
/* This was dropped in the last revision. Its a nice thing to know. */
|
45 |
|
|
#define TICKS_PER_SECOND() \
|
46 |
|
|
(1000000 / (Clock_isrs_per_tick * microseconds_per_isr))
|
47 |
|
|
#endif /* 0 */
|
48 |
|
|
|
49 |
|
|
/*-------------------------------------------------------------------------+
|
50 |
|
|
| Global Variables
|
51 |
|
|
+--------------------------------------------------------------------------*/
|
52 |
|
|
|
53 |
|
|
volatile rtems_unsigned32 Clock_driver_ticks; /* Tick (interrupt) counter. */
|
54 |
|
|
rtems_unsigned32 Clock_isrs_per_tick; /* ISRs per tick. */
|
55 |
|
|
rtems_unsigned32 Clock_isrs; /* ISRs until next tick. */
|
56 |
|
|
|
57 |
|
|
/* The following variables are set by the clock driver during its init */
|
58 |
|
|
|
59 |
|
|
rtems_device_major_number rtems_clock_major = ~0;
|
60 |
|
|
rtems_device_minor_number rtems_clock_minor;
|
61 |
|
|
|
62 |
|
|
/*-------------------------------------------------------------------------+
|
63 |
|
|
| Function: clockIsr
|
64 |
|
|
| Description: Interrupt Service Routine for clock (0h) interruption.
|
65 |
|
|
| Global Variables: Clock_driver_ticks, Clock_isrs.
|
66 |
|
|
| Arguments: vector - standard RTEMS argument - see documentation.
|
67 |
|
|
| Returns: standard return value - see documentation.
|
68 |
|
|
+--------------------------------------------------------------------------*/
|
69 |
|
|
static void clockIsr()
|
70 |
|
|
{
|
71 |
|
|
/*-------------------------------------------------------------------------+
|
72 |
|
|
| PLEASE NOTE: The following is directly transcribed from the go32 BSP for
|
73 |
|
|
| those who wish to use it with PENTIUM based machine. It needs
|
74 |
|
|
| to be correctly integrated with the rest of the code!!!
|
75 |
|
|
+--------------------------------------------------------------------------*/
|
76 |
|
|
|
77 |
|
|
#if 0 && defined(pentium) /* more accurate clock for PENTIUMs (not supported) */
|
78 |
|
|
{
|
79 |
|
|
extern long long Last_RDTSC;
|
80 |
|
|
__asm __volatile(".byte 0x0F, 0x31" : "=A" (Last_RDTSC));
|
81 |
|
|
}
|
82 |
|
|
#endif /* 0 && pentium */
|
83 |
|
|
|
84 |
|
|
Clock_driver_ticks++;
|
85 |
|
|
|
86 |
|
|
if ( Clock_isrs == 1 )
|
87 |
|
|
{
|
88 |
|
|
rtems_clock_tick();
|
89 |
|
|
Clock_isrs = Clock_isrs_per_tick;
|
90 |
|
|
}
|
91 |
|
|
else
|
92 |
|
|
Clock_isrs--;
|
93 |
|
|
|
94 |
|
|
} /* clockIsr */
|
95 |
|
|
|
96 |
|
|
/*-------------------------------------------------------------------------+
|
97 |
|
|
| Function: Clock_exit
|
98 |
|
|
| Description: Clock cleanup routine at RTEMS exit. NOTE: This routine is
|
99 |
|
|
| not really necessary, since there will be a reset at exit.
|
100 |
|
|
| Global Variables: None.
|
101 |
|
|
| Arguments: None.
|
102 |
|
|
| Returns: Nothing.
|
103 |
|
|
+--------------------------------------------------------------------------*/
|
104 |
|
|
void clockOff(const rtems_irq_connect_data* unused)
|
105 |
|
|
{
|
106 |
|
|
/* reset timer mode to standard (BIOS) value */
|
107 |
|
|
outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
|
108 |
|
|
outport_byte(TIMER_CNTR0, 0);
|
109 |
|
|
outport_byte(TIMER_CNTR0, 0);
|
110 |
|
|
} /* Clock_exit */
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
/*-------------------------------------------------------------------------+
|
114 |
|
|
| Function: Install_clock
|
115 |
|
|
| Description: Initialize and install clock interrupt handler.
|
116 |
|
|
| Global Variables: None.
|
117 |
|
|
| Arguments: None.
|
118 |
|
|
| Returns: Nothing.
|
119 |
|
|
+--------------------------------------------------------------------------*/
|
120 |
|
|
static void clockOn(const rtems_irq_connect_data* unused)
|
121 |
|
|
{
|
122 |
|
|
rtems_unsigned32 microseconds_per_isr;
|
123 |
|
|
|
124 |
|
|
#if 0
|
125 |
|
|
/* Initialize clock from on-board real time clock. This breaks the */
|
126 |
|
|
/* test code which assumes which assumes the application will do it. */
|
127 |
|
|
{
|
128 |
|
|
rtems_time_of_day now;
|
129 |
|
|
|
130 |
|
|
/* External Prototypes */
|
131 |
|
|
extern void init_rtc(void); /* defined in 'rtc.c' */
|
132 |
|
|
extern long rtc_read(rtems_time_of_day *); /* defined in 'rtc.c' */
|
133 |
|
|
|
134 |
|
|
init_rtc();
|
135 |
|
|
if (rtc_read(&now) >= 0)
|
136 |
|
|
clock_set(&now);
|
137 |
|
|
}
|
138 |
|
|
#endif /* 0 */
|
139 |
|
|
|
140 |
|
|
/* Start by assuming hardware counter is large enough, then scale it until
|
141 |
|
|
it actually fits. */
|
142 |
|
|
|
143 |
|
|
Clock_driver_ticks = 0;
|
144 |
|
|
Clock_isrs_per_tick = 1;
|
145 |
|
|
|
146 |
|
|
if (BSP_Configuration.microseconds_per_tick == 0)
|
147 |
|
|
microseconds_per_isr = 10000; /* default 10 ms */
|
148 |
|
|
else
|
149 |
|
|
microseconds_per_isr = BSP_Configuration.microseconds_per_tick;
|
150 |
|
|
while (US_TO_TICK(microseconds_per_isr) > 65535)
|
151 |
|
|
{
|
152 |
|
|
Clock_isrs_per_tick *= 10;
|
153 |
|
|
microseconds_per_isr /= 10;
|
154 |
|
|
}
|
155 |
|
|
|
156 |
|
|
Clock_isrs = Clock_isrs_per_tick; /* Initialize Clock_isrs */
|
157 |
|
|
|
158 |
|
|
{
|
159 |
|
|
/* 105/88 approximates TIMER_TICK * 1e-6 */
|
160 |
|
|
rtems_unsigned32 count = US_TO_TICK(microseconds_per_isr);
|
161 |
|
|
|
162 |
|
|
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
|
163 |
|
|
outport_byte(TIMER_CNTR0, count >> 0 & 0xff);
|
164 |
|
|
outport_byte(TIMER_CNTR0, count >> 8 & 0xff);
|
165 |
|
|
}
|
166 |
|
|
|
167 |
|
|
}
|
168 |
|
|
|
169 |
|
|
int clockIsOn(const rtems_irq_connect_data* unused)
|
170 |
|
|
{
|
171 |
|
|
return ((i8259s_cache & 0x1) == 0);
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
static rtems_irq_connect_data clockIrqData = {BSP_PERIODIC_TIMER,
|
175 |
|
|
clockIsr,
|
176 |
|
|
clockOn,
|
177 |
|
|
clockOff,
|
178 |
|
|
clockIsOn};
|
179 |
|
|
|
180 |
|
|
|
181 |
|
|
|
182 |
|
|
/*-------------------------------------------------------------------------+
|
183 |
|
|
| Clock device driver INITIALIZE entry point.
|
184 |
|
|
+--------------------------------------------------------------------------+
|
185 |
|
|
| Initilizes the clock driver.
|
186 |
|
|
+--------------------------------------------------------------------------*/
|
187 |
|
|
rtems_device_driver
|
188 |
|
|
Clock_initialize(rtems_device_major_number major,
|
189 |
|
|
rtems_device_minor_number minor,
|
190 |
|
|
void *pargp)
|
191 |
|
|
{
|
192 |
|
|
|
193 |
|
|
if (!BSP_install_rtems_irq_handler (&clockIrqData)) {
|
194 |
|
|
printk("Unable to initialize system clock\n");
|
195 |
|
|
rtems_fatal_error_occurred(1);
|
196 |
|
|
}
|
197 |
|
|
/* make major/minor avail to others such as shared memory driver */
|
198 |
|
|
|
199 |
|
|
rtems_clock_major = major;
|
200 |
|
|
rtems_clock_minor = minor;
|
201 |
|
|
|
202 |
|
|
return RTEMS_SUCCESSFUL;
|
203 |
|
|
} /* Clock_initialize */
|
204 |
|
|
|
205 |
|
|
|
206 |
|
|
/*-------------------------------------------------------------------------+
|
207 |
|
|
| Console device driver CONTROL entry point
|
208 |
|
|
+--------------------------------------------------------------------------*/
|
209 |
|
|
rtems_device_driver
|
210 |
|
|
Clock_control(rtems_device_major_number major,
|
211 |
|
|
rtems_device_minor_number minor,
|
212 |
|
|
void *pargp)
|
213 |
|
|
{
|
214 |
|
|
if (pargp != NULL)
|
215 |
|
|
{
|
216 |
|
|
rtems_libio_ioctl_args_t *args = pargp;
|
217 |
|
|
|
218 |
|
|
/*-------------------------------------------------------------------------+
|
219 |
|
|
| This is hokey, but until we get a defined interface to do this, it will
|
220 |
|
|
| just be this simple...
|
221 |
|
|
+-------------------------------------------------------------------------*/
|
222 |
|
|
|
223 |
|
|
if (args->command == rtems_build_name('I', 'S', 'R', ' '))
|
224 |
|
|
clockIsr();
|
225 |
|
|
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
|
226 |
|
|
{
|
227 |
|
|
if (!BSP_install_rtems_irq_handler (&clockIrqData)) {
|
228 |
|
|
printk("Error installing clock interrupt handler!\n");
|
229 |
|
|
rtems_fatal_error_occurred(1);
|
230 |
|
|
}
|
231 |
|
|
}
|
232 |
|
|
}
|
233 |
|
|
|
234 |
|
|
return RTEMS_SUCCESSFUL;
|
235 |
|
|
} /* Clock_control */
|
236 |
|
|
|
237 |
|
|
void Clock_exit()
|
238 |
|
|
{
|
239 |
|
|
BSP_remove_rtems_irq_handler (&clockIrqData);
|
240 |
|
|
}
|
241 |
|
|
|
242 |
|
|
/*-------------------------------------------------------------------------+
|
243 |
|
|
| PLEASE NOTE: The following is directly transcribed from the go32 BSP for
|
244 |
|
|
| those who wish to use it with PENTIUM based machine. It needs
|
245 |
|
|
| to be correctly integrated with the rest of the code!!!
|
246 |
|
|
+--------------------------------------------------------------------------*/
|
247 |
|
|
|
248 |
|
|
|
249 |
|
|
#if 0 && defined(pentium)
|
250 |
|
|
|
251 |
|
|
/* This can be used to get extremely accurate timing on a pentium. */
|
252 |
|
|
/* It isn't supported. [bryce] */
|
253 |
|
|
|
254 |
|
|
#define HZ 90.0
|
255 |
|
|
|
256 |
|
|
volatile long long Last_RDTSC;
|
257 |
|
|
|
258 |
|
|
#define RDTSC()\
|
259 |
|
|
({ long long _now; __asm __volatile (".byte 0x0F,0x31":"=A"(_now)); _now; })
|
260 |
|
|
|
261 |
|
|
long long Kernel_Time_ns( void )
|
262 |
|
|
{
|
263 |
|
|
extern rtems_unsigned32 _TOD_Ticks_per_second;
|
264 |
|
|
|
265 |
|
|
unsigned isrs_per_second = Clock_isrs_per_tick * _TOD_Ticks_per_second;
|
266 |
|
|
long long now;
|
267 |
|
|
int flags;
|
268 |
|
|
|
269 |
|
|
disable_intr(flags);
|
270 |
|
|
now = 1e9 * Clock_driver_ticks / isrs_per_second +
|
271 |
|
|
(RDTSC() - Last_RDTSC) * (1000.0/HZ);
|
272 |
|
|
enable_intr(flags);
|
273 |
|
|
return now;
|
274 |
|
|
} /* Kernel_Time_ns */
|
275 |
|
|
|
276 |
|
|
#endif /* 0 && pentium */
|