--- linux/drivers/char/Makefile-dist	Mon Sep  4 11:06:43 2000
+++ linux/drivers/char/Makefile	Mon Sep  4 11:07:46 2000
@@ -356,7 +356,7 @@
 endif
 
 ifeq ($(CONFIG_RTC),y)
-L_OBJS += rtc.o
+LX_OBJS += rtc.o
 endif
 
 ifeq ($(CONFIG_NVRAM),y)
--- linux/drivers/char/rtc.c-dist	Mon Sep  4 11:06:46 2000
+++ linux/drivers/char/rtc.c	Mon Sep  4 13:25:32 2000
@@ -57,6 +57,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -103,6 +104,8 @@
 unsigned long rtc_freq = 0;		/* Current periodic IRQ rate	*/
 unsigned long rtc_irq_data = 0;		/* our output to the world	*/
 
+static rtc_task_t *rtc_callback = NULL;
+
 /*
  *	If this driver ever becomes modularised, it will be really nice
  *	to make the epoch retain its value across module reload...
@@ -132,6 +135,8 @@
 	rtc_irq_data += 0x100;
 	rtc_irq_data &= ~0xff;
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+	if (rtc_callback)
+		rtc_callback->func(rtc_callback->private_data);
 	wake_up_interruptible(&rtc_wait);	
 
 	if (rtc_status & RTC_TIMER_ON)
@@ -183,8 +188,7 @@
 	return retval;
 }
 
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg)
+static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 {
 
 	unsigned long flags;
@@ -217,7 +221,7 @@
 		 * We don't really want Joe User enabling more
 		 * than 64Hz of interrupts on a multi-user machine.
 		 */
-		if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE)))
+		if (!kernel && (rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE)))
 			return -EACCES;
 
 		if (!(rtc_status & RTC_TIMER_ON)) {
@@ -391,7 +395,7 @@
 		 * We don't really want Joe User generating more
 		 * than 64Hz of interrupts on a multi-user machine.
 		 */
-		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
+		if (!kernel && (arg > 64) && (!capable(CAP_SYS_RESOURCE)))
 			return -EACCES;
 
 		while (arg > (1<<tmp))
@@ -439,6 +443,12 @@
 	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
 }
 
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	return rtc_do_ioctl(cmd, arg, 0);
+}
+
 /*
  *	We enforce only one user at a time here with the open/close.
  *	Also clear the previous interrupt data on an open, and clean
@@ -492,6 +502,82 @@
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
+
+/*
+ * exported stuffs
+ */
+
+EXPORT_SYMBOL(rtc_register);
+EXPORT_SYMBOL(rtc_unregister);
+EXPORT_SYMBOL(rtc_control);
+
+int rtc_register(rtc_task_t *task)
+{
+	unsigned long flags;
+
+	if (task == NULL || task->func == NULL)
+		return -EINVAL;
+	/*spin_lock_irqsave(&rtc_lock, flags);*/
+	save_flags(flags); cli();
+	if ((rtc_status & RTC_IS_OPEN) || rtc_callback) {
+		/*spin_unlock_irqrestore(&rtc_lock, flags);*/
+		restore_flags(flags);
+		return -EBUSY;
+	}
+	rtc_status |= RTC_IS_OPEN;
+	rtc_callback = task;
+	/*spin_unlock_irqrestore(&rtc_lock, flags);*/
+	restore_flags(flags);
+	
+	return 0;
+}
+
+int rtc_unregister(rtc_task_t *task)
+{
+	unsigned long flags;
+	unsigned char tmp;
+
+	/*spin_lock_irqsave(&rtc_lock, flags);*/
+	save_flags(flags); cli();
+	if (! (rtc_status & RTC_IS_OPEN) || rtc_callback != task) {
+		/*spin_unlock_irqrestore(&rtc_lock, flags);*/
+		restore_flags(flags);
+		return -ENXIO;
+	}
+	/* disable controls */
+	tmp = CMOS_READ(RTC_CONTROL);
+	tmp &= ~RTC_PIE;
+	tmp &= ~RTC_AIE;
+	tmp &= ~RTC_UIE;
+	CMOS_WRITE(tmp, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+	if (rtc_status & RTC_TIMER_ON) {
+		rtc_status &= ~RTC_TIMER_ON;
+		del_timer(&rtc_irq_timer);
+	}
+	rtc_callback = NULL;
+	rtc_status &= ~RTC_IS_OPEN;
+	/*spin_unlock_irqrestore(&rtc_lock, flags);*/
+	restore_flags(flags);
+	return 0;
+}
+
+int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
+{
+	unsigned long flags;
+
+	/*spin_lock_irqsave(&rtc_lock, flags);*/
+	save_flags(flags); cli();
+	if (! (rtc_status & RTC_IS_OPEN) || rtc_callback != task) {
+		/*spin_unlock_irqrestore(&rtc_lock, flags);*/
+		restore_flags(flags);
+		return -ENXIO;
+	}
+	/*spin_unlock_irqrestore(&rtc_lock, flags);*/
+	restore_flags(flags);
+	return rtc_do_ioctl(cmd, arg, 1);
+}
+
 
 /*
  *	The various file operations we support.
--- linux/include/linux/mc146818rtc.h-dist	Mon Sep  4 11:06:35 2000
+++ linux/include/linux/mc146818rtc.h	Mon Sep  4 11:07:46 2000
@@ -145,5 +145,17 @@
 #define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
 #define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
 
+/* Exported functions to other kernel drivers */
+
+#ifdef __KERNEL__
+typedef struct rtc_task {
+	void (*func)(void *private_data);
+	void *private_data;
+} rtc_task_t;
+
+int rtc_register(rtc_task_t *task);
+int rtc_unregister(rtc_task_t *task);
+int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
+#endif
 
 #endif /* _MC146818RTC_H */
