|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Real Time Clock interface for Linux
|
|
|
|
|
|
+ * Real Time Clock interface for Linux
|
|
*
|
|
*
|
|
* Copyright (C) 1996 Paul Gortmaker
|
|
* Copyright (C) 1996 Paul Gortmaker
|
|
*
|
|
*
|
|
@@ -17,7 +17,7 @@
|
|
* has been received. If a RTC interrupt has already happened,
|
|
* has been received. If a RTC interrupt has already happened,
|
|
* it will output an unsigned long and then block. The output value
|
|
* it will output an unsigned long and then block. The output value
|
|
* contains the interrupt status in the low byte and the number of
|
|
* contains the interrupt status in the low byte and the number of
|
|
- * interrupts since the last read in the remaining high bytes. The
|
|
|
|
|
|
+ * interrupts since the last read in the remaining high bytes. The
|
|
* /dev/rtc interface can also be used with the select(2) call.
|
|
* /dev/rtc interface can also be used with the select(2) call.
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -104,12 +104,12 @@ static int rtc_has_irq = 1;
|
|
|
|
|
|
#ifndef CONFIG_HPET_EMULATE_RTC
|
|
#ifndef CONFIG_HPET_EMULATE_RTC
|
|
#define is_hpet_enabled() 0
|
|
#define is_hpet_enabled() 0
|
|
-#define hpet_set_alarm_time(hrs, min, sec) 0
|
|
|
|
-#define hpet_set_periodic_freq(arg) 0
|
|
|
|
-#define hpet_mask_rtc_irq_bit(arg) 0
|
|
|
|
-#define hpet_set_rtc_irq_bit(arg) 0
|
|
|
|
-#define hpet_rtc_timer_init() do { } while (0)
|
|
|
|
-#define hpet_rtc_dropped_irq() 0
|
|
|
|
|
|
+#define hpet_set_alarm_time(hrs, min, sec) 0
|
|
|
|
+#define hpet_set_periodic_freq(arg) 0
|
|
|
|
+#define hpet_mask_rtc_irq_bit(arg) 0
|
|
|
|
+#define hpet_set_rtc_irq_bit(arg) 0
|
|
|
|
+#define hpet_rtc_timer_init() do { } while (0)
|
|
|
|
+#define hpet_rtc_dropped_irq() 0
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
|
|
static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
|
|
{
|
|
{
|
|
@@ -147,7 +147,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file,
|
|
static unsigned int rtc_poll(struct file *file, poll_table *wait);
|
|
static unsigned int rtc_poll(struct file *file, poll_table *wait);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-static void get_rtc_alm_time (struct rtc_time *alm_tm);
|
|
|
|
|
|
+static void get_rtc_alm_time(struct rtc_time *alm_tm);
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
static void set_rtc_irq_bit_locked(unsigned char bit);
|
|
static void set_rtc_irq_bit_locked(unsigned char bit);
|
|
static void mask_rtc_irq_bit_locked(unsigned char bit);
|
|
static void mask_rtc_irq_bit_locked(unsigned char bit);
|
|
@@ -185,9 +185,9 @@ static int rtc_proc_open(struct inode *inode, struct file *file);
|
|
* rtc_status but before mod_timer is called, which would then reenable the
|
|
* rtc_status but before mod_timer is called, which would then reenable the
|
|
* timer (but you would need to have an awful timing before you'd trip on it)
|
|
* timer (but you would need to have an awful timing before you'd trip on it)
|
|
*/
|
|
*/
|
|
-static unsigned long rtc_status = 0; /* bitmapped status byte. */
|
|
|
|
-static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */
|
|
|
|
-static unsigned long rtc_irq_data = 0; /* our output to the world */
|
|
|
|
|
|
+static unsigned long rtc_status; /* bitmapped status byte. */
|
|
|
|
+static unsigned long rtc_freq; /* Current periodic IRQ rate */
|
|
|
|
+static unsigned long rtc_irq_data; /* our output to the world */
|
|
static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
|
|
static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
|
|
|
|
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
@@ -195,7 +195,7 @@ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
|
|
* rtc_task_lock nests inside rtc_lock.
|
|
* rtc_task_lock nests inside rtc_lock.
|
|
*/
|
|
*/
|
|
static DEFINE_SPINLOCK(rtc_task_lock);
|
|
static DEFINE_SPINLOCK(rtc_task_lock);
|
|
-static rtc_task_t *rtc_callback = NULL;
|
|
|
|
|
|
+static rtc_task_t *rtc_callback;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -205,7 +205,7 @@ static rtc_task_t *rtc_callback = NULL;
|
|
|
|
|
|
static unsigned long epoch = 1900; /* year corresponding to 0x00 */
|
|
static unsigned long epoch = 1900; /* year corresponding to 0x00 */
|
|
|
|
|
|
-static const unsigned char days_in_mo[] =
|
|
|
|
|
|
+static const unsigned char days_in_mo[] =
|
|
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -242,7 +242,7 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id)
|
|
* the last read in the remainder of rtc_irq_data.
|
|
* the last read in the remainder of rtc_irq_data.
|
|
*/
|
|
*/
|
|
|
|
|
|
- spin_lock (&rtc_lock);
|
|
|
|
|
|
+ spin_lock(&rtc_lock);
|
|
rtc_irq_data += 0x100;
|
|
rtc_irq_data += 0x100;
|
|
rtc_irq_data &= ~0xff;
|
|
rtc_irq_data &= ~0xff;
|
|
if (is_hpet_enabled()) {
|
|
if (is_hpet_enabled()) {
|
|
@@ -259,16 +259,16 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id)
|
|
if (rtc_status & RTC_TIMER_ON)
|
|
if (rtc_status & RTC_TIMER_ON)
|
|
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
|
|
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
|
|
|
|
|
|
- spin_unlock (&rtc_lock);
|
|
|
|
|
|
+ spin_unlock(&rtc_lock);
|
|
|
|
|
|
/* Now do the rest of the actions */
|
|
/* Now do the rest of the actions */
|
|
spin_lock(&rtc_task_lock);
|
|
spin_lock(&rtc_task_lock);
|
|
if (rtc_callback)
|
|
if (rtc_callback)
|
|
rtc_callback->func(rtc_callback->private_data);
|
|
rtc_callback->func(rtc_callback->private_data);
|
|
spin_unlock(&rtc_task_lock);
|
|
spin_unlock(&rtc_task_lock);
|
|
- wake_up_interruptible(&rtc_wait);
|
|
|
|
|
|
+ wake_up_interruptible(&rtc_wait);
|
|
|
|
|
|
- kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
|
|
|
|
|
|
+ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
@@ -335,7 +335,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
unsigned long data;
|
|
unsigned long data;
|
|
ssize_t retval;
|
|
ssize_t retval;
|
|
-
|
|
|
|
|
|
+
|
|
if (rtc_has_irq == 0)
|
|
if (rtc_has_irq == 0)
|
|
return -EIO;
|
|
return -EIO;
|
|
|
|
|
|
@@ -358,11 +358,11 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
|
|
* confusing. And no, xchg() is not the answer. */
|
|
* confusing. And no, xchg() is not the answer. */
|
|
|
|
|
|
__set_current_state(TASK_INTERRUPTIBLE);
|
|
__set_current_state(TASK_INTERRUPTIBLE);
|
|
-
|
|
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
|
|
+
|
|
|
|
+ spin_lock_irq(&rtc_lock);
|
|
data = rtc_irq_data;
|
|
data = rtc_irq_data;
|
|
rtc_irq_data = 0;
|
|
rtc_irq_data = 0;
|
|
- spin_unlock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
if (data != 0)
|
|
if (data != 0)
|
|
break;
|
|
break;
|
|
@@ -378,10 +378,13 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
|
|
schedule();
|
|
schedule();
|
|
} while (1);
|
|
} while (1);
|
|
|
|
|
|
- if (count == sizeof(unsigned int))
|
|
|
|
- retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
|
|
|
|
- else
|
|
|
|
- retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
|
|
|
|
|
|
+ if (count == sizeof(unsigned int)) {
|
|
|
|
+ retval = put_user(data,
|
|
|
|
+ (unsigned int __user *)buf) ?: sizeof(int);
|
|
|
|
+ } else {
|
|
|
|
+ retval = put_user(data,
|
|
|
|
+ (unsigned long __user *)buf) ?: sizeof(long);
|
|
|
|
+ }
|
|
if (!retval)
|
|
if (!retval)
|
|
retval = count;
|
|
retval = count;
|
|
out:
|
|
out:
|
|
@@ -394,7 +397,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
|
|
|
|
|
|
static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
{
|
|
{
|
|
- struct rtc_time wtime;
|
|
|
|
|
|
+ struct rtc_time wtime;
|
|
|
|
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
if (rtc_has_irq == 0) {
|
|
if (rtc_has_irq == 0) {
|
|
@@ -426,35 +429,41 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
}
|
|
}
|
|
case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
|
|
case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
|
|
{
|
|
{
|
|
- unsigned long flags; /* can be called from isr via rtc_control() */
|
|
|
|
- spin_lock_irqsave (&rtc_lock, flags);
|
|
|
|
|
|
+ /* can be called from isr via rtc_control() */
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&rtc_lock, flags);
|
|
mask_rtc_irq_bit_locked(RTC_PIE);
|
|
mask_rtc_irq_bit_locked(RTC_PIE);
|
|
if (rtc_status & RTC_TIMER_ON) {
|
|
if (rtc_status & RTC_TIMER_ON) {
|
|
rtc_status &= ~RTC_TIMER_ON;
|
|
rtc_status &= ~RTC_TIMER_ON;
|
|
del_timer(&rtc_irq_timer);
|
|
del_timer(&rtc_irq_timer);
|
|
}
|
|
}
|
|
- spin_unlock_irqrestore (&rtc_lock, flags);
|
|
|
|
|
|
+ spin_unlock_irqrestore(&rtc_lock, flags);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
case RTC_PIE_ON: /* Allow periodic ints */
|
|
case RTC_PIE_ON: /* Allow periodic ints */
|
|
{
|
|
{
|
|
- unsigned long flags; /* can be called from isr via rtc_control() */
|
|
|
|
|
|
+ /* can be called from isr via rtc_control() */
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* We don't really want Joe User enabling more
|
|
* We don't really want Joe User enabling more
|
|
* than 64Hz of interrupts on a multi-user machine.
|
|
* than 64Hz of interrupts on a multi-user machine.
|
|
*/
|
|
*/
|
|
if (!kernel && (rtc_freq > rtc_max_user_freq) &&
|
|
if (!kernel && (rtc_freq > rtc_max_user_freq) &&
|
|
- (!capable(CAP_SYS_RESOURCE)))
|
|
|
|
|
|
+ (!capable(CAP_SYS_RESOURCE)))
|
|
return -EACCES;
|
|
return -EACCES;
|
|
|
|
|
|
- spin_lock_irqsave (&rtc_lock, flags);
|
|
|
|
|
|
+ spin_lock_irqsave(&rtc_lock, flags);
|
|
if (!(rtc_status & RTC_TIMER_ON)) {
|
|
if (!(rtc_status & RTC_TIMER_ON)) {
|
|
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq +
|
|
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq +
|
|
2*HZ/100);
|
|
2*HZ/100);
|
|
rtc_status |= RTC_TIMER_ON;
|
|
rtc_status |= RTC_TIMER_ON;
|
|
}
|
|
}
|
|
set_rtc_irq_bit_locked(RTC_PIE);
|
|
set_rtc_irq_bit_locked(RTC_PIE);
|
|
- spin_unlock_irqrestore (&rtc_lock, flags);
|
|
|
|
|
|
+ spin_unlock_irqrestore(&rtc_lock, flags);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
case RTC_UIE_OFF: /* Mask ints from RTC updates. */
|
|
case RTC_UIE_OFF: /* Mask ints from RTC updates. */
|
|
@@ -477,7 +486,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
*/
|
|
*/
|
|
memset(&wtime, 0, sizeof(struct rtc_time));
|
|
memset(&wtime, 0, sizeof(struct rtc_time));
|
|
get_rtc_alm_time(&wtime);
|
|
get_rtc_alm_time(&wtime);
|
|
- break;
|
|
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
case RTC_ALM_SET: /* Store a time into the alarm */
|
|
case RTC_ALM_SET: /* Store a time into the alarm */
|
|
{
|
|
{
|
|
@@ -505,16 +514,21 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
*/
|
|
*/
|
|
}
|
|
}
|
|
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
|
|
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
|
|
- RTC_ALWAYS_BCD)
|
|
|
|
- {
|
|
|
|
- if (sec < 60) BIN_TO_BCD(sec);
|
|
|
|
- else sec = 0xff;
|
|
|
|
-
|
|
|
|
- if (min < 60) BIN_TO_BCD(min);
|
|
|
|
- else min = 0xff;
|
|
|
|
-
|
|
|
|
- if (hrs < 24) BIN_TO_BCD(hrs);
|
|
|
|
- else hrs = 0xff;
|
|
|
|
|
|
+ RTC_ALWAYS_BCD) {
|
|
|
|
+ if (sec < 60)
|
|
|
|
+ BIN_TO_BCD(sec);
|
|
|
|
+ else
|
|
|
|
+ sec = 0xff;
|
|
|
|
+
|
|
|
|
+ if (min < 60)
|
|
|
|
+ BIN_TO_BCD(min);
|
|
|
|
+ else
|
|
|
|
+ min = 0xff;
|
|
|
|
+
|
|
|
|
+ if (hrs < 24)
|
|
|
|
+ BIN_TO_BCD(hrs);
|
|
|
|
+ else
|
|
|
|
+ hrs = 0xff;
|
|
}
|
|
}
|
|
CMOS_WRITE(hrs, RTC_HOURS_ALARM);
|
|
CMOS_WRITE(hrs, RTC_HOURS_ALARM);
|
|
CMOS_WRITE(min, RTC_MINUTES_ALARM);
|
|
CMOS_WRITE(min, RTC_MINUTES_ALARM);
|
|
@@ -563,11 +577,12 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
|
|
|
|
if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
|
|
if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
-
|
|
|
|
|
|
+
|
|
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
|
|
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if ((yrs -= epoch) > 255) /* They are unsigned */
|
|
|
|
|
|
+ yrs -= epoch;
|
|
|
|
+ if (yrs > 255) /* They are unsigned */
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
spin_lock_irq(&rtc_lock);
|
|
spin_lock_irq(&rtc_lock);
|
|
@@ -635,9 +650,10 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
{
|
|
{
|
|
int tmp = 0;
|
|
int tmp = 0;
|
|
unsigned char val;
|
|
unsigned char val;
|
|
- unsigned long flags; /* can be called from isr via rtc_control() */
|
|
|
|
|
|
+ /* can be called from isr via rtc_control() */
|
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
- /*
|
|
|
|
|
|
+ /*
|
|
* The max we can do is 8192Hz.
|
|
* The max we can do is 8192Hz.
|
|
*/
|
|
*/
|
|
if ((arg < 2) || (arg > 8192))
|
|
if ((arg < 2) || (arg > 8192))
|
|
@@ -646,7 +662,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
* We don't really want Joe User generating more
|
|
* We don't really want Joe User generating more
|
|
* than 64Hz of interrupts on a multi-user machine.
|
|
* than 64Hz of interrupts on a multi-user machine.
|
|
*/
|
|
*/
|
|
- if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
|
|
|
|
|
|
+ if (!kernel && (arg > rtc_max_user_freq) &&
|
|
|
|
+ !capable(CAP_SYS_RESOURCE))
|
|
return -EACCES;
|
|
return -EACCES;
|
|
|
|
|
|
while (arg > (1<<tmp))
|
|
while (arg > (1<<tmp))
|
|
@@ -674,11 +691,11 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
#endif
|
|
#endif
|
|
case RTC_EPOCH_READ: /* Read the epoch. */
|
|
case RTC_EPOCH_READ: /* Read the epoch. */
|
|
{
|
|
{
|
|
- return put_user (epoch, (unsigned long __user *)arg);
|
|
|
|
|
|
+ return put_user(epoch, (unsigned long __user *)arg);
|
|
}
|
|
}
|
|
case RTC_EPOCH_SET: /* Set the epoch. */
|
|
case RTC_EPOCH_SET: /* Set the epoch. */
|
|
{
|
|
{
|
|
- /*
|
|
|
|
|
|
+ /*
|
|
* There were no RTC clocks before 1900.
|
|
* There were no RTC clocks before 1900.
|
|
*/
|
|
*/
|
|
if (arg < 1900)
|
|
if (arg < 1900)
|
|
@@ -693,7 +710,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
default:
|
|
default:
|
|
return -ENOTTY;
|
|
return -ENOTTY;
|
|
}
|
|
}
|
|
- return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
|
|
|
|
|
|
+ return copy_to_user((void __user *)arg,
|
|
|
|
+ &wtime, sizeof wtime) ? -EFAULT : 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|
@@ -712,26 +730,25 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|
* needed here. Or anywhere else in this driver. */
|
|
* needed here. Or anywhere else in this driver. */
|
|
static int rtc_open(struct inode *inode, struct file *file)
|
|
static int rtc_open(struct inode *inode, struct file *file)
|
|
{
|
|
{
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_lock_irq(&rtc_lock);
|
|
|
|
|
|
- if(rtc_status & RTC_IS_OPEN)
|
|
|
|
|
|
+ if (rtc_status & RTC_IS_OPEN)
|
|
goto out_busy;
|
|
goto out_busy;
|
|
|
|
|
|
rtc_status |= RTC_IS_OPEN;
|
|
rtc_status |= RTC_IS_OPEN;
|
|
|
|
|
|
rtc_irq_data = 0;
|
|
rtc_irq_data = 0;
|
|
- spin_unlock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irq(&rtc_lock);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
out_busy:
|
|
out_busy:
|
|
- spin_unlock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irq(&rtc_lock);
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
}
|
|
}
|
|
|
|
|
|
-static int rtc_fasync (int fd, struct file *filp, int on)
|
|
|
|
-
|
|
|
|
|
|
+static int rtc_fasync(int fd, struct file *filp, int on)
|
|
{
|
|
{
|
|
- return fasync_helper (fd, filp, on, &rtc_async_queue);
|
|
|
|
|
|
+ return fasync_helper(fd, filp, on, &rtc_async_queue);
|
|
}
|
|
}
|
|
|
|
|
|
static int rtc_release(struct inode *inode, struct file *file)
|
|
static int rtc_release(struct inode *inode, struct file *file)
|
|
@@ -762,16 +779,16 @@ static int rtc_release(struct inode *inode, struct file *file)
|
|
}
|
|
}
|
|
spin_unlock_irq(&rtc_lock);
|
|
spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
- if (file->f_flags & FASYNC) {
|
|
|
|
- rtc_fasync (-1, file, 0);
|
|
|
|
- }
|
|
|
|
|
|
+ if (file->f_flags & FASYNC)
|
|
|
|
+ rtc_fasync(-1, file, 0);
|
|
no_irq:
|
|
no_irq:
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_lock_irq(&rtc_lock);
|
|
rtc_irq_data = 0;
|
|
rtc_irq_data = 0;
|
|
rtc_status &= ~RTC_IS_OPEN;
|
|
rtc_status &= ~RTC_IS_OPEN;
|
|
- spin_unlock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irq(&rtc_lock);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -786,9 +803,9 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
|
|
|
|
|
|
poll_wait(file, &rtc_wait, wait);
|
|
poll_wait(file, &rtc_wait, wait);
|
|
|
|
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_lock_irq(&rtc_lock);
|
|
l = rtc_irq_data;
|
|
l = rtc_irq_data;
|
|
- spin_unlock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
if (l != 0)
|
|
if (l != 0)
|
|
return POLLIN | POLLRDNORM;
|
|
return POLLIN | POLLRDNORM;
|
|
@@ -796,14 +813,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-/*
|
|
|
|
- * exported stuffs
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-EXPORT_SYMBOL(rtc_register);
|
|
|
|
-EXPORT_SYMBOL(rtc_unregister);
|
|
|
|
-EXPORT_SYMBOL(rtc_control);
|
|
|
|
-
|
|
|
|
int rtc_register(rtc_task_t *task)
|
|
int rtc_register(rtc_task_t *task)
|
|
{
|
|
{
|
|
#ifndef RTC_IRQ
|
|
#ifndef RTC_IRQ
|
|
@@ -829,6 +838,7 @@ int rtc_register(rtc_task_t *task)
|
|
return 0;
|
|
return 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL(rtc_register);
|
|
|
|
|
|
int rtc_unregister(rtc_task_t *task)
|
|
int rtc_unregister(rtc_task_t *task)
|
|
{
|
|
{
|
|
@@ -845,7 +855,7 @@ int rtc_unregister(rtc_task_t *task)
|
|
return -ENXIO;
|
|
return -ENXIO;
|
|
}
|
|
}
|
|
rtc_callback = NULL;
|
|
rtc_callback = NULL;
|
|
-
|
|
|
|
|
|
+
|
|
/* disable controls */
|
|
/* disable controls */
|
|
if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
|
|
if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
|
|
tmp = CMOS_READ(RTC_CONTROL);
|
|
tmp = CMOS_READ(RTC_CONTROL);
|
|
@@ -865,6 +875,7 @@ int rtc_unregister(rtc_task_t *task)
|
|
return 0;
|
|
return 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL(rtc_unregister);
|
|
|
|
|
|
int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
|
|
int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
|
|
{
|
|
{
|
|
@@ -883,7 +894,7 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
|
|
return rtc_do_ioctl(cmd, arg, 1);
|
|
return rtc_do_ioctl(cmd, arg, 1);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+EXPORT_SYMBOL(rtc_control);
|
|
|
|
|
|
/*
|
|
/*
|
|
* The various file operations we support.
|
|
* The various file operations we support.
|
|
@@ -910,11 +921,11 @@ static struct miscdevice rtc_dev = {
|
|
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
#ifdef CONFIG_PROC_FS
|
|
static const struct file_operations rtc_proc_fops = {
|
|
static const struct file_operations rtc_proc_fops = {
|
|
- .owner = THIS_MODULE,
|
|
|
|
- .open = rtc_proc_open,
|
|
|
|
- .read = seq_read,
|
|
|
|
- .llseek = seq_lseek,
|
|
|
|
- .release = single_release,
|
|
|
|
|
|
+ .owner = THIS_MODULE,
|
|
|
|
+ .open = rtc_proc_open,
|
|
|
|
+ .read = seq_read,
|
|
|
|
+ .llseek = seq_lseek,
|
|
|
|
+ .release = single_release,
|
|
};
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -965,7 +976,7 @@ static int __init rtc_init(void)
|
|
#ifdef CONFIG_SPARC32
|
|
#ifdef CONFIG_SPARC32
|
|
for_each_ebus(ebus) {
|
|
for_each_ebus(ebus) {
|
|
for_each_ebusdev(edev, ebus) {
|
|
for_each_ebusdev(edev, ebus) {
|
|
- if(strcmp(edev->prom_node->name, "rtc") == 0) {
|
|
|
|
|
|
+ if (strcmp(edev->prom_node->name, "rtc") == 0) {
|
|
rtc_port = edev->resource[0].start;
|
|
rtc_port = edev->resource[0].start;
|
|
rtc_irq = edev->irqs[0];
|
|
rtc_irq = edev->irqs[0];
|
|
goto found;
|
|
goto found;
|
|
@@ -986,7 +997,8 @@ found:
|
|
* XXX Interrupt pin #7 in Espresso is shared between RTC and
|
|
* XXX Interrupt pin #7 in Espresso is shared between RTC and
|
|
* PCI Slot 2 INTA# (and some INTx# in Slot 1).
|
|
* PCI Slot 2 INTA# (and some INTx# in Slot 1).
|
|
*/
|
|
*/
|
|
- if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) {
|
|
|
|
|
|
+ if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc",
|
|
|
|
+ (void *)&rtc_port)) {
|
|
rtc_has_irq = 0;
|
|
rtc_has_irq = 0;
|
|
printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
|
|
printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
|
|
return -EIO;
|
|
return -EIO;
|
|
@@ -1020,11 +1032,13 @@ no_irq:
|
|
rtc_int_handler_ptr = rtc_interrupt;
|
|
rtc_int_handler_ptr = rtc_interrupt;
|
|
}
|
|
}
|
|
|
|
|
|
- if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) {
|
|
|
|
|
|
+ if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED,
|
|
|
|
+ "rtc", NULL)) {
|
|
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
|
|
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
|
|
rtc_has_irq = 0;
|
|
rtc_has_irq = 0;
|
|
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
|
|
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
|
|
rtc_release_region();
|
|
rtc_release_region();
|
|
|
|
+
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
hpet_rtc_timer_init();
|
|
hpet_rtc_timer_init();
|
|
@@ -1052,21 +1066,21 @@ no_irq:
|
|
|
|
|
|
#if defined(__alpha__) || defined(__mips__)
|
|
#if defined(__alpha__) || defined(__mips__)
|
|
rtc_freq = HZ;
|
|
rtc_freq = HZ;
|
|
-
|
|
|
|
|
|
+
|
|
/* Each operating system on an Alpha uses its own epoch.
|
|
/* Each operating system on an Alpha uses its own epoch.
|
|
Let's try to guess which one we are using now. */
|
|
Let's try to guess which one we are using now. */
|
|
-
|
|
|
|
|
|
+
|
|
if (rtc_is_updating() != 0)
|
|
if (rtc_is_updating() != 0)
|
|
msleep(20);
|
|
msleep(20);
|
|
-
|
|
|
|
|
|
+
|
|
spin_lock_irq(&rtc_lock);
|
|
spin_lock_irq(&rtc_lock);
|
|
year = CMOS_READ(RTC_YEAR);
|
|
year = CMOS_READ(RTC_YEAR);
|
|
ctrl = CMOS_READ(RTC_CONTROL);
|
|
ctrl = CMOS_READ(RTC_CONTROL);
|
|
spin_unlock_irq(&rtc_lock);
|
|
spin_unlock_irq(&rtc_lock);
|
|
-
|
|
|
|
|
|
+
|
|
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
|
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
|
BCD_TO_BIN(year); /* This should never happen... */
|
|
BCD_TO_BIN(year); /* This should never happen... */
|
|
-
|
|
|
|
|
|
+
|
|
if (year < 20) {
|
|
if (year < 20) {
|
|
epoch = 2000;
|
|
epoch = 2000;
|
|
guess = "SRM (post-2000)";
|
|
guess = "SRM (post-2000)";
|
|
@@ -1087,7 +1101,8 @@ no_irq:
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
if (guess)
|
|
if (guess)
|
|
- printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
|
|
|
|
|
|
+ printk(KERN_INFO "rtc: %s epoch (%lu) detected\n",
|
|
|
|
+ guess, epoch);
|
|
#endif
|
|
#endif
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
if (rtc_has_irq == 0)
|
|
if (rtc_has_irq == 0)
|
|
@@ -1096,8 +1111,12 @@ no_irq:
|
|
spin_lock_irq(&rtc_lock);
|
|
spin_lock_irq(&rtc_lock);
|
|
rtc_freq = 1024;
|
|
rtc_freq = 1024;
|
|
if (!hpet_set_periodic_freq(rtc_freq)) {
|
|
if (!hpet_set_periodic_freq(rtc_freq)) {
|
|
- /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
|
|
|
|
- CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Initialize periodic frequency to CMOS reset default,
|
|
|
|
+ * which is 1024Hz
|
|
|
|
+ */
|
|
|
|
+ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06),
|
|
|
|
+ RTC_FREQ_SELECT);
|
|
}
|
|
}
|
|
spin_unlock_irq(&rtc_lock);
|
|
spin_unlock_irq(&rtc_lock);
|
|
no_irq2:
|
|
no_irq2:
|
|
@@ -1110,20 +1129,20 @@ no_irq2:
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void __exit rtc_exit (void)
|
|
|
|
|
|
+static void __exit rtc_exit(void)
|
|
{
|
|
{
|
|
cleanup_sysctl();
|
|
cleanup_sysctl();
|
|
- remove_proc_entry ("driver/rtc", NULL);
|
|
|
|
|
|
+ remove_proc_entry("driver/rtc", NULL);
|
|
misc_deregister(&rtc_dev);
|
|
misc_deregister(&rtc_dev);
|
|
|
|
|
|
#ifdef CONFIG_SPARC32
|
|
#ifdef CONFIG_SPARC32
|
|
if (rtc_has_irq)
|
|
if (rtc_has_irq)
|
|
- free_irq (rtc_irq, &rtc_port);
|
|
|
|
|
|
+ free_irq(rtc_irq, &rtc_port);
|
|
#else
|
|
#else
|
|
rtc_release_region();
|
|
rtc_release_region();
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
if (rtc_has_irq)
|
|
if (rtc_has_irq)
|
|
- free_irq (RTC_IRQ, NULL);
|
|
|
|
|
|
+ free_irq(RTC_IRQ, NULL);
|
|
#endif
|
|
#endif
|
|
#endif /* CONFIG_SPARC32 */
|
|
#endif /* CONFIG_SPARC32 */
|
|
}
|
|
}
|
|
@@ -1133,14 +1152,14 @@ module_exit(rtc_exit);
|
|
|
|
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
/*
|
|
/*
|
|
- * At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
|
|
|
|
|
|
+ * At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
|
|
* (usually during an IDE disk interrupt, with IRQ unmasking off)
|
|
* (usually during an IDE disk interrupt, with IRQ unmasking off)
|
|
* Since the interrupt handler doesn't get called, the IRQ status
|
|
* Since the interrupt handler doesn't get called, the IRQ status
|
|
* byte doesn't get read, and the RTC stops generating interrupts.
|
|
* byte doesn't get read, and the RTC stops generating interrupts.
|
|
* A timer is set, and will call this function if/when that happens.
|
|
* A timer is set, and will call this function if/when that happens.
|
|
* To get it out of this stalled state, we just read the status.
|
|
* To get it out of this stalled state, we just read the status.
|
|
* At least a jiffy of interrupts (rtc_freq/HZ) will have been lost.
|
|
* At least a jiffy of interrupts (rtc_freq/HZ) will have been lost.
|
|
- * (You *really* shouldn't be trying to use a non-realtime system
|
|
|
|
|
|
+ * (You *really* shouldn't be trying to use a non-realtime system
|
|
* for something that requires a steady > 1KHz signal anyways.)
|
|
* for something that requires a steady > 1KHz signal anyways.)
|
|
*/
|
|
*/
|
|
|
|
|
|
@@ -1148,7 +1167,7 @@ static void rtc_dropped_irq(unsigned long data)
|
|
{
|
|
{
|
|
unsigned long freq;
|
|
unsigned long freq;
|
|
|
|
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
|
|
+ spin_lock_irq(&rtc_lock);
|
|
|
|
|
|
if (hpet_rtc_dropped_irq()) {
|
|
if (hpet_rtc_dropped_irq()) {
|
|
spin_unlock_irq(&rtc_lock);
|
|
spin_unlock_irq(&rtc_lock);
|
|
@@ -1167,13 +1186,15 @@ static void rtc_dropped_irq(unsigned long data)
|
|
|
|
|
|
spin_unlock_irq(&rtc_lock);
|
|
spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
- if (printk_ratelimit())
|
|
|
|
- printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);
|
|
|
|
|
|
+ if (printk_ratelimit()) {
|
|
|
|
+ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
|
|
|
|
+ freq);
|
|
|
|
+ }
|
|
|
|
|
|
/* Now we have new data */
|
|
/* Now we have new data */
|
|
wake_up_interruptible(&rtc_wait);
|
|
wake_up_interruptible(&rtc_wait);
|
|
|
|
|
|
- kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
|
|
|
|
|
|
+ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -1277,7 +1298,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
|
|
* can take just over 2ms. We wait 20ms. There is no need to
|
|
* can take just over 2ms. We wait 20ms. There is no need to
|
|
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
|
|
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
|
|
* If you need to know *exactly* when a second has started, enable
|
|
* If you need to know *exactly* when a second has started, enable
|
|
- * periodic update complete interrupts, (via ioctl) and then
|
|
|
|
|
|
+ * periodic update complete interrupts, (via ioctl) and then
|
|
* immediately read /dev/rtc which will block until you get the IRQ.
|
|
* immediately read /dev/rtc which will block until you get the IRQ.
|
|
* Once the read clears, read the RTC time (again via ioctl). Easy.
|
|
* Once the read clears, read the RTC time (again via ioctl). Easy.
|
|
*/
|
|
*/
|
|
@@ -1307,8 +1328,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
|
|
ctrl = CMOS_READ(RTC_CONTROL);
|
|
ctrl = CMOS_READ(RTC_CONTROL);
|
|
spin_unlock_irqrestore(&rtc_lock, flags);
|
|
spin_unlock_irqrestore(&rtc_lock, flags);
|
|
|
|
|
|
- if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
|
|
|
- {
|
|
|
|
|
|
+ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
|
BCD_TO_BIN(rtc_tm->tm_sec);
|
|
BCD_TO_BIN(rtc_tm->tm_sec);
|
|
BCD_TO_BIN(rtc_tm->tm_min);
|
|
BCD_TO_BIN(rtc_tm->tm_min);
|
|
BCD_TO_BIN(rtc_tm->tm_hour);
|
|
BCD_TO_BIN(rtc_tm->tm_hour);
|
|
@@ -1326,7 +1346,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
|
|
* Account for differences between how the RTC uses the values
|
|
* Account for differences between how the RTC uses the values
|
|
* and how they are defined in a struct rtc_time;
|
|
* and how they are defined in a struct rtc_time;
|
|
*/
|
|
*/
|
|
- if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
|
|
|
|
|
|
+ rtc_tm->tm_year += epoch - 1900;
|
|
|
|
+ if (rtc_tm->tm_year <= 69)
|
|
rtc_tm->tm_year += 100;
|
|
rtc_tm->tm_year += 100;
|
|
|
|
|
|
rtc_tm->tm_mon--;
|
|
rtc_tm->tm_mon--;
|
|
@@ -1347,8 +1368,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm)
|
|
ctrl = CMOS_READ(RTC_CONTROL);
|
|
ctrl = CMOS_READ(RTC_CONTROL);
|
|
spin_unlock_irq(&rtc_lock);
|
|
spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
- if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
|
|
|
- {
|
|
|
|
|
|
+ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
|
BCD_TO_BIN(alm_tm->tm_sec);
|
|
BCD_TO_BIN(alm_tm->tm_sec);
|
|
BCD_TO_BIN(alm_tm->tm_min);
|
|
BCD_TO_BIN(alm_tm->tm_min);
|
|
BCD_TO_BIN(alm_tm->tm_hour);
|
|
BCD_TO_BIN(alm_tm->tm_hour);
|