This is the current version of the genrtc driver from the m68k
community. This is slightly different than the version I have sent
previously in that it has been switched to C99-style initializers,
which was done in the current m68k CVS tree by Geert Uytterhoeven, and
the needed changes to select/compile it in general. I had previously
asked the m68k community if anyone objected to this being submitted by me,
and I got Richard Zidlicky's (who's at the top of the file) approval, as
well as Geert Uytterhoeven's approval.
--
Tom Rini (TR1265)
http://gate.crashing.org/~trini/
===== drivers/char/Config.help 1.7 vs edited =====
--- 1.7/drivers/char/Config.help Mon Jul 8 06:36:29 2002
+++ edited/drivers/char/Config.help Wed Jul 24 09:06:46 2002
@@ -969,6 +969,31 @@
The module is called rtc.o. If you want to compile it as a module,
say M here and read <file:Documentation/modules.txt>.
+Generic Real Time Clock Support
+CONFIG_GEN_RTC
+ If you say Y here and create a character special file /dev/rtc with
+ major number 10 and minor number 135 using mknod ("man mknod"), you
+ will get access to the real time clock (or hardware clock) built
+ into your computer.
+
+ It reports status information via the file /proc/driver/rtc and its
+ behaviour is set by various ioctls on /dev/rtc. If you enable the
+ "extended RTC operation" below it will also provide an emulation
+ for RTC_UIE which is required by some programs and may improve
+ precision in some cases.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called genrtc.o. If you want to compile it as a module,
+ say M here and read <file:Documentation/modules.txt>. To load the
+ module automaticaly add 'alias char-major-10-135 genrtc' to your
+ /etc/modules.conf
+
+Extended RTC operation
+CONFIG_GEN_RTC_X
+ Provides an emulation for RTC_UIE which is required by some programs
+ and may improve precision of the generic RTC support in some cases.
+
CONFIG_H8
The Hitachi H8/337 is a microcontroller used to deal with the power
and thermal environment. If you say Y here, you will be able to
===== drivers/char/Config.in 1.30 vs edited =====
--- 1.30/drivers/char/Config.in Sun Jul 21 16:03:09 2002
+++ edited/drivers/char/Config.in Wed Jul 24 09:06:46 2002
@@ -151,6 +151,12 @@
fi
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
+if [ "$CONFIG_RTC" != "y" ]; then
+ tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+ if [ "$CONFIG_GEN_RTC" != "n" ]; then
+ bool ' Extended RTC operation' CONFIG_GEN_RTC_X
+ fi
+fi
if [ "$CONFIG_IA64" = "y" ]; then
bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
fi
===== drivers/char/Makefile 1.28 vs edited =====
--- 1.28/drivers/char/Makefile Tue Jul 23 20:26:06 2002
+++ edited/drivers/char/Makefile Wed Jul 24 09:06:47 2002
@@ -156,6 +156,7 @@
obj-$(CONFIG_SONYPI) += sonypi.o
obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_GEN_RTC) += genrtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
obj-$(CONFIG_NVRAM) += nvram.o
===== include/linux/rtc.h 1.3 vs edited =====
--- 1.3/include/linux/rtc.h Sun Feb 24 12:02:47 2002
+++ edited/include/linux/rtc.h Wed Jul 24 09:06:47 2002
@@ -39,10 +39,32 @@
struct rtc_time time; /* time the alarm is set to */
};
+/*
+ * Data structure to control PLL correction some better RTC feature
+ * pll_value is used to get or set current value of correction,
+ * the rest of the struct is used to query HW capabilities.
+ * This is modeled after the RTC used in Q40/Q60 computers but
+ * should be sufficiently flexible for other devices
+ *
+ * +ve pll_value means clock will run faster by
+ * pll_value*pll_posmult/pll_clock
+ * -ve pll_value means clock will run slower by
+ * pll_value*pll_negmult/pll_clock
+ */
+
+struct rtc_pll_info {
+ int pll_ctrl; /* placeholder for fancier control */
+ int pll_value; /* get/set correction value */
+ int pll_max; /* max +ve (faster) adjustment value */
+ int pll_min; /* max -ve (slower) adjustment value */
+ int pll_posmult; /* factor for +ve corection */
+ int pll_negmult; /* factor for -ve corection */
+ long pll_clock; /* base PLL frequency */
+};
/*
* ioctl calls that are permitted to the /dev/rtc interface, if
- * CONFIG_RTC/CONFIG_EFI_RTC was enabled.
+ * any of the RTC drivers are enabled.
*/
#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
@@ -65,6 +87,8 @@
#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
+#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */
+#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */
#ifdef __KERNEL__
--- /dev/null 1969-12-31 17:00:00.000000000 -0700
+++ linux-2.5/drivers/char/genrtc.c 2002-07-24 12:23:40.000000000 -0700
@@ -0,0 +1,518 @@
+/*
+ * Real Time Clock interface for q40 and other m68k machines
+ * emulate some RTC irq capabilities in software
+ *
+ * Copyright (C) 1999 Richard Zidlicky
+ *
+ * based on Paul Gortmaker's rtc.c device and
+ * Sam Creasey Generic rtc driver
+ *
+ * This driver allows use of the real time clock (built into
+ * nearly all computers) from user space. It exports the /dev/rtc
+ * interface supporting various ioctl() and also the /proc/dev/rtc
+ * pseudo-file for status information.
+ *
+ * The ioctls can be used to set the interrupt behaviour where
+ * supported.
+ *
+ * The /dev/rtc interface will block on reads until an interrupt
+ * has been received. If a RTC interrupt has already happened,
+ * it will output an unsigned long and then block. The output value
+ * contains the interrupt status in the low byte and the number of
+ * interrupts since the last read in the remaining high bytes. The
+ * /dev/rtc interface can also be used with the select(2) call.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+
+ * 1.01 fix for 2.3.X r...@linux-m68k.org
+ * 1.02 merged with code from genrtc.c r...@linux-m68k.org
+ * 1.03 make it more portable zip...@linux-m68k.org
+ * 1.04 removed useless timer code r...@linux-m68k.org
+ * 1.05 portable RTC_UIE emulation r...@linux-m68k.org
+ */
+
+#define RTC_VERSION "1.05"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/rtc.h>
+
+/*
+ * We sponge a minor off of the misc major. No need slurping
+ * up another valuable major dev number for this. If you add
+ * an ioctl, make sure you don't conflict with SPARC's RTC
+ * ioctls.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
+
+static int gen_rtc_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+/*
+ * Bits in gen_rtc_status.
+ */
+
+#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
+
+unsigned char gen_rtc_status; /* bitmapped status byte. */
+unsigned long gen_rtc_irq_data; /* our output to the world */
+
+/* months start at 0 now */
+unsigned char days_in_mo[] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int irq_active;
+
+#ifdef CONFIG_GEN_RTC_X
+struct tq_struct genrtc_task;
+static struct timer_list timer_task;
+
+static unsigned int oldsecs;
+static int lostint;
+static int tt_exp;
+
+void gen_rtc_timer(unsigned long data);
+
+static volatile int stask_active; /* schedule_task */
+static volatile int ttask_active; /* timer_task */
+static int stop_rtc_timers; /* don't requeue tasks */
+static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Routine to poll RTC seconds field for change as often as posible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+void genrtc_troutine(void *data)
+{
+ unsigned int tmp = get_rtc_ss();
+
+ if (stop_rtc_timers) {
+ stask_active = 0;
+ return;
+ }
+
+ if (oldsecs != tmp){
+ oldsecs = tmp;
+
+ timer_task.function = gen_rtc_timer;
+ timer_task.expires = jiffies + HZ - (HZ/10);
+ tt_exp=timer_task.expires;
+ ttask_active=1;
+ stask_active=0;
+ add_timer(&timer_task);
+
+ gen_rtc_interrupt(0);
+ } else if (schedule_task(&genrtc_task) == 0)
+ stask_active = 0;
+}
+
+void gen_rtc_timer(unsigned long data)
+{
+ lostint = get_rtc_ss() - oldsecs ;
+ if (lostint<0)
+ lostint = 60 - lostint;
+ if (jiffies-tt_exp>1)
+ printk("genrtc: timer task delayed by %ld jiffies\n",
+ jiffies-tt_exp);
+ ttask_active=0;
+ stask_active=1;
+ if ((schedule_task(&genrtc_task) == 0))
+ stask_active = 0;
+}
+
+/*
+ * call gen_rtc_interrupt function to signal an RTC_UIE,
+ * arg is unused.
+ * Could be invoked either from a real interrupt handler or
+ * from some routine that periodically (eg 100HZ) monitors
+ * whether RTC_SECS changed
+ */
+void gen_rtc_interrupt(unsigned long arg)
+{
+ /* We store the status in the low byte and the number of
+ * interrupts received since the last read in the remainder
+ * of rtc_irq_data. */
+
+ gen_rtc_irq_data += 0x100;
+ gen_rtc_irq_data &= ~0xff;
+ gen_rtc_irq_data |= RTC_UIE;
+
+ if (lostint){
+ printk("genrtc: system delaying clock ticks?\n");
+ /* increment count so that userspace knows something is wrong */
+ gen_rtc_irq_data += ((lostint-1)<<8);
+ lostint = 0;
+ }
+
+ wake_up_interruptible(&gen_rtc_wait);
+}
+
+/*
+ * Now all the
...
read more »