Statistics
| Branch: | Revision:

root / prex-0.9.0 / bsp / drv / dev / rtc / rtc.c @ 03e9c04a

History | View | Annotate | Download (5.66 KB)

1
/*
2
 * Copyright (c) 1988 University of Utah.
3
 * Copyright (c) 1982, 1990, 1993
4
 *        The Regents of the University of California.  All rights reserved.
5
 *
6
 * This code is derived from software contributed to Berkeley by
7
 * the Systems Programming Group of the University of Utah Computer
8
 * Science Department.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 * from: Utah $Hdr: clock.c 1.18 91/01/21$
35
 *
36
 *        @(#)clock.c        8.2 (Berkeley) 1/12/94
37
 */
38

    
39
/* Modified for Prex by Kohsuke Ohtani */
40

    
41
/*
42
 * rtc.c - machine independent RTC driver
43
 */
44

    
45
#include <sys/time.h>
46
#include <sys/ioctl.h>
47

    
48
#include <driver.h>
49
#include <rtc.h>
50

    
51
#define FEBRUARY        2
52
#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
53
#define        days_in_month(a)         (month_days[(a) - 1])
54

    
55
struct rtc_softc {
56
        device_t        dev;                /* device object */
57
        struct rtc_ops        *ops;                /* rtc operations */
58
        void                *aux;                /* cookie data */
59
        time_t                boot_sec;        /* Time (sec) at system boot */
60
        u_long                boot_ticks;        /* Time (ticks) at system boot */
61
};
62

    
63
static int rtc_ioctl(device_t, u_long, void *);
64
static int rtc_init(struct driver *);
65

    
66
static struct devops rtc_devops = {
67
        /* open */        no_open,
68
        /* close */        no_close,
69
        /* read */        no_read,
70
        /* write */        no_write,
71
        /* ioctl */        rtc_ioctl,
72
        /* devctl */        no_devctl,
73
};
74

    
75
struct driver rtc_driver = {
76
        /* name */        "rtc",
77
        /* devops */        &rtc_devops,
78
        /* devsz */        sizeof(struct rtc_softc),
79
        /* flags */        0,
80
        /* probe */        NULL,
81
        /* init */        rtc_init,
82
        /* shutdown */        NULL,
83
};
84

    
85
static const int month_days[12] = {
86
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
87
};
88

    
89
static int
90
leapyear(u_int year)
91
{
92
        int rv = 0;
93

    
94
        if ((year & 3) == 0) {
95
                rv = 1;
96
                if ((year % 100) == 0) {
97
                        rv = 0;
98
                        if ((year % 400) == 0)
99
                                rv = 1;
100
                }
101
        }
102
        return (rv);
103
}
104

    
105
time_t
106
rtc_ymdhms_to_secs(struct clock_ymdhms *dt)
107
{
108
        time_t secs;
109
        u_int i, year, days;
110

    
111
        year = dt->year;
112

    
113
        /*
114
         * Compute days since start of time.
115
         * First from years, then from months.
116
         */
117
        days = 0;
118
        for (i = POSIX_BASE_YEAR; i < year; i++)
119
                days += days_in_year(i);
120
        if (leapyear(year) && dt->mon > FEBRUARY)
121
                days++;
122

    
123
        /* Months */
124
        for (i = 1; i < dt->mon; i++)
125
                  days += days_in_month(i);
126
        days += (dt->day - 1);
127

    
128
        /* Add hours, minutes, seconds. */
129
        secs = (time_t)(((days * 24 + dt->hour) * 60 + dt->min)
130
                        * 60 + dt->sec);
131

    
132
        return (secs);
133
}
134

    
135
/* This function uses a copy of month_days[] */
136
#undef        days_in_month
137
#define        days_in_month(a)         (mthdays[(a) - 1])
138

    
139
void
140
rtc_secs_to_ymdhms(time_t secs, struct clock_ymdhms *dt)
141
{
142
        u_int mthdays[12];
143
        u_int i, days;
144
        u_int rsec;        /* remainder seconds */
145

    
146
        memcpy(mthdays, month_days, sizeof(mthdays));
147

    
148
        days = secs / SECDAY;
149
        rsec = secs % SECDAY;
150

    
151
        /* Day of week (Note: 1/1/1970 was a Thursday) */
152
        dt->dow = (days + 4) % 7;
153

    
154
        /* Subtract out whole years, counting them in i. */
155
        for (i = POSIX_BASE_YEAR; days >= days_in_year(i); i++)
156
                days -= days_in_year(i);
157
        dt->year = (u_short)i;
158

    
159
        /* Subtract out whole months, counting them in i. */
160
        if (leapyear(i))
161
                days_in_month(FEBRUARY) = 29;
162
        for (i = 1; days >= days_in_month(i); i++)
163
                days -= days_in_month(i);
164
        dt->mon = i;
165

    
166
        /* Days are what is left over (+1) from all that. */
167
        dt->day = days + 1;
168

    
169
        /* Hours, minutes, seconds are easy */
170
        dt->hour = rsec / 3600;
171
        rsec = rsec % 3600;
172
        dt->min  = rsec / 60;
173
        rsec = rsec % 60;
174
        dt->sec  = rsec;
175
}
176

    
177
static int
178
rtc_ioctl(device_t dev, u_long cmd, void *arg)
179
{
180
        struct rtc_softc *sc = device_private(dev);
181
        struct timeval tv;
182
        int error = 0;
183
        u_long msec;
184

    
185
        switch (cmd) {
186
        case RTCIOC_GET_TIME:
187
                /*
188
                 * Calculate current time (sec/usec) from
189
                 * boot time and current tick count.
190
                 */
191
                msec = hztoms(timer_ticks() - sc->boot_ticks);
192
                tv.tv_sec = sc->boot_sec + (msec / 1000);
193
                tv.tv_usec = (long)((msec * 1000) % 1000000);
194
                if (copyout(&tv, arg, sizeof(tv)))
195
                        return EFAULT;
196
                break;
197

    
198
        case RTCIOC_SET_TIME:
199
                /*
200
                 * TODO: We need new capability to set time.
201
                 */
202
                error = EINVAL;
203
                break;
204
        default:
205
                return EINVAL;
206
        }
207
        return error;
208
}
209

    
210
void
211
rtc_attach(struct rtc_ops *ops, void *aux)
212
{
213
        struct rtc_softc *sc;
214
        device_t dev;
215
        struct timeval tv;
216

    
217
        dev = device_create(&rtc_driver, "rtc", D_CHR);
218

    
219
        sc = device_private(dev);
220
        sc->dev = dev;
221
        sc->ops = ops;
222
        sc->aux = aux;
223

    
224
        /* Save boot time for later use. */
225
        ops->gettime(aux, &tv);
226
        sc->boot_sec = tv.tv_sec;
227
        sc->boot_ticks = timer_ticks();
228
}
229

    
230
static int
231
rtc_init(struct driver *self)
232
{
233

    
234
        return 0;
235
}