FreeBSD/Linux Kernel Cross Reference
sys/i386at/clockpit.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: clockpit.c,v $
29 * Revision 2.3 93/12/23 10:05:01 dbg
30 * Added missing include files.
31 * [93/12/14 dbg]
32 *
33 * Revision 2.2 93/11/17 16:41:54 dbg
34 * Used common routines from device/clock_dev.c
35 * [93/06/02 dbg]
36 *
37 * Changed mmap routines to return physical address instead of
38 * physical page number.
39 * [93/05/24 dbg]
40 *
41 * Added to microkernel mainline.
42 *
43 * Created
44 * [92/06/22 savage]
45 *
46 */
47 #include <clockpit.h>
48
49 #include <mach/boolean.h>
50 #include <mach/time_spec.h>
51 #include <kern/clock.h>
52 #include <kern/kern_io.h>
53 #include <vm/vm_kern.h>
54
55 #include <sys/types.h>
56 #include <chips/busses.h>
57 #include <device/device_types.h>
58 #include <device/clock_status.h>
59 #include <device/clock_dev.h>
60
61 #include <i386/machspl.h>
62 #include <i386/pio.h>
63 #include <i386/pit.h>
64
65 /*
66 * Adjust for PIT clock round off... Ugly, but true...
67 */
68 #define HZ 100 /* default frequency */
69
70 #define CLOCKPIT_SKEW(res) (((CLKNUM%(NANOSEC_PER_SEC/res)) \
71 * res) / CLKNUM)
72 #define CLOCKPIT_DEFAULT_RESOLUTION (NANOSEC_PER_SEC/HZ - \
73 CLOCKPIT_SKEW((NANOSEC_PER_SEC/HZ)))
74
75 #define CLOCKPIT_MAX_RESOLUTION (10000000)
76
77 /*
78 * Minimum set to 1/2 a millisecond... if you want to play with lower
79 * then change this number.
80 */
81 #define CLOCKPIT_MIN_RESOLUTION (500000)
82
83
84 mach_clock_data_t clockpit0;
85
86 mach_clock_t clockpit[] = {&clockpit0};
87
88 void clockpit_setresolution(mach_clock_t); /* forward */
89 void clockpit_write(mach_clock_t, time_spec_t);
90 void clockpit_enable_interrupts(mach_clock_t);
91
92 struct clock_ops clockpit_ops = {
93 clockpit_setresolution,
94 clockpit_write,
95 clockpit_enable_interrupts
96 };
97
98 void clockpitsysintr(int);
99
100 boolean_t clockpitprobe(
101 vm_offset_t port,
102 struct bus_device *dev);
103 void clockpitattach(
104 struct bus_device *dev);
105
106 static vm_offset_t clockpit_std[NCLOCKPIT] = { 0 };
107 static struct bus_device *clockpit_info[NCLOCKPIT];
108 struct bus_driver clockpitdriver = {
109 clockpitprobe, 0, clockpitattach, 0, clockpit_std, "clockpit",
110 clockpit_info,0, 0, 0};
111
112 boolean_t clockpitprobe(
113 vm_offset_t port,
114 struct bus_device *dev)
115 {
116 int unit = dev->unit;
117
118 if (unit < 0 || unit >= NCLOCKPIT)
119 return FALSE;
120
121 /*
122 * Always have one.
123 */
124 return TRUE;
125 }
126
127 void clockpitattach(
128 struct bus_device *dev)
129 {
130 int unit = dev->unit;
131 mach_clock_t clock = clockpit[unit];
132
133 clock_init(clock, &clockpit_ops);
134 clock->resolution = CLOCKPIT_DEFAULT_RESOLUTION;
135
136 if (sys_clock == 0) {
137 /*
138 * If no system clock already, use this as system clock.
139 */
140 sys_clock = &clockpit0;
141 dev->intr = clockpitsysintr; /* use system clock interrupt */
142 dev_change_indirect("clock_priv", "clockpit", unit);
143 /* set generic clock device */
144 set_clock_unpriv(); /* and unprivileged clock */
145 }
146
147 printf(", time = %u secs : %u nsecs, resolution = %u nsecs",
148 clock->time.seconds,
149 clock->time.nanoseconds,
150 clock->resolution);
151 }
152
153 /*
154 * Enable interrupts from PIT clock
155 */
156 void clockpit_enable_interrupts(
157 mach_clock_t clock)
158 {
159 take_dev_irq(clockpit_info[0]);
160 }
161
162 io_return_t clockpitopen(
163 int dev)
164 {
165 if (dev < 0 || dev >= NCLOCKPIT) {
166 return D_NO_SUCH_DEVICE;
167 }
168 return clock_open(clockpit[dev]);
169 }
170
171 io_return_t clockpitclose(
172 int dev)
173 {
174 return D_SUCCESS;
175 }
176
177 io_return_t clockpitgetstat(
178 int dev,
179 int flavor,
180 dev_status_t stat,
181 natural_t *count)
182 {
183 return clock_getstat(clockpit[dev], flavor, stat, count);
184 }
185
186 io_return_t clockpitsetstat(
187 int dev,
188 int flavor,
189 dev_status_t stat,
190 natural_t count)
191 {
192 mach_clock_t clock = clockpit[dev];
193 unsigned int frequency;
194 unsigned int skew;
195 spl_t s;
196
197 switch (flavor) {
198 case CLOCK_RESOLUTION:
199 {
200 clock_resolution_t request;
201
202 if (count < CLOCK_RESOLUTION_COUNT)
203 return D_INVALID_SIZE;
204
205 request = (clock_resolution_t)stat;
206 if (request->resolution < CLOCKPIT_MIN_RESOLUTION ||
207 request->resolution > CLOCKPIT_MAX_RESOLUTION)
208 {
209 return D_INVALID_SIZE;
210 }
211
212 frequency = NANOSEC_PER_SEC/request->resolution;
213 skew = CLOCKPIT_SKEW(request->resolution);
214
215 if (skew > request->skew) {
216 return D_INVALID_SIZE;
217 }
218
219 s = splsched();
220 clock_queue_lock(clock);
221
222 clock->new_resolution = request->resolution - skew;
223 clock->new_skew = request->skew + skew; /* ? */
224
225 clock_queue_unlock(clock);
226 splx(s);
227 return D_SUCCESS;
228 }
229
230 default:
231 return clock_setstat(clock, flavor, stat, count);
232 }
233 }
234
235 vm_offset_t clockpitmmap(
236 int dev,
237 vm_offset_t off,
238 vm_prot_t prot)
239 {
240 return clock_map_page(clockpit[dev], off, prot);
241 }
242
243 io_return_t clockpitinfo(
244 int dev,
245 int flavor,
246 mach_clock_t *info)
247 {
248 if (flavor == D_INFO_CLOCK) {
249 *info = clockpit[dev];
250 return D_SUCCESS;
251 }
252 else {
253 return D_INVALID_OPERATION;
254 }
255 }
256
257 void clockpit_setresolution(
258 mach_clock_t clock)
259 {
260 unsigned int pitval;
261 unsigned int frequency;
262
263 frequency = NANOSEC_PER_SEC/(clock->resolution);
264
265 pitval = CLKNUM/frequency;
266 outb(PITCTL_PORT, PIT_C0|PIT_SQUAREMODE|PIT_READMODE);
267 outb(PITCTR0_PORT, pitval);
268 outb(PITCTR0_PORT, pitval>>8);
269 }
270
271 void clockpit_write(
272 mach_clock_t clock,
273 time_spec_t new_time)
274 {
275 /* XXX no permanent clock storage XXX */
276 }
277
Cache object: 3055a5919d0099dc395b191ccaff7c5e
|