patch-2.0.34 linux/drivers/char/rtc.c
Next file: linux/drivers/char/scc.c
Previous file: linux/drivers/char/riscom8.h
Back to the patch index
Back to the overall index
- Lines: 330
- Date:
Wed Jun 3 15:17:47 1998
- Orig file:
v2.0.33/linux/drivers/char/rtc.c
- Orig date:
Mon May 27 21:39:18 1996
diff -u --recursive --new-file v2.0.33/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
@@ -28,9 +28,14 @@
* Based on other minimal char device drivers, like Alan's
* watchdog, Ted's random, etc. etc.
*
+ * 1.07 Paul Gortmaker.
+ * 1.08 Miquel van Smoorenburg: disallow certain things on the
+ * DEC Alpha as the CMOS clock is also used for other things.
+ * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup.
+ *
*/
-#define RTC_VERSION "1.07"
+#define RTC_VERSION "1.09"
#define RTC_IRQ 8 /* Can't see this changing soon. */
#define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */
@@ -98,6 +103,13 @@
unsigned long rtc_freq = 0; /* Current periodic IRQ rate */
unsigned long rtc_irq_data = 0; /* our output to the world */
+/*
+ * If this driver ever becomes modularised, it will be really nice
+ * to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900; /* year corresponding to 0x00 */
+
unsigned char days_in_mo[] =
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
@@ -106,8 +118,12 @@
* so that there is no possibility of conflicting with the
* set_rtc_mmss() call that happens during some timer interrupts.
* (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
+ *
+ * On Alpha we won't get any interrupts anyway, as they all end up
+ * in the system timer code.
*/
+#ifndef __alpha__
static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/*
@@ -128,9 +144,11 @@
add_timer(&rtc_irq_timer);
}
}
+#endif
/*
* Now all the various file operations that we export.
+ * They are all useless on Alpha... *sigh*.
*/
static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
@@ -141,6 +159,9 @@
static int rtc_read(struct inode *inode, struct file *file, char *buf, int count)
{
+#ifdef __alpha__
+ return -EIO;
+#else
struct wait_queue wait = { current, NULL };
int retval;
@@ -182,6 +203,7 @@
remove_wait_queue(&rtc_wait, &wait);
return retval;
+#endif
}
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -191,6 +213,7 @@
unsigned long flags;
switch (cmd) {
+#ifndef __alpha__
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
{
mask_rtc_irq_bit(RTC_AIE);
@@ -238,6 +261,7 @@
set_rtc_irq_bit(RTC_UIE);
return 0;
}
+#endif
case RTC_ALM_READ: /* Read the present alarm time */
{
/*
@@ -342,7 +366,7 @@
min = rtc_tm.tm_min;
sec = rtc_tm.tm_sec;
- if ((yrs < 1970) || (yrs > 2069))
+ if (yrs < 1970)
return -EINVAL;
leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
@@ -356,16 +380,19 @@
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
return -EINVAL;
- if (yrs >= 2000)
- yrs -= 2000; /* RTC (0, 1, ... 69) */
- else
- yrs -= 1900; /* RTC (70, 71, ... 99) */
+ if ((yrs -= epoch) > 255) /* They are unsigned */
+ return -EINVAL;
save_flags(flags);
cli();
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
- RTC_ALWAYS_BCD)
- {
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ if (yrs > 169) {
+ restore_flags(flags);
+ return -EINVAL;
+ }
+ if (yrs >= 100)
+ yrs -= 100;
+
BIN_TO_BCD(sec);
BIN_TO_BCD(min);
BIN_TO_BCD(hrs);
@@ -403,6 +430,7 @@
memcpy_tofs((unsigned long*)arg, &rtc_freq, sizeof(unsigned long));
return 0;
}
+#ifndef __alpha__
case RTC_IRQP_SET: /* Set periodic IRQ rate. */
{
int tmp = 0;
@@ -439,6 +467,34 @@
restore_flags(flags);
return 0;
}
+#endif
+#ifdef __alpha__
+ case RTC_EPOCH_READ: /* Read the epoch. */
+ {
+ int retval;
+
+ retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
+ if (retval != 0)
+ return retval;
+
+ memcpy_tofs((unsigned long*)arg, &epoch, sizeof(unsigned long));
+ return 0;
+ }
+ case RTC_EPOCH_SET: /* Set the epoch. */
+ {
+ /*
+ * There were no RTC clocks before 1900.
+ */
+ if (arg < 1900)
+ return -EINVAL;
+
+ if (!suser())
+ return -EACCES;
+
+ epoch = arg;
+ return 0;
+ }
+#endif
default:
return -EINVAL;
}
@@ -448,16 +504,18 @@
* We enforce only one user at a time here with the open/close.
* Also clear the previous interrupt data on an open, and clean
* up things on a close.
+ * On Alpha we just open, for we don't mess with interrups anyway.
*/
static int rtc_open(struct inode *inode, struct file *file)
{
-
+#ifndef __alpha__
if(rtc_status & RTC_IS_OPEN)
return -EBUSY;
rtc_status |= RTC_IS_OPEN;
rtc_irq_data = 0;
+#endif
return 0;
}
@@ -469,6 +527,7 @@
* in use, and clear the data.
*/
+#ifndef __alpha__
unsigned char tmp;
unsigned long flags;
@@ -489,8 +548,10 @@
rtc_irq_data = 0;
rtc_status &= ~RTC_IS_OPEN;
+#endif
}
+#ifndef __alpha__
static int rtc_select(struct inode *inode, struct file *file,
int sel_type, select_table *wait)
{
@@ -501,6 +562,7 @@
}
return 0;
}
+#endif
/*
* The various file operations we support.
@@ -511,7 +573,11 @@
rtc_read,
NULL, /* No write */
NULL, /* No readdir */
+#ifdef __alpha__
+ NULL, /* No select on Alpha */
+#else
rtc_select,
+#endif
rtc_ioctl,
NULL, /* No mmap */
rtc_open,
@@ -528,17 +594,54 @@
int rtc_init(void)
{
unsigned long flags;
+#ifdef __alpha__
+ unsigned int year, ctrl;
+ unsigned long uip_watchdog;
+ char *guess = NULL;
+#endif
printk("Real Time Clock Driver v%s\n", RTC_VERSION);
+#ifndef __alpha__
if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
{
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
printk("rtc: IRQ %d is not free.\n", RTC_IRQ);
return -EIO;
}
+#endif
misc_register(&rtc_dev);
/* Check region? Naaah! Just snarf it up. */
request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+#ifdef __alpha__
+ rtc_freq = HZ;
+
+ /* Each operating system on an Alpha uses its own epoch.
+ Let's try to guess which one we are using now. */
+
+ uip_watchdog = jiffies;
+ if (rtc_is_updating() != 0)
+ while (jiffies - uip_watchdog < 2*HZ/100)
+ barrier();
+
+ save_flags(flags);
+ cli();
+ year = CMOS_READ(RTC_YEAR);
+ ctrl = CMOS_READ(RTC_CONTROL);
+ restore_flags(flags);
+
+ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(year); /* This should never happen... */
+
+ if (year > 10 && year < 44) {
+ epoch = 1980;
+ guess = "ARC console";
+ } else if (year < 96) {
+ epoch = 1952;
+ guess = "Digital UNIX";
+ }
+ if (guess)
+ printk("rtc: %s epoch (%ld) detected\n", guess, epoch);
+#else
init_timer(&rtc_irq_timer);
rtc_irq_timer.function = rtc_dropped_irq;
rtc_wait = NULL;
@@ -548,6 +651,7 @@
CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
restore_flags(flags);
rtc_freq = 1024;
+#endif
return 0;
}
@@ -563,6 +667,7 @@
* for something that requires a steady > 1KHz signal anyways.)
*/
+#ifndef __alpha__
void rtc_dropped_irq(unsigned long data)
{
unsigned long flags;
@@ -579,6 +684,7 @@
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
restore_flags(flags);
}
+#endif
/*
* Info exported via "/proc/rtc".
@@ -723,7 +829,7 @@
* Account for differences between how the RTC uses the values
* and how they are defined in a struct rtc_time;
*/
- if (rtc_tm->tm_year <= 69)
+ if ((rtc_tm->tm_year += epoch - 1900) <= 69)
rtc_tm->tm_year += 100;
rtc_tm->tm_mon--;
@@ -763,6 +869,8 @@
* We also clear out any old irq data after an ioctl() that
* meddles with the interrupt enable/disable bits.
*/
+
+#ifndef __alpha__
void mask_rtc_irq_bit(unsigned char bit)
{
unsigned char val;
@@ -792,4 +900,4 @@
rtc_irq_data = 0;
restore_flags(flags);
}
-
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov