Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
m68k
bvme6000
rtc.c
Go to the documentation of this file.
1
/*
2
* Real Time Clock interface for Linux on the BVME6000
3
*
4
* Based on the PC driver by Paul Gortmaker.
5
*/
6
7
#define RTC_VERSION "1.00"
8
9
#include <linux/types.h>
10
#include <linux/errno.h>
11
#include <
linux/miscdevice.h
>
12
#include <
linux/ioport.h
>
13
#include <linux/capability.h>
14
#include <linux/fcntl.h>
15
#include <
linux/init.h
>
16
#include <linux/poll.h>
17
#include <linux/module.h>
18
#include <
linux/mc146818rtc.h
>
/* For struct rtc_time and ioctls, etc */
19
#include <
linux/bcd.h
>
20
#include <
asm/bvme6000hw.h
>
21
22
#include <asm/io.h>
23
#include <asm/uaccess.h>
24
#include <asm/setup.h>
25
26
/*
27
* We sponge a minor off of the misc major. No need slurping
28
* up another valuable major dev number for this. If you add
29
* an ioctl, make sure you don't conflict with SPARC's RTC
30
* ioctls.
31
*/
32
33
static
unsigned
char
days_in_mo[] =
34
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
35
36
static
atomic_t
rtc_status
=
ATOMIC_INIT
(1);
37
38
static
long
rtc_ioctl(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
39
{
40
volatile
RtcPtr_t
rtc
= (
RtcPtr_t
)
BVME_RTC_BASE
;
41
unsigned
char
msr;
42
unsigned
long
flags
;
43
struct
rtc_time
wtime;
44
void
__user
*
argp
= (
void
__user
*)arg;
45
46
switch
(cmd) {
47
case
RTC_RD_TIME
:
/* Read the time/date from RTC */
48
{
49
local_irq_save
(flags);
50
/* Ensure clock and real-time-mode-register are accessible */
51
msr = rtc->
msr
& 0xc0;
52
rtc->
msr
= 0x40;
53
memset
(&wtime, 0,
sizeof
(
struct
rtc_time
));
54
do
{
55
wtime.tm_sec =
bcd2bin
(rtc->
bcd_sec
);
56
wtime.tm_min =
bcd2bin
(rtc->
bcd_min
);
57
wtime.tm_hour =
bcd2bin
(rtc->
bcd_hr
);
58
wtime.tm_mday =
bcd2bin
(rtc->
bcd_dom
);
59
wtime.tm_mon =
bcd2bin
(rtc->
bcd_mth
)-1;
60
wtime.tm_year =
bcd2bin
(rtc->
bcd_year
);
61
if
(wtime.tm_year < 70)
62
wtime.tm_year += 100;
63
wtime.tm_wday =
bcd2bin
(rtc->
bcd_dow
)-1;
64
}
while
(wtime.tm_sec !=
bcd2bin
(rtc->
bcd_sec
));
65
rtc->
msr
= msr;
66
local_irq_restore
(flags);
67
return
copy_to_user
(argp, &wtime,
sizeof
wtime) ?
68
-
EFAULT
: 0;
69
}
70
case
RTC_SET_TIME
:
/* Set the RTC */
71
{
72
struct
rtc_time
rtc_tm;
73
unsigned
char
mon,
day
, hrs,
min
,
sec
, leap_yr;
74
unsigned
int
yrs;
75
76
if
(!
capable
(
CAP_SYS_ADMIN
))
77
return
-
EACCES
;
78
79
if
(
copy_from_user
(&rtc_tm, argp,
sizeof
(
struct
rtc_time
)))
80
return
-
EFAULT
;
81
82
yrs = rtc_tm.tm_year;
83
if
(yrs < 1900)
84
yrs += 1900;
85
mon = rtc_tm.tm_mon + 1;
/* tm_mon starts at zero */
86
day = rtc_tm.tm_mday;
87
hrs = rtc_tm.tm_hour;
88
min = rtc_tm.tm_min;
89
sec = rtc_tm.tm_sec;
90
91
leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
92
93
if
((mon > 12) || (mon < 1) || (day == 0))
94
return
-
EINVAL
;
95
96
if
(day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
97
return
-
EINVAL
;
98
99
if
((hrs >= 24) || (min >= 60) || (sec >= 60))
100
return
-
EINVAL
;
101
102
if
(yrs >= 2070)
103
return
-
EINVAL
;
104
105
local_irq_save
(flags);
106
/* Ensure clock and real-time-mode-register are accessible */
107
msr = rtc->
msr
& 0xc0;
108
rtc->
msr
= 0x40;
109
110
rtc->
t0cr_rtmr
= yrs%4;
111
rtc->
bcd_tenms
= 0;
112
rtc->
bcd_sec
=
bin2bcd
(sec);
113
rtc->
bcd_min
=
bin2bcd
(min);
114
rtc->
bcd_hr
=
bin2bcd
(hrs);
115
rtc->
bcd_dom
=
bin2bcd
(day);
116
rtc->
bcd_mth
=
bin2bcd
(mon);
117
rtc->
bcd_year
=
bin2bcd
(yrs%100);
118
if
(rtc_tm.tm_wday >= 0)
119
rtc->
bcd_dow
=
bin2bcd
(rtc_tm.tm_wday+1);
120
rtc->
t0cr_rtmr
= yrs%4 | 0x08;
121
122
rtc->
msr
= msr;
123
local_irq_restore
(flags);
124
return
0;
125
}
126
default
:
127
return
-
EINVAL
;
128
}
129
}
130
131
/*
132
* We enforce only one user at a time here with the open/close.
133
*/
134
static
int
rtc_open(
struct
inode
*
inode
,
struct
file *file)
135
{
136
if
(!
atomic_dec_and_test
(&rtc_status)) {
137
atomic_inc
(&rtc_status);
138
return
-
EBUSY
;
139
}
140
return
0;
141
}
142
143
static
int
rtc_release(
struct
inode *inode,
struct
file *file)
144
{
145
atomic_inc
(&rtc_status);
146
return
0;
147
}
148
149
/*
150
* The various file operations we support.
151
*/
152
153
static
const
struct
file_operations
rtc_fops = {
154
.unlocked_ioctl = rtc_ioctl,
155
.open = rtc_open,
156
.release = rtc_release,
157
.llseek =
noop_llseek
,
158
};
159
160
static
struct
miscdevice
rtc_dev = {
161
.minor =
RTC_MINOR
,
162
.name =
"rtc"
,
163
.fops = &rtc_fops
164
};
165
166
static
int
__init
rtc_DP8570A_init(
void
)
167
{
168
if
(!
MACH_IS_BVME6000
)
169
return
-
ENODEV
;
170
171
printk
(
KERN_INFO
"DP8570A Real Time Clock Driver v%s\n"
,
RTC_VERSION
);
172
return
misc_register
(&rtc_dev);
173
}
174
module_init
(rtc_DP8570A_init);
Generated on Thu Jan 10 2013 13:07:55 for Linux Kernel by
1.8.2