* 1.09a Pete Zaitcev: Sun SPARC
* 1.09b Jeff Garzik: Modularize, init cleanup
* 1.09c Jeff Garzik: SMP cleanup
- * 1.10 Paul Barton-Davis: add support for async I/O
+ * 1.10 Paul Barton-Davis: add support for async I/O
* 1.10a Andrea Arcangeli: Alpha updates
* 1.10b Andrew Morton: SMP lock fix
* 1.10c Cesar Barros: SMP locking fixes and cleanup
* 1.10d Paul Gortmaker: delete paranoia check in rtc_exit
* 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness.
- * 1.11 Takashi Iwai: Kernel access functions
+ * 1.11 Takashi Iwai: Kernel access functions
* rtc_register/rtc_unregister/rtc_control
* 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
* 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
* CONFIG_HPET_EMULATE_RTC
- *
+ * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly.
+ * 1.12ac Alan Cox: Allow read access to the day of week register
*/
-#define RTC_VERSION "1.12"
-
-#define RTC_IO_EXTENT 0x8
+#define RTC_VERSION "1.12ac"
/*
* Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
* this driver.)
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/sysctl.h>
#include <linux/wait.h>
#include <linux/bcd.h>
+#include <linux/delay.h>
#include <asm/current.h>
#include <asm/uaccess.h>
static int rtc_irq = PCI_IRQ_NONE;
#endif
-#if RTC_IRQ
+#ifdef CONFIG_HPET_RTC_IRQ
+#undef RTC_IRQ
+#endif
+
+#ifdef RTC_IRQ
static int rtc_has_irq = 1;
#endif
#define hpet_set_rtc_irq_bit(arg) 0
#define hpet_rtc_timer_init() do { } while (0)
#define hpet_rtc_dropped_irq() 0
-static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;}
+#ifdef RTC_IRQ
+static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
+{
+ return 0;
+}
+#endif
#else
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
#endif
/*
static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
-#if RTC_IRQ
+#ifdef RTC_IRQ
static struct timer_list rtc_irq_timer;
#endif
-static ssize_t rtc_read(struct file *file, char *buf,
+static ssize_t rtc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static int rtc_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
-#if RTC_IRQ
+#ifdef RTC_IRQ
static unsigned int rtc_poll(struct file *file, poll_table *wait);
#endif
static void get_rtc_alm_time (struct rtc_time *alm_tm);
-#if RTC_IRQ
+#ifdef RTC_IRQ
static void rtc_dropped_irq(unsigned long data);
-static void set_rtc_irq_bit(unsigned char bit);
-static void mask_rtc_irq_bit(unsigned char bit);
-#endif
+static void set_rtc_irq_bit_locked(unsigned char bit);
+static void mask_rtc_irq_bit_locked(unsigned char bit);
-static inline unsigned char rtc_is_updating(void);
+static inline void set_rtc_irq_bit(unsigned char bit)
+{
+ spin_lock_irq(&rtc_lock);
+ set_rtc_irq_bit_locked(bit);
+ spin_unlock_irq(&rtc_lock);
+}
-static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data);
+static void mask_rtc_irq_bit(unsigned char bit)
+{
+ spin_lock_irq(&rtc_lock);
+ mask_rtc_irq_bit_locked(bit);
+ spin_unlock_irq(&rtc_lock);
+}
+#endif
+
+#ifdef CONFIG_PROC_FS
+static int rtc_proc_open(struct inode *inode, struct file *file);
+#endif
/*
* Bits in rtc_status. (6 bits of room for future expansion)
static unsigned long rtc_irq_data = 0; /* our output to the world */
static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
-#if RTC_IRQ
+#ifdef RTC_IRQ
/*
* rtc_task_lock nests inside rtc_lock.
*/
-static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rtc_task_lock);
static rtc_task_t *rtc_callback = NULL;
#endif
static const unsigned char days_in_mo[] =
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-#if RTC_IRQ
/*
- * A very tiny interrupt handler. It runs with SA_INTERRUPT set,
+ * Returns true if a clock update is in progress
+ */
+static inline unsigned char rtc_is_updating(void)
+{
+ unsigned long flags;
+ unsigned char uip;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return uip;
+}
+
+#ifdef RTC_IRQ
+/*
+ * A very tiny interrupt handler. It runs with IRQF_DISABLED set,
* but there is possibility of conflicting with the set_rtc_mmss()
* call (the rtc irq and the timer irq can easily run at the same
* time in two different CPUs). So we need to serialize
* (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
*/
-irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t rtc_interrupt(int irq, void *dev_id)
{
/*
* Can be an alarm interrupt, update complete interrupt,
* Now all the various file operations that we export.
*/
-static ssize_t rtc_read(struct file *file, char *buf,
+static ssize_t rtc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
-#if !RTC_IRQ
+#ifndef RTC_IRQ
return -EIO;
#else
DECLARE_WAITQUEUE(wait, current);
if (rtc_has_irq == 0)
return -EIO;
- if (count < sizeof(unsigned))
+ /*
+ * Historically this function used to assume that sizeof(unsigned long)
+ * is the same in userspace and kernelspace. This lead to problems
+ * for configurations with multiple ABIs such a the MIPS o32 and 64
+ * ABIs supported on the same kernel. So now we support read of both
+ * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the
+ * userspace ABI.
+ */
+ if (count != sizeof(unsigned int) && count != sizeof(unsigned long))
return -EINVAL;
add_wait_queue(&rtc_wait, &wait);
schedule();
} while (1);
- if (count < sizeof(unsigned long))
- retval = put_user(data, (unsigned int *)buf) ?: sizeof(int);
+ if (count == sizeof(unsigned int))
+ retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
else
- retval = put_user(data, (unsigned long *)buf) ?: sizeof(long);
+ retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
+ if (!retval)
+ retval = count;
out:
current->state = TASK_RUNNING;
remove_wait_queue(&rtc_wait, &wait);
{
struct rtc_time wtime;
-#if RTC_IRQ
+#ifdef RTC_IRQ
if (rtc_has_irq == 0) {
switch (cmd) {
case RTC_AIE_OFF:
#endif
switch (cmd) {
-#if RTC_IRQ
+#ifdef RTC_IRQ
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
{
mask_rtc_irq_bit(RTC_AIE);
}
case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
{
- mask_rtc_irq_bit(RTC_PIE);
+ unsigned long flags; /* can be called from isr via rtc_control() */
+ spin_lock_irqsave (&rtc_lock, flags);
+ mask_rtc_irq_bit_locked(RTC_PIE);
if (rtc_status & RTC_TIMER_ON) {
- spin_lock_irq (&rtc_lock);
rtc_status &= ~RTC_TIMER_ON;
del_timer(&rtc_irq_timer);
- spin_unlock_irq (&rtc_lock);
}
+ spin_unlock_irqrestore (&rtc_lock, flags);
return 0;
}
case RTC_PIE_ON: /* Allow periodic ints */
{
-
+ unsigned long flags; /* can be called from isr via rtc_control() */
/*
* We don't really want Joe User enabling more
* than 64Hz of interrupts on a multi-user machine.
(!capable(CAP_SYS_RESOURCE)))
return -EACCES;
+ spin_lock_irqsave (&rtc_lock, flags);
if (!(rtc_status & RTC_TIMER_ON)) {
- spin_lock_irq (&rtc_lock);
rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
add_timer(&rtc_irq_timer);
rtc_status |= RTC_TIMER_ON;
- spin_unlock_irq (&rtc_lock);
}
- set_rtc_irq_bit(RTC_PIE);
+ set_rtc_irq_bit_locked(RTC_PIE);
+ spin_unlock_irqrestore (&rtc_lock, flags);
return 0;
}
case RTC_UIE_OFF: /* Mask ints from RTC updates. */
unsigned char hrs, min, sec;
struct rtc_time alm_tm;
- if (copy_from_user(&alm_tm, (struct rtc_time*)arg,
+ if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg,
sizeof(struct rtc_time)))
return -EFAULT;
unsigned char mon, day, hrs, min, sec, leap_yr;
unsigned char save_control, save_freq_select;
unsigned int yrs;
-#ifdef CONFIG_DECSTATION
+#ifdef CONFIG_MACH_DECSTATION
unsigned int real_yrs;
#endif
if (!capable(CAP_SYS_TIME))
return -EACCES;
- if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+ if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg,
sizeof(struct rtc_time)))
return -EFAULT;
return -EINVAL;
spin_lock_irq(&rtc_lock);
-#ifdef CONFIG_DECSTATION
+#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
yrs = 72;
save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-#ifdef CONFIG_DECSTATION
+#ifdef CONFIG_MACH_DECSTATION
CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
#endif
CMOS_WRITE(yrs, RTC_YEAR);
spin_unlock_irq(&rtc_lock);
return 0;
}
-#if RTC_IRQ
+#ifdef RTC_IRQ
case RTC_IRQP_READ: /* Read the periodic IRQ rate. */
{
- return put_user(rtc_freq, (unsigned long *)arg);
+ return put_user(rtc_freq, (unsigned long __user *)arg);
}
case RTC_IRQP_SET: /* Set periodic IRQ rate. */
{
int tmp = 0;
unsigned char val;
+ unsigned long flags; /* can be called from isr via rtc_control() */
/*
* The max we can do is 8192Hz.
if (arg != (1<<tmp))
return -EINVAL;
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
if (hpet_set_periodic_freq(arg)) {
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
rtc_freq = arg;
val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
val |= (16 - tmp);
CMOS_WRITE(val, RTC_FREQ_SELECT);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
#endif
case RTC_EPOCH_READ: /* Read the epoch. */
{
- return put_user (epoch, (unsigned long *)arg);
+ return put_user (epoch, (unsigned long __user *)arg);
}
case RTC_EPOCH_SET: /* Set the epoch. */
{
default:
return -ENOTTY;
}
- return copy_to_user((void *)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_release(struct inode *inode, struct file *file)
{
-#if RTC_IRQ
+#ifdef RTC_IRQ
unsigned char tmp;
if (rtc_has_irq == 0)
return 0;
}
-#if RTC_IRQ
+#ifdef RTC_IRQ
/* Called without the kernel lock - fine */
static unsigned int rtc_poll(struct file *file, poll_table *wait)
{
int rtc_register(rtc_task_t *task)
{
-#if !RTC_IRQ
+#ifndef RTC_IRQ
return -EIO;
#else
if (task == NULL || task->func == NULL)
int rtc_unregister(rtc_task_t *task)
{
-#if !RTC_IRQ
+#ifndef RTC_IRQ
return -EIO;
#else
unsigned char tmp;
int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
{
-#if !RTC_IRQ
+#ifndef RTC_IRQ
return -EIO;
#else
- spin_lock_irq(&rtc_task_lock);
+ unsigned long flags;
+ if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
+ return -EINVAL;
+ spin_lock_irqsave(&rtc_task_lock, flags);
if (rtc_callback != task) {
- spin_unlock_irq(&rtc_task_lock);
+ spin_unlock_irqrestore(&rtc_task_lock, flags);
return -ENXIO;
}
- spin_unlock_irq(&rtc_task_lock);
+ spin_unlock_irqrestore(&rtc_task_lock, flags);
return rtc_do_ioctl(cmd, arg, 1);
#endif
}
* The various file operations we support.
*/
-static struct file_operations rtc_fops = {
+static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_read,
-#if RTC_IRQ
+#ifdef RTC_IRQ
.poll = rtc_poll,
#endif
.ioctl = rtc_ioctl,
.fasync = rtc_fasync,
};
-static struct miscdevice rtc_dev=
-{
- RTC_MINOR,
- "rtc",
- &rtc_fops
+static struct miscdevice rtc_dev = {
+ .minor = RTC_MINOR,
+ .name = "rtc",
+ .fops = &rtc_fops,
};
-#if RTC_IRQ
-static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs);
+#ifdef CONFIG_PROC_FS
+static const struct file_operations rtc_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = rtc_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
static int __init rtc_init(void)
{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent;
+#endif
#if defined(__alpha__) || defined(__mips__)
unsigned int year, ctrl;
- unsigned long uip_watchdog;
char *guess = NULL;
#endif
#ifdef __sparc__
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
#endif
+#else
+ void *r;
+#ifdef RTC_IRQ
+ irq_handler_t rtc_int_handler_ptr;
+#endif
#endif
#ifdef __sparc__
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if(strcmp(edev->prom_name, "rtc") == 0) {
+ if(strcmp(edev->prom_node->name, "rtc") == 0) {
rtc_port = edev->resource[0].start;
rtc_irq = edev->irqs[0];
goto found;
#ifdef __sparc_v9__
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
- if (strcmp(isa_dev->prom_name, "rtc") == 0) {
+ if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
rtc_port = isa_dev->resource.start;
rtc_irq = isa_dev->irq;
goto found;
}
}
#endif
+ rtc_has_irq = 0;
printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
/*
* XXX Interrupt pin #7 in Espresso is shared between RTC and
- * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here
- * is asking for trouble with add-on boards. Change to SA_SHIRQ.
+ * PCI Slot 2 INTA# (and some INTx# in Slot 1).
*/
- if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {
- /*
- * Standard way for sparc to print irq's is to use
- * __irq_itoa(). I think for EBus it's ok to use %d.
- */
+ if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) {
+ rtc_has_irq = 0;
printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
return -EIO;
}
no_irq:
#else
- if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc")) {
- printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));
+ if (RTC_IOMAPPED)
+ r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ else
+ r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ if (!r) {
+#ifdef RTC_IRQ
+ rtc_has_irq = 0;
+#endif
+ printk(KERN_ERR "rtc: I/O resource %lx is not free.\n",
+ (long)(RTC_PORT(0)));
return -EIO;
}
-#if RTC_IRQ
+#ifdef RTC_IRQ
if (is_hpet_enabled()) {
rtc_int_handler_ptr = hpet_rtc_interrupt;
} else {
rtc_int_handler_ptr = rtc_interrupt;
}
- if(request_irq(RTC_IRQ, rtc_int_handler_ptr, SA_INTERRUPT, "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. */
+ rtc_has_irq = 0;
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ else
+ release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
return -EIO;
}
hpet_rtc_timer_init();
#endif /* __sparc__ vs. others */
if (misc_register(&rtc_dev)) {
-#if RTC_IRQ
+#ifdef RTC_IRQ
free_irq(RTC_IRQ, NULL);
+ rtc_has_irq = 0;
#endif
release_region(RTC_PORT(0), RTC_IO_EXTENT);
return -ENODEV;
}
- if (create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL) == NULL) {
-#if RTC_IRQ
- free_irq(RTC_IRQ, NULL);
+
+#ifdef CONFIG_PROC_FS
+ ent = create_proc_entry("driver/rtc", 0, NULL);
+ if (ent)
+ ent->proc_fops = &rtc_proc_fops;
+ else
+ printk(KERN_WARNING "rtc: Failed to register with procfs.\n");
#endif
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
- misc_deregister(&rtc_dev);
- return -ENOMEM;
- }
#if defined(__alpha__) || defined(__mips__)
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();
- cpu_relax();
- }
+ msleep(20);
spin_lock_irq(&rtc_lock);
year = CMOS_READ(RTC_YEAR);
if (guess)
printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
#endif
-#if RTC_IRQ
+#ifdef RTC_IRQ
if (rtc_has_irq == 0)
goto no_irq2;
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
- release_region (RTC_PORT (0), RTC_IO_EXTENT);
-#if RTC_IRQ
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ else
+ release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
+#ifdef RTC_IRQ
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
#endif
module_init(rtc_init);
module_exit(rtc_exit);
-#if RTC_IRQ
+#ifdef RTC_IRQ
/*
* At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
* (usually during an IDE disk interrupt, with IRQ unmasking off)
}
#endif
+#ifdef CONFIG_PROC_FS
/*
* Info exported via "/proc/driver/rtc".
*/
-static int rtc_proc_output (char *buf)
+static int rtc_proc_show(struct seq_file *seq, void *v)
{
#define YN(bit) ((ctrl & bit) ? "yes" : "no")
#define NY(bit) ((ctrl & bit) ? "no" : "yes")
- char *p;
struct rtc_time tm;
unsigned char batt, ctrl;
unsigned long freq;
freq = rtc_freq;
spin_unlock_irq(&rtc_lock);
- p = buf;
rtc_get_rtc_time(&tm);
* There is no way to tell if the luser has the RTC set for local
* time or for Universal Standard Time (GMT). Probably local though.
*/
- p += sprintf(p,
- "rtc_time\t: %02d:%02d:%02d\n"
- "rtc_date\t: %04d-%02d-%02d\n"
- "rtc_epoch\t: %04lu\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+ seq_printf(seq,
+ "rtc_time\t: %02d:%02d:%02d\n"
+ "rtc_date\t: %04d-%02d-%02d\n"
+ "rtc_epoch\t: %04lu\n",
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
get_rtc_alm_time(&tm);
* match any value for that particular field. Values that are
* greater than a valid time, but less than 0xc0 shouldn't appear.
*/
- p += sprintf(p, "alarm\t\t: ");
+ seq_puts(seq, "alarm\t\t: ");
if (tm.tm_hour <= 24)
- p += sprintf(p, "%02d:", tm.tm_hour);
+ seq_printf(seq, "%02d:", tm.tm_hour);
else
- p += sprintf(p, "**:");
+ seq_puts(seq, "**:");
if (tm.tm_min <= 59)
- p += sprintf(p, "%02d:", tm.tm_min);
+ seq_printf(seq, "%02d:", tm.tm_min);
else
- p += sprintf(p, "**:");
+ seq_puts(seq, "**:");
if (tm.tm_sec <= 59)
- p += sprintf(p, "%02d\n", tm.tm_sec);
+ seq_printf(seq, "%02d\n", tm.tm_sec);
else
- p += sprintf(p, "**\n");
-
- p += sprintf(p,
- "DST_enable\t: %s\n"
- "BCD\t\t: %s\n"
- "24hr\t\t: %s\n"
- "square_wave\t: %s\n"
- "alarm_IRQ\t: %s\n"
- "update_IRQ\t: %s\n"
- "periodic_IRQ\t: %s\n"
- "periodic_freq\t: %ld\n"
- "batt_status\t: %s\n",
- YN(RTC_DST_EN),
- NY(RTC_DM_BINARY),
- YN(RTC_24H),
- YN(RTC_SQWE),
- YN(RTC_AIE),
- YN(RTC_UIE),
- YN(RTC_PIE),
- freq,
- batt ? "okay" : "dead");
-
- return p - buf;
+ seq_puts(seq, "**\n");
+
+ seq_printf(seq,
+ "DST_enable\t: %s\n"
+ "BCD\t\t: %s\n"
+ "24hr\t\t: %s\n"
+ "square_wave\t: %s\n"
+ "alarm_IRQ\t: %s\n"
+ "update_IRQ\t: %s\n"
+ "periodic_IRQ\t: %s\n"
+ "periodic_freq\t: %ld\n"
+ "batt_status\t: %s\n",
+ YN(RTC_DST_EN),
+ NY(RTC_DM_BINARY),
+ YN(RTC_24H),
+ YN(RTC_SQWE),
+ YN(RTC_AIE),
+ YN(RTC_UIE),
+ YN(RTC_PIE),
+ freq,
+ batt ? "okay" : "dead");
+
+ return 0;
#undef YN
#undef NY
}
-static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = rtc_proc_output (page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
-}
-
-/*
- * Returns true if a clock update is in progress
- */
-/* FIXME shouldn't this be above rtc_init to make it fully inlined? */
-static inline unsigned char rtc_is_updating(void)
+static int rtc_proc_open(struct inode *inode, struct file *file)
{
- unsigned char uip;
-
- spin_lock_irq(&rtc_lock);
- uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
- spin_unlock_irq(&rtc_lock);
- return uip;
+ return single_open(file, rtc_proc_show, NULL);
}
+#endif
void rtc_get_rtc_time(struct rtc_time *rtc_tm)
{
- unsigned long uip_watchdog = jiffies;
+ unsigned long uip_watchdog = jiffies, flags;
unsigned char ctrl;
-#ifdef CONFIG_DECSTATION
+#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
#endif
/*
* read RTC once any update in progress is done. The update
- * can take just over 2ms. We wait 10 to 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.
* If you need to know *exactly* when a second has started, enable
* periodic update complete interrupts, (via ioctl) and then
* Once the read clears, read the RTC time (again via ioctl). Easy.
*/
- if (rtc_is_updating() != 0)
- while (jiffies - uip_watchdog < 2*HZ/100) {
- barrier();
- cpu_relax();
- }
+ while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100)
+ cpu_relax();
/*
* Only the values that we read from the RTC are set. We leave
- * tm_wday, tm_yday and tm_isdst untouched. Even though the
- * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
- * by the RTC when initially set to a non-zero value.
+ * tm_wday, tm_yday and tm_isdst untouched. Note that while the
+ * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is
+ * only updated by the RTC when initially set to a non-zero value.
*/
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
-#ifdef CONFIG_DECSTATION
+ /* Only set from 2.6.16 onwards */
+ rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+#ifdef CONFIG_MACH_DECSTATION
real_year = CMOS_READ(RTC_DEC_YEAR);
#endif
ctrl = CMOS_READ(RTC_CONTROL);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
BCD_TO_BIN(rtc_tm->tm_mday);
BCD_TO_BIN(rtc_tm->tm_mon);
BCD_TO_BIN(rtc_tm->tm_year);
+ BCD_TO_BIN(rtc_tm->tm_wday);
}
-#ifdef CONFIG_DECSTATION
+#ifdef CONFIG_MACH_DECSTATION
rtc_tm->tm_year += real_year - 72;
#endif
}
}
-#if RTC_IRQ
+#ifdef RTC_IRQ
/*
* Used to disable/enable interrupts for any one of UIE, AIE, PIE.
* Rumour has it that if you frob the interrupt enable/disable
* meddles with the interrupt enable/disable bits.
*/
-static void mask_rtc_irq_bit(unsigned char bit)
+static void mask_rtc_irq_bit_locked(unsigned char bit)
{
unsigned char val;
- spin_lock_irq(&rtc_lock);
- if (hpet_mask_rtc_irq_bit(bit)) {
- spin_unlock_irq(&rtc_lock);
+ if (hpet_mask_rtc_irq_bit(bit))
return;
- }
val = CMOS_READ(RTC_CONTROL);
val &= ~bit;
CMOS_WRITE(val, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
rtc_irq_data = 0;
- spin_unlock_irq(&rtc_lock);
}
-static void set_rtc_irq_bit(unsigned char bit)
+static void set_rtc_irq_bit_locked(unsigned char bit)
{
unsigned char val;
- spin_lock_irq(&rtc_lock);
- if (hpet_set_rtc_irq_bit(bit)) {
- spin_unlock_irq(&rtc_lock);
+ if (hpet_set_rtc_irq_bit(bit))
return;
- }
val = CMOS_READ(RTC_CONTROL);
val |= bit;
CMOS_WRITE(val, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
rtc_irq_data = 0;
- spin_unlock_irq(&rtc_lock);
}
#endif