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