[BACK]Return to rtc.c CVS log [TXT][DIR] Up to [local] / prex / dev / i386 / pc

Annotation of prex/dev/i386/pc/rtc.c, Revision 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:
        !            34: #include <sys/time.h>
        !            35: #include <sys/ioctl.h>
        !            36:
        !            37: #include <driver.h>
        !            38: #include <cpufunc.h>
        !            39:
        !            40: /* Cmos */
        !            41: #define CMOS_INDEX     0x70
        !            42: #define CMOS_DATA      0x71
        !            43:
        !            44: /* CMOS address */
        !            45: #define CMOS_SEC       0x00
        !            46: #define CMOS_MIN       0x02
        !            47: #define CMOS_HOUR      0x04
        !            48: #define CMOS_DAY       0x07
        !            49: #define CMOS_MON       0x08
        !            50: #define CMOS_YEAR      0x09
        !            51: #define CMOS_STS_A     0x0a
        !            52: #define CMOS_UIP         0x80
        !            53: #define CMOS_STS_B     0x0b
        !            54: #define CMOS_BCD         0x04
        !            55:
        !            56:
        !            57: #define DAYSPERYEAR    (31+28+31+30+31+30+31+31+30+31+30+31)
        !            58:
        !            59: static int rtc_read(device_t dev, char *buf, size_t *nbyte, int blkno);
        !            60: static int rtc_ioctl(device_t dev, u_long cmd, void *arg);
        !            61: static int rtc_init(void);
        !            62:
        !            63: /*
        !            64:  * Driver structure
        !            65:  */
        !            66: struct driver rtc_drv = {
        !            67:        /* name */      "Realtime Clock",
        !            68:        /* order */     4,
        !            69:        /* init */      rtc_init,
        !            70: };
        !            71:
        !            72: /*
        !            73:  * Device I/O table
        !            74:  */
        !            75: static struct devio rtc_io = {
        !            76:        /* open */      NULL,
        !            77:        /* close */     NULL,
        !            78:        /* read */      rtc_read,
        !            79:        /* write */     NULL,
        !            80:        /* ioctl */     rtc_ioctl,
        !            81:        /* event */     NULL,
        !            82: };
        !            83:
        !            84: static const int daysinmonth[] =
        !            85:     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        !            86:
        !            87: static device_t rtc_dev;       /* Device object */
        !            88: static u_long boot_sec;                /* Time (sec) at system boot */
        !            89: static u_long boot_ticks;      /* Time (ticks) at system boot */
        !            90:
        !            91:
        !            92: static u_int
        !            93: cmos_read(int index)
        !            94: {
        !            95:        u_int value;
        !            96:
        !            97:        irq_lock();
        !            98:        outb(index, CMOS_INDEX);
        !            99:        value = inb(CMOS_DATA);
        !           100:        irq_unlock();
        !           101:        return value;
        !           102: }
        !           103:
        !           104: /*
        !           105: static void
        !           106: cmos_write(int index, int value)
        !           107: {
        !           108:     irq_lock();
        !           109:     outb(index, CMOS_INDEX);
        !           110:     outb(value, CMOS_DATA);
        !           111:     irq_unlock();
        !           112: }
        !           113: */
        !           114:
        !           115: static u_int
        !           116: bcd2bin(u_int bcd)
        !           117: {
        !           118:
        !           119:        return (bcd & 0x0f) + ((bcd >> 4) & 0xf) * 10;
        !           120: }
        !           121:
        !           122: /*
        !           123: static int bin2bcd(int bin)
        !           124: {
        !           125:     return ((bin / 10) << 4) + (bin % 10);
        !           126: }
        !           127: */
        !           128:
        !           129: static int
        !           130: is_leap(u_int year)
        !           131: {
        !           132:
        !           133:        if ((year % 4 == 0) && (year % 100 != 0))
        !           134:                return 1;
        !           135:        if (year % 400 == 0)
        !           136:                return 1;
        !           137:        return 0;
        !           138: }
        !           139:
        !           140: /*
        !           141:  * Return current seconds (seconds since Epoch 1970/1/1 0:0:0)
        !           142:  */
        !           143: static u_long
        !           144: cmos_gettime(void)
        !           145: {
        !           146:        u_int sec, min, hour, day, mon, year;
        !           147:        u_int i;
        !           148:        u_int days;
        !           149:
        !           150:        /* Wait until data ready */
        !           151:        for (i = 0; i < 1000000; i++)
        !           152:                if (!(cmos_read(CMOS_STS_A) & CMOS_UIP))
        !           153:                        break;
        !           154:
        !           155:        sec = cmos_read(CMOS_SEC);
        !           156:        min = cmos_read(CMOS_MIN);
        !           157:        hour = cmos_read(CMOS_HOUR);
        !           158:        day = cmos_read(CMOS_DAY);
        !           159:        mon = cmos_read(CMOS_MON);
        !           160:        year = cmos_read(CMOS_YEAR);
        !           161:
        !           162:        if (!(cmos_read(CMOS_STS_B) & CMOS_BCD)) {
        !           163:                sec = bcd2bin(sec);
        !           164:                min = bcd2bin(min);
        !           165:                hour = bcd2bin(hour);
        !           166:                day = bcd2bin(day);
        !           167:                mon = bcd2bin(mon);
        !           168:                year = bcd2bin(year);
        !           169:        }
        !           170:        if (year < 80)
        !           171:                year += 2000;
        !           172:        else
        !           173:                year += 1900;
        !           174: #ifdef DEBUG
        !           175:        printf("rtc: system time was %d/%d/%d %d:%d:%d\n",
        !           176:                year, mon, day, hour, min, sec);
        !           177: #endif
        !           178:
        !           179:        days = 0;
        !           180:        for (i = 1970; i < year; i++)
        !           181:                days += DAYSPERYEAR + is_leap(i);
        !           182:        for (i = 1; i < mon; i++)
        !           183:                days += daysinmonth[i - 1];
        !           184:        if ((mon > 2) && is_leap(year))
        !           185:                days++;
        !           186:        days += day - 1;
        !           187:
        !           188:        sec = (((days * 24 + hour) * 60) + min) * 60 + sec;
        !           189:        return sec;
        !           190: }
        !           191:
        !           192: static int
        !           193: rtc_read(device_t dev, char *buf, size_t *nbyte, int blkno)
        !           194: {
        !           195:        u_long time;
        !           196:
        !           197:        if (*nbyte < sizeof(u_long))
        !           198:                return 0;
        !           199:
        !           200:        time = cmos_gettime();
        !           201:        if (umem_copyout(&time, buf, sizeof(u_long)))
        !           202:                return EFAULT;
        !           203:        *nbyte = sizeof(u_long);
        !           204:        return 0;
        !           205: }
        !           206:
        !           207: static int
        !           208: rtc_ioctl(device_t dev, u_long cmd, void *arg)
        !           209: {
        !           210:        struct timeval tv;
        !           211:        int err = 0;
        !           212:        u_long msec;
        !           213:
        !           214:        switch (cmd) {
        !           215:        case RTCIOC_GET_TIME:
        !           216:                /*
        !           217:                 * Calculate current time (sec/usec) from
        !           218:                 * boot time and current tick count.
        !           219:                 */
        !           220:                msec = tick_to_msec(timer_count() - boot_ticks);
        !           221:                tv.tv_sec = (long)(boot_sec + (msec / 1000));
        !           222:                tv.tv_usec = (long)((msec * 1000) % 1000000);
        !           223:                if (umem_copyout(&tv, arg, sizeof(tv)))
        !           224:                        return EFAULT;
        !           225:                break;
        !           226:        case RTCIOC_SET_TIME:
        !           227:                err = EINVAL;
        !           228:                break;
        !           229:        default:
        !           230:                return EINVAL;
        !           231:        }
        !           232:        return err;
        !           233: }
        !           234:
        !           235: /*
        !           236:  * Initialize
        !           237:  */
        !           238: static int
        !           239: rtc_init(void)
        !           240: {
        !           241:
        !           242:        /* Create device object */
        !           243:        rtc_dev = device_create(&rtc_io, "rtc", DF_CHR);
        !           244:        ASSERT(rtc_dev);
        !           245:        boot_sec = cmos_gettime();
        !           246:        boot_ticks = timer_count();
        !           247:        return 0;
        !           248: }

CVSweb