| @@ -1,627 +1,623 @@ | | | @@ -1,627 +1,623 @@ |
1 | /* $NetBSD: clock.c,v 1.37 2005/12/24 20:06:58 perry Exp $ */ | | 1 | /* $NetBSD: clock.c,v 1.37.34.1 2009/01/03 11:17:41 jdc Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1982, 1990 The Regents of the University of California. | | 4 | * Copyright (c) 1982, 1990 The Regents of the University of California. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * the Systems Programming Group of the University of Utah Computer | | 8 | * the Systems Programming Group of the University of Utah Computer |
9 | * Science Department. | | 9 | * Science Department. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * 3. Neither the name of the University nor the names of its contributors | | 19 | * 3. Neither the name of the University nor the names of its contributors |
20 | * may be used to endorse or promote products derived from this software | | 20 | * may be used to endorse or promote products derived from this software |
21 | * without specific prior written permission. | | 21 | * without specific prior written permission. |
22 | * | | 22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 | * SUCH DAMAGE. | | 33 | * SUCH DAMAGE. |
34 | * | | 34 | * |
35 | * from: Utah $Hdr: clock.c 1.18 91/01/21$ | | 35 | * from: Utah $Hdr: clock.c 1.18 91/01/21$ |
36 | * | | 36 | * |
37 | * @(#)clock.c 7.6 (Berkeley) 5/7/91 | | 37 | * @(#)clock.c 7.6 (Berkeley) 5/7/91 |
38 | */ | | 38 | */ |
39 | /* | | 39 | /* |
40 | * Copyright (c) 1988 University of Utah. | | 40 | * Copyright (c) 1988 University of Utah. |
41 | * | | 41 | * |
42 | * This code is derived from software contributed to Berkeley by | | 42 | * This code is derived from software contributed to Berkeley by |
43 | * the Systems Programming Group of the University of Utah Computer | | 43 | * the Systems Programming Group of the University of Utah Computer |
44 | * Science Department. | | 44 | * Science Department. |
45 | * | | 45 | * |
46 | * Redistribution and use in source and binary forms, with or without | | 46 | * Redistribution and use in source and binary forms, with or without |
47 | * modification, are permitted provided that the following conditions | | 47 | * modification, are permitted provided that the following conditions |
48 | * are met: | | 48 | * are met: |
49 | * 1. Redistributions of source code must retain the above copyright | | 49 | * 1. Redistributions of source code must retain the above copyright |
50 | * notice, this list of conditions and the following disclaimer. | | 50 | * notice, this list of conditions and the following disclaimer. |
51 | * 2. Redistributions in binary form must reproduce the above copyright | | 51 | * 2. Redistributions in binary form must reproduce the above copyright |
52 | * notice, this list of conditions and the following disclaimer in the | | 52 | * notice, this list of conditions and the following disclaimer in the |
53 | * documentation and/or other materials provided with the distribution. | | 53 | * documentation and/or other materials provided with the distribution. |
54 | * 3. All advertising materials mentioning features or use of this software | | 54 | * 3. All advertising materials mentioning features or use of this software |
55 | * must display the following acknowledgement: | | 55 | * must display the following acknowledgement: |
56 | * This product includes software developed by the University of | | 56 | * This product includes software developed by the University of |
57 | * California, Berkeley and its contributors. | | 57 | * California, Berkeley and its contributors. |
58 | * 4. Neither the name of the University nor the names of its contributors | | 58 | * 4. Neither the name of the University nor the names of its contributors |
59 | * may be used to endorse or promote products derived from this software | | 59 | * may be used to endorse or promote products derived from this software |
60 | * without specific prior written permission. | | 60 | * without specific prior written permission. |
61 | * | | 61 | * |
62 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 62 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
63 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 63 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
64 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 64 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
65 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 65 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
66 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 66 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
72 | * SUCH DAMAGE. | | 72 | * SUCH DAMAGE. |
73 | * | | 73 | * |
74 | * from: Utah $Hdr: clock.c 1.18 91/01/21$ | | 74 | * from: Utah $Hdr: clock.c 1.18 91/01/21$ |
75 | * | | 75 | * |
76 | * @(#)clock.c 7.6 (Berkeley) 5/7/91 | | 76 | * @(#)clock.c 7.6 (Berkeley) 5/7/91 |
77 | */ | | 77 | */ |
78 | | | 78 | |
79 | #include <sys/cdefs.h> | | 79 | #include <sys/cdefs.h> |
80 | __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.37 2005/12/24 20:06:58 perry Exp $"); | | 80 | __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.37.34.1 2009/01/03 11:17:41 jdc Exp $"); |
81 | | | 81 | |
82 | #include <sys/param.h> | | 82 | #include <sys/param.h> |
83 | #include <sys/kernel.h> | | 83 | #include <sys/kernel.h> |
84 | #include <sys/systm.h> | | 84 | #include <sys/systm.h> |
85 | #include <sys/device.h> | | 85 | #include <sys/device.h> |
86 | #include <sys/uio.h> | | 86 | #include <sys/uio.h> |
87 | #include <sys/conf.h> | | 87 | #include <sys/conf.h> |
88 | #include <sys/proc.h> | | 88 | #include <sys/proc.h> |
89 | #include <sys/event.h> | | 89 | #include <sys/event.h> |
90 | | | 90 | |
91 | #include <dev/clock_subr.h> | | 91 | #include <dev/clock_subr.h> |
92 | | | 92 | |
93 | #include <machine/psl.h> | | 93 | #include <machine/psl.h> |
94 | #include <machine/cpu.h> | | 94 | #include <machine/cpu.h> |
95 | #include <machine/iomap.h> | | 95 | #include <machine/iomap.h> |
96 | #include <machine/mfp.h> | | 96 | #include <machine/mfp.h> |
97 | #include <atari/dev/clockreg.h> | | 97 | #include <atari/dev/clockreg.h> |
98 | #include <atari/atari/device.h> | | 98 | #include <atari/atari/device.h> |
99 | | | 99 | |
100 | #if defined(GPROF) && defined(PROFTIMER) | | 100 | #if defined(GPROF) && defined(PROFTIMER) |
101 | #include <machine/profile.h> | | 101 | #include <machine/profile.h> |
102 | #endif | | 102 | #endif |
103 | | | 103 | |
104 | /* | | 104 | /* |
105 | * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider | | 105 | * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider |
106 | * of 200. Therefore the timer runs at an effective rate of: | | 106 | * of 200. Therefore the timer runs at an effective rate of: |
107 | * 2457600/200 = 12288Hz. | | 107 | * 2457600/200 = 12288Hz. |
108 | */ | | 108 | */ |
109 | #define CLOCK_HZ 12288 | | 109 | #define CLOCK_HZ 12288 |
110 | | | 110 | |
111 | /* | | 111 | /* |
112 | * Machine-dependent clock routines. | | 112 | * Machine-dependent clock routines. |
113 | * | | 113 | * |
114 | * Inittodr initializes the time of day hardware which provides | | 114 | * Inittodr initializes the time of day hardware which provides |
115 | * date functions. | | 115 | * date functions. |
116 | * | | 116 | * |
117 | * Resettodr restores the time of day hardware after a time change. | | 117 | * Resettodr restores the time of day hardware after a time change. |
118 | */ | | 118 | */ |
119 | | | 119 | |
120 | struct clock_softc { | | 120 | struct clock_softc { |
121 | struct device sc_dev; | | 121 | struct device sc_dev; |
122 | int sc_flags; | | 122 | int sc_flags; |
123 | }; | | 123 | }; |
124 | | | 124 | |
125 | /* | | 125 | /* |
126 | * 'sc_flags' state info. Only used by the rtc-device functions. | | 126 | * 'sc_flags' state info. Only used by the rtc-device functions. |
127 | */ | | 127 | */ |
128 | #define RTC_OPEN 1 | | 128 | #define RTC_OPEN 1 |
129 | | | 129 | |
130 | dev_type_open(rtcopen); | | 130 | dev_type_open(rtcopen); |
131 | dev_type_close(rtcclose); | | 131 | dev_type_close(rtcclose); |
132 | dev_type_read(rtcread); | | 132 | dev_type_read(rtcread); |
133 | dev_type_write(rtcwrite); | | 133 | dev_type_write(rtcwrite); |
134 | | | 134 | |
135 | static void clockattach __P((struct device *, struct device *, void *)); | | 135 | static void clockattach __P((struct device *, struct device *, void *)); |
136 | static int clockmatch __P((struct device *, struct cfdata *, void *)); | | 136 | static int clockmatch __P((struct device *, struct cfdata *, void *)); |
137 | | | 137 | |
138 | CFATTACH_DECL(clock, sizeof(struct clock_softc), | | 138 | CFATTACH_DECL(clock, sizeof(struct clock_softc), |
139 | clockmatch, clockattach, NULL, NULL); | | 139 | clockmatch, clockattach, NULL, NULL); |
140 | | | 140 | |
141 | extern struct cfdriver clock_cd; | | 141 | extern struct cfdriver clock_cd; |
142 | | | 142 | |
143 | const struct cdevsw rtc_cdevsw = { | | 143 | const struct cdevsw rtc_cdevsw = { |
144 | rtcopen, rtcclose, rtcread, rtcwrite, noioctl, | | 144 | rtcopen, rtcclose, rtcread, rtcwrite, noioctl, |
145 | nostop, notty, nopoll, nommap, nokqfilter, | | 145 | nostop, notty, nopoll, nommap, nokqfilter, |
146 | }; | | 146 | }; |
147 | | | 147 | |
148 | void statintr __P((struct clockframe)); | | 148 | void statintr __P((struct clockframe)); |
149 | | | 149 | |
150 | static u_long gettod __P((void)); | | 150 | static u_long gettod __P((void)); |
151 | static int twodigits __P((char *, int)); | | 151 | static int twodigits __P((char *, int)); |
152 | | | 152 | |
153 | static int divisor; /* Systemclock divisor */ | | 153 | static int divisor; /* Systemclock divisor */ |
154 | | | 154 | |
155 | /* | | 155 | /* |
156 | * Statistics and profile clock intervals and variances. Variance must | | 156 | * Statistics and profile clock intervals and variances. Variance must |
157 | * be a power of 2. Since this gives us an even number, not an odd number, | | 157 | * be a power of 2. Since this gives us an even number, not an odd number, |
158 | * we discard one case and compensate. That is, a variance of 64 would | | 158 | * we discard one case and compensate. That is, a variance of 64 would |
159 | * give us offsets in [0..63]. Instead, we take offsets in [1..63]. | | 159 | * give us offsets in [0..63]. Instead, we take offsets in [1..63]. |
160 | * This is symmetric around the point 32, or statvar/2, and thus averages | | 160 | * This is symmetric around the point 32, or statvar/2, and thus averages |
161 | * to that value (assuming uniform random numbers). | | 161 | * to that value (assuming uniform random numbers). |
162 | */ | | 162 | */ |
163 | #ifdef STATCLOCK | | 163 | #ifdef STATCLOCK |
164 | static int statvar = 32; /* {stat,prof}clock variance */ | | 164 | static int statvar = 32; /* {stat,prof}clock variance */ |
165 | static int statmin; /* statclock divisor - variance/2 */ | | 165 | static int statmin; /* statclock divisor - variance/2 */ |
166 | static int profmin; /* profclock divisor - variance/2 */ | | 166 | static int profmin; /* profclock divisor - variance/2 */ |
167 | static int clk2min; /* current, from above choices */ | | 167 | static int clk2min; /* current, from above choices */ |
168 | #endif | | 168 | #endif |
169 | | | 169 | |
170 | int | | 170 | int |
171 | clockmatch(pdp, cfp, auxp) | | 171 | clockmatch(pdp, cfp, auxp) |
172 | struct device *pdp; | | 172 | struct device *pdp; |
173 | struct cfdata *cfp; | | 173 | struct cfdata *cfp; |
174 | void *auxp; | | 174 | void *auxp; |
175 | { | | 175 | { |
176 | if (!atari_realconfig) { | | 176 | if (!atari_realconfig) { |
177 | /* | | 177 | /* |
178 | * Initialize Timer-B in the ST-MFP. This timer is used by | | 178 | * Initialize Timer-B in the ST-MFP. This timer is used by |
179 | * the 'delay' function below. This timer is setup to be | | 179 | * the 'delay' function below. This timer is setup to be |
180 | * continueously counting from 255 back to zero at a | | 180 | * continueously counting from 255 back to zero at a |
181 | * frequency of 614400Hz. We do this *early* in the | | 181 | * frequency of 614400Hz. We do this *early* in the |
182 | * initialisation process. | | 182 | * initialisation process. |
183 | */ | | 183 | */ |
184 | MFP->mf_tbcr = 0; /* Stop timer */ | | 184 | MFP->mf_tbcr = 0; /* Stop timer */ |
185 | MFP->mf_iera &= ~IA_TIMB; /* Disable timer interrupts */ | | 185 | MFP->mf_iera &= ~IA_TIMB; /* Disable timer interrupts */ |
186 | MFP->mf_tbdr = 0; | | 186 | MFP->mf_tbdr = 0; |
187 | MFP->mf_tbcr = T_Q004; /* Start timer */ | | 187 | MFP->mf_tbcr = T_Q004; /* Start timer */ |
188 | | | 188 | |
189 | /* | | 189 | /* |
190 | * Initialize the time structure | | 190 | * Initialize the time structure |
191 | */ | | 191 | */ |
192 | time.tv_sec = 0; | | 192 | time.tv_sec = 0; |
193 | time.tv_usec = 0; | | 193 | time.tv_usec = 0; |
194 | | | 194 | |
195 | return 0; | | 195 | return 0; |
196 | } | | 196 | } |
197 | if(!strcmp("clock", auxp)) | | 197 | if(!strcmp("clock", auxp)) |
198 | return(1); | | 198 | return(1); |
199 | return(0); | | 199 | return(0); |
200 | } | | 200 | } |
201 | | | 201 | |
202 | /* | | 202 | /* |
203 | * Start the real-time clock. | | 203 | * Start the real-time clock. |
204 | */ | | 204 | */ |
205 | void clockattach(pdp, dp, auxp) | | 205 | void clockattach(pdp, dp, auxp) |
206 | struct device *pdp, *dp; | | 206 | struct device *pdp, *dp; |
207 | void *auxp; | | 207 | void *auxp; |
208 | { | | 208 | { |
209 | struct clock_softc *sc = (void *)dp; | | 209 | struct clock_softc *sc = (void *)dp; |
210 | | | 210 | |
211 | sc->sc_flags = 0; | | 211 | sc->sc_flags = 0; |
212 | | | 212 | |
213 | /* | | 213 | /* |
214 | * Initialize Timer-A in the ST-MFP. We use a divisor of 200. | | 214 | * Initialize Timer-A in the ST-MFP. We use a divisor of 200. |
215 | * The MFP clock runs at 2457600Hz. Therefore the timer runs | | 215 | * The MFP clock runs at 2457600Hz. Therefore the timer runs |
216 | * at an effective rate of: 2457600/200 = 12288Hz. The | | 216 | * at an effective rate of: 2457600/200 = 12288Hz. The |
217 | * following expression works for 48, 64 or 96 hz. | | 217 | * following expression works for 48, 64 or 96 hz. |
218 | */ | | 218 | */ |
219 | divisor = CLOCK_HZ/hz; | | 219 | divisor = CLOCK_HZ/hz; |
220 | MFP->mf_tacr = 0; /* Stop timer */ | | 220 | MFP->mf_tacr = 0; /* Stop timer */ |
221 | MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */ | | 221 | MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */ |
222 | MFP->mf_tadr = divisor; /* Set divisor */ | | 222 | MFP->mf_tadr = divisor; /* Set divisor */ |
223 | | | 223 | |
224 | if (hz != 48 && hz != 64 && hz != 96) { /* XXX */ | | 224 | if (hz != 48 && hz != 64 && hz != 96) { /* XXX */ |
225 | printf (": illegal value %d for systemclock, reset to %d\n\t", | | 225 | printf (": illegal value %d for systemclock, reset to %d\n\t", |
226 | hz, 64); | | 226 | hz, 64); |
227 | hz = 64; | | 227 | hz = 64; |
228 | } | | 228 | } |
229 | printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor); | | 229 | printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor); |
230 | | | 230 | |
231 | #ifdef STATCLOCK | | 231 | #ifdef STATCLOCK |
232 | if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz)) | | 232 | if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz)) |
233 | stathz = hz; | | 233 | stathz = hz; |
234 | if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz)) | | 234 | if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz)) |
235 | profhz = hz << 1; | | 235 | profhz = hz << 1; |
236 | | | 236 | |
237 | MFP->mf_tcdcr &= 0x7; /* Stop timer */ | | 237 | MFP->mf_tcdcr &= 0x7; /* Stop timer */ |
238 | MFP->mf_ierb &= ~IB_TIMC; /* Disable timer inter. */ | | 238 | MFP->mf_ierb &= ~IB_TIMC; /* Disable timer inter. */ |
239 | MFP->mf_tcdr = CLOCK_HZ/stathz; /* Set divisor */ | | 239 | MFP->mf_tcdr = CLOCK_HZ/stathz; /* Set divisor */ |
240 | | | 240 | |
241 | statmin = (CLOCK_HZ/stathz) - (statvar >> 1); | | 241 | statmin = (CLOCK_HZ/stathz) - (statvar >> 1); |
242 | profmin = (CLOCK_HZ/profhz) - (statvar >> 1); | | 242 | profmin = (CLOCK_HZ/profhz) - (statvar >> 1); |
243 | clk2min = statmin; | | 243 | clk2min = statmin; |
244 | #endif /* STATCLOCK */ | | 244 | #endif /* STATCLOCK */ |
245 | | | 245 | |
246 | } | | 246 | } |
247 | | | 247 | |
248 | void cpu_initclocks() | | 248 | void cpu_initclocks() |
249 | { | | 249 | { |
250 | MFP->mf_tacr = T_Q200; /* Start timer */ | | 250 | MFP->mf_tacr = T_Q200; /* Start timer */ |
251 | MFP->mf_ipra = (u_int8_t)~IA_TIMA;/* Clear pending interrupts */ | | 251 | MFP->mf_ipra = (u_int8_t)~IA_TIMA;/* Clear pending interrupts */ |
252 | MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */ | | 252 | MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */ |
253 | MFP->mf_imra |= IA_TIMA; /* ..... */ | | 253 | MFP->mf_imra |= IA_TIMA; /* ..... */ |
254 | | | 254 | |
255 | #ifdef STATCLOCK | | 255 | #ifdef STATCLOCK |
256 | MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start */ | | 256 | MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start */ |
257 | MFP->mf_iprb = (u_int8_t)~IB_TIMC;/* Clear pending interrupts */ | | 257 | MFP->mf_iprb = (u_int8_t)~IB_TIMC;/* Clear pending interrupts */ |
258 | MFP->mf_ierb |= IB_TIMC; /* Enable timer interrupts */ | | 258 | MFP->mf_ierb |= IB_TIMC; /* Enable timer interrupts */ |
259 | MFP->mf_imrb |= IB_TIMC; /* ..... */ | | 259 | MFP->mf_imrb |= IB_TIMC; /* ..... */ |
260 | #endif /* STATCLOCK */ | | 260 | #endif /* STATCLOCK */ |
261 | } | | 261 | } |
262 | | | 262 | |
263 | void | | 263 | void |
264 | setstatclockrate(newhz) | | 264 | setstatclockrate(newhz) |
265 | int newhz; | | 265 | int newhz; |
266 | { | | 266 | { |
267 | #ifdef STATCLOCK | | 267 | #ifdef STATCLOCK |
268 | if (newhz == stathz) | | 268 | if (newhz == stathz) |
269 | clk2min = statmin; | | 269 | clk2min = statmin; |
270 | else clk2min = profmin; | | 270 | else clk2min = profmin; |
271 | #endif /* STATCLOCK */ | | 271 | #endif /* STATCLOCK */ |
272 | } | | 272 | } |
273 | | | 273 | |
274 | #ifdef STATCLOCK | | 274 | #ifdef STATCLOCK |
275 | void | | 275 | void |
276 | statintr(frame) | | 276 | statintr(frame) |
277 | struct clockframe frame; | | 277 | struct clockframe frame; |
278 | { | | 278 | { |
279 | register int var, r; | | 279 | register int var, r; |
280 | | | 280 | |
281 | var = statvar - 1; | | 281 | var = statvar - 1; |
282 | do { | | 282 | do { |
283 | r = random() & var; | | 283 | r = random() & var; |
284 | } while(r == 0); | | 284 | } while(r == 0); |
285 | | | 285 | |
286 | /* | | 286 | /* |
287 | * Note that we are always lagging behind as the new divisor | | 287 | * Note that we are always lagging behind as the new divisor |
288 | * value will not be loaded until the next interrupt. This | | 288 | * value will not be loaded until the next interrupt. This |
289 | * shouldn't disturb the median frequency (I think ;-) ) as | | 289 | * shouldn't disturb the median frequency (I think ;-) ) as |
290 | * only the value used when switching frequencies is used | | 290 | * only the value used when switching frequencies is used |
291 | * twice. This shouldn't happen very often. | | 291 | * twice. This shouldn't happen very often. |
292 | */ | | 292 | */ |
293 | MFP->mf_tcdr = clk2min + r; | | 293 | MFP->mf_tcdr = clk2min + r; |
294 | | | 294 | |
295 | statclock(&frame); | | 295 | statclock(&frame); |
296 | } | | 296 | } |
297 | #endif /* STATCLOCK */ | | 297 | #endif /* STATCLOCK */ |
298 | | | 298 | |
299 | /* | | 299 | /* |
300 | * Returns number of usec since last recorded clock "tick" | | 300 | * Returns number of usec since last recorded clock "tick" |
301 | * (i.e. clock interrupt). | | 301 | * (i.e. clock interrupt). |
302 | */ | | 302 | */ |
303 | long | | 303 | long |
304 | clkread() | | 304 | clkread() |
305 | { | | 305 | { |
306 | u_int delta; | | 306 | u_int delta; |
307 | u_char ipra, tadr; | | 307 | u_char ipra, tadr; |
308 | | | 308 | |
309 | /* | | 309 | /* |
310 | * Note: Order is important! | | 310 | * Note: Order is important! |
311 | * By reading 'ipra' before 'tadr' and caching the data, I try to avoid | | 311 | * By reading 'ipra' before 'tadr' and caching the data, I try to avoid |
312 | * the situation that very low value in 'tadr' is read (== a big delta) | | 312 | * the situation that very low value in 'tadr' is read (== a big delta) |
313 | * while also acccounting for a full 'tick' because the counter went | | 313 | * while also acccounting for a full 'tick' because the counter went |
314 | * through zero during the calculations. | | 314 | * through zero during the calculations. |
315 | */ | | 315 | */ |
316 | ipra = MFP->mf_ipra; tadr = MFP->mf_tadr; | | 316 | ipra = MFP->mf_ipra; tadr = MFP->mf_tadr; |
317 | | | 317 | |
318 | delta = ((divisor - tadr) * tick) / divisor; | | 318 | delta = ((divisor - tadr) * tick) / divisor; |
319 | /* | | 319 | /* |
320 | * Account for pending clock interrupts | | 320 | * Account for pending clock interrupts |
321 | */ | | 321 | */ |
322 | if(ipra & IA_TIMA) | | 322 | if(ipra & IA_TIMA) |
323 | return(delta + tick); | | 323 | return(delta + tick); |
324 | return(delta); | | 324 | return(delta); |
325 | } | | 325 | } |
326 | | | 326 | |
327 | #define TIMB_FREQ 614400 | | 327 | #define TIMB_FREQ 614400 |
328 | #define TIMB_LIMIT 256 | | 328 | #define TIMB_LIMIT 256 |
329 | | | 329 | |
330 | /* | | 330 | /* |
331 | * Wait "n" microseconds. | | 331 | * Wait "n" microseconds. |
332 | * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz. | | 332 | * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz. |
333 | * Note: timer had better have been programmed before this is first used! | | 333 | * Note: timer had better have been programmed before this is first used! |
334 | */ | | 334 | */ |
335 | void | | 335 | void |
336 | delay(n) | | 336 | delay(unsigned int n) |
337 | int n; | | | |
338 | { | | 337 | { |
339 | int ticks, otick; | | 338 | int ticks, otick, remaining; |
340 | | | 339 | |
341 | /* | | 340 | /* |
342 | * Read the counter first, so that the rest of the setup overhead is | | 341 | * Read the counter first, so that the rest of the setup overhead is |
343 | * counted. | | 342 | * counted. |
344 | */ | | 343 | */ |
345 | otick = MFP->mf_tbdr; | | 344 | otick = MFP->mf_tbdr; |
346 | | | 345 | |
347 | /* | | 346 | if (n <= UINT_MAX / TIMB_FREQ) { |
348 | * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so | | 347 | /* |
349 | * we can take advantage of the intermediate 64-bit quantity to prevent | | 348 | * For unsigned arithmetic, division can be replaced with |
350 | * loss of significance. | | 349 | * multiplication with the inverse and a shift. |
351 | */ | | 350 | */ |
352 | n -= 5; | | 351 | remaining = n * TIMB_FREQ / 1000000; |
353 | if(n < 0) | | 352 | } else { |
354 | return; | | 353 | /* This is a very long delay. |
355 | { | | 354 | * Being slow here doesn't matter. |
356 | u_int temp; | | 355 | */ |
357 | | | 356 | remaining = (unsigned long long) n * TIMB_FREQ / 1000000; |
358 | __asm volatile ("mulul %2,%1:%0" : "=d" (n), "=d" (temp) | | | |
359 | : "d" (TIMB_FREQ), "d" (n)); | | | |
360 | __asm volatile ("divul %1,%2:%0" : "=d" (n) | | | |
361 | : "d"(1000000),"d"(temp),"0"(n)); | | | |
362 | } | | 357 | } |
363 | | | 358 | |
364 | while(n > 0) { | | 359 | while(remaining > 0) { |
365 | ticks = MFP->mf_tbdr; | | 360 | ticks = MFP->mf_tbdr; |
366 | if(ticks > otick) | | 361 | if(ticks > otick) |
367 | n -= TIMB_LIMIT - (ticks - otick); | | 362 | remaining -= TIMB_LIMIT - (ticks - otick); |
368 | else n -= otick - ticks; | | 363 | else |
| | | 364 | remaining -= otick - ticks; |
369 | otick = ticks; | | 365 | otick = ticks; |
370 | } | | 366 | } |
371 | } | | 367 | } |
372 | | | 368 | |
373 | #ifdef GPROF | | 369 | #ifdef GPROF |
374 | /* | | 370 | /* |
375 | * profclock() is expanded in line in lev6intr() unless profiling kernel. | | 371 | * profclock() is expanded in line in lev6intr() unless profiling kernel. |
376 | * Assumes it is called with clock interrupts blocked. | | 372 | * Assumes it is called with clock interrupts blocked. |
377 | */ | | 373 | */ |
378 | profclock(pc, ps) | | 374 | profclock(pc, ps) |
379 | caddr_t pc; | | 375 | caddr_t pc; |
380 | int ps; | | 376 | int ps; |
381 | { | | 377 | { |
382 | /* | | 378 | /* |
383 | * Came from user mode. | | 379 | * Came from user mode. |
384 | * If this process is being profiled record the tick. | | 380 | * If this process is being profiled record the tick. |
385 | */ | | 381 | */ |
386 | if (USERMODE(ps)) { | | 382 | if (USERMODE(ps)) { |
387 | if (p->p_stats.p_prof.pr_scale) | | 383 | if (p->p_stats.p_prof.pr_scale) |
388 | addupc(pc, &curproc->p_stats.p_prof, 1); | | 384 | addupc(pc, &curproc->p_stats.p_prof, 1); |
389 | } | | 385 | } |
390 | /* | | 386 | /* |
391 | * Came from kernel (supervisor) mode. | | 387 | * Came from kernel (supervisor) mode. |
392 | * If we are profiling the kernel, record the tick. | | 388 | * If we are profiling the kernel, record the tick. |
393 | */ | | 389 | */ |
394 | else if (profiling < 2) { | | 390 | else if (profiling < 2) { |
395 | register int s = pc - s_lowpc; | | 391 | register int s = pc - s_lowpc; |
396 | | | 392 | |
397 | if (s < s_textsize) | | 393 | if (s < s_textsize) |
398 | kcount[s / (HISTFRACTION * sizeof (*kcount))]++; | | 394 | kcount[s / (HISTFRACTION * sizeof (*kcount))]++; |
399 | } | | 395 | } |
400 | /* | | 396 | /* |
401 | * Kernel profiling was on but has been disabled. | | 397 | * Kernel profiling was on but has been disabled. |
402 | * Mark as no longer profiling kernel and if all profiling done, | | 398 | * Mark as no longer profiling kernel and if all profiling done, |
403 | * disable the clock. | | 399 | * disable the clock. |
404 | */ | | 400 | */ |
405 | if (profiling && (profon & PRF_KERNEL)) { | | 401 | if (profiling && (profon & PRF_KERNEL)) { |
406 | profon &= ~PRF_KERNEL; | | 402 | profon &= ~PRF_KERNEL; |
407 | if (profon == PRF_NONE) | | 403 | if (profon == PRF_NONE) |
408 | stopprofclock(); | | 404 | stopprofclock(); |
409 | } | | 405 | } |
410 | } | | 406 | } |
411 | #endif | | 407 | #endif |
412 | | | 408 | |
413 | /*********************************************************************** | | 409 | /*********************************************************************** |
414 | * Real Time Clock support * | | 410 | * Real Time Clock support * |
415 | ***********************************************************************/ | | 411 | ***********************************************************************/ |
416 | | | 412 | |
417 | u_int mc146818_read(rtc, regno) | | 413 | u_int mc146818_read(rtc, regno) |
418 | void *rtc; | | 414 | void *rtc; |
419 | u_int regno; | | 415 | u_int regno; |
420 | { | | 416 | { |
421 | ((struct rtc *)rtc)->rtc_regno = regno; | | 417 | ((struct rtc *)rtc)->rtc_regno = regno; |
422 | return(((struct rtc *)rtc)->rtc_data & 0377); | | 418 | return(((struct rtc *)rtc)->rtc_data & 0377); |
423 | } | | 419 | } |
424 | | | 420 | |
425 | void mc146818_write(rtc, regno, value) | | 421 | void mc146818_write(rtc, regno, value) |
426 | void *rtc; | | 422 | void *rtc; |
427 | u_int regno, value; | | 423 | u_int regno, value; |
428 | { | | 424 | { |
429 | ((struct rtc *)rtc)->rtc_regno = regno; | | 425 | ((struct rtc *)rtc)->rtc_regno = regno; |
430 | ((struct rtc *)rtc)->rtc_data = value; | | 426 | ((struct rtc *)rtc)->rtc_data = value; |
431 | } | | 427 | } |
432 | | | 428 | |
433 | /* | | 429 | /* |
434 | * Initialize the time of day register, assuming the RTC runs in UTC. | | 430 | * Initialize the time of day register, assuming the RTC runs in UTC. |
435 | * Since we've got the 'rtc' device, this functionality should be removed | | 431 | * Since we've got the 'rtc' device, this functionality should be removed |
436 | * from the kernel. The only problem to be solved before that can happen | | 432 | * from the kernel. The only problem to be solved before that can happen |
437 | * is the possibility of init(1) providing a way (rc.boot?) to set | | 433 | * is the possibility of init(1) providing a way (rc.boot?) to set |
438 | * the RTC before single-user mode is entered. | | 434 | * the RTC before single-user mode is entered. |
439 | */ | | 435 | */ |
440 | void | | 436 | void |
441 | inittodr(base) | | 437 | inittodr(base) |
442 | time_t base; | | 438 | time_t base; |
443 | { | | 439 | { |
444 | /* Battery clock does not store usec's, so forget about it. */ | | 440 | /* Battery clock does not store usec's, so forget about it. */ |
445 | time.tv_sec = gettod(); | | 441 | time.tv_sec = gettod(); |
446 | time.tv_usec = 0; | | 442 | time.tv_usec = 0; |
447 | } | | 443 | } |
448 | | | 444 | |
449 | /* | | 445 | /* |
450 | * Function turned into a No-op. Use /dev/rtc to update the RTC. | | 446 | * Function turned into a No-op. Use /dev/rtc to update the RTC. |
451 | */ | | 447 | */ |
452 | void | | 448 | void |
453 | resettodr() | | 449 | resettodr() |
454 | { | | 450 | { |
455 | return; | | 451 | return; |
456 | } | | 452 | } |
457 | | | 453 | |
458 | static u_long | | 454 | static u_long |
459 | gettod() | | 455 | gettod() |
460 | { | | 456 | { |
461 | int sps; | | 457 | int sps; |
462 | mc_todregs clkregs; | | 458 | mc_todregs clkregs; |
463 | u_int regb; | | 459 | u_int regb; |
464 | struct clock_ymdhms dt; | | 460 | struct clock_ymdhms dt; |
465 | | | 461 | |
466 | sps = splhigh(); | | 462 | sps = splhigh(); |
467 | regb = mc146818_read(RTC, MC_REGB); | | 463 | regb = mc146818_read(RTC, MC_REGB); |
468 | MC146818_GETTOD(RTC, &clkregs); | | 464 | MC146818_GETTOD(RTC, &clkregs); |
469 | splx(sps); | | 465 | splx(sps); |
470 | | | 466 | |
471 | regb &= MC_REGB_24HR|MC_REGB_BINARY; | | 467 | regb &= MC_REGB_24HR|MC_REGB_BINARY; |
472 | if (regb != (MC_REGB_24HR|MC_REGB_BINARY)) { | | 468 | if (regb != (MC_REGB_24HR|MC_REGB_BINARY)) { |
473 | printf("Error: Nonstandard RealTimeClock Configuration -" | | 469 | printf("Error: Nonstandard RealTimeClock Configuration -" |
474 | " value ignored\n" | | 470 | " value ignored\n" |
475 | " A write to /dev/rtc will correct this.\n"); | | 471 | " A write to /dev/rtc will correct this.\n"); |
476 | return(0); | | 472 | return(0); |
477 | } | | 473 | } |
478 | if(clkregs[MC_SEC] > 59) | | 474 | if(clkregs[MC_SEC] > 59) |
479 | return(0); | | 475 | return(0); |
480 | if(clkregs[MC_MIN] > 59) | | 476 | if(clkregs[MC_MIN] > 59) |
481 | return(0); | | 477 | return(0); |
482 | if(clkregs[MC_HOUR] > 23) | | 478 | if(clkregs[MC_HOUR] > 23) |
483 | return(0); | | 479 | return(0); |
484 | if(range_test(clkregs[MC_DOM], 1, 31)) | | 480 | if(range_test(clkregs[MC_DOM], 1, 31)) |
485 | return(0); | | 481 | return(0); |
486 | if (range_test(clkregs[MC_MONTH], 1, 12)) | | 482 | if (range_test(clkregs[MC_MONTH], 1, 12)) |
487 | return(0); | | 483 | return(0); |
488 | if(clkregs[MC_YEAR] > 99) | | 484 | if(clkregs[MC_YEAR] > 99) |
489 | return(0); | | 485 | return(0); |
490 | | | 486 | |
491 | dt.dt_year = clkregs[MC_YEAR] + GEMSTARTOFTIME; | | 487 | dt.dt_year = clkregs[MC_YEAR] + GEMSTARTOFTIME; |
492 | dt.dt_mon = clkregs[MC_MONTH]; | | 488 | dt.dt_mon = clkregs[MC_MONTH]; |
493 | dt.dt_day = clkregs[MC_DOM]; | | 489 | dt.dt_day = clkregs[MC_DOM]; |
494 | dt.dt_hour = clkregs[MC_HOUR]; | | 490 | dt.dt_hour = clkregs[MC_HOUR]; |
495 | dt.dt_min = clkregs[MC_MIN]; | | 491 | dt.dt_min = clkregs[MC_MIN]; |
496 | dt.dt_sec = clkregs[MC_SEC]; | | 492 | dt.dt_sec = clkregs[MC_SEC]; |
497 | | | 493 | |
498 | return(clock_ymdhms_to_secs(&dt)); | | 494 | return(clock_ymdhms_to_secs(&dt)); |
499 | } | | 495 | } |
500 | /*********************************************************************** | | 496 | /*********************************************************************** |
501 | * RTC-device support * | | 497 | * RTC-device support * |
502 | ***********************************************************************/ | | 498 | ***********************************************************************/ |
503 | int | | 499 | int |
504 | rtcopen(dev, flag, mode, l) | | 500 | rtcopen(dev, flag, mode, l) |
505 | dev_t dev; | | 501 | dev_t dev; |
506 | int flag, mode; | | 502 | int flag, mode; |
507 | struct lwp *l; | | 503 | struct lwp *l; |
508 | { | | 504 | { |
509 | int unit = minor(dev); | | 505 | int unit = minor(dev); |
510 | struct clock_softc *sc; | | 506 | struct clock_softc *sc; |
511 | | | 507 | |
512 | if (unit >= clock_cd.cd_ndevs) | | 508 | if (unit >= clock_cd.cd_ndevs) |
513 | return ENXIO; | | 509 | return ENXIO; |
514 | sc = clock_cd.cd_devs[unit]; | | 510 | sc = clock_cd.cd_devs[unit]; |
515 | if (!sc) | | 511 | if (!sc) |
516 | return ENXIO; | | 512 | return ENXIO; |
517 | if (sc->sc_flags & RTC_OPEN) | | 513 | if (sc->sc_flags & RTC_OPEN) |
518 | return EBUSY; | | 514 | return EBUSY; |
519 | | | 515 | |
520 | sc->sc_flags = RTC_OPEN; | | 516 | sc->sc_flags = RTC_OPEN; |
521 | return 0; | | 517 | return 0; |
522 | } | | 518 | } |
523 | | | 519 | |
524 | int | | 520 | int |
525 | rtcclose(dev, flag, mode, l) | | 521 | rtcclose(dev, flag, mode, l) |
526 | dev_t dev; | | 522 | dev_t dev; |
527 | int flag; | | 523 | int flag; |
528 | int mode; | | 524 | int mode; |
529 | struct lwp *l; | | 525 | struct lwp *l; |
530 | { | | 526 | { |
531 | int unit = minor(dev); | | 527 | int unit = minor(dev); |
532 | struct clock_softc *sc = clock_cd.cd_devs[unit]; | | 528 | struct clock_softc *sc = clock_cd.cd_devs[unit]; |
533 | | | 529 | |
534 | sc->sc_flags = 0; | | 530 | sc->sc_flags = 0; |
535 | return 0; | | 531 | return 0; |
536 | } | | 532 | } |
537 | | | 533 | |
538 | int | | 534 | int |
539 | rtcread(dev, uio, flags) | | 535 | rtcread(dev, uio, flags) |
540 | dev_t dev; | | 536 | dev_t dev; |
541 | struct uio *uio; | | 537 | struct uio *uio; |
542 | int flags; | | 538 | int flags; |
543 | { | | 539 | { |
544 | struct clock_softc *sc; | | 540 | struct clock_softc *sc; |
545 | mc_todregs clkregs; | | 541 | mc_todregs clkregs; |
546 | int s, length; | | 542 | int s, length; |
547 | char buffer[16]; | | 543 | char buffer[16]; |
548 | | | 544 | |
549 | sc = clock_cd.cd_devs[minor(dev)]; | | 545 | sc = clock_cd.cd_devs[minor(dev)]; |
550 | | | 546 | |
551 | s = splhigh(); | | 547 | s = splhigh(); |
552 | MC146818_GETTOD(RTC, &clkregs); | | 548 | MC146818_GETTOD(RTC, &clkregs); |
553 | splx(s); | | 549 | splx(s); |
554 | | | 550 | |
555 | sprintf(buffer, "%4d%02d%02d%02d%02d.%02d\n", | | 551 | sprintf(buffer, "%4d%02d%02d%02d%02d.%02d\n", |
556 | clkregs[MC_YEAR] + GEMSTARTOFTIME, | | 552 | clkregs[MC_YEAR] + GEMSTARTOFTIME, |
557 | clkregs[MC_MONTH], clkregs[MC_DOM], | | 553 | clkregs[MC_MONTH], clkregs[MC_DOM], |
558 | clkregs[MC_HOUR], clkregs[MC_MIN], clkregs[MC_SEC]); | | 554 | clkregs[MC_HOUR], clkregs[MC_MIN], clkregs[MC_SEC]); |
559 | | | 555 | |
560 | if (uio->uio_offset > strlen(buffer)) | | 556 | if (uio->uio_offset > strlen(buffer)) |
561 | return 0; | | 557 | return 0; |
562 | | | 558 | |
563 | length = strlen(buffer) - uio->uio_offset; | | 559 | length = strlen(buffer) - uio->uio_offset; |
564 | if (length > uio->uio_resid) | | 560 | if (length > uio->uio_resid) |
565 | length = uio->uio_resid; | | 561 | length = uio->uio_resid; |
566 | | | 562 | |
567 | return(uiomove((caddr_t)buffer, length, uio)); | | 563 | return(uiomove((caddr_t)buffer, length, uio)); |
568 | } | | 564 | } |
569 | | | 565 | |
570 | static int | | 566 | static int |
571 | twodigits(buffer, pos) | | 567 | twodigits(buffer, pos) |
572 | char *buffer; | | 568 | char *buffer; |
573 | int pos; | | 569 | int pos; |
574 | { | | 570 | { |
575 | int result = 0; | | 571 | int result = 0; |
576 | | | 572 | |
577 | if (buffer[pos] >= '0' && buffer[pos] <= '9') | | 573 | if (buffer[pos] >= '0' && buffer[pos] <= '9') |
578 | result = (buffer[pos] - '0') * 10; | | 574 | result = (buffer[pos] - '0') * 10; |
579 | if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9') | | 575 | if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9') |
580 | result += (buffer[pos+1] - '0'); | | 576 | result += (buffer[pos+1] - '0'); |
581 | return(result); | | 577 | return(result); |
582 | } | | 578 | } |
583 | | | 579 | |
584 | int | | 580 | int |
585 | rtcwrite(dev, uio, flags) | | 581 | rtcwrite(dev, uio, flags) |
586 | dev_t dev; | | 582 | dev_t dev; |
587 | struct uio *uio; | | 583 | struct uio *uio; |
588 | int flags; | | 584 | int flags; |
589 | { | | 585 | { |
590 | mc_todregs clkregs; | | 586 | mc_todregs clkregs; |
591 | int s, length, error; | | 587 | int s, length, error; |
592 | char buffer[16]; | | 588 | char buffer[16]; |
593 | | | 589 | |
594 | /* | | 590 | /* |
595 | * We require atomic updates! | | 591 | * We require atomic updates! |
596 | */ | | 592 | */ |
597 | length = uio->uio_resid; | | 593 | length = uio->uio_resid; |
598 | if (uio->uio_offset || (length != sizeof(buffer) | | 594 | if (uio->uio_offset || (length != sizeof(buffer) |
599 | && length != sizeof(buffer - 1))) | | 595 | && length != sizeof(buffer - 1))) |
600 | return(EINVAL); | | 596 | return(EINVAL); |
601 | | | 597 | |
602 | if ((error = uiomove((caddr_t)buffer, sizeof(buffer), uio))) | | 598 | if ((error = uiomove((caddr_t)buffer, sizeof(buffer), uio))) |
603 | return(error); | | 599 | return(error); |
604 | | | 600 | |
605 | if (length == sizeof(buffer) && buffer[sizeof(buffer) - 1] != '\n') | | 601 | if (length == sizeof(buffer) && buffer[sizeof(buffer) - 1] != '\n') |
606 | return(EINVAL); | | 602 | return(EINVAL); |
607 | | | 603 | |
608 | s = splclock(); | | 604 | s = splclock(); |
609 | mc146818_write(RTC, MC_REGB, | | 605 | mc146818_write(RTC, MC_REGB, |
610 | mc146818_read(RTC, MC_REGB) | MC_REGB_24HR | MC_REGB_BINARY); | | 606 | mc146818_read(RTC, MC_REGB) | MC_REGB_24HR | MC_REGB_BINARY); |
611 | MC146818_GETTOD(RTC, &clkregs); | | 607 | MC146818_GETTOD(RTC, &clkregs); |
612 | splx(s); | | 608 | splx(s); |
613 | | | 609 | |
614 | clkregs[MC_SEC] = twodigits(buffer, 13); | | 610 | clkregs[MC_SEC] = twodigits(buffer, 13); |
615 | clkregs[MC_MIN] = twodigits(buffer, 10); | | 611 | clkregs[MC_MIN] = twodigits(buffer, 10); |
616 | clkregs[MC_HOUR] = twodigits(buffer, 8); | | 612 | clkregs[MC_HOUR] = twodigits(buffer, 8); |
617 | clkregs[MC_DOM] = twodigits(buffer, 6); | | 613 | clkregs[MC_DOM] = twodigits(buffer, 6); |
618 | clkregs[MC_MONTH] = twodigits(buffer, 4); | | 614 | clkregs[MC_MONTH] = twodigits(buffer, 4); |
619 | s = twodigits(buffer, 0) * 100 + twodigits(buffer, 2); | | 615 | s = twodigits(buffer, 0) * 100 + twodigits(buffer, 2); |
620 | clkregs[MC_YEAR] = s - GEMSTARTOFTIME; | | 616 | clkregs[MC_YEAR] = s - GEMSTARTOFTIME; |
621 | | | 617 | |
622 | s = splclock(); | | 618 | s = splclock(); |
623 | MC146818_PUTTOD(RTC, &clkregs); | | 619 | MC146818_PUTTOD(RTC, &clkregs); |
624 | splx(s); | | 620 | splx(s); |
625 | | | 621 | |
626 | return(0); | | 622 | return(0); |
627 | } | | 623 | } |