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