Skip to content

Commit

Permalink
[PATCH] RTC subsystem: proc interface
Browse files Browse the repository at this point in the history
Add the proc interface to the RTC subsystem.

The first RTC driver which registers with the class will be accessible by
/proc/driver/rtc .

This is required for compatibility with the standard RTC driver and to avoid
breaking any user space application which may erroneusly rely on this.

Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Alessandro Zummo authored and Linus Torvalds committed Mar 27, 2006
1 parent c5c3e19 commit 728a294
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 1 deletion.
11 changes: 11 additions & 0 deletions drivers/rtc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ config RTC_INTF_SYSFS
This driver can also be built as a module. If so, the module
will be called rtc-sysfs.

config RTC_INTF_PROC
tristate "proc"
depends on RTC_CLASS && PROC_FS
default RTC_CLASS
help
Say yes here if you want to use your RTC using the proc
interface, /proc/driver/rtc .

This driver can also be built as a module. If so, the module
will be called rtc-proc.

comment "RTC drivers"
depends on RTC_CLASS

Expand Down
2 changes: 1 addition & 1 deletion drivers/rtc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o

obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o

obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
162 changes: 162 additions & 0 deletions drivers/rtc/rtc-proc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* RTC subsystem, proc interface
*
* Copyright (C) 2005-06 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* based on arch/arm/common/rtctime.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

static struct class_device *rtc_dev = NULL;
static DEFINE_MUTEX(rtc_lock);

static int rtc_proc_show(struct seq_file *seq, void *offset)
{
int err;
struct class_device *class_dev = seq->private;
struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
struct rtc_wkalrm alrm;
struct rtc_time tm;

err = rtc_read_time(class_dev, &tm);
if (err == 0) {
seq_printf(seq,
"rtc_time\t: %02d:%02d:%02d\n"
"rtc_date\t: %04d-%02d-%02d\n",
tm.tm_hour, tm.tm_min, tm.tm_sec,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
}

err = rtc_read_alarm(class_dev, &alrm);
if (err == 0) {
seq_printf(seq, "alrm_time\t: ");
if ((unsigned int)alrm.time.tm_hour <= 24)
seq_printf(seq, "%02d:", alrm.time.tm_hour);
else
seq_printf(seq, "**:");
if ((unsigned int)alrm.time.tm_min <= 59)
seq_printf(seq, "%02d:", alrm.time.tm_min);
else
seq_printf(seq, "**:");
if ((unsigned int)alrm.time.tm_sec <= 59)
seq_printf(seq, "%02d\n", alrm.time.tm_sec);
else
seq_printf(seq, "**\n");

seq_printf(seq, "alrm_date\t: ");
if ((unsigned int)alrm.time.tm_year <= 200)
seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
else
seq_printf(seq, "****-");
if ((unsigned int)alrm.time.tm_mon <= 11)
seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
else
seq_printf(seq, "**-");
if ((unsigned int)alrm.time.tm_mday <= 31)
seq_printf(seq, "%02d\n", alrm.time.tm_mday);
else
seq_printf(seq, "**\n");
seq_printf(seq, "alrm_wakeup\t: %s\n",
alrm.enabled ? "yes" : "no");
seq_printf(seq, "alrm_pending\t: %s\n",
alrm.pending ? "yes" : "no");
}

if (ops->proc)
ops->proc(class_dev->dev, seq);

return 0;
}

static int rtc_proc_open(struct inode *inode, struct file *file)
{
struct class_device *class_dev = PDE(inode)->data;

if (!try_module_get(THIS_MODULE))
return -ENODEV;

return single_open(file, rtc_proc_show, class_dev);
}

static int rtc_proc_release(struct inode *inode, struct file *file)
{
int res = single_release(inode, file);
module_put(THIS_MODULE);
return res;
}

static struct file_operations rtc_proc_fops = {
.open = rtc_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = rtc_proc_release,
};

static int rtc_proc_add_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
mutex_lock(&rtc_lock);
if (rtc_dev == NULL) {
struct proc_dir_entry *ent;

rtc_dev = class_dev;

ent = create_proc_entry("driver/rtc", 0, NULL);
if (ent) {
struct rtc_device *rtc = to_rtc_device(class_dev);

ent->proc_fops = &rtc_proc_fops;
ent->owner = rtc->owner;
ent->data = class_dev;

dev_info(class_dev->dev, "rtc intf: proc\n");
}
else
rtc_dev = NULL;
}
mutex_unlock(&rtc_lock);

return 0;
}

static void rtc_proc_remove_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
mutex_lock(&rtc_lock);
if (rtc_dev == class_dev) {
remove_proc_entry("driver/rtc", NULL);
rtc_dev = NULL;
}
mutex_unlock(&rtc_lock);
}

static struct class_interface rtc_proc_interface = {
.add = &rtc_proc_add_device,
.remove = &rtc_proc_remove_device,
};

static int __init rtc_proc_init(void)
{
return rtc_interface_register(&rtc_proc_interface);
}

static void __exit rtc_proc_exit(void)
{
class_interface_unregister(&rtc_proc_interface);
}

module_init(rtc_proc_init);
module_exit(rtc_proc_exit);

MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("RTC class proc interface");
MODULE_LICENSE("GPL");

0 comments on commit 728a294

Please sign in to comment.