Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xiphi1978
linux
提交
8ba706a9
L
linux
项目概览
xiphi1978
/
linux
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8ba706a9
编写于
3月 01, 2006
作者:
D
David S. Miller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[SPARC64]: Add mini-RTC driver for Starfire and SUN4V.
Signed-off-by:
N
David S. Miller
<
davem@davemloft.net
>
上级
b830ab66
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
279 addition
and
0 deletion
+279
-0
arch/sparc64/kernel/time.c
arch/sparc64/kernel/time.c
+279
-0
未找到文件。
arch/sparc64/kernel/time.c
浏览文件 @
8ba706a9
...
...
@@ -30,6 +30,8 @@
#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <linux/profile.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
...
...
@@ -45,6 +47,7 @@
#include <asm/smp.h>
#include <asm/sections.h>
#include <asm/cpudata.h>
#include <asm/uaccess.h>
DEFINE_SPINLOCK
(
mostek_lock
);
DEFINE_SPINLOCK
(
rtc_lock
);
...
...
@@ -702,6 +705,14 @@ static u32 starfire_get_time(void)
return
unix_tod
;
}
static
int
starfire_set_time
(
u32
val
)
{
/* Do nothing, time is set using the service processor
* console on this platform.
*/
return
0
;
}
static
u32
hypervisor_get_time
(
void
)
{
register
unsigned
long
func
asm
(
"%o5"
);
...
...
@@ -731,6 +742,33 @@ static u32 hypervisor_get_time(void)
return
0
;
}
static
int
hypervisor_set_time
(
u32
secs
)
{
register
unsigned
long
func
asm
(
"%o5"
);
register
unsigned
long
arg0
asm
(
"%o0"
);
int
retries
=
10000
;
retry:
func
=
HV_FAST_TOD_SET
;
arg0
=
secs
;
__asm__
__volatile__
(
"ta %4"
:
"=&r"
(
func
),
"=&r"
(
arg0
)
:
"0"
(
func
),
"1"
(
arg0
),
"i"
(
HV_FAST_TRAP
));
if
(
arg0
==
HV_EOK
)
return
0
;
if
(
arg0
==
HV_EWOULDBLOCK
)
{
if
(
--
retries
>
0
)
{
udelay
(
100
);
goto
retry
;
}
printk
(
KERN_WARNING
"SUN4V: tod_set() timed out.
\n
"
);
return
-
EAGAIN
;
}
printk
(
KERN_WARNING
"SUN4V: tod_set() not supported.
\n
"
);
return
-
EOPNOTSUPP
;
}
void
__init
clock_probe
(
void
)
{
struct
linux_prom_registers
clk_reg
[
2
];
...
...
@@ -1221,3 +1259,244 @@ static int set_rtc_mmss(unsigned long nowtime)
return
retval
;
}
}
#define RTC_IS_OPEN 0x01
/* means /dev/rtc is in use */
static
unsigned
char
mini_rtc_status
;
/* bitmapped status byte. */
/* months start at 0 now */
static
unsigned
char
days_in_mo
[]
=
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
};
#define FEBRUARY 2
#define STARTOFTIME 1970
#define SECDAY 86400L
#define SECYR (SECDAY * 365)
#define leapyear(year) ((year) % 4 == 0 && \
((year) % 100 != 0 || (year) % 400 == 0))
#define days_in_year(a) (leapyear(a) ? 366 : 365)
#define days_in_month(a) (month_days[(a) - 1])
static
int
month_days
[
12
]
=
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
};
/*
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
*/
static
void
GregorianDay
(
struct
rtc_time
*
tm
)
{
int
leapsToDate
;
int
lastYear
;
int
day
;
int
MonthOffset
[]
=
{
0
,
31
,
59
,
90
,
120
,
151
,
181
,
212
,
243
,
273
,
304
,
334
};
lastYear
=
tm
->
tm_year
-
1
;
/*
* Number of leap corrections to apply up to end of last year
*/
leapsToDate
=
lastYear
/
4
-
lastYear
/
100
+
lastYear
/
400
;
/*
* This year is a leap year if it is divisible by 4 except when it is
* divisible by 100 unless it is divisible by 400
*
* e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
*/
day
=
tm
->
tm_mon
>
2
&&
leapyear
(
tm
->
tm_year
);
day
+=
lastYear
*
365
+
leapsToDate
+
MonthOffset
[
tm
->
tm_mon
-
1
]
+
tm
->
tm_mday
;
tm
->
tm_wday
=
day
%
7
;
}
static
void
to_tm
(
int
tim
,
struct
rtc_time
*
tm
)
{
register
int
i
;
register
long
hms
,
day
;
day
=
tim
/
SECDAY
;
hms
=
tim
%
SECDAY
;
/* Hours, minutes, seconds are easy */
tm
->
tm_hour
=
hms
/
3600
;
tm
->
tm_min
=
(
hms
%
3600
)
/
60
;
tm
->
tm_sec
=
(
hms
%
3600
)
%
60
;
/* Number of years in days */
for
(
i
=
STARTOFTIME
;
day
>=
days_in_year
(
i
);
i
++
)
day
-=
days_in_year
(
i
);
tm
->
tm_year
=
i
;
/* Number of months in days left */
if
(
leapyear
(
tm
->
tm_year
))
days_in_month
(
FEBRUARY
)
=
29
;
for
(
i
=
1
;
day
>=
days_in_month
(
i
);
i
++
)
day
-=
days_in_month
(
i
);
days_in_month
(
FEBRUARY
)
=
28
;
tm
->
tm_mon
=
i
;
/* Days are what is left over (+1) from all that. */
tm
->
tm_mday
=
day
+
1
;
/*
* Determine the day of week
*/
GregorianDay
(
tm
);
}
/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
* aka Unix time. So we have to convert to/from rtc_time.
*/
static
inline
void
mini_get_rtc_time
(
struct
rtc_time
*
time
)
{
unsigned
long
flags
;
u32
seconds
;
spin_lock_irqsave
(
&
rtc_lock
,
flags
);
seconds
=
0
;
if
(
this_is_starfire
)
seconds
=
starfire_get_time
();
else
if
(
tlb_type
==
hypervisor
)
seconds
=
hypervisor_get_time
();
spin_unlock_irqrestore
(
&
rtc_lock
,
flags
);
to_tm
(
seconds
,
time
);
}
static
inline
int
mini_set_rtc_time
(
struct
rtc_time
*
time
)
{
u32
seconds
=
mktime
(
time
->
tm_year
+
1900
,
time
->
tm_mon
+
1
,
time
->
tm_mday
,
time
->
tm_hour
,
time
->
tm_min
,
time
->
tm_sec
);
unsigned
long
flags
;
int
err
;
spin_lock_irqsave
(
&
rtc_lock
,
flags
);
err
=
-
ENODEV
;
if
(
this_is_starfire
)
err
=
starfire_set_time
(
seconds
);
else
if
(
tlb_type
==
hypervisor
)
err
=
hypervisor_set_time
(
seconds
);
spin_unlock_irqrestore
(
&
rtc_lock
,
flags
);
return
err
;
}
static
int
mini_rtc_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
rtc_time
wtime
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
switch
(
cmd
)
{
case
RTC_PLL_GET
:
return
-
EINVAL
;
case
RTC_PLL_SET
:
return
-
EINVAL
;
case
RTC_UIE_OFF
:
/* disable ints from RTC updates. */
return
0
;
case
RTC_UIE_ON
:
/* enable ints for RTC updates. */
return
-
EINVAL
;
case
RTC_RD_TIME
:
/* Read the time/date from RTC */
/* this doesn't get week-day, who cares */
memset
(
&
wtime
,
0
,
sizeof
(
wtime
));
mini_get_rtc_time
(
&
wtime
);
return
copy_to_user
(
argp
,
&
wtime
,
sizeof
(
wtime
))
?
-
EFAULT
:
0
;
case
RTC_SET_TIME
:
/* Set the RTC */
{
int
year
;
unsigned
char
leap_yr
;
if
(
!
capable
(
CAP_SYS_TIME
))
return
-
EACCES
;
if
(
copy_from_user
(
&
wtime
,
argp
,
sizeof
(
wtime
)))
return
-
EFAULT
;
year
=
wtime
.
tm_year
+
1900
;
leap_yr
=
((
!
(
year
%
4
)
&&
(
year
%
100
))
||
!
(
year
%
400
));
if
((
wtime
.
tm_mon
<
0
||
wtime
.
tm_mon
>
11
)
||
(
wtime
.
tm_mday
<
1
))
return
-
EINVAL
;
if
(
wtime
.
tm_mday
<
0
||
wtime
.
tm_mday
>
(
days_in_mo
[
wtime
.
tm_mon
]
+
((
wtime
.
tm_mon
==
1
)
&&
leap_yr
)))
return
-
EINVAL
;
if
(
wtime
.
tm_hour
<
0
||
wtime
.
tm_hour
>=
24
||
wtime
.
tm_min
<
0
||
wtime
.
tm_min
>=
60
||
wtime
.
tm_sec
<
0
||
wtime
.
tm_sec
>=
60
)
return
-
EINVAL
;
return
mini_set_rtc_time
(
&
wtime
);
}
}
return
-
EINVAL
;
}
static
int
mini_rtc_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
mini_rtc_status
&
RTC_IS_OPEN
)
return
-
EBUSY
;
mini_rtc_status
|=
RTC_IS_OPEN
;
return
0
;
}
static
int
mini_rtc_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
mini_rtc_status
&=
~
RTC_IS_OPEN
;
return
0
;
}
static
struct
file_operations
mini_rtc_fops
=
{
.
owner
=
THIS_MODULE
,
.
ioctl
=
mini_rtc_ioctl
,
.
open
=
mini_rtc_open
,
.
release
=
mini_rtc_release
,
};
static
struct
miscdevice
rtc_mini_dev
=
{
.
minor
=
RTC_MINOR
,
.
name
=
"rtc"
,
.
fops
=
&
mini_rtc_fops
,
};
static
int
__init
rtc_mini_init
(
void
)
{
int
retval
;
if
(
tlb_type
!=
hypervisor
&&
!
this_is_starfire
)
return
-
ENODEV
;
printk
(
KERN_INFO
"Mini RTC Driver
\n
"
);
retval
=
misc_register
(
&
rtc_mini_dev
);
if
(
retval
<
0
)
return
retval
;
return
0
;
}
static
void
__exit
rtc_mini_exit
(
void
)
{
misc_deregister
(
&
rtc_mini_dev
);
}
module_init
(
rtc_mini_init
);
module_exit
(
rtc_mini_exit
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录