Commit 0c86edc0d4970649f39748c4ce4f2895f728468f

Authored by Alessandro Zummo
Committed by Linus Torvalds
1 parent 4079c39aaa

[PATCH] RTC subsystem: class

Add the basic RTC subsystem infrastructure to the kernel.

rtc/class.c - registration facilities for RTC drivers
rtc/interface.c - kernel/rtc interface functions
rtc/hctosys.c - snippet of code that copies hw clock to sw clock
		at bootup, if configured to do so.

Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 8 changed files with 633 additions and 5 deletions Side-by-side Diff

... ... @@ -3741,10 +3741,11 @@
3741 3741 D: Miscellaneous kernel fixes
3742 3742  
3743 3743 N: Alessandro Zummo
3744   -E: azummo@ita.flashnet.it
3745   -W: http://freepage.logicom.it/azummo/
  3744 +E: a.zummo@towertech.it
3746 3745 D: CMI8330 support is sb_card.c
3747 3746 D: ISAPnP fixes in sb_card.c
  3747 +D: ZyXEL omni.net lcd plus driver
  3748 +D: RTC subsystem
3748 3749 S: Italy
3749 3750  
3750 3751 N: Marc Zyngier
... ... @@ -2233,6 +2233,12 @@
2233 2233 L: linux-kernel@vger.kernel.org
2234 2234 S: Maintained
2235 2235  
  2236 +REAL TIME CLOCK (RTC) SUBSYSTEM
  2237 +P: Alessandro Zummo
  2238 +M: a.zummo@towertech.it
  2239 +L: linux-kernel@vger.kernel.org
  2240 +S: Maintained
  2241 +
2236 2242 REISERFS FILE SYSTEM
2237 2243 P: Hans Reiser
2238 2244 M: reiserfs-dev@namesys.com
1   -#
  1 +\#
2 2 # RTC class/drivers configuration
3 3 #
4 4  
  5 +menu "Real Time Clock"
  6 +
5 7 config RTC_LIB
6 8 tristate
  9 +
  10 +config RTC_CLASS
  11 + tristate "RTC class"
  12 + depends on EXPERIMENTAL
  13 + default n
  14 + select RTC_LIB
  15 + help
  16 + Generic RTC class support. If you say yes here, you will
  17 + be allowed to plug one or more RTCs to your system. You will
  18 + probably want to enable one of more of the interfaces below.
  19 +
  20 + This driver can also be built as a module. If so, the module
  21 + will be called rtc-class.
  22 +
  23 +config RTC_HCTOSYS
  24 + bool "Set system time from RTC on startup"
  25 + depends on RTC_CLASS = y
  26 + default y
  27 + help
  28 + If you say yes here, the system time will be set using
  29 + the value read from the specified RTC device. This is useful
  30 + in order to avoid unnecessary fschk runs.
  31 +
  32 +config RTC_HCTOSYS_DEVICE
  33 + string "The RTC to read the time from"
  34 + depends on RTC_HCTOSYS = y
  35 + default "rtc0"
  36 + help
  37 + The RTC device that will be used as the source for
  38 + the system time, usually rtc0.
  39 +
  40 +comment "RTC interfaces"
  41 + depends on RTC_CLASS
  42 +
  43 +comment "RTC drivers"
  44 + depends on RTC_CLASS
  45 +
  46 +endmenu
drivers/rtc/Makefile
... ... @@ -2,5 +2,8 @@
2 2 # Makefile for RTC class/drivers.
3 3 #
4 4  
5   -obj-$(CONFIG_RTC_LIB) += rtc-lib.o
  5 +obj-$(CONFIG_RTC_LIB) += rtc-lib.o
  6 +obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
  7 +obj-$(CONFIG_RTC_CLASS) += rtc-core.o
  8 +rtc-core-y := class.o interface.o
  1 +/*
  2 + * RTC subsystem, base class
  3 + *
  4 + * Copyright (C) 2005 Tower Technologies
  5 + * Author: Alessandro Zummo <a.zummo@towertech.it>
  6 + *
  7 + * class skeleton from drivers/hwmon/hwmon.c
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License version 2 as
  11 + * published by the Free Software Foundation.
  12 +*/
  13 +
  14 +#include <linux/module.h>
  15 +#include <linux/rtc.h>
  16 +#include <linux/kdev_t.h>
  17 +#include <linux/idr.h>
  18 +
  19 +static DEFINE_IDR(rtc_idr);
  20 +static DEFINE_MUTEX(idr_lock);
  21 +struct class *rtc_class;
  22 +
  23 +static void rtc_device_release(struct class_device *class_dev)
  24 +{
  25 + struct rtc_device *rtc = to_rtc_device(class_dev);
  26 + mutex_lock(&idr_lock);
  27 + idr_remove(&rtc_idr, rtc->id);
  28 + mutex_unlock(&idr_lock);
  29 + kfree(rtc);
  30 +}
  31 +
  32 +/**
  33 + * rtc_device_register - register w/ RTC class
  34 + * @dev: the device to register
  35 + *
  36 + * rtc_device_unregister() must be called when the class device is no
  37 + * longer needed.
  38 + *
  39 + * Returns the pointer to the new struct class device.
  40 + */
  41 +struct rtc_device *rtc_device_register(const char *name, struct device *dev,
  42 + struct rtc_class_ops *ops,
  43 + struct module *owner)
  44 +{
  45 + struct rtc_device *rtc;
  46 + int id, err;
  47 +
  48 + if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
  49 + err = -ENOMEM;
  50 + goto exit;
  51 + }
  52 +
  53 +
  54 + mutex_lock(&idr_lock);
  55 + err = idr_get_new(&rtc_idr, NULL, &id);
  56 + mutex_unlock(&idr_lock);
  57 +
  58 + if (err < 0)
  59 + goto exit;
  60 +
  61 + id = id & MAX_ID_MASK;
  62 +
  63 + rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
  64 + if (rtc == NULL) {
  65 + err = -ENOMEM;
  66 + goto exit_idr;
  67 + }
  68 +
  69 + rtc->id = id;
  70 + rtc->ops = ops;
  71 + rtc->owner = owner;
  72 + rtc->class_dev.dev = dev;
  73 + rtc->class_dev.class = rtc_class;
  74 + rtc->class_dev.release = rtc_device_release;
  75 +
  76 + mutex_init(&rtc->ops_lock);
  77 + spin_lock_init(&rtc->irq_lock);
  78 + spin_lock_init(&rtc->irq_task_lock);
  79 +
  80 + strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
  81 + snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
  82 +
  83 + err = class_device_register(&rtc->class_dev);
  84 + if (err)
  85 + goto exit_kfree;
  86 +
  87 + dev_info(dev, "rtc core: registered %s as %s\n",
  88 + rtc->name, rtc->class_dev.class_id);
  89 +
  90 + return rtc;
  91 +
  92 +exit_kfree:
  93 + kfree(rtc);
  94 +
  95 +exit_idr:
  96 + idr_remove(&rtc_idr, id);
  97 +
  98 +exit:
  99 + return ERR_PTR(err);
  100 +}
  101 +EXPORT_SYMBOL_GPL(rtc_device_register);
  102 +
  103 +
  104 +/**
  105 + * rtc_device_unregister - removes the previously registered RTC class device
  106 + *
  107 + * @rtc: the RTC class device to destroy
  108 + */
  109 +void rtc_device_unregister(struct rtc_device *rtc)
  110 +{
  111 + mutex_lock(&rtc->ops_lock);
  112 + rtc->ops = NULL;
  113 + mutex_unlock(&rtc->ops_lock);
  114 + class_device_unregister(&rtc->class_dev);
  115 +}
  116 +EXPORT_SYMBOL_GPL(rtc_device_unregister);
  117 +
  118 +int rtc_interface_register(struct class_interface *intf)
  119 +{
  120 + intf->class = rtc_class;
  121 + return class_interface_register(intf);
  122 +}
  123 +EXPORT_SYMBOL_GPL(rtc_interface_register);
  124 +
  125 +static int __init rtc_init(void)
  126 +{
  127 + rtc_class = class_create(THIS_MODULE, "rtc");
  128 + if (IS_ERR(rtc_class)) {
  129 + printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
  130 + return PTR_ERR(rtc_class);
  131 + }
  132 + return 0;
  133 +}
  134 +
  135 +static void __exit rtc_exit(void)
  136 +{
  137 + class_destroy(rtc_class);
  138 +}
  139 +
  140 +module_init(rtc_init);
  141 +module_exit(rtc_exit);
  142 +
  143 +MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
  144 +MODULE_DESCRIPTION("RTC class support");
  145 +MODULE_LICENSE("GPL");
drivers/rtc/hctosys.c
  1 +/*
  2 + * RTC subsystem, initialize system time on startup
  3 + *
  4 + * Copyright (C) 2005 Tower Technologies
  5 + * Author: Alessandro Zummo <a.zummo@towertech.it>
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License version 2 as
  9 + * published by the Free Software Foundation.
  10 +*/
  11 +
  12 +#include <linux/rtc.h>
  13 +
  14 +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
  15 + * whether it stores the most close value or the value with partial
  16 + * seconds truncated. However, it is important that we use it to store
  17 + * the truncated value. This is because otherwise it is necessary,
  18 + * in an rtc sync function, to read both xtime.tv_sec and
  19 + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
  20 + * of >32bits is not possible. So storing the most close value would
  21 + * slow down the sync API. So here we have the truncated value and
  22 + * the best guess is to add 0.5s.
  23 + */
  24 +
  25 +static int __init rtc_hctosys(void)
  26 +{
  27 + int err;
  28 + struct rtc_time tm;
  29 + struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
  30 +
  31 + if (class_dev == NULL) {
  32 + printk("%s: unable to open rtc device (%s)\n",
  33 + __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
  34 + return -ENODEV;
  35 + }
  36 +
  37 + err = rtc_read_time(class_dev, &tm);
  38 + if (err == 0) {
  39 + err = rtc_valid_tm(&tm);
  40 + if (err == 0) {
  41 + struct timespec tv;
  42 +
  43 + tv.tv_nsec = NSEC_PER_SEC >> 1;
  44 +
  45 + rtc_tm_to_time(&tm, &tv.tv_sec);
  46 +
  47 + do_settimeofday(&tv);
  48 +
  49 + dev_info(class_dev->dev,
  50 + "setting the system clock to "
  51 + "%d-%02d-%02d %02d:%02d:%02d (%u)\n",
  52 + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
  53 + tm.tm_hour, tm.tm_min, tm.tm_sec,
  54 + (unsigned int) tv.tv_sec);
  55 + }
  56 + else
  57 + dev_err(class_dev->dev,
  58 + "hctosys: invalid date/time\n");
  59 + }
  60 + else
  61 + dev_err(class_dev->dev,
  62 + "hctosys: unable to read the hardware clock\n");
  63 +
  64 + rtc_class_close(class_dev);
  65 +
  66 + return 0;
  67 +}
  68 +
  69 +late_initcall(rtc_hctosys);
drivers/rtc/interface.c
  1 +/*
  2 + * RTC subsystem, interface functions
  3 + *
  4 + * Copyright (C) 2005 Tower Technologies
  5 + * Author: Alessandro Zummo <a.zummo@towertech.it>
  6 + *
  7 + * based on arch/arm/common/rtctime.c
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License version 2 as
  11 + * published by the Free Software Foundation.
  12 +*/
  13 +
  14 +#include <linux/rtc.h>
  15 +
  16 +int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
  17 +{
  18 + int err;
  19 + struct rtc_device *rtc = to_rtc_device(class_dev);
  20 +
  21 + err = mutex_lock_interruptible(&rtc->ops_lock);
  22 + if (err)
  23 + return -EBUSY;
  24 +
  25 + if (!rtc->ops)
  26 + err = -ENODEV;
  27 + else if (!rtc->ops->read_time)
  28 + err = -EINVAL;
  29 + else {
  30 + memset(tm, 0, sizeof(struct rtc_time));
  31 + err = rtc->ops->read_time(class_dev->dev, tm);
  32 + }
  33 +
  34 + mutex_unlock(&rtc->ops_lock);
  35 + return err;
  36 +}
  37 +EXPORT_SYMBOL_GPL(rtc_read_time);
  38 +
  39 +int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
  40 +{
  41 + int err;
  42 + struct rtc_device *rtc = to_rtc_device(class_dev);
  43 +
  44 + err = rtc_valid_tm(tm);
  45 + if (err != 0)
  46 + return err;
  47 +
  48 + err = mutex_lock_interruptible(&rtc->ops_lock);
  49 + if (err)
  50 + return -EBUSY;
  51 +
  52 + if (!rtc->ops)
  53 + err = -ENODEV;
  54 + else if (!rtc->ops->set_time)
  55 + err = -EINVAL;
  56 + else
  57 + err = rtc->ops->set_time(class_dev->dev, tm);
  58 +
  59 + mutex_unlock(&rtc->ops_lock);
  60 + return err;
  61 +}
  62 +EXPORT_SYMBOL_GPL(rtc_set_time);
  63 +
  64 +int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
  65 +{
  66 + int err;
  67 + struct rtc_device *rtc = to_rtc_device(class_dev);
  68 +
  69 + err = mutex_lock_interruptible(&rtc->ops_lock);
  70 + if (err)
  71 + return -EBUSY;
  72 +
  73 + if (!rtc->ops)
  74 + err = -ENODEV;
  75 + else if (rtc->ops->set_mmss)
  76 + err = rtc->ops->set_mmss(class_dev->dev, secs);
  77 + else if (rtc->ops->read_time && rtc->ops->set_time) {
  78 + struct rtc_time new, old;
  79 +
  80 + err = rtc->ops->read_time(class_dev->dev, &old);
  81 + if (err == 0) {
  82 + rtc_time_to_tm(secs, &new);
  83 +
  84 + /*
  85 + * avoid writing when we're going to change the day of
  86 + * the month. We will retry in the next minute. This
  87 + * basically means that if the RTC must not drift
  88 + * by more than 1 minute in 11 minutes.
  89 + */
  90 + if (!((old.tm_hour == 23 && old.tm_min == 59) ||
  91 + (new.tm_hour == 23 && new.tm_min == 59)))
  92 + err = rtc->ops->set_time(class_dev->dev, &new);
  93 + }
  94 + }
  95 + else
  96 + err = -EINVAL;
  97 +
  98 + mutex_unlock(&rtc->ops_lock);
  99 +
  100 + return err;
  101 +}
  102 +EXPORT_SYMBOL_GPL(rtc_set_mmss);
  103 +
  104 +int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
  105 +{
  106 + int err;
  107 + struct rtc_device *rtc = to_rtc_device(class_dev);
  108 +
  109 + err = mutex_lock_interruptible(&rtc->ops_lock);
  110 + if (err)
  111 + return -EBUSY;
  112 +
  113 + if (rtc->ops == NULL)
  114 + err = -ENODEV;
  115 + else if (!rtc->ops->read_alarm)
  116 + err = -EINVAL;
  117 + else {
  118 + memset(alarm, 0, sizeof(struct rtc_wkalrm));
  119 + err = rtc->ops->read_alarm(class_dev->dev, alarm);
  120 + }
  121 +
  122 + mutex_unlock(&rtc->ops_lock);
  123 + return err;
  124 +}
  125 +EXPORT_SYMBOL_GPL(rtc_read_alarm);
  126 +
  127 +int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
  128 +{
  129 + int err;
  130 + struct rtc_device *rtc = to_rtc_device(class_dev);
  131 +
  132 + err = mutex_lock_interruptible(&rtc->ops_lock);
  133 + if (err)
  134 + return -EBUSY;
  135 +
  136 + if (!rtc->ops)
  137 + err = -ENODEV;
  138 + else if (!rtc->ops->set_alarm)
  139 + err = -EINVAL;
  140 + else
  141 + err = rtc->ops->set_alarm(class_dev->dev, alarm);
  142 +
  143 + mutex_unlock(&rtc->ops_lock);
  144 + return err;
  145 +}
  146 +EXPORT_SYMBOL_GPL(rtc_set_alarm);
  147 +
  148 +void rtc_update_irq(struct class_device *class_dev,
  149 + unsigned long num, unsigned long events)
  150 +{
  151 + struct rtc_device *rtc = to_rtc_device(class_dev);
  152 +
  153 + spin_lock(&rtc->irq_lock);
  154 + rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
  155 + spin_unlock(&rtc->irq_lock);
  156 +
  157 + spin_lock(&rtc->irq_task_lock);
  158 + if (rtc->irq_task)
  159 + rtc->irq_task->func(rtc->irq_task->private_data);
  160 + spin_unlock(&rtc->irq_task_lock);
  161 +
  162 + wake_up_interruptible(&rtc->irq_queue);
  163 + kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
  164 +}
  165 +EXPORT_SYMBOL_GPL(rtc_update_irq);
  166 +
  167 +struct class_device *rtc_class_open(char *name)
  168 +{
  169 + struct class_device *class_dev = NULL,
  170 + *class_dev_tmp;
  171 +
  172 + down(&rtc_class->sem);
  173 + list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
  174 + if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
  175 + class_dev = class_dev_tmp;
  176 + break;
  177 + }
  178 + }
  179 +
  180 + if (class_dev) {
  181 + if (!try_module_get(to_rtc_device(class_dev)->owner))
  182 + class_dev = NULL;
  183 + }
  184 + up(&rtc_class->sem);
  185 +
  186 + return class_dev;
  187 +}
  188 +EXPORT_SYMBOL_GPL(rtc_class_open);
  189 +
  190 +void rtc_class_close(struct class_device *class_dev)
  191 +{
  192 + module_put(to_rtc_device(class_dev)->owner);
  193 +}
  194 +EXPORT_SYMBOL_GPL(rtc_class_close);
  195 +
  196 +int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
  197 +{
  198 + int retval = -EBUSY;
  199 + struct rtc_device *rtc = to_rtc_device(class_dev);
  200 +
  201 + if (task == NULL || task->func == NULL)
  202 + return -EINVAL;
  203 +
  204 + spin_lock(&rtc->irq_task_lock);
  205 + if (rtc->irq_task == NULL) {
  206 + rtc->irq_task = task;
  207 + retval = 0;
  208 + }
  209 + spin_unlock(&rtc->irq_task_lock);
  210 +
  211 + return retval;
  212 +}
  213 +EXPORT_SYMBOL_GPL(rtc_irq_register);
  214 +
  215 +void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
  216 +{
  217 + struct rtc_device *rtc = to_rtc_device(class_dev);
  218 +
  219 + spin_lock(&rtc->irq_task_lock);
  220 + if (rtc->irq_task == task)
  221 + rtc->irq_task = NULL;
  222 + spin_unlock(&rtc->irq_task_lock);
  223 +}
  224 +EXPORT_SYMBOL_GPL(rtc_irq_unregister);
  225 +
  226 +int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
  227 +{
  228 + int err = 0;
  229 + unsigned long flags;
  230 + struct rtc_device *rtc = to_rtc_device(class_dev);
  231 +
  232 + spin_lock_irqsave(&rtc->irq_task_lock, flags);
  233 + if (rtc->irq_task != task)
  234 + err = -ENXIO;
  235 + spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
  236 +
  237 + if (err == 0)
  238 + err = rtc->ops->irq_set_state(class_dev->dev, enabled);
  239 +
  240 + return err;
  241 +}
  242 +EXPORT_SYMBOL_GPL(rtc_irq_set_state);
  243 +
  244 +int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
  245 +{
  246 + int err = 0, tmp = 0;
  247 + unsigned long flags;
  248 + struct rtc_device *rtc = to_rtc_device(class_dev);
  249 +
  250 + /* allowed range is 2-8192 */
  251 + if (freq < 2 || freq > 8192)
  252 + return -EINVAL;
  253 +/*
  254 + FIXME: this does not belong here, will move where appropriate
  255 + at a later stage. It cannot hurt right now, trust me :)
  256 + if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
  257 + return -EACCES;
  258 +*/
  259 + /* check if freq is a power of 2 */
  260 + while (freq > (1 << tmp))
  261 + tmp++;
  262 +
  263 + if (freq != (1 << tmp))
  264 + return -EINVAL;
  265 +
  266 + spin_lock_irqsave(&rtc->irq_task_lock, flags);
  267 + if (rtc->irq_task != task)
  268 + err = -ENXIO;
  269 + spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
  270 +
  271 + if (err == 0) {
  272 + err = rtc->ops->irq_set_freq(class_dev->dev, freq);
  273 + if (err == 0)
  274 + rtc->irq_freq = freq;
  275 + }
  276 + return err;
  277 +}
... ... @@ -91,6 +91,12 @@
91 91 #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */
92 92 #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */
93 93  
  94 +/* interrupt flags */
  95 +#define RTC_IRQF 0x80 /* any of the following is active */
  96 +#define RTC_PF 0x40
  97 +#define RTC_AF 0x20
  98 +#define RTC_UF 0x10
  99 +
94 100 #ifdef __KERNEL__
95 101  
96 102 #include <linux/interrupt.h>
... ... @@ -99,6 +105,87 @@
99 105 extern int rtc_valid_tm(struct rtc_time *tm);
100 106 extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
101 107 extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
  108 +
  109 +#include <linux/device.h>
  110 +#include <linux/seq_file.h>
  111 +#include <linux/cdev.h>
  112 +#include <linux/poll.h>
  113 +#include <linux/mutex.h>
  114 +
  115 +extern struct class *rtc_class;
  116 +
  117 +struct rtc_class_ops {
  118 + int (*open)(struct device *);
  119 + void (*release)(struct device *);
  120 + int (*ioctl)(struct device *, unsigned int, unsigned long);
  121 + int (*read_time)(struct device *, struct rtc_time *);
  122 + int (*set_time)(struct device *, struct rtc_time *);
  123 + int (*read_alarm)(struct device *, struct rtc_wkalrm *);
  124 + int (*set_alarm)(struct device *, struct rtc_wkalrm *);
  125 + int (*proc)(struct device *, struct seq_file *);
  126 + int (*set_mmss)(struct device *, unsigned long secs);
  127 + int (*irq_set_state)(struct device *, int enabled);
  128 + int (*irq_set_freq)(struct device *, int freq);
  129 + int (*read_callback)(struct device *, int data);
  130 +};
  131 +
  132 +#define RTC_DEVICE_NAME_SIZE 20
  133 +struct rtc_task;
  134 +
  135 +struct rtc_device
  136 +{
  137 + struct class_device class_dev;
  138 + struct module *owner;
  139 +
  140 + int id;
  141 + char name[RTC_DEVICE_NAME_SIZE];
  142 +
  143 + struct rtc_class_ops *ops;
  144 + struct mutex ops_lock;
  145 +
  146 + struct class_device *rtc_dev;
  147 + struct cdev char_dev;
  148 + struct mutex char_lock;
  149 +
  150 + unsigned long irq_data;
  151 + spinlock_t irq_lock;
  152 + wait_queue_head_t irq_queue;
  153 + struct fasync_struct *async_queue;
  154 +
  155 + struct rtc_task *irq_task;
  156 + spinlock_t irq_task_lock;
  157 + int irq_freq;
  158 +};
  159 +#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
  160 +
  161 +extern struct rtc_device *rtc_device_register(const char *name,
  162 + struct device *dev,
  163 + struct rtc_class_ops *ops,
  164 + struct module *owner);
  165 +extern void rtc_device_unregister(struct rtc_device *rdev);
  166 +extern int rtc_interface_register(struct class_interface *intf);
  167 +
  168 +extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
  169 +extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
  170 +extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs);
  171 +extern int rtc_read_alarm(struct class_device *class_dev,
  172 + struct rtc_wkalrm *alrm);
  173 +extern int rtc_set_alarm(struct class_device *class_dev,
  174 + struct rtc_wkalrm *alrm);
  175 +extern void rtc_update_irq(struct class_device *class_dev,
  176 + unsigned long num, unsigned long events);
  177 +
  178 +extern struct class_device *rtc_class_open(char *name);
  179 +extern void rtc_class_close(struct class_device *class_dev);
  180 +
  181 +extern int rtc_irq_register(struct class_device *class_dev,
  182 + struct rtc_task *task);
  183 +extern void rtc_irq_unregister(struct class_device *class_dev,
  184 + struct rtc_task *task);
  185 +extern int rtc_irq_set_state(struct class_device *class_dev,
  186 + struct rtc_task *task, int enabled);
  187 +extern int rtc_irq_set_freq(struct class_device *class_dev,
  188 + struct rtc_task *task, int freq);
102 189  
103 190 typedef struct rtc_task {
104 191 void (*func)(void *private_data);