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