]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/AT386/bbclock.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / osfmk / i386 / AT386 / bbclock.c
CommitLineData
21362eb3
A
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
36Permission to use, copy, modify, and distribute this software and
37its documentation for any purpose and without fee is hereby
38granted, provided that the above copyright notice appears in all
39copies and that both the copyright notice and this permission notice
40appear in supporting documentation, and that the name of Intel
41not be used in advertising or publicity pertaining to distribution
42of the software without specific, written prior permission.
43
44INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
45INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
46IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
47CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
48LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
49NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
50WITH 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 */
67static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
68
69extern char dectohexdec(
70 int n);
71extern int hexdectodec(
72 char c);
73extern int yeartoday(
74 int yr);
75extern void rtcput(
76 struct rtc_st * regs);
77extern 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 */
86int
87bbc_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 */
121kern_return_t
122bbc_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 */
174kern_return_t
175bbc_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
227int
228rtcget(
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
241void
242rtcput(
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
256int
257yeartoday(
258 int year)
259{
260 year += 1900;
261 return((year % 4) ? 365 :
262 ((year % 100) ? 366 : ((year % 400) ? 365: 366)));
263}
264
265int
266hexdectodec(
267 char n)
268{
269 return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
270}
271
272char
273dectohexdec(
274 int n)
275{
276 return ((char)(((n / 10) << 4) & 0xF0) | ((n % 10) & 0x0F));
277}