patch-2.3.41 linux/drivers/char/rtc.c
Next file: linux/drivers/char/saa5249.c
Previous file: linux/drivers/char/random.c
Back to the patch index
Back to the overall index
- Lines: 454
- Date:
Tue Jan 25 14:13:47 2000
- Orig file:
v2.3.40/linux/drivers/char/rtc.c
- Orig date:
Tue Nov 23 22:42:20 1999
diff -u --recursive --new-file v2.3.40/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
@@ -5,8 +5,8 @@
*
* 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/rtc
- * pseudo-file for status information.
+ * interface supporting various ioctl() and also the
+ * /proc/driver/rtc pseudo-file for status information.
*
* The ioctls can be used to set the interrupt behaviour and
* generation rate from the RTC via IRQ 8. Then the /dev/rtc
@@ -60,6 +60,7 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -81,6 +82,8 @@
static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
+static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+
static struct timer_list rtc_irq_timer;
static long long rtc_llseek(struct file *file, loff_t offset, int origin);
@@ -103,7 +106,7 @@
static inline unsigned char rtc_is_updating(void);
static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data);
+ int count, int *eof, void *data);
/*
* Bits in rtc_status. (6 bits of room for future expansion)
@@ -112,7 +115,7 @@
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
#define RTC_TIMER_ON 0x02 /* missed irq timer active */
-static unsigned char rtc_status = 0; /* bitmapped status byte. */
+static atomic_t rtc_status = ATOMIC_INIT(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 */
@@ -142,12 +145,15 @@
* the last read in the remainder of rtc_irq_data.
*/
+ spin_lock (&rtc_lock);
rtc_irq_data += 0x100;
rtc_irq_data &= ~0xff;
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+ spin_unlock (&rtc_lock);
+
wake_up_interruptible(&rtc_wait);
- if (rtc_status & RTC_TIMER_ON)
+ if (atomic_read(&rtc_status) & RTC_TIMER_ON)
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
}
@@ -217,9 +223,10 @@
case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
{
mask_rtc_irq_bit(RTC_PIE);
- if (rtc_status & RTC_TIMER_ON) {
+ if (atomic_read(&rtc_status) & RTC_TIMER_ON) {
del_timer(&rtc_irq_timer);
- rtc_status &= ~RTC_TIMER_ON;
+ atomic_set(&rtc_status,
+ atomic_read(&rtc_status) & ~RTC_TIMER_ON);
}
return 0;
}
@@ -233,8 +240,9 @@
if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE)))
return -EACCES;
- if (!(rtc_status & RTC_TIMER_ON)) {
- rtc_status |= RTC_TIMER_ON;
+ if (!(atomic_read(&rtc_status) & RTC_TIMER_ON)) {
+ atomic_set(&rtc_status,
+ atomic_read(&rtc_status) | RTC_TIMER_ON);
rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
add_timer(&rtc_irq_timer);
}
@@ -289,8 +297,7 @@
if (sec >= 60)
sec = 0xff;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
RTC_ALWAYS_BCD)
{
@@ -301,7 +308,7 @@
CMOS_WRITE(hrs, RTC_HOURS_ALARM);
CMOS_WRITE(min, RTC_MINUTES_ALARM);
CMOS_WRITE(sec, RTC_SECONDS_ALARM);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
@@ -349,8 +356,7 @@
if ((yrs -= epoch) > 255) /* They are unsigned */
return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
if (yrs > 169) {
@@ -383,7 +389,7 @@
CMOS_WRITE(save_control, RTC_CONTROL);
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
case RTC_IRQP_READ: /* Read the periodic IRQ rate. */
@@ -418,12 +424,11 @@
rtc_freq = arg;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
val |= (16 - tmp);
CMOS_WRITE(val, RTC_FREQ_SELECT);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
#ifdef __alpha__
@@ -460,13 +465,18 @@
static int rtc_open(struct inode *inode, struct file *file)
{
- if(rtc_status & RTC_IS_OPEN)
+ unsigned long flags;
+
+ if(atomic_read(&rtc_status) & RTC_IS_OPEN)
return -EBUSY;
MOD_INC_USE_COUNT;
- rtc_status |= RTC_IS_OPEN;
+ atomic_set(&rtc_status, atomic_read(&rtc_status) | RTC_IS_OPEN);
+
+ spin_lock_irqsave (&rtc_lock, flags);
rtc_irq_data = 0;
+ spin_unlock_irqrestore (&rtc_lock, flags);
return 0;
}
@@ -480,32 +490,40 @@
unsigned char tmp;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
tmp = CMOS_READ(RTC_CONTROL);
tmp &= ~RTC_PIE;
tmp &= ~RTC_AIE;
tmp &= ~RTC_UIE;
CMOS_WRITE(tmp, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
- if (rtc_status & RTC_TIMER_ON) {
- rtc_status &= ~RTC_TIMER_ON;
+ if (atomic_read(&rtc_status) & RTC_TIMER_ON) {
+ atomic_set(&rtc_status, atomic_read(&rtc_status) & ~RTC_TIMER_ON);
del_timer(&rtc_irq_timer);
}
MOD_DEC_USE_COUNT;
+ spin_lock_irqsave (&rtc_lock, flags);
rtc_irq_data = 0;
- rtc_status &= ~RTC_IS_OPEN;
+ spin_unlock_irqrestore (&rtc_lock, flags);
+ atomic_set(&rtc_status, atomic_read(&rtc_status) & ~RTC_IS_OPEN);
return 0;
}
static unsigned int rtc_poll(struct file *file, poll_table *wait)
{
+ unsigned long l, flags;
+
poll_wait(file, &rtc_wait, wait);
- if (rtc_irq_data != 0)
+
+ spin_lock_irqsave (&rtc_lock, flags);
+ l = rtc_irq_data;
+ spin_unlock_irqrestore (&rtc_lock, flags);
+
+ if (l != 0)
return POLLIN | POLLRDNORM;
return 0;
}
@@ -547,7 +565,6 @@
struct linux_ebus_device *edev;
#endif
- printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
#ifdef __sparc__
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
@@ -575,20 +592,26 @@
printk("rtc: cannot register IRQ %d\n", rtc_irq);
return -EIO;
}
- misc_register(&rtc_dev);
#else
+ if (check_region (RTC_PORT (0), RTC_IO_EXTENT))
+ {
+ printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));
+ return -EIO;
+ }
+
if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
{
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
return -EIO;
}
- misc_register(&rtc_dev);
- create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL);
- /* Check region? Naaah! Just snarf it up. */
request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
#endif /* __sparc__ vs. others */
+
+ misc_register(&rtc_dev);
+ create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
+
#ifdef __alpha__
rtc_freq = HZ;
@@ -600,11 +623,10 @@
while (jiffies - uip_watchdog < 2*HZ/100)
barrier();
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
year = CMOS_READ(RTC_YEAR);
ctrl = CMOS_READ(RTC_CONTROL);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(year); /* This should never happen... */
@@ -621,20 +643,25 @@
#endif
init_timer(&rtc_irq_timer);
rtc_irq_timer.function = rtc_dropped_irq;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
rtc_freq = 1024;
+
+ printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
+
return 0;
}
static void __exit rtc_exit (void)
{
- /* interrupts and timer disabled at this point by rtc_release */
+ /* interrupts and maybe timer disabled at this point by rtc_release */
+
+ if (atomic_read(&rtc_status) & RTC_TIMER_ON)
+ del_timer(&rtc_irq_timer);
- remove_proc_entry ("rtc", NULL);
+ remove_proc_entry ("driver/rtc", NULL);
misc_deregister(&rtc_dev);
#ifdef __sparc__
@@ -668,30 +695,30 @@
printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq);
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
rtc_irq_data += ((rtc_freq/HZ)<<8);
rtc_irq_data &= ~0xff;
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
}
/*
- * Info exported via "/proc/rtc".
+ * Info exported via "/proc/driver/rtc".
*/
-static int rtc_get_status(char *buf)
+static int rtc_proc_output (char *buf)
{
+#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 flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
batt = CMOS_READ(RTC_VALID) & RTC_VRT;
ctrl = CMOS_READ(RTC_CONTROL);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
p = buf;
@@ -741,23 +768,25 @@
"periodic_IRQ\t: %s\n"
"periodic_freq\t: %ld\n"
"batt_status\t: %s\n",
- (ctrl & RTC_DST_EN) ? "yes" : "no",
- (ctrl & RTC_DM_BINARY) ? "no" : "yes",
- (ctrl & RTC_24H) ? "yes" : "no",
- (ctrl & RTC_SQWE) ? "yes" : "no",
- (ctrl & RTC_AIE) ? "yes" : "no",
- (ctrl & RTC_UIE) ? "yes" : "no",
- (ctrl & RTC_PIE) ? "yes" : "no",
+ YN(RTC_DST_EN),
+ NY(RTC_DM_BINARY),
+ YN(RTC_24H),
+ YN(RTC_SQWE),
+ YN(RTC_AIE),
+ YN(RTC_UIE),
+ YN(RTC_PIE),
rtc_freq,
batt ? "okay" : "dead");
return p - buf;
+#undef YN
+#undef NY
}
static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
- int len = rtc_get_status(page);
+ int len = rtc_proc_output (page);
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
@@ -774,10 +803,9 @@
unsigned long flags;
unsigned char uip;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return uip;
}
@@ -807,8 +835,7 @@
* 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.
*/
- save_flags(flags);
- cli();
+ 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);
@@ -816,7 +843,7 @@
rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
ctrl = CMOS_READ(RTC_CONTROL);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
@@ -847,13 +874,12 @@
* Only the values that we read from the RTC are set. That
* means only tm_hour, tm_min, and tm_sec.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);
alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);
ctrl = CMOS_READ(RTC_CONTROL);
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
@@ -873,19 +899,18 @@
* meddles with the interrupt enable/disable bits.
*/
-void mask_rtc_irq_bit(unsigned char bit)
+static void mask_rtc_irq_bit(unsigned char bit)
{
unsigned char val;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
val = CMOS_READ(RTC_CONTROL);
val &= ~bit;
CMOS_WRITE(val, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
- restore_flags(flags);
rtc_irq_data = 0;
+ spin_unlock_irqrestore(&rtc_lock, flags);
}
static void set_rtc_irq_bit(unsigned char bit)
@@ -893,12 +918,11 @@
unsigned char val;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&rtc_lock, flags);
val = CMOS_READ(RTC_CONTROL);
val |= bit;
CMOS_WRITE(val, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
rtc_irq_data = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)