]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/AT386/bbclock.c
cefba69305c364a2a4319a68900ed16f10a376a5
[apple/xnu.git] / osfmk / i386 / AT386 / bbclock.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33 /*
34 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
35
36 All Rights Reserved
37
38 Permission to use, copy, modify, and distribute this software and
39 its documentation for any purpose and without fee is hereby
40 granted, provided that the above copyright notice appears in all
41 copies and that both the copyright notice and this permission notice
42 appear in supporting documentation, and that the name of Intel
43 not be used in advertising or publicity pertaining to distribution
44 of the software without specific, written prior permission.
45
46 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
47 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
48 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
49 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
50 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
51 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53 */
54
55 #include <types.h>
56 #include <mach/message.h>
57 #include <kern/thread.h>
58 #include <kern/clock.h>
59 #include <kern/spl.h>
60 #include <kern/processor.h>
61 #include <kern/misc_protos.h>
62 #include <i386/cpu_data.h>
63 #include <i386/cpu_number.h>
64 #include <i386/pio.h>
65 #include <i386/AT386/rtc.h>
66 #include <i386/AT386/bbclock_entries.h>
67
68 /* local data */
69 static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
70
71 extern char dectohexdec(
72 int n);
73 extern int hexdectodec(
74 char c);
75 extern int yeartoday(
76 int yr);
77 extern void rtcput(
78 struct rtc_st * regs);
79 extern int rtcget(
80 struct rtc_st * regs);
81
82 #define LOCK_BBC() splclock()
83 #define UNLOCK_BBC(s) splx(s)
84
85 /*
86 * Configure battery-backed clock.
87 */
88 int
89 bbc_config(void)
90 {
91 int BbcFlag;
92 struct rtc_st rtclk;
93
94 mp_disable_preemption();
95 if (cpu_number() != master_cpu) {
96 mp_enable_preemption();
97 return(1);
98 }
99
100 /*
101 * Setup device.
102 */
103 outb(RTC_ADDR, RTC_A);
104 outb(RTC_DATA, RTC_DIV2 | RTC_RATE6);
105 outb(RTC_ADDR, RTC_B);
106 outb(RTC_DATA, RTC_HM);
107
108 /*
109 * Probe the device by trying to read it.
110 */
111 BbcFlag = (rtcget(&rtclk) ? 0 : 1);
112 if (BbcFlag)
113 printf("battery clock configured\n");
114 else
115 printf("WARNING: Battery Clock Failure!\n");
116 mp_enable_preemption();
117 return (BbcFlag);
118 }
119
120 /*
121 * Get the current clock time.
122 */
123 kern_return_t
124 bbc_gettime(
125 mach_timespec_t *cur_time) /* OUT */
126 {
127 struct rtc_st rtclk;
128 time_t n;
129 int sec, min, hr, dom, mon, yr;
130 int i, days = 0;
131 spl_t s;
132 thread_t thread;
133
134 if ((thread = current_thread()) != THREAD_NULL) {
135 thread_bind(thread, master_processor);
136 mp_disable_preemption();
137 if (current_processor() != master_processor) {
138 mp_enable_preemption();
139 thread_block(THREAD_CONTINUE_NULL);
140 } else {
141 mp_enable_preemption();
142 }
143 }
144
145 s = LOCK_BBC();
146 rtcget(&rtclk);
147 sec = hexdectodec(rtclk.rtc_sec);
148 min = hexdectodec(rtclk.rtc_min);
149 hr = hexdectodec(rtclk.rtc_hr);
150 dom = hexdectodec(rtclk.rtc_dom);
151 mon = hexdectodec(rtclk.rtc_mon);
152 yr = hexdectodec(rtclk.rtc_yr);
153 yr = (yr < 70) ? yr+100 : yr;
154 n = sec + 60 * min + 3600 * hr;
155 n += (dom - 1) * 3600 * 24;
156 if (yeartoday(yr) == 366)
157 month[1] = 29;
158 for (i = mon - 2; i >= 0; i--)
159 days += month[i];
160 month[1] = 28;
161 for (i = 70; i < yr; i++)
162 days += yeartoday(i);
163 n += days * 3600 * 24;
164 cur_time->tv_sec = n;
165 cur_time->tv_nsec = 0;
166 UNLOCK_BBC(s);
167
168 if (thread != THREAD_NULL)
169 thread_bind(thread, PROCESSOR_NULL);
170 return (KERN_SUCCESS);
171 }
172
173 /*
174 * Set the current clock time.
175 */
176 kern_return_t
177 bbc_settime(
178 mach_timespec_t *new_time)
179 {
180 struct rtc_st rtclk;
181 time_t n;
182 int diff, i, j;
183 spl_t s;
184 thread_t thread;
185
186 if ((thread = current_thread()) != THREAD_NULL) {
187 thread_bind(thread, master_processor);
188 mp_disable_preemption();
189 if (current_processor() != master_processor) {
190 mp_enable_preemption();
191 thread_block(THREAD_CONTINUE_NULL);
192 } else {
193 mp_enable_preemption();
194 }
195 }
196
197 s = LOCK_BBC();
198 rtcget(&rtclk);
199 diff = 0;
200 n = (new_time->tv_sec - diff) % (3600 * 24); /* hrs+mins+secs */
201 rtclk.rtc_sec = dectohexdec(n%60);
202 n /= 60;
203 rtclk.rtc_min = dectohexdec(n%60);
204 rtclk.rtc_hr = dectohexdec(n/60);
205 n = (new_time->tv_sec - diff) / (3600 * 24); /* days */
206 rtclk.rtc_dow = (n + 4) % 7; /* 1/1/70 is Thursday */
207 for (j = 70; n >= (i = yeartoday(j)); j++)
208 n -= i;
209 rtclk.rtc_yr = dectohexdec(j % 100);
210 if (yeartoday(j) == 366)
211 month[1] = 29;
212 for (i = 0; n >= month[i]; i++)
213 n -= month[i];
214 month[1] = 28;
215 rtclk.rtc_mon = dectohexdec(++i);
216 rtclk.rtc_dom = dectohexdec(++n);
217 rtcput(&rtclk);
218 UNLOCK_BBC(s);
219
220 if (thread != THREAD_NULL)
221 thread_bind(current_thread(), PROCESSOR_NULL);
222
223 return (KERN_SUCCESS);
224 }
225
226 \f
227 /* DEVICE SPECIFIC ROUTINES */
228
229 int
230 rtcget(
231 struct rtc_st * regs)
232 {
233 outb(RTC_ADDR, RTC_D);
234 if ((inb(RTC_DATA) & RTC_VRT) == 0)
235 return (-1);
236 outb(RTC_ADDR, RTC_A);
237 while (inb(RTC_DATA) & RTC_UIP) /* busy wait */
238 outb(RTC_ADDR, RTC_A);
239 load_rtc((unsigned char *)regs);
240 return (0);
241 }
242
243 void
244 rtcput(
245 struct rtc_st * regs)
246 {
247 register unsigned char x;
248
249 outb(RTC_ADDR, RTC_B);
250 x = inb(RTC_DATA);
251 outb(RTC_ADDR, RTC_B);
252 outb(RTC_DATA, x | RTC_SET);
253 save_rtc((unsigned char *)regs);
254 outb(RTC_ADDR, RTC_B);
255 outb(RTC_DATA, x & ~RTC_SET);
256 }
257
258 int
259 yeartoday(
260 int year)
261 {
262 year += 1900;
263 return((year % 4) ? 365 :
264 ((year % 100) ? 366 : ((year % 400) ? 365: 366)));
265 }
266
267 int
268 hexdectodec(
269 char n)
270 {
271 return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
272 }
273
274 char
275 dectohexdec(
276 int n)
277 {
278 return ((char)(((n / 10) << 4) & 0xF0) | ((n % 10) & 0x0F));
279 }