Annotation of prex-old/dev/i386/pc/rtc.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * rtc.c - Real time clock driver
32: */
33: #include <sys/time.h>
34: #include <sys/ioctl.h>
35:
36: #include <driver.h>
37: #include <cpu.h>
38:
39: /* Cmos */
40: #define CMOS_INDEX 0x70
41: #define CMOS_DATA 0x71
42:
43: /* CMOS address */
44: #define CMOS_SEC 0x00
45: #define CMOS_MIN 0x02
46: #define CMOS_HOUR 0x04
47: #define CMOS_DAY 0x07
48: #define CMOS_MON 0x08
49: #define CMOS_YEAR 0x09
50: #define CMOS_STS_A 0x0a
51: #define CMOS_UIP 0x80
52: #define CMOS_STS_B 0x0b
53: #define CMOS_BCD 0x04
54:
55:
56: #define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
57:
58: static int rtc_read(device_t dev, char *buf, size_t *nbyte, int blkno);
59: static int rtc_ioctl(device_t dev, int cmd, u_long arg);
60: static int rtc_init(void);
61:
62: /*
63: * Driver structure
64: */
65: struct driver rtc_drv = {
66: /* name */ "Realtime Clock",
67: /* order */ 4,
68: /* init */ rtc_init,
69: };
70:
71: static struct devio rtc_io = {
72: /* open */ NULL,
73: /* close */ NULL,
74: /* read */ rtc_read,
75: /* write */ NULL,
76: /* ioctl */ rtc_ioctl,
77: /* event */ NULL,
78: };
79:
80: static const int daysinmonth[] =
81: { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
82:
83: static device_t rtc_dev; /* Device object */
84: static long boot_sec; /* Time (sec) at system boot */
85: static long boot_ticks; /* Time (sec) at system boot */
86:
87:
88: static u_int
89: cmos_read(int index)
90: {
91: u_int value;
92:
93: irq_lock();
94: outb(index, CMOS_INDEX);
95: value = inb(CMOS_DATA);
96: irq_unlock();
97: return value;
98: }
99:
100: /*
101: static void
102: cmos_write(int index, int value)
103: {
104: irq_lock();
105: outb(index, CMOS_INDEX);
106: outb(value, CMOS_DATA);
107: irq_unlock();
108: }
109: */
110:
111: static int
112: bcd2bin(int bcd)
113: {
114:
115: return (bcd & 0x0f) + ((bcd >> 4) & 0xf) * 10;
116: }
117:
118: /*
119: static int bin2bcd(int bin)
120: {
121: return ((bin / 10) << 4) + (bin % 10);
122: }
123: */
124:
125: static int
126: is_leap(int year)
127: {
128:
129: if ((year % 4 == 0) && (year % 100 != 0))
130: return 1;
131: if (year % 400 == 0)
132: return 1;
133: return 0;
134: }
135:
136: /*
137: * Return current seconds (seconds since Epoch 1970/1/1 0:0:0)
138: */
139: static u_long
140: cmos_gettime(void)
141: {
142: unsigned int sec, min, hour, day, mon, year;
143: unsigned int i;
144: unsigned int days;
145:
146: /* Wait until data ready */
147: for (i = 0; i < 1000000; i++)
148: if (!(cmos_read(CMOS_STS_A) & CMOS_UIP))
149: break;
150:
151: sec = cmos_read(CMOS_SEC);
152: min = cmos_read(CMOS_MIN);
153: hour = cmos_read(CMOS_HOUR);
154: day = cmos_read(CMOS_DAY);
155: mon = cmos_read(CMOS_MON);
156: year = cmos_read(CMOS_YEAR);
157:
158: if (!(cmos_read(CMOS_STS_B) & CMOS_BCD)) {
159: sec = bcd2bin(sec);
160: min = bcd2bin(min);
161: hour = bcd2bin(hour);
162: day = bcd2bin(day);
163: mon = bcd2bin(mon);
164: year = bcd2bin(year);
165: }
166: if (year < 80)
167: year += 2000;
168: else
169: year += 1900;
170:
171: printk("rtc: system time was %d/%d/%d %d:%d:%d\n",
172: year, mon, day, hour, min, sec);
173:
174: days = 0;
175: for (i = 1970; i < year; i++)
176: days += DAYSPERYEAR + is_leap(i);
177: for (i = 1; i < mon; i++)
178: days += daysinmonth[i - 1];
179: if ((mon > 2) && is_leap(year))
180: days++;
181: days += day - 1;
182:
183: sec = (((days * 24 + hour) * 60) + min) * 60 + sec;
184: return sec;
185: }
186:
187: static int
188: rtc_read(device_t dev, char *buf, size_t *nbyte, int blkno)
189: {
190:
191: if (*nbyte < sizeof(u_long))
192: return 0;
193: *(u_long *)buf = cmos_gettime();
194: *nbyte = sizeof(u_long);
195: return 0;
196: }
197:
198: static int
199: rtc_ioctl(device_t dev, int cmd, u_long arg)
200: {
201: struct timeval tv;
202: int err = 0;
203: long msec;
204:
205: switch (cmd) {
206: case RTCIOC_GET_TIME:
207: /*
208: * Calculate current time (sec/usec) from
209: * boot time and current tick count.
210: */
211: msec = tick_to_msec(timer_count() - boot_ticks);
212: tv.tv_sec = boot_sec + (msec / 1000);
213: tv.tv_usec = (msec * 1000) % 1000000;
214: if (umem_copyout(&tv, (int *)arg, sizeof(tv)))
215: return EFAULT;
216: break;
217: case RTCIOC_SET_TIME:
218: err = EINVAL;
219: break;
220: default:
221: return EINVAL;
222: }
223: return err;
224: }
225:
226: /*
227: * Initialize
228: */
229: static int
230: rtc_init(void)
231: {
232:
233: /* Create device object */
234: rtc_dev = device_create(&rtc_io, "rtc", DF_CHR);
235: ASSERT(rtc_dev);
236: boot_sec = cmos_gettime();
237: boot_ticks = timer_count();
238: return 0;
239: }
CVSweb